1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.soap.addressing.version;
18
19 import java.net.URI;
20 import java.net.URISyntaxException;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Map;
26 import javax.xml.namespace.QName;
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29 import javax.xml.parsers.ParserConfigurationException;
30 import javax.xml.transform.Result;
31 import javax.xml.transform.Source;
32 import javax.xml.transform.TransformerException;
33 import javax.xml.transform.dom.DOMResult;
34 import javax.xml.transform.dom.DOMSource;
35
36 import org.springframework.util.StringUtils;
37 import org.springframework.ws.soap.SoapFault;
38 import org.springframework.ws.soap.SoapHeader;
39 import org.springframework.ws.soap.SoapHeaderElement;
40 import org.springframework.ws.soap.SoapMessage;
41 import org.springframework.ws.soap.addressing.AddressingException;
42 import org.springframework.ws.soap.addressing.core.EndpointReference;
43 import org.springframework.ws.soap.addressing.core.MessageAddressingProperties;
44 import org.springframework.ws.soap.soap11.Soap11Body;
45 import org.springframework.ws.soap.soap12.Soap12Body;
46 import org.springframework.ws.soap.soap12.Soap12Fault;
47 import org.springframework.xml.namespace.QNameUtils;
48 import org.springframework.xml.transform.TransformerObjectSupport;
49 import org.springframework.xml.xpath.XPathExpression;
50 import org.springframework.xml.xpath.XPathExpressionFactory;
51
52 import org.w3c.dom.Document;
53 import org.w3c.dom.Element;
54 import org.w3c.dom.Node;
55
56
57
58
59
60
61
62
63 public abstract class AbstractAddressingVersion extends TransformerObjectSupport implements AddressingVersion {
64
65 private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
66
67 private final XPathExpression toExpression;
68
69 private final XPathExpression actionExpression;
70
71 private final XPathExpression messageIdExpression;
72
73 private final XPathExpression fromExpression;
74
75 private final XPathExpression replyToExpression;
76
77 private final XPathExpression faultToExpression;
78
79 private final XPathExpression addressExpression;
80
81 private final XPathExpression referencePropertiesExpression;
82
83 private final XPathExpression referenceParametersExpression;
84
85 protected AbstractAddressingVersion() {
86 Map<String, String> namespaces = new HashMap<String, String>();
87 namespaces.put(getNamespacePrefix(), getNamespaceUri());
88 toExpression = createNormalizedExpression(getToName(), namespaces);
89 actionExpression = createNormalizedExpression(getActionName(), namespaces);
90 messageIdExpression = createNormalizedExpression(getMessageIdName(), namespaces);
91 fromExpression = createExpression(getFromName(), namespaces);
92 replyToExpression = createExpression(getReplyToName(), namespaces);
93 faultToExpression = createExpression(getFaultToName(), namespaces);
94 addressExpression = createNormalizedExpression(getAddressName(), namespaces);
95 if (getReferencePropertiesName() != null) {
96 referencePropertiesExpression = createChildrenExpression(getReferencePropertiesName(), namespaces);
97 }
98 else {
99 referencePropertiesExpression = null;
100 }
101 if (getReferenceParametersName() != null) {
102 referenceParametersExpression = createChildrenExpression(getReferenceParametersName(), namespaces);
103 }
104 else {
105 referenceParametersExpression = null;
106 }
107 }
108
109 private XPathExpression createExpression(QName name, Map<String, String> namespaces) {
110 String expression = name.getPrefix() + ":" + name.getLocalPart();
111 return XPathExpressionFactory.createXPathExpression(expression, namespaces);
112 }
113
114 private XPathExpression createNormalizedExpression(QName name, Map<String, String> namespaces) {
115 String expression = "normalize-space(" + name.getPrefix() + ":" + name.getLocalPart() + ")";
116 return XPathExpressionFactory.createXPathExpression(expression, namespaces);
117 }
118
119 private XPathExpression createChildrenExpression(QName name, Map<String, String> namespaces) {
120 String expression = name.getPrefix() + ":" + name.getLocalPart() + "/*";
121 return XPathExpressionFactory.createXPathExpression(expression, namespaces);
122 }
123
124 public MessageAddressingProperties getMessageAddressingProperties(SoapMessage message) {
125 Element headerElement = getSoapHeaderElement(message);
126 URI to = getUri(headerElement, toExpression);
127 if (to == null) {
128 to = getDefaultTo();
129 }
130 EndpointReference from = getEndpointReference(fromExpression.evaluateAsNode(headerElement));
131 EndpointReference replyTo = getEndpointReference(replyToExpression.evaluateAsNode(headerElement));
132 if (replyTo == null) {
133 replyTo = getDefaultReplyTo(from);
134 }
135 EndpointReference faultTo = getEndpointReference(faultToExpression.evaluateAsNode(headerElement));
136 if (faultTo == null) {
137 faultTo = replyTo;
138 }
139 URI action = getUri(headerElement, actionExpression);
140 URI messageId = getUri(headerElement, messageIdExpression);
141 return new MessageAddressingProperties(to, from, replyTo, faultTo, action, messageId);
142 }
143
144 private URI getUri(Node node, XPathExpression expression) {
145 String messageId = expression.evaluateAsString(node);
146 if (!StringUtils.hasLength(messageId)) {
147 return null;
148 }
149 try {
150 return new URI(messageId);
151 }
152 catch (URISyntaxException e) {
153 return null;
154 }
155 }
156
157 private Element getSoapHeaderElement(SoapMessage message) {
158 Source source = message.getSoapHeader().getSource();
159 if (source instanceof DOMSource) {
160 DOMSource domSource = (DOMSource) source;
161 if (domSource.getNode() != null && domSource.getNode().getNodeType() == Node.ELEMENT_NODE) {
162 return (Element) domSource.getNode();
163 }
164 }
165 try {
166 DOMResult domResult = new DOMResult();
167 transform(source, domResult);
168 Document document = (Document) domResult.getNode();
169 return document.getDocumentElement();
170 }
171 catch (TransformerException ex) {
172 throw new AddressingException("Could not transform SoapHeader to Document", ex);
173 }
174 }
175
176
177 private EndpointReference getEndpointReference(Node node) {
178 if (node == null) {
179 return null;
180 }
181 URI address = getUri(node, addressExpression);
182 if (address == null) {
183 return null;
184 }
185 List<Node> referenceProperties =
186 referencePropertiesExpression != null ? referencePropertiesExpression.evaluateAsNodeList(node) :
187 Collections.<Node>emptyList();
188 List<Node> referenceParameters =
189 referenceParametersExpression != null ? referenceParametersExpression.evaluateAsNodeList(node) :
190 Collections.<Node>emptyList();
191 return new EndpointReference(address, referenceProperties, referenceParameters);
192 }
193
194 public void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map) {
195 SoapHeader header = message.getSoapHeader();
196 header.addNamespaceDeclaration(getNamespacePrefix(), getNamespaceUri());
197
198 if (map.getTo() != null) {
199 SoapHeaderElement to = header.addHeaderElement(getToName());
200 to.setText(map.getTo().toString());
201 to.setMustUnderstand(true);
202 }
203
204 if (map.getFrom() != null) {
205 SoapHeaderElement from = header.addHeaderElement(getFromName());
206 addEndpointReference(from, map.getFrom());
207 }
208
209 if (map.getReplyTo() != null) {
210 SoapHeaderElement replyTo = header.addHeaderElement(getReplyToName());
211 addEndpointReference(replyTo, map.getReplyTo());
212 }
213
214 if (map.getFaultTo() != null) {
215 SoapHeaderElement faultTo = header.addHeaderElement(getFaultToName());
216 addEndpointReference(faultTo, map.getFaultTo());
217 }
218
219 SoapHeaderElement action = header.addHeaderElement(getActionName());
220 action.setText(map.getAction().toString());
221
222 if (map.getMessageId() != null) {
223 SoapHeaderElement messageId = header.addHeaderElement(getMessageIdName());
224 messageId.setText(map.getMessageId().toString());
225 }
226
227 if (map.getRelatesTo() != null) {
228 SoapHeaderElement relatesTo = header.addHeaderElement(getRelatesToName());
229 relatesTo.setText(map.getRelatesTo().toString());
230 }
231 addReferenceNodes(header.getResult(), map.getReferenceParameters());
232 addReferenceNodes(header.getResult(), map.getReferenceProperties());
233 }
234
235 public final boolean understands(SoapHeaderElement headerElement) {
236 return getNamespaceUri().equals(headerElement.getName().getNamespaceURI());
237 }
238
239
240 protected void addEndpointReference(SoapHeaderElement headerElement, EndpointReference epr) {
241 if (epr == null || epr.getAddress() == null) {
242 return;
243 }
244 try {
245 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
246 Document document = documentBuilder.newDocument();
247 Element address = document.createElementNS(getNamespaceUri(), QNameUtils.toQualifiedName(getAddressName()));
248 address.setTextContent(epr.getAddress().toString());
249 transform(new DOMSource(address), headerElement.getResult());
250 if (getReferenceParametersName() != null && !epr.getReferenceParameters().isEmpty()) {
251 Element referenceParams = document.createElementNS(getNamespaceUri(),
252 QNameUtils.toQualifiedName(getReferenceParametersName()));
253 addReferenceNodes(new DOMResult(referenceParams), epr.getReferenceParameters());
254 transform(new DOMSource(referenceParams), headerElement.getResult());
255 }
256 if (getReferencePropertiesName() != null && !epr.getReferenceProperties().isEmpty()) {
257 Element referenceProps = document.createElementNS(getNamespaceUri(),
258 QNameUtils.toQualifiedName(getReferencePropertiesName()));
259 addReferenceNodes(new DOMResult(referenceProps), epr.getReferenceProperties());
260 transform(new DOMSource(referenceProps), headerElement.getResult());
261 }
262 }
263 catch (ParserConfigurationException ex) {
264 throw new AddressingException("Could not add Endpoint Reference [" + epr + "] to header element", ex);
265 }
266 catch (TransformerException ex) {
267 throw new AddressingException("Could not add reference properties/parameters to message", ex);
268 }
269 }
270
271 protected void addReferenceNodes(Result result, List<Node> nodes) {
272 try {
273 for (Node node : nodes) {
274 DOMSource source = new DOMSource(node);
275 transform(source, result);
276 }
277 }
278 catch (TransformerException ex) {
279 throw new AddressingException("Could not add reference properties/parameters to message", ex);
280 }
281 }
282
283 public final SoapFault addInvalidAddressingHeaderFault(SoapMessage message) {
284 return addAddressingFault(message, getInvalidAddressingHeaderFaultSubcode(),
285 getInvalidAddressingHeaderFaultReason());
286 }
287
288 public final SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message) {
289 return addAddressingFault(message, getMessageAddressingHeaderRequiredFaultSubcode(),
290 getMessageAddressingHeaderRequiredFaultReason());
291 }
292
293 private SoapFault addAddressingFault(SoapMessage message, QName subcode, String reason) {
294 if (message.getSoapBody() instanceof Soap11Body) {
295 Soap11Body soapBody = (Soap11Body) message.getSoapBody();
296 return soapBody.addFault(subcode, reason, Locale.ENGLISH);
297 }
298 else if (message.getSoapBody() instanceof Soap12Body) {
299 Soap12Body soapBody = (Soap12Body) message.getSoapBody();
300 Soap12Fault soapFault = (Soap12Fault) soapBody.addClientOrSenderFault(reason, Locale.ENGLISH);
301 soapFault.addFaultSubcode(subcode);
302 return soapFault;
303 }
304 return null;
305 }
306
307
308
309
310
311 public final boolean hasAnonymousAddress(EndpointReference epr) {
312 URI anonymous = getAnonymous();
313 return anonymous != null && anonymous.equals(epr.getAddress());
314 }
315
316 public final boolean hasNoneAddress(EndpointReference epr) {
317 URI none = getNone();
318 return none != null && none.equals(epr.getAddress());
319 }
320
321
322 protected String getNamespacePrefix() {
323 return "wsa";
324 }
325
326
327 protected abstract String getNamespaceUri();
328
329
330
331
332
333
334 protected QName getToName() {
335 return QNameUtils.createQName(getNamespaceUri(), "To", getNamespacePrefix());
336 }
337
338
339 protected QName getFromName() {
340 return QNameUtils.createQName(getNamespaceUri(), "From", getNamespacePrefix());
341 }
342
343
344 protected QName getReplyToName() {
345 return QNameUtils.createQName(getNamespaceUri(), "ReplyTo", getNamespacePrefix());
346 }
347
348
349 protected QName getFaultToName() {
350 return QNameUtils.createQName(getNamespaceUri(), "FaultTo", getNamespacePrefix());
351 }
352
353
354 protected QName getActionName() {
355 return QNameUtils.createQName(getNamespaceUri(), "Action", getNamespacePrefix());
356 }
357
358
359 protected QName getMessageIdName() {
360 return QNameUtils.createQName(getNamespaceUri(), "MessageID", getNamespacePrefix());
361 }
362
363
364 protected QName getRelatesToName() {
365 return QNameUtils.createQName(getNamespaceUri(), "RelatesTo", getNamespacePrefix());
366 }
367
368
369 protected QName getRelationshipTypeName() {
370 return new QName("RelationshipType");
371 }
372
373
374
375
376
377 protected QName getReferencePropertiesName() {
378 return QNameUtils.createQName(getNamespaceUri(), "ReferenceProperties", getNamespacePrefix());
379 }
380
381
382
383
384
385 protected QName getReferenceParametersName() {
386 return QNameUtils.createQName(getNamespaceUri(), "ReferenceParameters", getNamespacePrefix());
387 }
388
389
390
391
392
393
394 protected QName getAddressName() {
395 return QNameUtils.createQName(getNamespaceUri(), "Address", getNamespacePrefix());
396 }
397
398
399 protected abstract URI getDefaultTo();
400
401
402 protected abstract EndpointReference getDefaultReplyTo(EndpointReference from);
403
404
405
406
407
408
409 protected abstract URI getAnonymous();
410
411
412 protected abstract URI getNone();
413
414
415
416
417
418
419 protected abstract QName getMessageAddressingHeaderRequiredFaultSubcode();
420
421
422 protected abstract String getMessageAddressingHeaderRequiredFaultReason();
423
424
425 protected abstract QName getInvalidAddressingHeaderFaultSubcode();
426
427
428 protected abstract String getInvalidAddressingHeaderFaultReason();
429 }