1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ws.addressing.handler;
18
19 import org.apache.axis.message.addressing.Action;
20 import org.apache.axis.message.addressing.AddressingHeaders;
21 import org.apache.axis.message.addressing.AttributedURI;
22 import org.apache.axis.message.addressing.Constants;
23 import org.apache.axis.message.addressing.EndpointReference;
24 import org.apache.axis.message.addressing.MessageID;
25 import org.apache.axis.message.addressing.To;
26 import org.apache.axis.message.addressing.util.AddressingUtils;
27 import org.apache.axis.types.URI;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import javax.xml.namespace.QName;
32 import javax.xml.rpc.Call;
33 import javax.xml.rpc.JAXRPCException;
34 import javax.xml.rpc.ServiceException;
35 import javax.xml.rpc.ServiceFactory;
36 import javax.xml.rpc.handler.MessageContext;
37 import javax.xml.rpc.handler.soap.SOAPMessageContext;
38 import javax.xml.soap.Node;
39 import javax.xml.soap.SOAPBody;
40 import javax.xml.soap.SOAPConnection;
41 import javax.xml.soap.SOAPConnectionFactory;
42 import javax.xml.soap.SOAPElement;
43 import javax.xml.soap.SOAPMessage;
44 import javax.xml.transform.TransformerFactory;
45 import java.net.MalformedURLException;
46 import java.net.URL;
47 import java.util.ArrayList;
48 import java.util.Iterator;
49 import java.util.List;
50
51 /***
52 * A server-side JAX-RPC {@link javax.xml.rpc.handler.Handler} that extracts
53 * WS-Addressing headers from incoming SOAP requests and inserts them into
54 * outgoing SOAP responses.
55 *
56 * @author Davanum Srinivas (dims@yahoo.com)
57 * @author Ian P. Springer <ian_springer@hp.com>
58 */
59 public class ServerSideAddressingHandler extends AbstractAddressingHandler
60 {
61
62 private static final Log LOG =
63 LogFactory.getLog( ServerSideAddressingHandler.class.getName() );
64
65 /***
66 * thread local that gives each thread its own TransformerFactory (since it is not thread-safe)
67 */
68 public static ThreadLocal TRANSFORMER_FACTORY =
69 new ThreadLocal()
70 {
71 protected synchronized Object initialValue()
72 {
73 return TransformerFactory.newInstance();
74 }
75 };
76
77 public boolean handleRequest( MessageContext msgContext )
78 {
79 SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
80 try
81 {
82 SOAPMessage msg = soapMsgContext.getMessage();
83 if ( msg == null )
84 {
85 return CONTINUE_HANDLER_CHAIN_PROCESSING;
86 }
87 AddressingHeaders headers =
88 new AddressingHeaders( msg.getSOAPPart().getEnvelope(),
89 getActor(),
90 true,
91 isRemoveHeadersEnabled(),
92 false,
93 getReferencePropertyQNames() );
94
95 if (headers.getTo()==null)
96 {
97
98 return CONTINUE_HANDLER_CHAIN_PROCESSING;
99 }
100 if (headers.getAction()==null)
101 {
102
103 LOG.debug("WS-A request to endpoint " + headers.getTo() + " is missing the required wsa:Action header.");
104 }
105 msgContext.setProperty( Constants.ENV_ADDRESSING_REQUEST_HEADERS,
106 headers );
107
108
109
110 setTargetService( soapMsgContext, headers );
111 }
112 catch ( Exception e )
113 {
114 if ( LOG.isDebugEnabled() )
115 {
116 e.printStackTrace();
117 }
118 throw new JAXRPCException( "unexpected error in handleRequest()", e );
119 }
120 return CONTINUE_HANDLER_CHAIN_PROCESSING;
121 }
122
123 public boolean handleResponse( MessageContext msgContext )
124 {
125 SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
126 try
127 {
128 SOAPMessage msg = soapMsgContext.getMessage();
129 if ( msg == null )
130 {
131 return CONTINUE_HANDLER_CHAIN_PROCESSING;
132 }
133
134 AddressingHeaders reqHeaders =
135 (AddressingHeaders) msgContext.getProperty( Constants.ENV_ADDRESSING_REQUEST_HEADERS );
136
137 if ( reqHeaders == null )
138 {
139
140 return CONTINUE_HANDLER_CHAIN_PROCESSING;
141 }
142 AddressingHeaders resHeaders =
143 AddressingUtils.getResponseHeaders( msgContext );
144 resHeaders.setSetMustUnderstand( isMustUnderstandEnabled( msgContext ) );
145 processFromHeader( reqHeaders, resHeaders );
146 processActionHeader( reqHeaders, resHeaders );
147 processToHeader( reqHeaders, resHeaders );
148 processRelatesToHeader( reqHeaders, resHeaders );
149 processMessageIdHeader( resHeaders );
150 resHeaders.toEnvelope( msg.getSOAPPart().getEnvelope(), getActor() );
151 processReplyToHeader( reqHeaders, soapMsgContext );
152 }
153 catch ( Exception e )
154 {
155 if ( LOG.isDebugEnabled() )
156 {
157 e.printStackTrace();
158 }
159 throw new JAXRPCException( "unexpected error in handleResponse()", e );
160 }
161 return CONTINUE_HANDLER_CHAIN_PROCESSING;
162 }
163
164 public boolean handleFault( MessageContext msgContext )
165 {
166 SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
167 try
168 {
169 AddressingHeaders reqHeaders =
170 (AddressingHeaders) msgContext.getProperty( Constants.ENV_ADDRESSING_REQUEST_HEADERS );
171 if ( reqHeaders == null )
172 {
173
174 return CONTINUE_HANDLER_CHAIN_PROCESSING;
175 }
176 AddressingHeaders resHeaders =
177 AddressingUtils.getResponseHeaders( msgContext );
178 processFromHeader( reqHeaders, resHeaders );
179
180 if ( ! reqHeaders.getNamespaceURI().equals( Constants.NS_URI_ADDRESSING_2003_03 ) )
181 {
182 resHeaders.setAction( new Action( new URI( Constants.FAULT_ACTION ) ) );
183 }
184 addRelatesToHeader( reqHeaders, resHeaders );
185 addMessageIdHeader( resHeaders );
186 addAddressingHeadersToSOAPEnvelope( soapMsgContext, resHeaders );
187 processFaultToHeader( reqHeaders, soapMsgContext );
188 }
189 catch ( Exception e )
190 {
191 if ( LOG.isDebugEnabled() )
192 {
193 e.printStackTrace();
194 }
195 throw new JAXRPCException( "unexpected error in handleFault()", e );
196 }
197 return CONTINUE_HANDLER_CHAIN_PROCESSING;
198 }
199
200 /***
201 * Forward the SOAP message contained in the specified SOAP message context
202 * on to the specified endpoint reference.
203 *
204 * @param soapMsgContext
205 * @param endpointRef
206 */
207 protected void forwardMessage( SOAPMessageContext soapMsgContext, EndpointReference endpointRef )
208 {
209 try
210 {
211 SOAPConnection soapConn = SOAPConnectionFactory.newInstance().createConnection();
212 soapConn.call( soapMsgContext.getMessage(), toURL( endpointRef.getAddress() ) );
213 soapConn.close();
214 SOAPBody responseBody = soapMsgContext.getMessage().getSOAPPart().getEnvelope().getBody();
215 removeAllChildElements( responseBody );
216 }
217 catch ( Exception e )
218 {
219 throw new JAXRPCException( "Failed to forward SOAP message." );
220 }
221 }
222
223 private URL toURL( AttributedURI addr )
224 throws MalformedURLException
225 {
226 return new URL( addr.toString() );
227 }
228
229 /***
230 * Override this method if you need something other than the default Service.<br>
231 * The service returned by this method is used in creating the new Call object.
232 * Something like: <br>
233 * <pre>
234 * Service service = getService(msgContext);
235 * Call call = service.createCall()
236 * call.setTargetEndpointAddress(toEndPointReference.getAddress().toString());
237 * </pre>
238 *
239 * @param msgContext
240 *
241 * @return
242 */
243 protected javax.xml.rpc.Service getService( MessageContext msgContext ) throws ServiceException
244 {
245 return ServiceFactory.newInstance().createService( new QName( "" ) );
246 }
247
248 /***
249 * Override this method to prepare the new call, for instance to add
250 * properties from the old MessageContext that may be needed by other
251 * handlers.
252 *
253 * @param call Call object about to be invoked
254 * @param oldContext MessageContext of the original request/response.
255 */
256 protected void configureCall( Call call, MessageContext oldContext )
257 {
258 return;
259 }
260
261 /***
262 * Can be overridden by subclasses to customize how the wsa:to header is interpreted.
263 */
264 protected String getTargetServiceName( AddressingHeaders headers )
265 throws Exception
266 {
267 To toURI = headers.getTo();
268 if ( toURI == null )
269 {
270 return null;
271 }
272 String to = toURI.getPath();
273 if ( to == null )
274 {
275 return null;
276 }
277
278 return ( to.substring( to.lastIndexOf( '/' ) + 1 ) );
279 }
280
281 /***
282 * Platform-specific subclasses can optionally implement this method.
283 *
284 * @param soapMsgContext
285 * @param headers
286 *
287 * @throws Exception
288 */
289 protected void setTargetService( SOAPMessageContext soapMsgContext, AddressingHeaders headers )
290 throws Exception
291 {
292 return;
293 }
294
295 private void processFromHeader( AddressingHeaders requestAddrHeaders, AddressingHeaders responseAddrHeaders )
296 {
297 EndpointReference fromEPR = responseAddrHeaders.getFrom();
298 if ( fromEPR == null )
299 {
300 To toURI = requestAddrHeaders.getTo();
301 if ( toURI != null )
302 {
303 fromEPR = new EndpointReference( toURI );
304 fromEPR.setProperties( requestAddrHeaders.getReferenceProperties() );
305 responseAddrHeaders.setFrom( fromEPR );
306 }
307 }
308 }
309
310 private void processActionHeader( AddressingHeaders requestAddrHeaders, AddressingHeaders responseAddrHeaders )
311 throws URI.MalformedURIException
312 {
313 Action action = responseAddrHeaders.getAction();
314 if ( action == null )
315 {
316
317 action = requestAddrHeaders.getAction();
318 if ( action != null )
319 {
320 responseAddrHeaders.setAction( new Action( new URI( action.toString() +
321 "Response" ) ) );
322 }
323 }
324 }
325
326 private void processToHeader( AddressingHeaders requestAddrHeaders, AddressingHeaders responseAddrHeaders )
327 throws URI.MalformedURIException
328 {
329 if ( responseAddrHeaders.getFrom() == null && requestAddrHeaders.getFrom() != null )
330 {
331 responseAddrHeaders.setTo( requestAddrHeaders.getFrom().getAddress() );
332 }
333 else
334 {
335 responseAddrHeaders.setTo( new To( Constants.NS_URI_ANONYMOUS ) );
336 }
337 }
338
339 private void processRelatesToHeader( AddressingHeaders requestAddrHeaders, AddressingHeaders responseAddrHeaders )
340 throws URI.MalformedURIException
341 {
342 MessageID msgID = requestAddrHeaders.getMessageID();
343 if ( msgID != null )
344 {
345 responseAddrHeaders.addRelatesTo( msgID.toString(),
346 Constants.QNAME_RESPONSE );
347 }
348 }
349
350 private void processMessageIdHeader( AddressingHeaders responseAddrHeaders )
351 throws URI.MalformedURIException
352 {
353 responseAddrHeaders.setMessageID( createMessageID() );
354 }
355
356 private void processReplyToHeader( AddressingHeaders requestAddrHeaders, SOAPMessageContext soapMsgContext )
357 throws Exception
358 {
359 EndpointReference replyTo = requestAddrHeaders.getReplyTo();
360 if ( replyTo != null )
361 {
362 AttributedURI address = replyTo.getAddress();
363 if ( address != null )
364 {
365 String uri = address.toString();
366 if ( uri != null && !uri.equals( Constants.NS_URI_ANONYMOUS ) )
367 {
368 forwardMessage( soapMsgContext, replyTo );
369 }
370 }
371 }
372 }
373
374 private void addAddressingHeadersToSOAPEnvelope( SOAPMessageContext soapMsgContext, AddressingHeaders resHeaders )
375 throws Exception
376 {
377 SOAPMessage msg = soapMsgContext.getMessage();
378 if ( msg == null )
379 {
380 throw new JAXRPCException( "Unable to obtain response message from SOAP message context." );
381 }
382 resHeaders.toEnvelope( msg.getSOAPPart().getEnvelope() );
383 }
384
385 private void processFaultToHeader( AddressingHeaders reqHeaders, SOAPMessageContext soapMsgContext )
386 throws Exception
387 {
388 EndpointReference faultTo = reqHeaders.getFaultTo();
389 if ( faultTo != null )
390 {
391 AttributedURI address = faultTo.getAddress();
392 if ( address != null && address.toString() != null )
393 {
394 forwardMessage( soapMsgContext, faultTo );
395 }
396 }
397 }
398
399 private void addRelatesToHeader( AddressingHeaders reqHeaders, AddressingHeaders resHeaders )
400 throws URI.MalformedURIException
401 {
402 MessageID msgID = reqHeaders.getMessageID();
403 if ( msgID != null )
404 {
405 resHeaders.addRelatesTo( msgID.toString(),
406 Constants.QNAME_RESPONSE );
407 }
408 }
409
410 private void addMessageIdHeader( AddressingHeaders resHeaders )
411 throws URI.MalformedURIException
412 {
413 MessageID msgID = new MessageID( new URI( "uuid:" + generateUUId() ) );
414 resHeaders.setMessageID( msgID );
415 }
416
417 /***
418 * Removes all child elements from the specified {@link javax.xml.soap.SOAPElement}.
419 * NOTE: w
420 */
421 protected static void removeAllChildElements( SOAPElement soapElem )
422 {
423 Iterator iter = soapElem.getChildElements();
424
425
426 List children = toList( iter );
427 for ( int i = 0; i < children.size(); i++ )
428 {
429 Node child = (Node) children.get( i );
430 if ( child.getParentElement() != null )
431 {
432 child.detachNode();
433 child.recycleNode();
434 }
435 }
436 }
437
438 private static List toList( Iterator iter )
439 {
440 List list = new ArrayList();
441 while ( iter.hasNext() )
442 {
443 list.add( iter.next() );
444 }
445 return list;
446 }
447
448 }
449