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 EndpointReference from = getEndpointReference(fromExpression.evaluateAsNode(headerElement));
127 EndpointReference replyTo = getEndpointReference(replyToExpression.evaluateAsNode(headerElement));
128 if (replyTo == null) {
129 replyTo = getDefaultReplyTo(from);
130 }
131 EndpointReference faultTo = getEndpointReference(faultToExpression.evaluateAsNode(headerElement));
132 if (faultTo == null) {
133 faultTo = replyTo;
134 }
135 URI action = getUri(headerElement, actionExpression);
136 URI messageId = getUri(headerElement, messageIdExpression);
137 return new MessageAddressingProperties(to, from, replyTo, faultTo, action, messageId);
138 }
139
140 private URI getUri(Node node, XPathExpression expression) {
141 String messageId = expression.evaluateAsString(node);
142 if (!StringUtils.hasLength(messageId)) {
143 return null;
144 }
145 try {
146 return new URI(messageId);
147 }
148 catch (URISyntaxException e) {
149 return null;
150 }
151 }
152
153 private Element getSoapHeaderElement(SoapMessage message) {
154 SoapHeader header = message.getSoapHeader();
155 if (header.getSource() instanceof DOMSource) {
156 DOMSource domSource = (DOMSource) header.getSource();
157 if (domSource.getNode() != null && domSource.getNode().getNodeType() == Node.ELEMENT_NODE) {
158 return (Element) domSource.getNode();
159 }
160 }
161 try {
162 DOMResult domResult = new DOMResult();
163 transform(header.getSource(), domResult);
164 Document document = (Document) domResult.getNode();
165 return document.getDocumentElement();
166 }
167 catch (TransformerException ex) {
168 throw new AddressingException("Could not transform SoapHeader to Document", ex);
169 }
170 }
171
172
173 private EndpointReference getEndpointReference(Node node) {
174 if (node == null) {
175 return null;
176 }
177 URI address = getUri(node, addressExpression);
178 if (address == null) {
179 return null;
180 }
181 List referenceProperties = referencePropertiesExpression != null ?
182 referencePropertiesExpression.evaluateAsNodeList(node) : Collections.EMPTY_LIST;
183 List referenceParameters = referenceParametersExpression != null ?
184 referenceParametersExpression.evaluateAsNodeList(node) : Collections.EMPTY_LIST;
185 return new EndpointReference(address, referenceProperties, referenceParameters);
186 }
187
188 public void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map) {
189 SoapHeader header = message.getSoapHeader();
190
191 if (map.getTo() != null) {
192 SoapHeaderElement to = header.addHeaderElement(getToName());
193 to.setText(map.getTo().toString());
194 to.setMustUnderstand(true);
195 }
196
197 if (map.getFrom() != null) {
198 SoapHeaderElement from = header.addHeaderElement(getFromName());
199 addEndpointReference(from, map.getFrom());
200 }
201
202 if (map.getReplyTo() != null) {
203 SoapHeaderElement replyTo = header.addHeaderElement(getReplyToName());
204 addEndpointReference(replyTo, map.getReplyTo());
205 }
206
207 if (map.getFaultTo() != null) {
208 SoapHeaderElement faultTo = header.addHeaderElement(getFaultToName());
209 addEndpointReference(faultTo, map.getFaultTo());
210 }
211
212 SoapHeaderElement action = header.addHeaderElement(getActionName());
213 action.setText(map.getAction().toString());
214
215 if (map.getMessageId() != null) {
216 SoapHeaderElement messageId = header.addHeaderElement(getMessageIdName());
217 messageId.setText(map.getMessageId().toString());
218 }
219
220 if (map.getRelatesTo() != null) {
221 SoapHeaderElement relatesTo = header.addHeaderElement(getRelatesToName());
222 relatesTo.setText(map.getRelatesTo().toString());
223 }
224 addReferenceNodes(header.getResult(), map.getReferenceParameters());
225 addReferenceNodes(header.getResult(), map.getReferenceProperties());
226 }
227
228 public final boolean understands(SoapHeaderElement headerElement) {
229 return getNamespaceUri().equals(headerElement.getName().getNamespaceURI());
230 }
231
232
233 protected void addEndpointReference(SoapHeaderElement headerElement, EndpointReference epr) {
234 if (epr == null || epr.getAddress() == null) {
235 return;
236 }
237 try {
238 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
239 Document document = documentBuilder.newDocument();
240 Element address = document.createElementNS(getNamespaceUri(), QNameUtils.toQualifiedName(getAddressName()));
241 address.setTextContent(epr.getAddress().toString());
242 transform(new DOMSource(address), headerElement.getResult());
243 if (getReferenceParametersName() != null && !epr.getReferenceParameters().isEmpty()) {
244 Element referenceParams = document.createElementNS(getNamespaceUri(),
245 QNameUtils.toQualifiedName(getReferenceParametersName()));
246 addReferenceNodes(new DOMResult(referenceParams), epr.getReferenceParameters());
247 transform(new DOMSource(referenceParams), headerElement.getResult());
248 }
249 if (getReferencePropertiesName() != null && !epr.getReferenceProperties().isEmpty()) {
250 Element referenceProps = document.createElementNS(getNamespaceUri(),
251 QNameUtils.toQualifiedName(getReferencePropertiesName()));
252 addReferenceNodes(new DOMResult(referenceProps), epr.getReferenceProperties());
253 transform(new DOMSource(referenceProps), headerElement.getResult());
254 }
255 }
256 catch (ParserConfigurationException ex) {
257 throw new AddressingException("Could not add Endpoint Reference [" + epr + "] to header element", ex);
258 }
259 catch (TransformerException ex) {
260 throw new AddressingException("Could not add reference properties/parameters to message", ex);
261 }
262 }
263
264 protected void addReferenceNodes(Result result, List nodes) {
265 try {
266 for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
267 Node node = (Node) iterator.next();
268 DOMSource source = new DOMSource(node);
269 transform(source, result);
270 }
271 }
272 catch (TransformerException ex) {
273 throw new AddressingException("Could not add reference properties/parameters to message", ex);
274 }
275 }
276
277 public final SoapFault addInvalidAddressingHeaderFault(SoapMessage message) {
278 return addAddressingFault(message, getInvalidAddressingHeaderFaultSubcode(),
279 getInvalidAddressingHeaderFaultReason());
280 }
281
282 public final SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message) {
283 return addAddressingFault(message, getMessageAddressingHeaderRequiredFaultSubcode(),
284 getMessageAddressingHeaderRequiredFaultReason());
285 }
286
287 private SoapFault addAddressingFault(SoapMessage message, QName subcode, String reason) {
288 if (message.getSoapBody() instanceof Soap11Body) {
289 Soap11Body soapBody = (Soap11Body) message.getSoapBody();
290 return soapBody.addFault(subcode, reason, Locale.ENGLISH);
291 }
292 else if (message.getSoapBody() instanceof Soap12Body) {
293 Soap12Body soapBody = (Soap12Body) message.getSoapBody();
294 Soap12Fault soapFault = (Soap12Fault) soapBody.addClientOrSenderFault(reason, Locale.ENGLISH);
295 soapFault.addFaultSubcode(subcode);
296 return soapFault;
297 }
298 return null;
299 }
300
301
302
303
304
305 public final boolean hasAnonymousAddress(EndpointReference epr) {
306 URI anonymous = getAnonymous();
307 return anonymous != null && anonymous.equals(epr.getAddress());
308 }
309
310 public final boolean hasNoneAddress(EndpointReference epr) {
311 URI none = getNone();
312 return none != null && none.equals(epr.getAddress());
313 }
314
315
316 protected String getNamespacePrefix() {
317 return "wsa";
318 }
319
320
321 protected abstract String getNamespaceUri();
322
323
324
325
326
327
328 protected QName getToName() {
329 return QNameUtils.createQName(getNamespaceUri(), "To", getNamespacePrefix());
330 }
331
332
333 protected QName getFromName() {
334 return QNameUtils.createQName(getNamespaceUri(), "From", getNamespacePrefix());
335 }
336
337
338 protected QName getReplyToName() {
339 return QNameUtils.createQName(getNamespaceUri(), "ReplyTo", getNamespacePrefix());
340 }
341
342
343 protected QName getFaultToName() {
344 return QNameUtils.createQName(getNamespaceUri(), "FaultTo", getNamespacePrefix());
345 }
346
347
348 protected QName getActionName() {
349 return QNameUtils.createQName(getNamespaceUri(), "Action", getNamespacePrefix());
350 }
351
352
353 protected QName getMessageIdName() {
354 return QNameUtils.createQName(getNamespaceUri(), "MessageID", getNamespacePrefix());
355 }
356
357
358 protected QName getRelatesToName() {
359 return QNameUtils.createQName(getNamespaceUri(), "RelatesTo", getNamespacePrefix());
360 }
361
362
363 protected QName getRelationshipTypeName() {
364 return new QName("RelationshipType");
365 }
366
367
368
369
370
371 protected QName getReferencePropertiesName() {
372 return QNameUtils.createQName(getNamespaceUri(), "ReferenceProperties", getNamespacePrefix());
373 }
374
375
376
377
378
379 protected QName getReferenceParametersName() {
380 return QNameUtils.createQName(getNamespaceUri(), "ReferenceParameters", getNamespacePrefix());
381 }
382
383
384
385
386
387
388 protected QName getAddressName() {
389 return QNameUtils.createQName(getNamespaceUri(), "Address", getNamespacePrefix());
390 }
391
392
393 protected abstract EndpointReference getDefaultReplyTo(EndpointReference from);
394
395
396
397
398
399
400 protected abstract URI getAnonymous();
401
402
403 protected abstract URI getNone();
404
405
406
407
408
409
410 protected abstract QName getMessageAddressingHeaderRequiredFaultSubcode();
411
412
413 protected abstract String getMessageAddressingHeaderRequiredFaultReason();
414
415
416 protected abstract QName getInvalidAddressingHeaderFaultSubcode();
417
418
419 protected abstract String getInvalidAddressingHeaderFaultReason();
420 }