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.Iterator;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Properties;
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.TransformerException;
32 import javax.xml.transform.dom.DOMResult;
33 import javax.xml.transform.dom.DOMSource;
34
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.Node;
38
39 import org.springframework.util.StringUtils;
40 import org.springframework.ws.soap.SoapFault;
41 import org.springframework.ws.soap.SoapHeader;
42 import org.springframework.ws.soap.SoapHeaderElement;
43 import org.springframework.ws.soap.SoapMessage;
44 import org.springframework.ws.soap.addressing.AddressingException;
45 import org.springframework.ws.soap.addressing.core.EndpointReference;
46 import org.springframework.ws.soap.addressing.core.MessageAddressingProperties;
47 import org.springframework.ws.soap.soap11.Soap11Body;
48 import org.springframework.ws.soap.soap12.Soap12Body;
49 import org.springframework.ws.soap.soap12.Soap12Fault;
50 import org.springframework.xml.namespace.QNameUtils;
51 import org.springframework.xml.transform.TransformerObjectSupport;
52 import org.springframework.xml.xpath.XPathExpression;
53 import org.springframework.xml.xpath.XPathExpressionFactory;
54
55
56
57
58
59
60
61
62 public abstract class AbstractAddressingVersion extends TransformerObjectSupport implements AddressingVersion {
63
64 private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
65
66 private final XPathExpression toExpression;
67
68 private final XPathExpression actionExpression;
69
70 private final XPathExpression messageIdExpression;
71
72 private final XPathExpression fromExpression;
73
74 private final XPathExpression replyToExpression;
75
76 private final XPathExpression faultToExpression;
77
78 private final XPathExpression addressExpression;
79
80 private final XPathExpression referencePropertiesExpression;
81
82 private final XPathExpression referenceParametersExpression;
83
84 protected AbstractAddressingVersion() {
85 Properties namespaces = new Properties();
86 namespaces.setProperty(getNamespacePrefix(), getNamespaceUri());
87 toExpression = createNormalizedExpression(getToName(), namespaces);
88 actionExpression = createNormalizedExpression(getActionName(), namespaces);
89 messageIdExpression = createNormalizedExpression(getMessageIdName(), namespaces);
90 fromExpression = createExpression(getFromName(), namespaces);
91 replyToExpression = createExpression(getReplyToName(), namespaces);
92 faultToExpression = createExpression(getFaultToName(), namespaces);
93 addressExpression = createNormalizedExpression(getAddressName(), namespaces);
94 if (getReferencePropertiesName() != null) {
95 referencePropertiesExpression = createChildrenExpression(getReferencePropertiesName(), namespaces);
96 }
97 else {
98 referencePropertiesExpression = null;
99 }
100 if (getReferenceParametersName() != null) {
101 referenceParametersExpression = createChildrenExpression(getReferenceParametersName(), namespaces);
102 }
103 else {
104 referenceParametersExpression = null;
105 }
106 }
107
108 private XPathExpression createExpression(QName name, Properties namespaces) {
109 String expression = name.getPrefix() + ":" + name.getLocalPart();
110 return XPathExpressionFactory.createXPathExpression(expression, namespaces);
111 }
112
113 private XPathExpression createNormalizedExpression(QName name, Properties namespaces) {
114 String expression = "normalize-space(" + name.getPrefix() + ":" + name.getLocalPart() + ")";
115 return XPathExpressionFactory.createXPathExpression(expression, namespaces);
116 }
117
118 private XPathExpression createChildrenExpression(QName name, Properties namespaces) {
119 String expression = name.getPrefix() + ":" + name.getLocalPart() + "/*";
120 return XPathExpressionFactory.createXPathExpression(expression, namespaces);
121 }
122
123 public MessageAddressingProperties getMessageAddressingProperties(SoapMessage message) {
124 Element headerElement = getSoapHeaderElement(message);
125 URI to = getUri(headerElement, toExpression);
126 if (to == null) {
127 to = getDefaultTo();
128 }
129 EndpointReference from = getEndpointReference(fromExpression.evaluateAsNode(headerElement));
130 EndpointReference replyTo = getEndpointReference(replyToExpression.evaluateAsNode(headerElement));
131 if (replyTo == null) {
132 replyTo = getDefaultReplyTo(from);
133 }
134 EndpointReference faultTo = getEndpointReference(faultToExpression.evaluateAsNode(headerElement));
135 if (faultTo == null) {
136 faultTo = replyTo;
137 }
138 URI action = getUri(headerElement, actionExpression);
139 URI messageId = getUri(headerElement, messageIdExpression);
140 return new MessageAddressingProperties(to, from, replyTo, faultTo, action, messageId);
141 }
142
143 private URI getUri(Node node, XPathExpression expression) {
144 String messageId = expression.evaluateAsString(node);
145 if (!StringUtils.hasLength(messageId)) {
146 return null;
147 }
148 try {
149 return new URI(messageId);
150 }
151 catch (URISyntaxException e) {
152 return null;
153 }
154 }
155
156 private Element getSoapHeaderElement(SoapMessage message) {
157 SoapHeader header = message.getSoapHeader();
158 if (header.getSource() instanceof DOMSource) {
159 DOMSource domSource = (DOMSource) header.getSource();
160 if (domSource.getNode() != null && domSource.getNode().getNodeType() == Node.ELEMENT_NODE) {
161 return (Element) domSource.getNode();
162 }
163 }
164 try {
165 DOMResult domResult = new DOMResult();
166 transform(header.getSource(), domResult);
167 Document document = (Document) domResult.getNode();
168 return document.getDocumentElement();
169 }
170 catch (TransformerException ex) {
171 throw new AddressingException("Could not transform SoapHeader to Document", ex);
172 }
173 }
174
175
176 private EndpointReference getEndpointReference(Node node) {
177 if (node == null) {
178 return null;
179 }
180 URI address = getUri(node, addressExpression);
181 if (address == null) {
182 return null;
183 }
184 List referenceProperties =
185 referencePropertiesExpression != null ? referencePropertiesExpression.evaluateAsNodeList(node) :
186 Collections.EMPTY_LIST;
187 List referenceParameters =
188 referenceParametersExpression != null ? referenceParametersExpression.evaluateAsNodeList(node) :
189 Collections.EMPTY_LIST;
190 return new EndpointReference(address, referenceProperties, referenceParameters);
191 }
192
193 public void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map) {
194 SoapHeader header = message.getSoapHeader();
195 header.addNamespaceDeclaration(getNamespacePrefix(), getNamespaceUri());
196
197 if (map.getTo() != null) {
198 SoapHeaderElement to = header.addHeaderElement(getToName());
199 to.setText(map.getTo().toString());
200 to.setMustUnderstand(true);
201 }
202
203 if (map.getFrom() != null) {
204 SoapHeaderElement from = header.addHeaderElement(getFromName());
205 addEndpointReference(from, map.getFrom());
206 }
207
208 if (map.getReplyTo() != null) {
209 SoapHeaderElement replyTo = header.addHeaderElement(getReplyToName());
210 addEndpointReference(replyTo, map.getReplyTo());
211 }
212
213 if (map.getFaultTo() != null) {
214 SoapHeaderElement faultTo = header.addHeaderElement(getFaultToName());
215 addEndpointReference(faultTo, map.getFaultTo());
216 }
217
218 SoapHeaderElement action = header.addHeaderElement(getActionName());
219 action.setText(map.getAction().toString());
220
221 if (map.getMessageId() != null) {
222 SoapHeaderElement messageId = header.addHeaderElement(getMessageIdName());
223 messageId.setText(map.getMessageId().toString());
224 }
225
226 if (map.getRelatesTo() != null) {
227 SoapHeaderElement relatesTo = header.addHeaderElement(getRelatesToName());
228 relatesTo.setText(map.getRelatesTo().toString());
229 }
230 addReferenceNodes(header.getResult(), map.getReferenceParameters());
231 addReferenceNodes(header.getResult(), map.getReferenceProperties());
232 }
233
234 public final boolean understands(SoapHeaderElement headerElement) {
235 return getNamespaceUri().equals(headerElement.getName().getNamespaceURI());
236 }
237
238
239 protected void addEndpointReference(SoapHeaderElement headerElement, EndpointReference epr) {
240 if (epr == null || epr.getAddress() == null) {
241 return;
242 }
243 try {
244 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
245 Document document = documentBuilder.newDocument();
246 Element address = document.createElementNS(getNamespaceUri(), QNameUtils.toQualifiedName(getAddressName()));
247 address.setTextContent(epr.getAddress().toString());
248 transform(new DOMSource(address), headerElement.getResult());
249 if (getReferenceParametersName() != null && !epr.getReferenceParameters().isEmpty()) {
250 Element referenceParams = document.createElementNS(getNamespaceUri(),
251 QNameUtils.toQualifiedName(getReferenceParametersName()));
252 addReferenceNodes(new DOMResult(referenceParams), epr.getReferenceParameters());
253 transform(new DOMSource(referenceParams), headerElement.getResult());
254 }
255 if (getReferencePropertiesName() != null && !epr.getReferenceProperties().isEmpty()) {
256 Element referenceProps = document.createElementNS(getNamespaceUri(),
257 QNameUtils.toQualifiedName(getReferencePropertiesName()));
258 addReferenceNodes(new DOMResult(referenceProps), epr.getReferenceProperties());
259 transform(new DOMSource(referenceProps), headerElement.getResult());
260 }
261 }
262 catch (ParserConfigurationException ex) {
263 throw new AddressingException("Could not add Endpoint Reference [" + epr + "] to header element", ex);
264 }
265 catch (TransformerException ex) {
266 throw new AddressingException("Could not add reference properties/parameters to message", ex);
267 }
268 }
269
270 protected void addReferenceNodes(Result result, List nodes) {
271 try {
272 for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
273 Node node = (Node) iterator.next();
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 }