ExceptionContext.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.math4.legacy.exception.util;
- import java.util.List;
- import java.util.ArrayList;
- import java.util.Set;
- import java.util.Map;
- import java.io.IOException;
- import java.io.Serializable;
- import java.io.ObjectOutputStream;
- import java.io.ObjectInputStream;
- import java.util.HashMap;
- import java.text.MessageFormat;
- import java.util.Locale;
- /**
- * Class that contains the actual implementation of the functionality mandated
- * by the {@link ExceptionContext} interface.
- * All Commons Math exceptions delegate the interface's methods to this class.
- *
- * @since 3.0
- */
- public class ExceptionContext implements Serializable {
- /** Serializable version Id. */
- private static final long serialVersionUID = -6024911025449780478L;
- /**
- * The throwable to which this context refers to.
- */
- private Throwable throwable;
- /**
- * Various informations that enrich the informative message.
- */
- private List<Localizable> msgPatterns;
- /**
- * Various informations that enrich the informative message.
- * The arguments will replace the corresponding place-holders in
- * {@link #msgPatterns}.
- */
- private List<Object[]> msgArguments;
- /**
- * Arbitrary context information.
- */
- private Map<String, Object> context;
- /** Simple constructor.
- * @param throwable the exception this context refers too
- */
- public ExceptionContext(final Throwable throwable) {
- this.throwable = throwable;
- msgPatterns = new ArrayList<>();
- msgArguments = new ArrayList<>();
- context = new HashMap<>();
- }
- /** Get a reference to the exception to which the context relates.
- * @return a reference to the exception to which the context relates
- */
- public Throwable getThrowable() {
- return throwable;
- }
- /**
- * Adds a message.
- *
- * @param pattern Message pattern.
- * @param arguments Values for replacing the placeholders in the message
- * pattern.
- */
- public void addMessage(Localizable pattern,
- Object... arguments) {
- msgPatterns.add(pattern);
- msgArguments.add(ArgUtils.flatten(arguments));
- }
- /**
- * Sets the context (key, value) pair.
- * Keys are assumed to be unique within an instance. If the same key is
- * assigned a new value, the previous one will be lost.
- *
- * @param key Context key (not null).
- * @param value Context value.
- */
- public void setValue(String key, Object value) {
- context.put(key, value);
- }
- /**
- * Gets the value associated to the given context key.
- *
- * @param key Context key.
- * @return the context value or {@code null} if the key does not exist.
- */
- public Object getValue(String key) {
- return context.get(key);
- }
- /**
- * Gets all the keys stored in the exception.
- *
- * @return the set of keys.
- */
- public Set<String> getKeys() {
- return context.keySet();
- }
- /**
- * Gets the default message.
- *
- * @return the message.
- */
- public String getMessage() {
- return getMessage(Locale.US);
- }
- /**
- * Gets the message in the default locale.
- *
- * @return the localized message.
- */
- public String getLocalizedMessage() {
- return getMessage(Locale.getDefault());
- }
- /**
- * Gets the message in a specified locale.
- *
- * @param locale Locale in which the message should be translated.
- * @return the localized message.
- */
- public String getMessage(final Locale locale) {
- return buildMessage(locale, ": ");
- }
- /**
- * Gets the message in a specified locale.
- *
- * @param locale Locale in which the message should be translated.
- * @param separator Separator inserted between the message parts.
- * @return the localized message.
- */
- public String getMessage(final Locale locale,
- final String separator) {
- return buildMessage(locale, separator);
- }
- /**
- * Builds a message string.
- *
- * @param locale Locale in which the message should be translated.
- * @param separator Message separator.
- * @return a localized message string.
- */
- private String buildMessage(Locale locale,
- String separator) {
- final StringBuilder sb = new StringBuilder();
- int count = 0;
- final int len = msgPatterns.size();
- for (int i = 0; i < len; i++) {
- final Localizable pat = msgPatterns.get(i);
- final Object[] args = msgArguments.get(i);
- final MessageFormat fmt = new MessageFormat(pat.getLocalizedString(locale),
- locale);
- sb.append(fmt.format(args));
- if (++count < len) {
- // Add a separator if there are other messages.
- sb.append(separator);
- }
- }
- return sb.toString();
- }
- /**
- * Serialize this object to the given stream.
- *
- * @param out Stream.
- * @throws IOException This should never happen.
- */
- private void writeObject(ObjectOutputStream out)
- throws IOException {
- out.writeObject(throwable);
- serializeMessages(out);
- serializeContext(out);
- }
- /**
- * Deserialize this object from the given stream.
- *
- * @param in Stream.
- * @throws IOException This should never happen.
- * @throws ClassNotFoundException This should never happen.
- */
- private void readObject(ObjectInputStream in)
- throws IOException,
- ClassNotFoundException {
- throwable = (Throwable) in.readObject();
- deSerializeMessages(in);
- deSerializeContext(in);
- }
- /**
- * Serialize {@link #msgPatterns} and {@link #msgArguments}.
- *
- * @param out Stream.
- * @throws IOException This should never happen.
- */
- private void serializeMessages(ObjectOutputStream out)
- throws IOException {
- // Step 1.
- final int len = msgPatterns.size();
- out.writeInt(len);
- // Step 2.
- for (int i = 0; i < len; i++) {
- final Localizable pat = msgPatterns.get(i);
- // Step 3.
- out.writeObject(pat);
- final Object[] args = msgArguments.get(i);
- final int aLen = args.length;
- // Step 4.
- out.writeInt(aLen);
- for (int j = 0; j < aLen; j++) {
- if (args[j] instanceof Serializable) {
- // Step 5a.
- out.writeObject(args[j]);
- } else {
- // Step 5b.
- out.writeObject(nonSerializableReplacement(args[j]));
- }
- }
- }
- }
- /**
- * Deserialize {@link #msgPatterns} and {@link #msgArguments}.
- *
- * @param in Stream.
- * @throws IOException This should never happen.
- * @throws ClassNotFoundException This should never happen.
- */
- private void deSerializeMessages(ObjectInputStream in)
- throws IOException,
- ClassNotFoundException {
- // Step 1.
- final int len = in.readInt();
- msgPatterns = new ArrayList<>(len);
- msgArguments = new ArrayList<>(len);
- // Step 2.
- for (int i = 0; i < len; i++) {
- // Step 3.
- final Localizable pat = (Localizable) in.readObject();
- msgPatterns.add(pat);
- // Step 4.
- final int aLen = in.readInt();
- final Object[] args = new Object[aLen];
- for (int j = 0; j < aLen; j++) {
- // Step 5.
- args[j] = in.readObject();
- }
- msgArguments.add(args);
- }
- }
- /**
- * Serialize {@link #context}.
- *
- * @param out Stream.
- * @throws IOException This should never happen.
- */
- private void serializeContext(ObjectOutputStream out)
- throws IOException {
- // Step 1.
- final int len = context.size();
- out.writeInt(len);
- for (Map.Entry<String, Object> entry : context.entrySet()) {
- // Step 2.
- out.writeObject(entry.getKey());
- final Object value = entry.getValue();
- if (value instanceof Serializable) {
- // Step 3a.
- out.writeObject(value);
- } else {
- // Step 3b.
- out.writeObject(nonSerializableReplacement(value));
- }
- }
- }
- /**
- * Deserialize {@link #context}.
- *
- * @param in Stream.
- * @throws IOException This should never happen.
- * @throws ClassNotFoundException This should never happen.
- */
- private void deSerializeContext(ObjectInputStream in)
- throws IOException,
- ClassNotFoundException {
- // Step 1.
- final int len = in.readInt();
- context = new HashMap<>();
- for (int i = 0; i < len; i++) {
- // Step 2.
- final String key = (String) in.readObject();
- // Step 3.
- final Object value = in.readObject();
- context.put(key, value);
- }
- }
- /**
- * Replaces a non-serializable object with an error message string.
- *
- * @param obj Object that does not implement the {@code Serializable}
- * interface.
- * @return a string that mentions which class could not be serialized.
- */
- private static String nonSerializableReplacement(Object obj) {
- return "[Object could not be serialized: " + obj.getClass().getName() + "]";
- }
- }