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