• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.List;
22 import java.util.Set;
23 import java.util.stream.Collectors;
24 import java.util.stream.Stream;
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<>();
48 
49     /**
50      * {@inheritDoc}
51      */
52     @Override
addContextValue(final String label, final Object value)53     public DefaultExceptionContext addContextValue(final String label, final Object value) {
54         contextValues.add(new ImmutablePair<>(label, value));
55         return this;
56     }
57 
58     /**
59      * {@inheritDoc}
60      */
61     @Override
getContextEntries()62     public List<Pair<String, Object>> getContextEntries() {
63         return contextValues;
64     }
65 
66     /**
67      * {@inheritDoc}
68      */
69     @Override
getContextLabels()70     public Set<String> getContextLabels() {
71         return stream().map(Pair::getKey).collect(Collectors.toSet());
72     }
73 
74     /**
75      * {@inheritDoc}
76      */
77     @Override
getContextValues(final String label)78     public List<Object> getContextValues(final String label) {
79         return stream().filter(pair -> StringUtils.equals(label, pair.getKey())).map(Pair::getValue).collect(Collectors.toList());
80     }
81 
82     /**
83      * {@inheritDoc}
84      */
85     @Override
getFirstContextValue(final String label)86     public Object getFirstContextValue(final String label) {
87         return stream().filter(pair -> StringUtils.equals(label, pair.getKey())).findFirst().map(Pair::getValue).orElse(null);
88     }
89 
90     /**
91      * Builds the message containing the contextual information.
92      *
93      * @param baseMessage  the base exception message <b>without</b> context information appended
94      * @return the exception message <b>with</b> context information appended, never null
95      */
96     @Override
getFormattedExceptionMessage(final String baseMessage)97     public String getFormattedExceptionMessage(final String baseMessage) {
98         final StringBuilder buffer = new StringBuilder(256);
99         if (baseMessage != null) {
100             buffer.append(baseMessage);
101         }
102 
103         if (!contextValues.isEmpty()) {
104             if (buffer.length() > 0) {
105                 buffer.append('\n');
106             }
107             buffer.append("Exception Context:\n");
108 
109             int i = 0;
110             for (final Pair<String, Object> pair : contextValues) {
111                 buffer.append("\t[");
112                 buffer.append(++i);
113                 buffer.append(':');
114                 buffer.append(pair.getKey());
115                 buffer.append("=");
116                 final Object value = pair.getValue();
117                 if (value == null) {
118                     buffer.append("null");
119                 } else {
120                     String valueStr;
121                     try {
122                         valueStr = value.toString();
123                     } catch (final Exception e) {
124                         valueStr = "Exception thrown on toString(): " + ExceptionUtils.getStackTrace(e);
125                     }
126                     buffer.append(valueStr);
127                 }
128                 buffer.append("]\n");
129             }
130             buffer.append("---------------------------------");
131         }
132         return buffer.toString();
133     }
134 
135     /**
136      * {@inheritDoc}
137      */
138     @Override
setContextValue(final String label, final Object value)139     public DefaultExceptionContext setContextValue(final String label, final Object value) {
140         contextValues.removeIf(p -> StringUtils.equals(label, p.getKey()));
141         addContextValue(label, value);
142         return this;
143     }
144 
stream()145     private Stream<Pair<String, Object>> stream() {
146         return contextValues.stream();
147     }
148 
149 }
150