1 /*
2 * Copyright 2005-2010 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 * http://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
17 package org.springframework.ws.soap.server.endpoint;
18
19 import java.util.LinkedHashMap;
20 import java.util.Map;
21 import java.util.Properties;
22
23 import org.springframework.util.CollectionUtils;
24
25 /**
26 * Exception resolver that allows for mapping exception class names to SOAP Faults. The mappings are set using the
27 * <code>exceptionMappings</code> property, the format of which is documented in {@link SoapFaultDefinitionEditor}.
28 *
29 * @author Arjen Poutsma
30 * @since 1.0.0
31 */
32 public class SoapFaultMappingExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver {
33
34 private Map<String, String> exceptionMappings = new LinkedHashMap<String, String>();
35
36 /**
37 * Set the mappings between exception class names and SOAP Faults. The exception class name can be a substring, with
38 * no wildcard support at present.
39 * <p/>
40 * The values of the given properties object should use the format described in
41 * <code>SoapFaultDefinitionEditor</code>.
42 * <p/>
43 * Follows the same matching algorithm as <code>SimpleMappingExceptionResolver</code>.
44 *
45 * @param mappings exception patterns (can also be fully qualified class names) as keys, fault definition texts as
46 * values
47 * @see SoapFaultDefinitionEditor
48 */
49 public void setExceptionMappings(Properties mappings) {
50 for (Map.Entry<Object, Object> entry : mappings.entrySet()) {
51 if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
52 exceptionMappings.put((String)entry.getKey(), (String)entry.getValue());
53 }
54 }
55 }
56
57 @Override
58 protected SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) {
59 if (!CollectionUtils.isEmpty(exceptionMappings)) {
60 String definitionText = null;
61 int deepest = Integer.MAX_VALUE;
62 for (String exceptionMapping : exceptionMappings.keySet()) {
63 int depth = getDepth(exceptionMapping, ex);
64 if (depth >= 0 && depth < deepest) {
65 deepest = depth;
66 definitionText = exceptionMappings.get(exceptionMapping);
67 }
68 }
69 if (definitionText != null) {
70 SoapFaultDefinitionEditor editor = new SoapFaultDefinitionEditor();
71 editor.setAsText(definitionText);
72 return (SoapFaultDefinition) editor.getValue();
73 }
74 }
75 return null;
76 }
77
78 /**
79 * Return the depth to the superclass matching. <code>0</code> means ex matches exactly. Returns <code>-1</code> if
80 * there's no match. Otherwise, returns depth. Lowest depth wins.
81 * <p/>
82 * Follows the same algorithm as RollbackRuleAttribute, and SimpleMappingExceptionResolver
83 */
84 protected int getDepth(String exceptionMapping, Exception ex) {
85 return getDepth(exceptionMapping, ex.getClass(), 0);
86 }
87
88 @SuppressWarnings("unchecked")
89 private int getDepth(String exceptionMapping, Class<? extends Exception> exceptionClass, int depth) {
90 if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
91 return depth;
92 }
93 if (exceptionClass.equals(Throwable.class)) {
94 return -1;
95 }
96 return getDepth(exceptionMapping, (Class<? extends Exception>) exceptionClass.getSuperclass(), depth + 1);
97 }
98
99 }