f07d42e5f7bc24075fb2926a16cb6659f7e9b10f
[SpringWebServicesForFun/.git] /
1 package de.spring.webservices.endpoints;
2
3 import java.io.PrintWriter;
4 import java.io.StringWriter;
5 import java.util.LinkedHashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Properties;
9
10 import javax.xml.transform.Result;
11
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14 import org.springframework.oxm.Marshaller;
15 import org.springframework.util.CollectionUtils;
16 import org.springframework.ws.soap.SoapFault;
17 import org.springframework.ws.soap.SoapFaultDetail;
18 import org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver;
19 import org.springframework.ws.soap.server.endpoint.SoapFaultDefinition;
20 import org.springframework.ws.soap.server.endpoint.SoapFaultDefinitionEditor;
21
22 import de.spring.webservices.auto.Element;
23 import de.spring.webservices.auto.ExampleFault;
24 import de.spring.webservices.exceptions.CustomBusinessException;
25
26 public class MyCustomMappingExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver {
27         private static final Logger LOGGER = LoggerFactory.getLogger(MyCustomMappingExceptionResolver.class);
28         
29         private Marshaller marshaller;
30
31         private Map<String, String> exceptionMappings = new LinkedHashMap<>();
32
33         /**
34          * Set the mappings between exception class names and SOAP Faults. The exception class name can be a substring, with
35          * no wildcard support at present.
36          *
37          * <p>The values of the given properties object should use the format described in
38          * {@code SoapFaultDefinitionEditor}.
39          *
40          * <p>Follows the same matching algorithm as {@code SimpleMappingExceptionResolver}.
41          *
42          * @param mappings exception patterns (can also be fully qualified class names) as keys, fault definition texts as
43          *                                 values
44          * @see SoapFaultDefinitionEditor
45          */
46         public void setExceptionMappings(Properties mappings) {
47                 for (Map.Entry<Object, Object> entry : mappings.entrySet()) {
48                         if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
49                                 exceptionMappings.put((String)entry.getKey(), (String)entry.getValue());
50                         }
51                 }
52         }
53         
54         @Override
55         protected SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) {
56                 if (!CollectionUtils.isEmpty(exceptionMappings)) {
57                         String definitionText = null;
58                         int deepest = Integer.MAX_VALUE;
59                         for (String exceptionMapping : exceptionMappings.keySet()) {
60                                 int depth = getDepth(exceptionMapping, ex);
61                                 if (depth >= 0 && depth < deepest) {
62                                         deepest = depth;
63                                         definitionText = exceptionMappings.get(exceptionMapping);
64                                 }
65                         }
66                         if (definitionText != null) {
67                                 SoapFaultDefinitionEditor editor = new SoapFaultDefinitionEditor();
68                                 editor.setAsText(definitionText);
69                                 return (SoapFaultDefinition) editor.getValue();
70                         }
71                 }
72                 return null;
73         }
74
75         /**
76          * Return the depth to the superclass matching. {@code 0} means ex matches exactly. Returns {@code -1} if
77          * there's no match. Otherwise, returns depth. Lowest depth wins.
78          *
79          * <p>Follows the same algorithm as RollbackRuleAttribute, and SimpleMappingExceptionResolver
80          */
81         protected int getDepth(String exceptionMapping, Exception ex) {
82                 return getDepth(exceptionMapping, ex.getClass(), 0);
83         }
84
85         @SuppressWarnings("unchecked")
86         private int getDepth(String exceptionMapping, Class<? extends Exception> exceptionClass, int depth) {
87                 if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
88                         return depth;
89                 }
90                 if (exceptionClass.equals(Throwable.class)) {
91                         return -1;
92                 }
93                 return getDepth(exceptionMapping, (Class<? extends Exception>) exceptionClass.getSuperclass(), depth + 1);
94         }
95
96         protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
97                 ExampleFault customFault = new ExampleFault();
98                 customFault.setTechnicalError(getStackTrace(ex));
99                 
100                 Element element = buildElement(ex);
101                 List<Element> elements = customFault.getElements();
102                 elements.add(element);
103                 
104                 SoapFaultDetail detail = fault.addFaultDetail();
105                 Result result = detail.getResult();
106                 try {
107                         marshaller.marshal(customFault, result);
108                 } catch (Exception marshallEx) {
109                         LOGGER.error("MyCustomMappingExceptionResolver: marshaller error", marshallEx);
110                 }
111         }
112         
113         public void setMarshaller(Marshaller marshaller) {
114                 this.marshaller = marshaller;
115         }
116                 
117         private Element buildElement(Exception ex) {
118                 Element element = new Element();
119                 element.setMessage(ex.getMessage());
120                 
121                 if (ex instanceof CustomBusinessException) {
122                         CustomBusinessException customEx = (CustomBusinessException) ex;
123                         List<String> messageArgs = element.getMessageArgs();
124                         List<String> argumentsEx = customEx.getArguments();
125                         
126                         for (String argumentEx: argumentsEx) {
127                                 messageArgs.add(argumentEx);
128                         }
129                 }
130                 
131                 return element;
132         }
133         
134         private String getStackTrace(Throwable throwable) {
135              final StringWriter sw = new StringWriter();
136              final PrintWriter pw = new PrintWriter(sw, true);
137              throwable.printStackTrace(pw);
138              return sw.getBuffer().toString();
139         }
140 }