View Javadoc

1   /*
2    *  Copyright (c) 2008 Rodrigo Ruiz
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.apache.ws.addressing.handler;
17  
18  import java.io.IOException;
19  
20  import javax.xml.rpc.JAXRPCException;
21  import javax.xml.rpc.handler.MessageContext;
22  import javax.xml.rpc.handler.soap.SOAPMessageContext;
23  import javax.xml.soap.SOAPException;
24  import javax.xml.soap.SOAPMessage;
25  
26  import org.apache.axis.message.addressing.Action;
27  import org.apache.axis.message.addressing.AddressingHeaders;
28  import org.apache.axis.message.addressing.Constants;
29  import org.apache.axis.message.addressing.EndpointReference;
30  import org.apache.axis.message.addressing.To;
31  import org.apache.axis.message.addressing.util.AddressingUtils;
32  import org.apache.axis.types.URI.MalformedURIException;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  /**
37   * A client-side JAX-RPC {@link javax.xml.rpc.handler.Handler} that inserts
38   * WS-Addressing headers into outgoing SOAP requests
39   * and extracts them from incoming SOAP responses.
40   *
41   * @author Davanum Srinivas
42   * @author Ian P. Springer
43   * @version $Revision: 14 $
44   */
45  public class ClientSideAddressingHandler extends AbstractAddressingHandler {
46    /**
47     * Class logger.
48     */
49    private static final Log LOG = LogFactory.getLog(ClientSideAddressingHandler.class);
50  
51    /**
52     * SOAP Action property name.
53     */
54    private static final String MSG_CONTEXT_PROP_SOAP_ACTION
55      = javax.xml.rpc.Call.SOAPACTION_URI_PROPERTY;
56  
57    /**
58     * {@inheritDoc}
59     */
60    public boolean handleRequest(MessageContext msgContext) {
61      SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
62      try {
63        AddressingHeaders headers = (AddressingHeaders) msgContext
64        .getProperty(Constants.ENV_ADDRESSING_REQUEST_HEADERS);
65        if (headers == null) {
66          headers = new AddressingHeaders();
67        }
68        headers.setSetMustUnderstand(isMustUnderstandEnabled(msgContext));
69        addMessageIdHeader(headers);
70        addToHeader(headers, msgContext);
71        addActionHeader(headers, msgContext);
72        addFromHeader(headers, msgContext);
73        addReplyToHeader(headers, msgContext);
74        if (headers.getFaultTo() == null
75            && msgContext.containsProperty(Constants.ENV_ADDRESSING_FAULTTO_URI)) {
76          headers.setFaultTo(new EndpointReference((String) msgContext
77              .getProperty(Constants.ENV_ADDRESSING_FAULTTO_URI)));
78        }
79  
80        SOAPMessage msg = soapMsgContext.getMessage();
81        headers.toEnvelope(msg.getSOAPPart().getEnvelope(), getActor());
82        msgContext.setProperty(Constants.ENV_ADDRESSING_REQUEST_HEADERS, headers);
83      } catch (IOException e) {
84        if (LOG.isDebugEnabled()) {
85          LOG.debug("Unexpected error in handleRequest()", e);
86        }
87        throw new JAXRPCException("unexpected error in handleRequest()", e);
88      } catch (SOAPException e) {
89        if (LOG.isDebugEnabled()) {
90          LOG.debug("Unexpected error in handleRequest()", e);
91        }
92        throw new JAXRPCException("unexpected error in handleRequest()", e);
93      }
94      return CONTINUE_HANDLER_CHAIN_PROCESSING;
95    }
96  
97    /**
98     * {@inheritDoc}
99     */
100   public boolean handleResponse(MessageContext msgContext) {
101     SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
102     try {
103       SOAPMessage msg = soapMsgContext.getMessage();
104       if (msg == null) {
105         return CONTINUE_HANDLER_CHAIN_PROCESSING;
106       }
107 
108       AddressingHeaders headers = new AddressingHeaders(
109         msg.getSOAPPart().getEnvelope(), getActor(), true, isRemoveHeadersEnabled(),
110         false, getReferencePropertyQNames());
111       msgContext.setProperty(Constants.ENV_ADDRESSING_RESPONSE_HEADERS, headers);
112     } catch (Exception e) {
113       if (LOG.isDebugEnabled()) {
114         e.printStackTrace();
115       }
116       throw new JAXRPCException("unexpected error in handleResponse(): " + e, e);
117     }
118     return CONTINUE_HANDLER_CHAIN_PROCESSING;
119   }
120 
121   /**
122    * {@inheritDoc}
123    */
124   public boolean handleFault(MessageContext messageContext) {
125     return CONTINUE_HANDLER_CHAIN_PROCESSING;
126   }
127 
128   /**
129    * The JAX-RPC APIs don't provide a way to retrieve the value of the SOAPAction
130    * HTTP header, so platform-specific subclasses should implement this method if
131    * feasible.
132    *
133    * @param msgContext JAX-RPC message context
134    * @return the value of the SOAPAction HTTP header
135    */
136   protected String getSOAPAction(MessageContext msgContext) {
137     return (String) msgContext.getProperty(MSG_CONTEXT_PROP_SOAP_ACTION);
138   }
139 
140   /**
141    * The JAX-RPC APIs don't provide a way to set the value of the SOAPAction HTTP header,
142    * so platform-specific subclasses should implement this method if feasible.
143    *
144    * @param msgContext JAX-RPC message context
145    * @param actionURI  the SOAPAction URI to be set
146    */
147   protected void setSOAPAction(MessageContext msgContext, String actionURI) {
148     msgContext.setProperty(MSG_CONTEXT_PROP_SOAP_ACTION, actionURI);
149   }
150 
151   /**
152    * Returns the endpoint URL for the specified message context. Since there's no
153    * generic JAX-RPC way to obtain the request's endpoint URL, we return null here.
154    * Platform-specific handlers can override if the platform provides a means to
155    * obtain the endpoint URL.
156    *
157    * @param msgContext Context information
158    * @return the endpoint URL for the specified message context
159    */
160   protected String getEndpointURL(MessageContext msgContext) {
161     return null;
162   }
163 
164   /**
165    * Builds a ReplyTo header and adds it to the headers instance.
166    *
167    * @param addrHeaders Headers container
168    * @param msgContext  Context information
169    * @throws MalformedURIException If an invalid URI is built
170    */
171   private void addReplyToHeader(AddressingHeaders addrHeaders, MessageContext msgContext)
172     throws MalformedURIException {
173     if (isPropertyTrue(msgContext, Constants.ENV_ADDRESSING_SEND_REPLYTO)
174         && addrHeaders.getReplyTo() == null) {
175       if (msgContext.containsProperty(Constants.ENV_ADDRESSING_REPLYTO_URI)) {
176         addrHeaders.setReplyTo(new EndpointReference((String) msgContext
177             .getProperty(Constants.ENV_ADDRESSING_REPLYTO_URI)));
178       } else {
179         addrHeaders.setReplyTo(addrHeaders.getFrom());
180       }
181     }
182   }
183 
184   /**
185    * Builds a From header and adds it to the specified headers container.
186    *
187    * @param addrHeaders Container
188    * @param ctx  Context information
189    * @throws MalformedURIException If an invalid URI is built
190    */
191   private void addFromHeader(AddressingHeaders addrHeaders, MessageContext ctx)
192     throws MalformedURIException {
193     if (addrHeaders.getFrom() == null) {
194       String uri = (String)ctx.getProperty(Constants.ENV_ADDRESSING_FROM_URI);
195       if (uri == null) {
196         uri = AddressingUtils.getAnonymousRoleURI(ctx);
197       }
198       addrHeaders.setFrom(new EndpointReference(uri));
199     }
200   }
201 
202   /**
203    * Builds a MessageID header and adds it to the specified headers container.
204    *
205    * @param addrHeaders Container
206    * @throws MalformedURIException If an invalid URI is built
207    */
208   private void addMessageIdHeader(AddressingHeaders addrHeaders)
209     throws MalformedURIException {
210     if (addrHeaders.getMessageID() == null) {
211       addrHeaders.setMessageID(createMessageID());
212     }
213   }
214 
215   /**
216    * Builds a To header and adds it to the specified headers container.
217    *
218    * @param addrHeaders Container
219    * @param msgContext  Context information
220    * @throws MalformedURIException If an invalid URI is built
221    */
222   private void addToHeader(AddressingHeaders addrHeaders, MessageContext msgContext)
223     throws MalformedURIException {
224     if (addrHeaders.getTo() == null) {
225       String endpointURL = getEndpointURL(msgContext);
226       addrHeaders.setTo(endpointURL != null ? new To(endpointURL) : null);
227     }
228   }
229 
230   /**
231    * Builds an Action header and adds it to the specified headers container.
232    *
233    * @param addrHeaders Container
234    * @param msgContext  Context information
235    * @throws MalformedURIException If an invalid URI is built
236    */
237   private void addActionHeader(AddressingHeaders addrHeaders, MessageContext msgContext)
238     throws MalformedURIException {
239     String actionURI = getSOAPAction(msgContext);
240     if (actionURI != null) {
241       addrHeaders.setAction(new Action(actionURI));
242     } else if (addrHeaders.getAction() != null) {
243       setSOAPAction(msgContext, addrHeaders.getAction().toString());
244     }
245   }
246 }