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