001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.server.axis;
017:
018: import java.io.InputStream;
019: import java.io.IOException;
020: import java.net.URI;
021: import java.net.URL;
022: import java.util.Iterator;
023: import java.util.Map;
024: import javax.servlet.http.HttpServletResponse;
025: import javax.wsdl.OperationType;
026: import javax.xml.soap.MimeHeader;
027: import javax.xml.soap.MimeHeaders;
028: import javax.xml.soap.SOAPMessage;
029:
030: import org.apache.axis.AxisEngine;
031: import org.apache.axis.AxisFault;
032: import org.apache.axis.Constants;
033: import org.apache.axis.Message;
034: import org.apache.axis.MessageContext;
035: import org.apache.axis.SOAPPart;
036: import org.apache.axis.handlers.soap.SOAPService;
037: import org.apache.axis.message.SOAPEnvelope;
038: import org.apache.axis.soap.SOAPConstants;
039: import org.apache.axis.transport.http.HTTPConstants;
040: import org.apache.axis.utils.Messages;
041: import org.apache.openejb.server.webservices.WsConstants;
042: import org.apache.openejb.server.webservices.saaj.SaajUniverse;
043: import org.apache.openejb.server.httpd.HttpRequest;
044: import org.apache.openejb.server.httpd.HttpResponse;
045: import org.apache.openejb.server.httpd.HttpListener;
046: import org.apache.openejb.util.Logger;
047: import org.apache.openejb.util.LogCategory;
048: import org.w3c.dom.Element;
049:
050: public class AxisWsContainer implements HttpListener {
051: private static final Logger logger = Logger.getInstance(
052: LogCategory.AXIS, AxisWsContainer.class);
053: public static final String REQUEST = AxisWsContainer.class
054: .getName()
055: + "@Request";
056: public static final String RESPONSE = AxisWsContainer.class
057: .getName()
058: + "@Response";
059:
060: public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema";
061:
062: private final URL wsdlLocation;
063: private final SOAPService service;
064:
065: private final ClassLoader classLoader;
066: private final Map wsdlMap;
067:
068: public AxisWsContainer(URL wsdlURL, SOAPService service,
069: Map wsdlMap, ClassLoader classLoader) {
070: this .wsdlLocation = wsdlURL;
071: this .service = service;
072: this .wsdlMap = wsdlMap;
073: if (classLoader == null) {
074: this .classLoader = Thread.currentThread()
075: .getContextClassLoader();
076: } else {
077: this .classLoader = classLoader;
078: }
079: }
080:
081: public void onMessage(HttpRequest request, HttpResponse response)
082: throws Exception {
083: SaajUniverse universe = new SaajUniverse();
084: universe.set(SaajUniverse.AXIS1);
085: try {
086: doService(request, response);
087: } finally {
088: universe.unset();
089: }
090: }
091:
092: protected void doService(HttpRequest req, HttpResponse res)
093: throws Exception {
094: org.apache.axis.MessageContext messageContext = new org.apache.axis.MessageContext(
095: null);
096: req.setAttribute(WsConstants.MESSAGE_CONTEXT, messageContext);
097:
098: messageContext.setClassLoader(classLoader);
099:
100: Message responseMessage = null;
101:
102: String contentType = req
103: .getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
104: String contentLocation = req
105: .getHeader(HTTPConstants.HEADER_CONTENT_LOCATION);
106: InputStream inputStream = req.getInputStream();
107: Message requestMessage = new Message(inputStream, false,
108: contentType, contentLocation);
109:
110: messageContext.setRequestMessage(requestMessage);
111: messageContext.setProperty(
112: HTTPConstants.MC_HTTP_SERVLETPATHINFO, req.getURI()
113: .getPath());
114: messageContext.setProperty(
115: org.apache.axis.MessageContext.TRANS_URL, req.getURI()
116: .toString());
117: messageContext.setService(service);
118: messageContext.setProperty(REQUEST, req);
119: messageContext.setProperty(RESPONSE, res);
120: messageContext.setProperty(AxisEngine.PROP_DISABLE_PRETTY_XML,
121: Boolean.TRUE);
122:
123: ClassLoader oldClassLoader = Thread.currentThread()
124: .getContextClassLoader();
125: try {
126: try {
127: String characterEncoding = (String) requestMessage
128: .getProperty(SOAPMessage.CHARACTER_SET_ENCODING);
129: if (characterEncoding != null) {
130: messageContext.setProperty(
131: SOAPMessage.CHARACTER_SET_ENCODING,
132: characterEncoding);
133: } else {
134: messageContext
135: .setProperty(
136: SOAPMessage.CHARACTER_SET_ENCODING,
137: "UTF-8");
138: }
139:
140: String soapAction = req
141: .getHeader(HTTPConstants.HEADER_SOAP_ACTION);
142: if (soapAction != null) {
143: messageContext.setUseSOAPAction(true);
144: messageContext.setSOAPActionURI(soapAction);
145: }
146:
147: SOAPEnvelope env = requestMessage.getSOAPEnvelope();
148: if (env != null && env.getSOAPConstants() != null) {
149: messageContext.setSOAPConstants(env
150: .getSOAPConstants());
151: }
152: SOAPService service = messageContext.getService();
153:
154: Thread.currentThread().setContextClassLoader(
155: classLoader);
156: service.invoke(messageContext);
157:
158: responseMessage = messageContext.getResponseMessage();
159: } catch (AxisFault fault) {
160:
161: if (req.getMethod() == HttpRequest.Method.GET
162: && req.getParameters().isEmpty()) {
163: String serviceName = req.getURI().getRawPath();
164: serviceName = serviceName.substring(serviceName
165: .lastIndexOf("/") + 1);
166: printServiceInfo(res, serviceName);
167: return;
168: } else {
169: responseMessage = handleFault(fault, res,
170: messageContext);
171: }
172:
173: } catch (Exception e) {
174: responseMessage = handleException(messageContext, res,
175: e);
176: }
177: //TODO investigate and fix operation == null!
178: if (messageContext.getOperation() != null) {
179: if (messageContext.getOperation().getMep() == OperationType.ONE_WAY) {
180: // No content, so just indicate accepted
181: res.setStatusCode(202);
182: return;
183: } else if (responseMessage == null) {
184: responseMessage = handleException(
185: messageContext,
186: null,
187: new RuntimeException(
188: "No response for non-one-way operation"));
189: }
190: } else if (responseMessage == null) {
191: res.setStatusCode(202);
192: return;
193: }
194: try {
195: SOAPConstants soapConstants = messageContext
196: .getSOAPConstants();
197: String contentType1 = responseMessage
198: .getContentType(soapConstants);
199: res.setContentType(contentType1);
200: // Transfer MIME headers to HTTP headers for response message.
201: MimeHeaders responseMimeHeaders = responseMessage
202: .getMimeHeaders();
203: for (Iterator i = responseMimeHeaders.getAllHeaders(); i
204: .hasNext();) {
205: MimeHeader responseMimeHeader = (MimeHeader) i
206: .next();
207: res.setHeader(responseMimeHeader.getName(),
208: responseMimeHeader.getValue());
209: }
210: //TODO discuss this with dims.
211: // // synchronize the character encoding of request and response
212: // String responseEncoding = (String) messageContext.getProperty(
213: // SOAPMessage.CHARACTER_SET_ENCODING);
214: // if (responseEncoding != null) {
215: // try {
216: // responseMessage.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
217: // responseEncoding);
218: // } catch (SOAPException e) {
219: // log.info(Messages.getMessage("exception00"), e);
220: // }
221: // }
222: //determine content type from message response
223: contentType = responseMessage
224: .getContentType(messageContext
225: .getSOAPConstants());
226: responseMessage.writeTo(res.getOutputStream());
227: } catch (Exception e) {
228: logger.warning(Messages.getMessage("exception00"), e);
229: }
230: } finally {
231: Thread.currentThread()
232: .setContextClassLoader(oldClassLoader);
233: }
234: }
235:
236: private Message handleException(MessageContext context,
237: HttpResponse res, Exception e) {
238: Message responseMessage;
239: //other exceptions are internal trouble
240: responseMessage = context.getResponseMessage();
241: res.setStatusCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
242: Message responseMsg = responseMessage;
243: logger.warning(Messages.getMessage("exception00"), e);
244: if (responseMsg == null) {
245: AxisFault fault = AxisFault.makeFault(e);
246: //log the fault
247: Element runtimeException = fault
248: .lookupFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
249: if (runtimeException != null) {
250: logger.debug(Messages.getMessage("axisFault00"), fault);
251: //strip runtime details
252: fault
253: .removeFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
254: }
255: responseMsg = new Message(fault);
256: }
257: responseMessage = responseMsg;
258: SOAPPart soapPart = (SOAPPart) responseMessage.getSOAPPart();
259: soapPart.getMessage().setMessageContext(context);
260: return responseMessage;
261: }
262:
263: private Message handleFault(AxisFault fault, HttpResponse res,
264: MessageContext context) {
265: Message responseMessage;
266: Element runtimeException = fault
267: .lookupFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
268:
269: logger.warning(Messages.getMessage("axisFault00"), fault);
270: if (runtimeException != null) {
271: //strip runtime details
272: fault
273: .removeFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION);
274: }
275:
276: int status = fault.getFaultCode().getLocalPart().startsWith(
277: "Server.Unauth") ? HttpServletResponse.SC_UNAUTHORIZED
278: : HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
279: if (status == HttpServletResponse.SC_UNAUTHORIZED) {
280: // unauth access results in authentication request
281: // TODO: less generic realm choice?
282: res.setHeader("WWW-Authenticate", "Basic realm=\"AXIS\"");
283: }
284: res.setStatusCode(status);
285: responseMessage = context.getResponseMessage();
286: if (responseMessage == null) {
287: responseMessage = new Message(fault);
288: SOAPPart soapPart = (SOAPPart) responseMessage
289: .getSOAPPart();
290: soapPart.getMessage().setMessageContext(context);
291: }
292: return responseMessage;
293: }
294:
295: public void getWsdl(HttpRequest request, HttpResponse response)
296: throws Exception {
297: URI realLocation = request.getURI();
298: // log.info("Request at " + realLocation);
299: String query = realLocation.getQuery();
300: if (query == null || !query.toLowerCase().startsWith("wsdl")) {
301: throw new IllegalStateException(
302: "request must contain a wsdl or WSDL parameter: "
303: + request.getParameters());
304: }
305: String locationKey;
306: if (query.length() > 4) {
307: locationKey = query.substring(5);
308: } else {
309: locationKey = wsdlLocation.toString();
310: }
311: Object wsdl = wsdlMap.get(locationKey);
312: if (wsdl == null) {
313: throw new IllegalStateException(
314: "No wsdl or schema known at location: "
315: + locationKey);
316: }
317: URI updated = new URI(realLocation.getScheme(), realLocation
318: .getUserInfo(), realLocation.getHost(), realLocation
319: .getPort(), null, //try null for no path
320: null, null);
321: String replaced = ((String) wsdl).replaceAll(
322: WsConstants.LOCATION_REPLACEMENT_TOKEN, updated
323: .toString());
324: response.getOutputStream().write(replaced.getBytes());
325: response.getOutputStream().flush();
326: }
327:
328: public void destroy() {
329: }
330:
331: /**
332: * print a snippet of service info.
333: * @param response response
334: * @param serviceName Name of the service
335: */
336:
337: private void printServiceInfo(HttpResponse response,
338: String serviceName) throws IOException {
339: response.setContentType("text/html; charset=utf-8");
340: StringBuffer output = new StringBuffer("<h1>").append(
341: serviceName).append("</h1>\n");
342:
343: output.append("<p>").append(
344: Messages.getMessage("axisService00")).append("</p>\n");
345: output.append("<i>").append(Messages.getMessage("perhaps00"))
346: .append("</i>\n");
347: response.getOutputStream().write(output.toString().getBytes());
348: }
349:
350: }
|