View Javadoc

1   package org.codehaus.xfire.handler;
2   
3   import java.util.Stack;
4   
5   import javax.xml.namespace.QName;
6   import javax.xml.stream.XMLStreamException;
7   import javax.xml.stream.XMLStreamReader;
8   import javax.xml.stream.XMLStreamWriter;
9   
10  import org.codehaus.xfire.MessageContext;
11  import org.codehaus.xfire.attachments.Attachments;
12  import org.codehaus.xfire.fault.XFireFault;
13  import org.codehaus.xfire.util.DOMUtils;
14  import org.codehaus.xfire.util.STAXUtils;
15  import org.w3c.dom.Document;
16  import org.w3c.dom.Element;
17  
18  /***
19   * Processes SOAP invocations. The process is as follows:
20   * <ul>
21   * <li>Read in Headers to a DOM tree</li>
22   * <li>Check "role" and MustUnderstand attributes for validity</li>
23   * <li>Invoke the request HandlerPipeline</li>
24   * <li>Invoke the service EndpointHandler</li>
25   * <li>Invoke the response HandlerPipeline</li>
26   * <li>Invoke <code>writeResponse</code> on the EndpointHandler</li>
27   * </ul>
28   * 
29   * TODO: outline what happens when a fault occurrs.
30   * 
31   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
32   * @since Oct 28, 2004
33   */
34  public class SoapHandler 
35      extends AbstractHandler
36  {
37      public static final String REQUEST_HEADER_KEY = "xfire.request-header";
38      public static final String RESPONSE_HEADER_KEY = "xfire.response-header";
39  
40      private EndpointHandler bodyHandler;
41      private Handler headerHandler;
42      private static final String HANDLER_STACK = "xfire.handlerStack";
43  
44      public SoapHandler( EndpointHandler bodyHandler )
45      {
46          this.bodyHandler = bodyHandler;
47      }
48  
49      /***
50       * Invoke the Header and Body Handlers for the SOAP message.
51       */
52      public void invoke(MessageContext context)
53      	throws Exception
54      {
55          XMLStreamReader reader = context.getXMLStreamReader();
56          XMLStreamWriter writer = null;
57          String encoding = null;
58  
59          Stack handlerStack = new Stack();
60          context.setProperty(HANDLER_STACK, handlerStack);
61  
62          boolean end = false;
63          while ( !end && reader.hasNext() )
64          {
65              int event = reader.next();
66              switch( event )
67              {
68              case XMLStreamReader.START_DOCUMENT:
69                  encoding = reader.getCharacterEncodingScheme();
70                  break;
71              case XMLStreamReader.END_DOCUMENT:
72                  end = true;
73                  break;
74              case XMLStreamReader.END_ELEMENT:
75                  break;
76              case XMLStreamReader.START_ELEMENT:
77                  if( reader.getLocalName().equals("Header") && headerHandler != null )
78                  {
79                      readHeaders(context);
80                      validateHeaders(context);
81                  }
82                  else if ( reader.getLocalName().equals("Body") )
83                  {
84                      invokeRequestPipeline(handlerStack, context);
85  
86                      handlerStack.push(bodyHandler);
87                      bodyHandler.invoke(context);
88                  }
89                  else if ( reader.getLocalName().equals("Envelope") )
90                  {
91                      context.setSoapVersion(reader.getNamespaceURI());
92                  }
93                  break;
94              default:
95                  break;
96              }
97          }
98  
99          Attachments atts = (Attachments) context.getProperty(Attachments.ATTACHMENTS_KEY);
100         if (atts != null && atts.size() > 0)
101         {
102             createMimeOutputStream(context);
103         }
104         
105         writer = createResponseWriter(context, encoding);
106 
107         writeHeaders(context, writer);
108 
109         invokeResponsePipeline(handlerStack, context);
110 
111         QName body = context.getSoapVersion().getBody();
112         writer.writeStartElement(body.getPrefix(), 
113                                  body.getLocalPart(),
114                                  body.getNamespaceURI());
115         
116         bodyHandler.writeResponse(context);
117         writer.writeEndElement();
118         
119         writer.writeEndElement();  // Envelope
120 
121         writer.writeEndDocument();
122         writer.close();       
123     }
124 
125     private void createMimeOutputStream(MessageContext context)
126     {
127         // TODO No outgoing attachment support yet.
128     }
129 
130     public void handleFault(XFireFault fault, MessageContext context) 
131     {
132         Stack handlerStack = (Stack) context.getProperty(HANDLER_STACK);
133 
134         while (!handlerStack.empty())
135         {
136             Handler handler = (Handler) handlerStack.pop();
137             handler.handleFault(fault, context);
138         }
139     }
140 
141     protected void invokeRequestPipeline(Stack handlerStack, MessageContext context) 
142     	throws Exception
143     {
144         if (context.getTransport() != null )
145             invokePipeline( context.getTransport().getRequestPipeline(), handlerStack, context );
146 
147         if (context.getService() != null )
148             invokePipeline( context.getService().getRequestPipeline(), handlerStack, context );
149     }
150 
151     protected void invokeResponsePipeline(Stack handlerStack, MessageContext context) 
152         throws Exception
153     {
154        if (context.getService() != null )
155             invokePipeline( context.getService().getResponsePipeline(), handlerStack, context );
156 
157        if (context.getTransport() != null )
158            invokePipeline( context.getTransport().getResponsePipeline(), handlerStack, context );
159     }
160 
161     protected void invokePipeline(HandlerPipeline pipeline, 
162                                   Stack handlerStack, 
163                                   MessageContext context)
164         throws Exception
165     {
166         if ( pipeline != null )
167         {
168             handlerStack.push(pipeline);    
169             pipeline.invoke(context);
170         }
171     }
172 
173     protected void readHeaders( MessageContext context ) 
174     	throws XMLStreamException
175     {
176         Document doc = DOMUtils.createDocument();
177         Element e = doc.createElementNS(context.getSoapVersion().getNamespace(), "Header");
178         
179         STAXUtils.readElements(e, context.getXMLStreamReader());
180             
181         context.setProperty(REQUEST_HEADER_KEY, e);
182     }
183     
184     protected void writeHeaders( MessageContext context, XMLStreamWriter writer ) 
185     	throws XMLStreamException
186     {
187         Element e = (Element) context.getProperty(REQUEST_HEADER_KEY);
188         if ( e != null )
189         {
190             writer.writeStartElement("soap", "Body", context.getSoapVersion().getNamespace());
191 
192             STAXUtils.writeElement(e, writer);
193             
194             writer.writeEndElement();
195         }
196     }
197 
198     protected void validateHeaders(MessageContext context)
199     {
200         /* TODO Check MustUnderstand and Role attributes
201          */ 
202     }
203     
204     private XMLStreamWriter createResponseWriter(MessageContext context, 
205                                                  String encoding)
206         throws XMLStreamException, XFireFault
207     {
208         XMLStreamWriter writer = getXMLStreamWriter(context);
209 
210         if ( encoding == null )
211             writer.writeStartDocument("UTF-8", "1.0");
212         else
213             writer.writeStartDocument(encoding, "1.0");
214         
215         QName env  = context.getSoapVersion().getEnvelope();
216         writer.setPrefix(env.getPrefix(), env.getNamespaceURI());
217         writer.writeStartElement(env.getPrefix(), 
218                                  env.getLocalPart(),
219                                  env.getNamespaceURI());
220         writer.writeNamespace(env.getPrefix(), env.getNamespaceURI());
221 
222         return writer;
223     }
224 }