001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.lang3.exception;
018    
019    import java.io.Serializable;
020    import java.util.ArrayList;
021    import java.util.HashSet;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Set;
025    
026    import org.apache.commons.lang3.StringUtils;
027    import org.apache.commons.lang3.tuple.ImmutablePair;
028    import org.apache.commons.lang3.tuple.Pair;
029    
030    /**
031     * Default implementation of the context storing the label-value pairs for contexted exceptions.
032     * <p>
033     * This implementation is serializable, however this is dependent on the values that
034     * are added also being serializable.
035     * </p>
036     * 
037     * @see ContextedException
038     * @see ContextedRuntimeException
039     * @since 3.0
040     */
041    public class DefaultExceptionContext implements ExceptionContext, Serializable {
042    
043        /** The serialization version. */
044        private static final long serialVersionUID = 20110706L;
045    
046        /** The list storing the label-data pairs. */
047        private final List<Pair<String, Object>> contextValues = new ArrayList<Pair<String,Object>>();
048    
049        /**
050         * {@inheritDoc}
051         */
052        public DefaultExceptionContext addContextValue(String label, Object value) {
053            contextValues.add(new ImmutablePair<String, Object>(label, value));
054            return this;
055        }
056    
057        /**
058         * {@inheritDoc}
059         */
060        public DefaultExceptionContext setContextValue(String label, Object value) {
061            for (final Iterator<Pair<String, Object>> iter = contextValues.iterator(); iter.hasNext();) {
062                final Pair<String, Object> p = iter.next();
063                if (StringUtils.equals(label, p.getKey())) {
064                    iter.remove();
065                }
066            }
067            addContextValue(label, value);
068            return this;
069        }
070    
071        /**
072         * {@inheritDoc}
073         */
074        public List<Object> getContextValues(String label) {
075            final List<Object> values = new ArrayList<Object>();
076            for (final Pair<String, Object> pair : contextValues) {
077                if (StringUtils.equals(label, pair.getKey())) {
078                    values.add(pair.getValue());
079                }
080            }
081            return values;
082        }
083    
084        /**
085         * {@inheritDoc}
086         */
087        public Object getFirstContextValue(String label) {
088            for (final Pair<String, Object> pair : contextValues) {
089                if (StringUtils.equals(label, pair.getKey())) {
090                    return pair.getValue();
091                }
092            }
093            return null;
094        }
095    
096        /**
097         * {@inheritDoc}
098         */
099        public Set<String> getContextLabels() {
100            final Set<String> labels = new HashSet<String>();
101            for (final Pair<String, Object> pair : contextValues) {
102                labels.add(pair.getKey());
103            }
104            return labels;
105        }
106    
107        /**
108         * {@inheritDoc}
109         */
110        public List<Pair<String, Object>> getContextEntries() {
111            return contextValues;
112        }
113    
114        /**
115         * Builds the message containing the contextual information.
116         * 
117         * @param baseMessage  the base exception message <b>without</b> context information appended
118         * @return the exception message <b>with</b> context information appended, never null
119         */
120        public String getFormattedExceptionMessage(String baseMessage){
121            StringBuilder buffer = new StringBuilder(256);
122            if (baseMessage != null) {
123                buffer.append(baseMessage);
124            }
125            
126            if (contextValues.size() > 0) {
127                if (buffer.length() > 0) {
128                    buffer.append('\n');
129                }
130                buffer.append("Exception Context:\n");
131                
132                int i = 0;
133                for (final Pair<String, Object> pair : contextValues) {
134                    buffer.append("\t[");
135                    buffer.append(++i);
136                    buffer.append(':');
137                    buffer.append(pair.getKey());
138                    buffer.append("=");
139                    final Object value = pair.getValue();
140                    if (value == null) {
141                        buffer.append("null");
142                    } else {
143                        String valueStr;
144                        try {
145                            valueStr = value.toString();
146                        } catch (Exception e) {
147                            valueStr = "Exception thrown on toString(): " + ExceptionUtils.getStackTrace(e);
148                        }
149                        buffer.append(valueStr);
150                    }
151                    buffer.append("]\n");
152                }
153                buffer.append("---------------------------------");
154            }
155            return buffer.toString();
156        }
157    
158    }