/*
 * 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.math3.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 ExceptionContext interface. All Commons Math exceptions delegate the interface's methods to this class.
Since:3.0
/** * 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.
/** Serializable version Id. */
private static final long serialVersionUID = -6024911025449780478L;
The throwable to which this context refers to.
/** * The throwable to which this context refers to. */
private Throwable throwable;
Various informations that enrich the informative message.
/** * 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 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.
/** * Arbitrary context information. */
private Map<String, Object> context;
Simple constructor.
Params:
  • throwable – the exception this context refers too
/** Simple constructor. * @param throwable the exception this context refers too */
public ExceptionContext(final Throwable throwable) { this.throwable = throwable; msgPatterns = new ArrayList<Localizable>(); msgArguments = new ArrayList<Object[]>(); context = new HashMap<String, Object>(); }
Get a reference to the exception to which the context relates.
Returns:a reference to the exception to which the context relates
/** 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.
Params:
  • pattern – Message pattern.
  • arguments – Values for replacing the placeholders in the message pattern.
/** * 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.
Params:
  • key – Context key (not null).
  • value – Context value.
/** * 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.
Params:
  • key – Context key.
Returns:the context value or null if the key does not exist.
/** * 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
Returns:the set of keys.
/** * Gets all the keys stored in the exception * * @return the set of keys. */
public Set<String> getKeys() { return context.keySet(); }
Gets the default message.
Returns:the message.
/** * Gets the default message. * * @return the message. */
public String getMessage() { return getMessage(Locale.US); }
Gets the message in the default locale.
Returns:the localized message.
/** * 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.
Params:
  • locale – Locale in which the message should be translated.
Returns:the localized message.
/** * 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.
Params:
  • locale – Locale in which the message should be translated.
  • separator – Separator inserted between the message parts.
Returns:the localized message.
/** * 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.
Params:
  • locale – Locale in which the message should be translated.
  • separator – Message separator.
Returns:a localized message string.
/** * 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.
Params:
  • out – Stream.
Throws:
/** * 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.
Params:
  • in – Stream.
Throws:
/** * 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 msgPatterns and msgArguments.
Params:
  • out – Stream.
Throws:
/** * 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 msgPatterns and msgArguments.
Params:
  • in – Stream.
Throws:
/** * 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<Localizable>(len); msgArguments = new ArrayList<Object[]>(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 context.
Params:
  • out – Stream.
Throws:
/** * 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 context.
Params:
  • in – Stream.
Throws:
/** * 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<String, Object>(); 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.
Params:
  • obj – Object that does not implement the Serializable interface.
Returns:a string that mentions which class could not be serialized.
/** * 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 String nonSerializableReplacement(Object obj) { return "[Object could not be serialized: " + obj.getClass().getName() + "]"; } }