commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From er...@apache.org
Subject svn commit: r1099771 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math/exception/ main/java/org/apache/commons/math/exception/util/ test/java/org/apache/commons/math/exception/util/
Date Thu, 05 May 2011 12:37:31 GMT
Author: erans
Date: Thu May  5 12:37:31 2011
New Revision: 1099771

URL: http://svn.apache.org/viewvc?rev=1099771&view=rev
Log:
MATH-566
Created "ExceptionContext" class.
Made "MathIllegalArgumentException" inherit from the Java standard
"IllegalArgumentException".

Added:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContext.java
  (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContextProvider.java
  (with props)
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/util/ExceptionContextTest.java
  (with props)
Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathIllegalArgumentException.java

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathIllegalArgumentException.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathIllegalArgumentException.java?rev=1099771&r1=1099770&r2=1099771&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathIllegalArgumentException.java
(original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathIllegalArgumentException.java
Thu May  5 12:37:31 2011
@@ -17,20 +17,24 @@
 package org.apache.commons.math.exception;
 
 import org.apache.commons.math.exception.util.Localizable;
+import org.apache.commons.math.exception.util.ExceptionContext;
+import org.apache.commons.math.exception.util.ExceptionContextProvider;
 
 /**
  * Base class for all preconditions violation exceptions.
  * In most cases, this class should not be instantiated directly: it should
- * serve as a base class to create all the exceptions that share the semantics
- * of the standard {@link IllegalArgumentException}, but must also provide a
- * localized message.
+ * serve as a base class to create all the exceptions that have the semantics
+ * of the standard {@link IllegalArgumentException}.
  *
  * @since 2.2
  * @version $Revision$ $Date$
  */
-public class MathIllegalArgumentException extends MathRuntimeException {
+public class MathIllegalArgumentException extends IllegalArgumentException
+    implements ExceptionContextProvider {
     /** Serializable version Id. */
     private static final long serialVersionUID = -6024911025449780478L;
+    /** Context. */
+    private final ExceptionContext context = new ExceptionContext();
 
     /**
      * @param pattern Message pattern explaining the cause of the error.
@@ -38,6 +42,23 @@ public class MathIllegalArgumentExceptio
      */
     public MathIllegalArgumentException(Localizable pattern,
                                         Object ... args) {
-        addMessage(pattern, args);
+        context.addMessage(pattern, args);
+    }
+
+    /** {@inheritDoc} */
+    public ExceptionContext getContext() {
+        return context;
+    }
+
+   /** {@inheritDoc} */
+    @Override
+    public String getMessage() {
+        return context.getMessage();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getLocalizedMessage() {
+        return context.getLocalizedMessage();
     }
 }

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContext.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContext.java?rev=1099771&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContext.java
(added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContext.java
Thu May  5 12:37:31 2011
@@ -0,0 +1,312 @@
+/*
+ * 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.math.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
+ * @version $Id$
+ */
+public class ExceptionContext implements Serializable {
+    /** Serializable version Id. */
+    private static final long serialVersionUID = -6024911025449780478L;
+    /**
+     * Various informations that enrich the informative message.
+     */
+    private List<Localizable> msgPatterns = new ArrayList<Localizable>();
+    /**
+     * Various informations that enrich the informative message.
+     * The arguments will replace the corresponding place-holders in
+     * {@link #msgPatterns}.
+     */
+    private List<Object[]> msgArguments = new ArrayList<Object[]>();
+    /**
+     * Arbitrary context information.
+     */
+    private Map<String, Object> context = new HashMap<String, Object>();
+
+    /**
+     * Sets 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 {
+        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 {
+        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<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 {@link #context}.
+     *
+     * @param out Stream.
+     * @throws IOException This should never happen.
+     */
+    private void serializeContext(ObjectOutputStream out)
+        throws IOException {
+        // Step 1.
+        final int len = context.keySet().size();
+        out.writeInt(len);
+        for (String key : context.keySet()) {
+            // Step 2.
+            out.writeObject(key);
+            final Object value = context.get(key);
+            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<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.
+     *
+     * @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() + "]";
+    }
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContextProvider.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContextProvider.java?rev=1099771&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContextProvider.java
(added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContextProvider.java
Thu May  5 12:37:31 2011
@@ -0,0 +1,33 @@
+/*
+ * 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.math.exception.util;
+
+/**
+ * Interface for accessing the context data structure stored in Commons Math
+ * exceptions.
+ *
+ * @version $Id$
+ */
+public interface ExceptionContextProvider {
+    /**
+     * Gets a reference to the "rich context" data structure that allows to
+     * customize error messages and store key, value pairs in exceptions.
+     *
+     * @return a reference to the exception context.
+     */
+    ExceptionContext getContext();
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/util/ExceptionContextProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/util/ExceptionContextTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/util/ExceptionContextTest.java?rev=1099771&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/util/ExceptionContextTest.java
(added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/util/ExceptionContextTest.java
Thu May  5 12:37:31 2011
@@ -0,0 +1,133 @@
+/*
+ * 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.math.exception.util;
+
+import java.util.Locale;
+import java.util.Arrays;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test for {@link ExceptionContext}.
+ * 
+ * @version $Id$
+ */
+public class ExceptionContextTest {
+    @Test
+    public void testMessageChain() {
+        final ExceptionContext c = new ExceptionContext();
+        final String sep = " | "; // Non-default separator.
+        final String m1 = "column index (0)";
+        c.addMessage(LocalizedFormats.COLUMN_INDEX, 0);
+        final String m2 = "got 1x2 but expected 3x4";
+        c.addMessage(LocalizedFormats.DIMENSIONS_MISMATCH_2x2, 1, 2, 3, 4);
+        final String m3 = "It didn't work out";
+        c.addMessage(LocalizedFormats.SIMPLE_MESSAGE, m3);
+
+        Assert.assertEquals(c.getMessage(Locale.US, sep),
+                            m1 + sep + m2 + sep + m3);
+    }
+
+    @Test
+    public void testNoArgAddMessage() {
+        final ExceptionContext c = new ExceptionContext();
+        c.addMessage(LocalizedFormats.SIMPLE_MESSAGE);
+        Assert.assertEquals(c.getMessage(), "{0}");
+    }
+
+    @Test
+    public void testContext() {
+        final ExceptionContext c = new ExceptionContext();
+
+        final String[] keys = {"Key 1", "Key 2"};
+        final Object[] values = {"Value 1", Integer.valueOf(2)};
+
+        for (int i = 0; i < keys.length; i++) {
+            c.setValue(keys[i], values[i]);
+        }
+
+        // Check that all keys are present.
+        Assert.assertTrue(c.getKeys().containsAll(Arrays.asList(keys)));
+
+        // Check that all values are correctly stored.
+        for (int i = 0; i < keys.length; i++) {
+            Assert.assertEquals(values[i], c.getValue(keys[i]));
+        }
+
+        // Check behaviour on missing key.
+        Assert.assertNull(c.getValue("xyz"));
+    }
+
+    @Test
+    public void testSerialize()
+        throws IOException,
+               ClassNotFoundException {
+        final ExceptionContext cOut = new ExceptionContext();
+        cOut.addMessage(LocalizedFormats.COLUMN_INDEX, 0);
+        cOut.setValue("Key 1", Integer.valueOf(0));
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(cOut);
+
+        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+        ObjectInputStream ois = new ObjectInputStream(bis);
+        ExceptionContext cIn = (ExceptionContext) ois.readObject();
+
+        Assert.assertTrue(cOut.getMessage().equals(cIn.getMessage()));
+        for (String key : cIn.getKeys()) {
+            Assert.assertTrue(cOut.getValue(key).equals(cIn.getValue(key)));
+        }
+    }
+
+    @Test
+    public void testSerializeUnserializable() {
+        final ExceptionContext cOut = new ExceptionContext();
+        cOut.addMessage(LocalizedFormats.SIMPLE_MESSAGE, "OK");
+        cOut.addMessage(LocalizedFormats.SIMPLE_MESSAGE, new Unserializable());
+        String key = "Key 1";
+        cOut.setValue(key, new Unserializable());
+
+        try {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(bos);
+            oos.writeObject(cOut);
+
+            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+            ObjectInputStream ois = new ObjectInputStream(bis);
+            ExceptionContext cIn = (ExceptionContext) ois.readObject();
+
+            String nsObjStr = (String) cIn.getValue(key);
+            Assert.assertTrue(nsObjStr.matches(".*could not be serialized.*"));
+        } catch (Exception e) {
+            Assert.fail(e.toString());
+        }
+    }
+
+    /**
+     * Class used by {@link #testSerializeUnserializable()}.
+     */
+    private static class Unserializable {
+        Unserializable() {}
+    }
+}

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/util/ExceptionContextTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message