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: 520432 $ $Date: 2007-03-20 11:35:27 -0400 (Tue, 20 Mar 2007) $ 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