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
018 package org.apache.geronimo.axis2;
019
020 import java.io.ByteArrayInputStream;
021 import java.io.PrintWriter;
022 import java.net.HttpURLConnection;
023 import java.net.URL;
024 import java.util.List;
025
026 import javax.naming.Context;
027 import javax.servlet.ServletContext;
028 import javax.servlet.http.HttpServletRequest;
029 import javax.servlet.http.HttpServletResponse;
030 import javax.xml.ws.Binding;
031 import javax.xml.ws.WebServiceException;
032 import javax.xml.ws.handler.Handler;
033
034 import org.apache.axiom.om.util.UUIDGenerator;
035 import org.apache.axis2.AxisFault;
036 import org.apache.axis2.Constants;
037 import org.apache.axis2.addressing.AddressingHelper;
038 import org.apache.axis2.addressing.EndpointReference;
039 import org.apache.axis2.context.ConfigurationContext;
040 import org.apache.axis2.context.ConfigurationContextFactory;
041 import org.apache.axis2.context.MessageContext;
042 import org.apache.axis2.context.OperationContext;
043 import org.apache.axis2.description.AxisService;
044 import org.apache.axis2.description.TransportInDescription;
045 import org.apache.axis2.description.TransportOutDescription;
046 import org.apache.axis2.engine.AxisEngine;
047 import org.apache.axis2.engine.Handler.InvocationResponse;
048 import org.apache.axis2.jaxws.binding.BindingImpl;
049 import org.apache.axis2.jaxws.binding.BindingUtils;
050 import org.apache.axis2.jaxws.description.EndpointDescription;
051 import org.apache.axis2.jaxws.description.impl.DescriptionUtils;
052 import org.apache.axis2.jaxws.description.xml.handler.HandlerChainType;
053 import org.apache.axis2.jaxws.description.xml.handler.HandlerChainsType;
054 import org.apache.axis2.jaxws.description.xml.handler.HandlerType;
055 import org.apache.axis2.jaxws.handler.lifecycle.factory.HandlerLifecycleManagerFactory;
056 import org.apache.axis2.jaxws.registry.FactoryRegistry;
057 import org.apache.axis2.jaxws.server.JAXWSMessageReceiver;
058 import org.apache.axis2.transport.OutTransportInfo;
059 import org.apache.axis2.transport.RequestResponseTransport;
060 import org.apache.axis2.transport.http.HTTPConstants;
061 import org.apache.axis2.transport.http.HTTPTransportReceiver;
062 import org.apache.axis2.transport.http.HTTPTransportUtils;
063 import org.apache.axis2.transport.http.TransportHeaders;
064 import org.apache.axis2.transport.http.util.RESTUtil;
065 import org.apache.axis2.util.MessageContextBuilder;
066 import org.apache.commons.logging.Log;
067 import org.apache.commons.logging.LogFactory;
068 import org.apache.geronimo.axis2.client.Axis2ConfigGBean;
069 import org.apache.geronimo.jaxws.JAXWSAnnotationProcessor;
070 import org.apache.geronimo.jaxws.JAXWSUtils;
071 import org.apache.geronimo.jaxws.JNDIResolver;
072 import org.apache.geronimo.jaxws.PortInfo;
073 import org.apache.geronimo.jaxws.ServerJNDIResolver;
074 import org.apache.geronimo.jaxws.annotations.AnnotationException;
075 import org.apache.geronimo.webservices.WebServiceContainer;
076 import org.apache.geronimo.webservices.saaj.SAAJUniverse;
077
078 /**
079 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
080 */
081 public abstract class Axis2WebServiceContainer implements WebServiceContainer {
082
083 private static final Log LOG = LogFactory.getLog(Axis2WebServiceContainer.class);
084
085 public static final String REQUEST = Axis2WebServiceContainer.class.getName() + "@Request";
086 public static final String RESPONSE = Axis2WebServiceContainer.class.getName() + "@Response";
087
088 private transient final ClassLoader classLoader;
089
090 protected String endpointClassName;
091 protected org.apache.geronimo.jaxws.PortInfo portInfo;
092 protected ConfigurationContext configurationContext;
093 protected JNDIResolver jndiResolver;
094 protected Class endpointClass;
095 protected AxisService service;
096 protected URL configurationBaseUrl;
097 protected WSDLQueryHandler wsdlQueryHandler;
098 protected Binding binding;
099 protected JAXWSAnnotationProcessor annotationProcessor;
100 protected Context context;
101
102 public Axis2WebServiceContainer(PortInfo portInfo,
103 String endpointClassName,
104 ClassLoader classLoader,
105 Context context,
106 URL configurationBaseUrl) {
107 this.classLoader = classLoader;
108 this.endpointClassName = endpointClassName;
109 this.portInfo = portInfo;
110 this.configurationBaseUrl = configurationBaseUrl;
111 this.context = context;
112 this.jndiResolver = new ServerJNDIResolver(context);
113 }
114
115 public void init() throws Exception {
116 this.endpointClass = classLoader.loadClass(this.endpointClassName);
117
118 Axis2ConfigGBean.registerClientConfigurationFactory();
119
120 configurationContext = ConfigurationContextFactory.createBasicConfigurationContext("META-INF/geronimo-axis2.xml");
121
122 // check to see if the wsdlLocation property is set in portInfo,
123 // if not checking if wsdlLocation exists in annotation
124 // if already set, annotation should not overwrite it.
125 if (portInfo.getWsdlFile() == null || portInfo.getWsdlFile().equals("")) {
126 // getwsdllocation from annotation if it exists
127 if (JAXWSUtils.containsWsdlLocation(this.endpointClass, classLoader)) {
128 portInfo.setWsdlFile(JAXWSUtils.getServiceWsdlLocation(this.endpointClass, classLoader));
129 }
130 }
131
132 AxisServiceGenerator serviceGen = createServiceGenerator();
133 if (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().equals("")) {
134 // WSDL file has been provided
135 service = serviceGen.getServiceFromWSDL(portInfo, endpointClass, configurationBaseUrl);
136 } else {
137 // No WSDL, let Axis2 handle it.
138 service = serviceGen.getServiceFromClass(this.endpointClass);
139 }
140
141 service.setScope(Constants.SCOPE_APPLICATION);
142 configurationContext.getAxisConfiguration().addService(service);
143
144 this.wsdlQueryHandler = new WSDLQueryHandler(this.service);
145
146 /*
147 * This replaces HandlerLifecycleManagerFactory for all web services.
148 * This should be ok as we do our own handler instance managment and injection.
149 * Also, this does not affect service-ref clients, as we install our own
150 * HandlerResolver.
151 */
152 FactoryRegistry.setFactory(HandlerLifecycleManagerFactory.class,
153 new GeronimoHandlerLifecycleManagerFactory());
154 }
155
156 protected AxisServiceGenerator createServiceGenerator() {
157 return new AxisServiceGenerator();
158 }
159
160 public void getWsdl(Request request, Response response) throws Exception {
161 doService(request, response);
162 }
163
164 public void invoke(Request request, Response response) throws Exception {
165 SAAJUniverse universe = new SAAJUniverse();
166 universe.set(SAAJUniverse.AXIS2);
167 try {
168 doService(request, response);
169 } finally {
170 universe.unset();
171 }
172 }
173
174 protected void doService(final Request request, final Response response)
175 throws Exception {
176
177 if (LOG.isDebugEnabled()) {
178 LOG.debug("Target URI: " + request.getURI());
179 }
180
181 MessageContext msgContext = new MessageContext();
182 msgContext.setIncomingTransportName(Constants.TRANSPORT_HTTP);
183 msgContext.setProperty(MessageContext.REMOTE_ADDR, request.getRemoteAddr());
184
185 try {
186 TransportOutDescription transportOut = this.configurationContext.getAxisConfiguration()
187 .getTransportOut(Constants.TRANSPORT_HTTP);
188 TransportInDescription transportIn = this.configurationContext.getAxisConfiguration()
189 .getTransportIn(Constants.TRANSPORT_HTTP);
190
191 msgContext.setConfigurationContext(this.configurationContext);
192
193 //TODO: Port this segment for session support.
194 // String sessionKey = (String) this.httpcontext.getAttribute(HTTPConstants.COOKIE_STRING);
195 // if (this.configurationContext.getAxisConfiguration().isManageTransportSession()) {
196 // SessionContext sessionContext = this.sessionManager.getSessionContext(sessionKey);
197 // msgContext.setSessionContext(sessionContext);
198 // }
199 msgContext.setTransportIn(transportIn);
200 msgContext.setTransportOut(transportOut);
201 msgContext.setServiceGroupContextId(UUIDGenerator.getUUID());
202 msgContext.setServerSide(true);
203 msgContext.setAxisService(this.service);
204
205 doService2(request, response, msgContext);
206 } catch (AxisFault e) {
207 LOG.debug(e.getMessage(), e);
208 handleFault(msgContext, response, e);
209 } catch (Throwable e) {
210 String msg = "Exception occurred while trying to invoke service method doService()";
211 LOG.error(msg, e);
212 handleFault(msgContext, response, new AxisFault(msg, e));
213 }
214
215 }
216
217 private void handleFault(MessageContext msgContext, Response response, AxisFault e) {
218 // If the fault is not going along the back channel we should be 202ing
219 if (AddressingHelper.isFaultRedirected(msgContext)) {
220 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED);
221 } else {
222 response.setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR);
223 }
224
225 msgContext.setProperty(MessageContext.TRANSPORT_OUT, response.getOutputStream());
226 msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, new Axis2TransportInfo(response));
227
228 try {
229 MessageContext faultContext = MessageContextBuilder.createFaultMessageContext(msgContext, e);
230 AxisEngine.sendFault(faultContext);
231 } catch (Exception ex) {
232 LOG.warn("Error sending fault", ex);
233 if (!AddressingHelper.isFaultRedirected(msgContext)) {
234 response.setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR);
235 response.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, "text/plain");
236 PrintWriter pw = new PrintWriter(response.getOutputStream());
237 ex.printStackTrace(pw);
238 pw.flush();
239 }
240 }
241 }
242
243 protected String getServicePath(String contextRoot) {
244 String location = this.portInfo.getLocation();
245 if (location != null && location.startsWith(contextRoot)) {
246 return location.substring(contextRoot.length());
247 }
248 return null;
249 }
250
251 public static String trimContext(String contextPath) {
252 if (contextPath != null) {
253 if (contextPath.startsWith("/")) {
254 contextPath = contextPath.substring(1);
255 }
256 if (contextPath.endsWith("/")) {
257 contextPath = contextPath.substring(0, contextPath.length() - 1);
258 }
259 }
260 return contextPath;
261 }
262
263 public void doService2(Request request,
264 Response response,
265 MessageContext msgContext) throws Exception {
266
267 if (request.getMethod() == Request.GET) {
268 processGETRequest(request, response, this.service, msgContext);
269 } else if (request.getMethod() == Request.POST) {
270 processPOSTRequest(request, response, this.service, msgContext);
271 } else {
272 throw new UnsupportedOperationException("[" + request.getMethod() + " ] method not supported");
273 }
274
275 // Finalize response
276 OperationContext operationContext = msgContext.getOperationContext();
277 Object contextWritten = null;
278 Object isTwoChannel = null;
279 if (operationContext != null) {
280 contextWritten = operationContext.getProperty(Constants.RESPONSE_WRITTEN);
281 isTwoChannel = operationContext.getProperty(Constants.DIFFERENT_EPR);
282 }
283
284 if ((contextWritten != null) && Constants.VALUE_TRUE.equals(contextWritten)) {
285 if ((isTwoChannel != null) && Constants.VALUE_TRUE.equals(isTwoChannel)) {
286 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED);
287 return;
288 }
289 response.setStatusCode(HttpURLConnection.HTTP_OK);
290 } else {
291 response.setStatusCode(HttpURLConnection.HTTP_ACCEPTED);
292 }
293 }
294
295 public void destroy() {
296 }
297
298 public static class Axis2TransportInfo implements OutTransportInfo {
299 private Response response;
300
301 public Axis2TransportInfo(Response response) {
302 this.response = response;
303 }
304
305 public void setContentType(String contentType) {
306 response.setHeader(HTTPConstants.HEADER_CONTENT_TYPE, contentType);
307 }
308 }
309
310 protected void processGETRequest(Request request, Response response, AxisService service, MessageContext msgContext) throws Exception{
311 String query = request.getURI().getQuery();
312 if (query != null &&
313 (query.startsWith("wsdl") || query.startsWith("WSDL") ||
314 query.startsWith("xsd") || query.startsWith("XSD"))) {
315 // wsdl or xsd request
316
317 if (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().equals("")) {
318 URL wsdlURL = AxisServiceGenerator.getWsdlURL(portInfo.getWsdlFile(),
319 configurationBaseUrl,
320 classLoader);
321 this.wsdlQueryHandler.writeResponse(request.getURI().toString(),
322 wsdlURL.toString(),
323 response.getOutputStream());
324 } else {
325 throw new Exception("Service does not have WSDL");
326 }
327 } else if (AxisServiceGenerator.isSOAP11(service)) {
328 response.setContentType("text/html");
329 PrintWriter pw = new PrintWriter(response.getOutputStream());
330 pw.write("<html><title>Web Service</title><body>");
331 pw.write("Hi, this is '" + service.getName() + "' web service.");
332 pw.write("</body></html>");
333 pw.flush();
334 } else {
335 // REST request
336 processURLRequest(request, response, service, msgContext);
337 }
338 }
339
340 protected void processPOSTRequest(Request request, Response response, AxisService service, MessageContext msgContext) throws Exception {
341 processXMLRequest(request, response, service, msgContext);
342 }
343
344 protected void setMsgContextProperties(Request request, Response response, AxisService service, MessageContext msgContext) {
345 msgContext.setProperty(MessageContext.TRANSPORT_OUT, response.getOutputStream());
346 msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, new Axis2TransportInfo(response));
347 msgContext.setProperty(RequestResponseTransport.TRANSPORT_CONTROL,
348 new Axis2RequestResponseTransport(response));
349 msgContext.setProperty(Constants.Configuration.TRANSPORT_IN_URL, request.getURI().toString());
350 msgContext.setIncomingTransportName(Constants.TRANSPORT_HTTP);
351
352 HttpServletRequest servletRequest =
353 (HttpServletRequest)request.getAttribute(WebServiceContainer.SERVLET_REQUEST);
354 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST, servletRequest);
355
356 HttpServletResponse servletResponse =
357 (HttpServletResponse)request.getAttribute(WebServiceContainer.SERVLET_RESPONSE);
358 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE, servletResponse);
359
360 ServletContext servletContext =
361 (ServletContext)request.getAttribute(WebServiceContainer.SERVLET_CONTEXT);
362 msgContext.setProperty(HTTPConstants.MC_HTTP_SERVLETCONTEXT, servletContext);
363
364 if (servletRequest != null) {
365 msgContext.setProperty(MessageContext.TRANSPORT_HEADERS,
366 new TransportHeaders(servletRequest));
367 }
368
369 if (this.binding != null) {
370 msgContext.setProperty(JAXWSMessageReceiver.PARAM_BINDING, this.binding);
371 }
372
373 msgContext.setTo(new EndpointReference(request.getURI().toString()));
374 }
375
376 protected void processXMLRequest(Request request,
377 Response response,
378 AxisService service,
379 MessageContext msgContext) throws Exception {
380 String contentType = request.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
381 String soapAction = request.getHeader(HTTPConstants.HEADER_SOAP_ACTION);
382 if (soapAction == null) {
383 soapAction = "\"\"";
384 }
385
386 ConfigurationContext configurationContext = msgContext.getConfigurationContext();
387 configurationContext.fillServiceContextAndServiceGroupContext(msgContext);
388
389 setMsgContextProperties(request, response, service, msgContext);
390
391 if (!HTTPTransportUtils.isRESTRequest(contentType)) {
392 HTTPTransportUtils.processHTTPPostRequest(msgContext,
393 request.getInputStream(),
394 response.getOutputStream(),
395 contentType,
396 soapAction,
397 request.getURI().getPath());
398 } else {
399 RESTUtil.processXMLRequest(msgContext,
400 request.getInputStream(),
401 response.getOutputStream(),
402 contentType);
403 }
404 }
405
406 protected void processURLRequest(Request request,
407 Response response,
408 AxisService service,
409 MessageContext msgContext) throws Exception {
410 String contentType = request.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
411
412 ConfigurationContext configurationContext = msgContext.getConfigurationContext();
413 configurationContext.fillServiceContextAndServiceGroupContext(msgContext);
414
415 setMsgContextProperties(request, response, service, msgContext);
416
417 InvocationResponse processed = RESTUtil.processURLRequest(msgContext,
418 response.getOutputStream(),
419 contentType);
420
421 if (!processed.equals(InvocationResponse.CONTINUE)) {
422 response.setStatusCode(HttpURLConnection.HTTP_OK);
423 String s = HTTPTransportReceiver.getServicesHTML(configurationContext);
424 PrintWriter pw = new PrintWriter(response.getOutputStream());
425 pw.write(s);
426 pw.flush();
427 }
428 }
429
430 /*
431 * Gets the right handlers for the port/service/bindings and performs injection.
432 */
433 protected void configureHandlers() throws Exception {
434 EndpointDescription desc = AxisServiceGenerator.getEndpointDescription(this.service);
435 if (desc == null) {
436 this.binding = new BindingImpl("");
437 } else {
438 String xml = this.portInfo.getHandlersAsXML();
439 HandlerChainsType handlerChains = null;
440 if (xml != null) {
441 ByteArrayInputStream in = new ByteArrayInputStream(xml.getBytes("UTF-8"));
442 handlerChains = DescriptionUtils.loadHandlerChains(in);
443 desc.setHandlerChain(handlerChains);
444 }
445
446 if (LOG.isDebugEnabled()) {
447 logHandlers(desc.getHandlerChain());
448 }
449
450 this.binding = BindingUtils.createBinding(desc);
451
452 DescriptionUtils.registerHandlerHeaders(desc.getAxisService(), this.binding.getHandlerChain());
453 }
454 }
455
456 private void logHandlers(HandlerChainsType handlerChains) {
457 if (handlerChains == null || handlerChains.getHandlerChain() == null
458 || handlerChains.getHandlerChain().isEmpty()) {
459 LOG.debug("No handlers");
460 return;
461 }
462
463 for (HandlerChainType chains : handlerChains.getHandlerChain()) {
464 LOG.debug("Handler chain: " + chains.getServiceNamePattern() + " " +
465 chains.getPortNamePattern() + " " + chains.getProtocolBindings());
466 if (chains.getHandler() != null) {
467 for (HandlerType chain : chains.getHandler()) {
468 LOG.debug(" Handler: " + chain.getHandlerName().getValue() + " " +
469 chain.getHandlerClass().getValue());
470 }
471 }
472 }
473 }
474
475 protected void injectHandlers() {
476 List<Handler> handlers = this.binding.getHandlerChain();
477 try {
478 for (Handler handler : handlers) {
479 injectResources(handler);
480 }
481 } catch (AnnotationException e) {
482 throw new WebServiceException("Handler annotation failed", e);
483 }
484 }
485
486 protected void destroyHandlers() {
487 if (this.annotationProcessor != null) {
488 // call handlers preDestroy
489 List<Handler> handlers = this.binding.getHandlerChain();
490 for (Handler handler : handlers) {
491 this.annotationProcessor.invokePreDestroy(handler);
492 }
493 }
494 }
495
496 protected void injectResources(Object instance) throws AnnotationException {
497 this.annotationProcessor.processAnnotations(instance);
498 this.annotationProcessor.invokePostConstruct(instance);
499 }
500
501 }