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