1 /*
2  * Copyright 2006-2013 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.springframework.classify;
17
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.Map;
21
22 /**
23  * A {@link Classifier} for exceptions that has only two classes (true and
24  * false). Classifies objects according to their inheritance relation with the
25  * supplied types. If the object to be classified is one of the provided types,
26  * or is a subclass of one of the types, then the non-default value is returned
27  * (usually true).
28  *
29  * @see SubclassClassifier
30  *
31  * @author Dave Syer
32  * @author Gary Russell
33  *
34  */

35 @SuppressWarnings("serial")
36 public class BinaryExceptionClassifier extends SubclassClassifier<Throwable, Boolean> {
37
38     private boolean traverseCauses;
39
40     /**
41      * Create a binary exception classifier with the provided default value.
42      *
43      * @param defaultValue defaults to false
44      */

45     public BinaryExceptionClassifier(boolean defaultValue) {
46         super(defaultValue);
47     }
48
49     /**
50      * Create a binary exception classifier with the provided classes and their
51      * subclasses. The mapped value for these exceptions will be the one
52      * provided (which will be the opposite of the default).
53      *
54      * @param exceptionClasses the exceptions to classify among
55      * @param value the value to classify
56      */

57     public BinaryExceptionClassifier(Collection<Class<? extends Throwable>> exceptionClasses, boolean value) {
58         this(!value);
59         if (exceptionClasses != null) {
60             Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>();
61             for (Class<? extends Throwable> type : exceptionClasses) {
62                 map.put(type, !getDefault());
63             }
64             setTypeMap(map);
65         }
66     }
67
68     /**
69      * Create a binary exception classifier with the default value false and
70      * value mapping true for the provided classes and their subclasses.
71      *
72      * @param exceptionClasses the exception types to throw
73      */

74     public BinaryExceptionClassifier(Collection<Class<? extends Throwable>> exceptionClasses) {
75         this(exceptionClasses, true);
76     }
77
78     /**
79      * Create a binary exception classifier using the given classification map
80      * and a default classification of false.
81      * @param typeMap the map of types
82      */

83     public BinaryExceptionClassifier(Map<Class<? extends Throwable>, Boolean> typeMap) {
84         this(typeMap, false);
85     }
86
87     /**
88      * Create a binary exception classifier using the given classification map
89      * and a default classification of false.
90      *
91      * @param defaultValue the default value to use
92      * @param typeMap the map of types to classify
93      */

94     public BinaryExceptionClassifier(Map<Class<? extends Throwable>, Boolean> typeMap, boolean defaultValue) {
95         super(typeMap, defaultValue);
96     }
97
98
99     public void setTraverseCauses(boolean traverseCauses) {
100         this.traverseCauses = traverseCauses;
101     }
102
103     @Override
104     public Boolean classify(Throwable classifiable) {
105         Boolean classified = super.classify(classifiable);
106         if (!this.traverseCauses) {
107             return classified;
108         }
109
110         /*
111          * If the result is the default, we need to find out if it was by default
112          * or so configured; if defaulttry the cause(es).
113          */

114         if (classified.equals(this.getDefault())) {
115             Throwable cause = classifiable;
116             do {
117                 if (this.getClassified().containsKey(cause.getClass())) {
118                     return classified; // non-default classification
119                 }
120                 cause = cause.getCause();
121                 classified = super.classify(cause);
122             }
123             while (cause != null && classified.equals(this.getDefault()));
124         }
125
126         return classified;
127     }
128
129 }
130