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