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();
120
121 writer.writeEndDocument();
122 writer.close();
123 }
124
125 private void createMimeOutputStream(MessageContext context)
126 {
127
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
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 }