View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.exception;
18  
19  import java.io.Serializable;
20  import java.util.ArrayList;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Set;
25  
26  import org.apache.commons.lang3.StringUtils;
27  import org.apache.commons.lang3.tuple.ImmutablePair;
28  import org.apache.commons.lang3.tuple.Pair;
29  
30  /**
31   * Default implementation of the context storing the label-value pairs for contexted exceptions.
32   * <p>
33   * This implementation is serializable, however this is dependent on the values that
34   * are added also being serializable.
35   * </p>
36   * 
37   * @see ContextedException
38   * @see ContextedRuntimeException
39   * @since 3.0
40   */
41  public class DefaultExceptionContext implements ExceptionContext, Serializable {
42  
43      /** The serialization version. */
44      private static final long serialVersionUID = 20110706L;
45  
46      /** The list storing the label-data pairs. */
47      private final List<Pair<String, Object>> contextValues = new ArrayList<Pair<String,Object>>();
48  
49      /**
50       * {@inheritDoc}
51       */
52      @Override
53      public DefaultExceptionContext addContextValue(final String label, final Object value) {
54          contextValues.add(new ImmutablePair<String, Object>(label, value));
55          return this;
56      }
57  
58      /**
59       * {@inheritDoc}
60       */
61      @Override
62      public DefaultExceptionContext setContextValue(final String label, final Object value) {
63          for (final Iterator<Pair<String, Object>> iter = contextValues.iterator(); iter.hasNext();) {
64              final Pair<String, Object> p = iter.next();
65              if (StringUtils.equals(label, p.getKey())) {
66                  iter.remove();
67              }
68          }
69          addContextValue(label, value);
70          return this;
71      }
72  
73      /**
74       * {@inheritDoc}
75       */
76      @Override
77      public List<Object> getContextValues(final String label) {
78          final List<Object> values = new ArrayList<Object>();
79          for (final Pair<String, Object> pair : contextValues) {
80              if (StringUtils.equals(label, pair.getKey())) {
81                  values.add(pair.getValue());
82              }
83          }
84          return values;
85      }
86  
87      /**
88       * {@inheritDoc}
89       */
90      @Override
91      public Object getFirstContextValue(final String label) {
92          for (final Pair<String, Object> pair : contextValues) {
93              if (StringUtils.equals(label, pair.getKey())) {
94                  return pair.getValue();
95              }
96          }
97          return null;
98      }
99  
100     /**
101      * {@inheritDoc}
102      */
103     @Override
104     public Set<String> getContextLabels() {
105         final Set<String> labels = new HashSet<String>();
106         for (final Pair<String, Object> pair : contextValues) {
107             labels.add(pair.getKey());
108         }
109         return labels;
110     }
111 
112     /**
113      * {@inheritDoc}
114      */
115     @Override
116     public List<Pair<String, Object>> getContextEntries() {
117         return contextValues;
118     }
119 
120     /**
121      * Builds the message containing the contextual information.
122      * 
123      * @param baseMessage  the base exception message <b>without</b> context information appended
124      * @return the exception message <b>with</b> context information appended, never null
125      */
126     @Override
127     public String getFormattedExceptionMessage(final String baseMessage){
128         final StringBuilder buffer = new StringBuilder(256);
129         if (baseMessage != null) {
130             buffer.append(baseMessage);
131         }
132         
133         if (contextValues.size() > 0) {
134             if (buffer.length() > 0) {
135                 buffer.append('\n');
136             }
137             buffer.append("Exception Context:\n");
138             
139             int i = 0;
140             for (final Pair<String, Object> pair : contextValues) {
141                 buffer.append("\t[");
142                 buffer.append(++i);
143                 buffer.append(':');
144                 buffer.append(pair.getKey());
145                 buffer.append("=");
146                 final Object value = pair.getValue();
147                 if (value == null) {
148                     buffer.append("null");
149                 } else {
150                     String valueStr;
151                     try {
152                         valueStr = value.toString();
153                     } catch (final Exception e) {
154                         valueStr = "Exception thrown on toString(): " + ExceptionUtils.getStackTrace(e);
155                     }
156                     buffer.append(valueStr);
157                 }
158                 buffer.append("]\n");
159             }
160             buffer.append("---------------------------------");
161         }
162         return buffer.toString();
163     }
164 
165 }