1 package org.codehaus.xfire.transport.http;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.UnsupportedEncodingException;
6 import java.util.Properties;
7
8 import javax.mail.MessagingException;
9 import javax.mail.Session;
10 import javax.mail.internet.MimeMessage;
11 import javax.mail.internet.MimeMultipart;
12 import javax.servlet.ServletException;
13 import javax.servlet.http.HttpServletRequest;
14 import javax.servlet.http.HttpServletResponse;
15 import javax.xml.stream.XMLStreamException;
16 import javax.xml.stream.XMLStreamReader;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.codehaus.xfire.MessageContext;
21 import org.codehaus.xfire.XFire;
22 import org.codehaus.xfire.XFireRuntimeException;
23 import org.codehaus.xfire.attachments.JavaMailAttachments;
24 import org.codehaus.xfire.exchange.InMessage;
25 import org.codehaus.xfire.service.Service;
26 import org.codehaus.xfire.service.ServiceRegistry;
27 import org.codehaus.xfire.soap.SoapTransport;
28 import org.codehaus.xfire.transport.Channel;
29 import org.codehaus.xfire.transport.Transport;
30 import org.codehaus.xfire.transport.TransportManager;
31 import org.codehaus.xfire.util.STAXUtils;
32
33 /***
34 * Loads XFire and processes requests.
35 *
36 * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
37 * @since Feb 13, 2004
38 */
39 public class XFireServletController
40 {
41 private static ThreadLocal requests = new ThreadLocal();
42 private static ThreadLocal responses = new ThreadLocal();
43 private final static Log logger = LogFactory.getLog(XFireServletController.class);
44
45 protected XFire xfire;
46
47 protected Transport transport;
48
49 public XFireServletController(XFire xfire)
50 {
51 this.xfire = xfire;
52 this.transport = SoapTransport.createSoapTransport(new SoapHttpTransport());
53
54 registerTransport();
55 }
56
57 protected void registerTransport()
58 {
59 TransportManager service = getTransportManager();
60 service.register(transport);
61 }
62
63 public static HttpServletRequest getRequest()
64 {
65 return (HttpServletRequest) requests.get();
66 }
67
68 public static HttpServletResponse getResponse()
69 {
70 return (HttpServletResponse) responses.get();
71 }
72
73 protected TransportManager getTransportManager()
74 {
75 return getXFire().getTransportManager();
76 }
77
78 /***
79 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
80 * javax.servlet.http.HttpServletResponse)
81 */
82 public void doService(HttpServletRequest request,
83 HttpServletResponse response)
84 throws ServletException, IOException
85 {
86 String serviceName = getService(request);
87 ServiceRegistry reg = getServiceRegistry();
88
89 response.setHeader("Content-Type", "UTF-8");
90
91 requests.set(request);
92 responses.set(response);
93
94 if (serviceName == null || serviceName.length() == 0 || !reg.hasService(serviceName))
95 {
96 if (!reg.hasService(serviceName))
97 {
98 response.setStatus(404);
99 }
100
101 generateServices(response);
102 return;
103 }
104
105 try
106 {
107 if (request.getQueryString() != null &&
108 request.getQueryString().trim().equalsIgnoreCase("wsdl"))
109 {
110 generateWSDL(response, serviceName);
111 }
112 else
113 {
114 invoke(request, response, serviceName);
115 }
116 }
117 catch (Exception e)
118 {
119 logger.error("Couldn't invoke servlet request.", e);
120
121 if (e instanceof ServletException)
122 {
123 throw (ServletException) e;
124 }
125 else
126 {
127 throw new ServletException(e);
128 }
129 }
130 finally
131 {
132 requests.set(null);
133 responses.set(null);
134 }
135 }
136
137 protected void generateService(HttpServletResponse response, String serviceName)
138 throws ServletException, IOException
139
140 {
141 response.setContentType("text/html");
142 Service endpoint = getServiceRegistry().getService(serviceName);
143 HtmlServiceWriter writer = new HtmlServiceWriter();
144 try
145 {
146 writer.write(response.getOutputStream(), endpoint);
147 }
148 catch (XMLStreamException e)
149 {
150 throw new ServletException("Error writing HTML services list", e);
151 }
152 }
153
154
155 /***
156 * @param response
157 */
158 protected void generateServices(HttpServletResponse response)
159 throws ServletException, IOException
160 {
161 response.setContentType("text/html");
162
163 HtmlServiceWriter writer = new HtmlServiceWriter();
164 try
165 {
166 writer.write(response.getOutputStream(), getServiceRegistry().getServices());
167 }
168 catch (XMLStreamException e)
169 {
170 throw new ServletException("Error writing HTML services list", e);
171 }
172 }
173
174 /***
175 * @param request
176 * @param response
177 * @param service
178 * @throws ServletException
179 * @throws IOException
180 * @throws UnsupportedEncodingException
181 */
182 protected void invoke(HttpServletRequest request,
183 HttpServletResponse response,
184 String service)
185 throws ServletException, IOException, UnsupportedEncodingException
186 {
187
188
189
190
191 response.setStatus(200);
192
193
194 XFireHttpSession session = new XFireHttpSession(request);
195 MessageContext context = new MessageContext();
196 context.setXFire(getXFire());
197 context.setSession(session);
198 context.setService(getService(service));
199
200 Channel channel;
201 try
202 {
203 channel = transport.createChannel(request.getRequestURI());
204 }
205 catch (Exception e)
206 {
207 throw new ServletException("Couldn't open channel.", e);
208 }
209
210 String contentType = request.getContentType();
211 if (null == contentType)
212 {
213 response.setContentType("text/html; charset=UTF-8");
214
215
216 response.getWriter().write("<html><body>Invalid SOAP request.</body></html>");
217 response.getWriter().close();
218 }
219 else if (contentType.toLowerCase().indexOf("multipart/related") != -1)
220 {
221 try
222 {
223 response.setContentType("text/xml; charset=UTF-8");
224 InputStream stream = createMIMERequest(request, context);
225
226 XMLStreamReader reader =
227 STAXUtils.createXMLStreamReader(stream, request.getCharacterEncoding());
228 InMessage message = new InMessage(reader, request.getRequestURI());
229 channel.receive(context, message);
230 }
231 catch (MessagingException e)
232 {
233 throw new XFireRuntimeException("Couldn't parse request message.", e);
234 }
235 }
236 else
237 {
238 response.setContentType("text/xml; charset=UTF-8");
239 XMLStreamReader reader =
240 STAXUtils.createXMLStreamReader(request.getInputStream(),
241 request.getCharacterEncoding());
242
243 InMessage message = new InMessage(reader, request.getRequestURI());
244 channel.receive(context, message);
245 }
246 }
247
248 protected InputStream createMIMERequest(HttpServletRequest request, MessageContext context)
249 throws MessagingException, IOException
250 {
251 Session session = Session.getDefaultInstance(new Properties(), null);
252 MimeMessage inMsg = new MimeMessage(session, request.getInputStream());
253 inMsg.addHeaderLine("Content-Type: " + request.getContentType());
254
255 final Object content = inMsg.getContent();
256
257 if (content instanceof MimeMultipart)
258 {
259 MimeMultipart inMP = (MimeMultipart) content;
260
261 JavaMailAttachments atts = new JavaMailAttachments(inMP);
262 context.setProperty(JavaMailAttachments.ATTACHMENTS_KEY, atts);
263
264 return atts.getSoapMessage().getDataHandler().getInputStream();
265 }
266 else
267 {
268 throw new UnsupportedOperationException();
269
270 }
271 }
272
273 /***
274 * @param response
275 * @param service
276 * @throws ServletException
277 * @throws IOException
278 */
279 protected void generateWSDL(HttpServletResponse response, String service)
280 throws ServletException, IOException
281 {
282 response.setStatus(200);
283 response.setContentType("text/xml");
284
285 getXFire().generateWSDL(service, response.getOutputStream());
286 }
287
288 /***
289 * Get the service that is mapped to the specified request.
290 */
291 protected String getService(HttpServletRequest request)
292 {
293 String pathInfo = request.getPathInfo();
294
295 if (pathInfo == null)
296 return null;
297
298 String serviceName;
299
300 if (pathInfo.startsWith("/"))
301 {
302 serviceName = pathInfo.substring(1);
303 }
304 else
305 {
306 serviceName = pathInfo;
307 }
308
309 return serviceName;
310 }
311
312 protected Service getService(String name)
313 {
314 return getXFire().getServiceRegistry().getService(name);
315 }
316
317 public XFire getXFire()
318 {
319 return xfire;
320 }
321
322 public ServiceRegistry getServiceRegistry()
323 {
324 return xfire.getServiceRegistry();
325 }
326 }