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