001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.receivers;
021:
022: import org.apache.axiom.om.OMAbstractFactory;
023: import org.apache.axiom.soap.SOAP11Constants;
024: import org.apache.axiom.soap.SOAP12Constants;
025: import org.apache.axiom.soap.SOAPFactory;
026: import org.apache.axis2.AxisFault;
027: import org.apache.axis2.Constants;
028: import org.apache.axis2.addressing.EndpointReference;
029: import org.apache.axis2.clustering.context.Replicator;
030: import org.apache.axis2.clustering.ClusteringFault;
031: import org.apache.axis2.context.MessageContext;
032: import org.apache.axis2.context.ServiceContext;
033: import org.apache.axis2.description.AxisService;
034: import org.apache.axis2.description.Parameter;
035: import org.apache.axis2.description.InOnlyAxisOperation;
036: import org.apache.axis2.description.WSDL2Constants;
037: import org.apache.axis2.engine.DependencyManager;
038: import org.apache.axis2.engine.MessageReceiver;
039: import org.apache.axis2.engine.AxisEngine;
040: import org.apache.axis2.i18n.Messages;
041: import org.apache.axis2.util.Loader;
042: import org.apache.axis2.util.MessageContextBuilder;
043: import org.apache.axis2.classloader.MultiParentClassLoader;
044: import org.apache.commons.logging.Log;
045: import org.apache.commons.logging.LogFactory;
046:
047: import java.lang.reflect.Method;
048: import java.net.URL;
049:
050: public abstract class AbstractMessageReceiver implements
051: MessageReceiver {
052: protected static final Log log = LogFactory
053: .getLog(AbstractMessageReceiver.class);
054:
055: public static final String SCOPE = "scope";
056: protected String serviceTCCL = null;
057: public static final String SAVED_TCCL = "_SAVED_TCCL_";
058: public static final String SAVED_MC = "_SAVED_MC_";
059: public static final String DO_ASYNC = "messageReceiver.invokeOnSeparateThread";
060:
061: // Place to store previous values
062: public class ThreadContextDescriptor {
063: public ClassLoader oldClassLoader;
064: public MessageContext oldMessageContext;
065: }
066:
067: protected void replicateState(MessageContext messageContext)
068: throws ClusteringFault {
069: Replicator.replicate(messageContext);
070: }
071:
072: /**
073: * Do the actual work of the MessageReceiver. Must be overridden by concrete subclasses.
074: *
075: * @param messageCtx active MessageContext
076: * @throws AxisFault if a problem occurred
077: */
078: protected abstract void invokeBusinessLogic(
079: MessageContext messageCtx) throws AxisFault;
080:
081: /**
082: *
083: * @param messageCtx active MessageContext
084: * @throws AxisFault if a problem occurred
085: */
086: public void receive(final MessageContext messageCtx)
087: throws AxisFault {
088: if (messageCtx.isPropertyTrue(DO_ASYNC)) {
089: EndpointReference replyTo = messageCtx.getReplyTo();
090: if (replyTo != null && !replyTo.hasAnonymousAddress()) {
091: AsyncMessageReceiverWorker worker = new AsyncMessageReceiverWorker(
092: messageCtx);
093: messageCtx.getEnvelope().build();
094: messageCtx.getConfigurationContext().getThreadPool()
095: .execute(worker);
096: return;
097: }
098: }
099:
100: ThreadContextDescriptor tc = setThreadContext(messageCtx);
101: try {
102: invokeBusinessLogic(messageCtx);
103: } catch (AxisFault fault) {
104: // If we're in-only, eat this. Otherwise, toss it upwards!
105: if ((messageCtx.getAxisOperation() instanceof InOnlyAxisOperation)
106: && !WSDL2Constants.MEP_URI_ROBUST_IN_ONLY
107: .equals(messageCtx.getAxisOperation()
108: .getMessageExchangePattern())) {
109: log.error(fault);
110: } else {
111: throw fault;
112: }
113: } finally {
114: restoreThreadContext(tc);
115: }
116: }
117:
118: /**
119: * Several pieces of information need to be available to the service
120: * implementation class. For one, the ThreadContextClassLoader needs
121: * to be correct, and for another we need to give the service code
122: * access to the MessageContext (getCurrentContext()). So we toss these
123: * things in TLS.
124: *
125: * @param msgContext the current MessageContext
126: * @return a ThreadContextDescriptor containing the old values
127: */
128: protected ThreadContextDescriptor setThreadContext(
129: MessageContext msgContext) {
130: ThreadContextDescriptor tc = new ThreadContextDescriptor();
131: tc.oldMessageContext = (MessageContext) MessageContext.currentMessageContext
132: .get();
133: ClassLoader contextClassLoader = Thread.currentThread()
134: .getContextClassLoader();
135: tc.oldClassLoader = contextClassLoader;
136:
137: AxisService service = msgContext.getAxisService();
138: String serviceTCCL = (String) service
139: .getParameterValue(Constants.SERVICE_TCCL);
140: if (serviceTCCL != null) {
141: serviceTCCL = serviceTCCL.trim().toLowerCase();
142:
143: if (serviceTCCL.equals(Constants.TCCL_COMPOSITE)) {
144: Thread.currentThread().setContextClassLoader(
145: new MultiParentClassLoader(new URL[] {},
146: new ClassLoader[] {
147: msgContext.getAxisService()
148: .getClassLoader(),
149: contextClassLoader, }));
150: } else if (serviceTCCL.equals(Constants.TCCL_SERVICE)) {
151: Thread.currentThread().setContextClassLoader(
152: msgContext.getAxisService().getClassLoader());
153: }
154: }
155: MessageContext.setCurrentMessageContext(msgContext);
156: return tc;
157: }
158:
159: protected void restoreThreadContext(ThreadContextDescriptor tc) {
160: Thread.currentThread().setContextClassLoader(tc.oldClassLoader);
161: MessageContext.currentMessageContext.set(tc.oldMessageContext);
162: }
163:
164: /**
165: * Create a new service object. Override if you want to customize how
166: * this happens in your own MessageReceiver.
167: *
168: * @param msgContext
169: * @return Returns Object.
170: * @throws AxisFault
171: */
172: protected Object makeNewServiceObject(MessageContext msgContext)
173: throws AxisFault {
174: try {
175: AxisService service = msgContext.getAxisService();
176: ClassLoader classLoader = service.getClassLoader();
177:
178: // allow alternative definition of makeNewServiceObject
179: if (service.getParameter(Constants.SERVICE_OBJECT_SUPPLIER) != null) {
180: Parameter serviceObjectParam = service
181: .getParameter(Constants.SERVICE_OBJECT_SUPPLIER);
182: Class serviceObjectMaker = Loader.loadClass(
183: classLoader, ((String) serviceObjectParam
184: .getValue()).trim());
185:
186: // Find static getServiceObject() method, call it if there
187: Method method = serviceObjectMaker.getMethod(
188: "getServiceObject",
189: new Class[] { AxisService.class });
190: if (method != null) {
191: return method.invoke(serviceObjectMaker
192: .newInstance(), new Object[] { service });
193: }
194: }
195:
196: Parameter implInfoParam = service
197: .getParameter(Constants.SERVICE_CLASS);
198: if (implInfoParam != null) {
199: Class implClass = Loader.loadClass(classLoader,
200: ((String) implInfoParam.getValue()).trim());
201:
202: return implClass.newInstance();
203: } else {
204: throw new AxisFault(Messages.getMessage(
205: "paramIsNotSpecified",
206: "SERVICE_OBJECT_SUPPLIER"));
207: }
208: } catch (Exception e) {
209: throw AxisFault.makeFault(e);
210: }
211: }
212:
213: public SOAPFactory getSOAPFactory(MessageContext msgContext)
214: throws AxisFault {
215: String nsURI = msgContext.getEnvelope().getNamespace()
216: .getNamespaceURI();
217: if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(nsURI)) {
218: return OMAbstractFactory.getSOAP12Factory();
219: } else if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI
220: .equals(nsURI)) {
221: return OMAbstractFactory.getSOAP11Factory();
222: } else {
223: throw new AxisFault(Messages
224: .getMessage("invalidSOAPversion"));
225: }
226: }
227:
228: /**
229: * Retrieve the implementation object. This will either return a cached
230: * object if present in the ServiceContext, or create a new one via
231: * makeNewServiceObject() (and then cache that).
232: *
233: * @param msgContext the active MessageContext
234: * @return the appropriate back-end service object.
235: * @throws AxisFault if there's a problem
236: */
237: protected Object getTheImplementationObject(
238: MessageContext msgContext) throws AxisFault {
239: ServiceContext serviceContext = msgContext.getServiceContext();
240: Object serviceimpl = serviceContext
241: .getProperty(ServiceContext.SERVICE_OBJECT);
242: if (serviceimpl != null) {
243: // since service impl is there in service context , take that from there
244: return serviceimpl;
245: } else {
246: // create a new service impl class for that service
247: serviceimpl = makeNewServiceObject(msgContext);
248: //Service initialization
249: DependencyManager.initServiceObject(serviceimpl, msgContext
250: .getServiceContext());
251: serviceContext.setProperty(ServiceContext.SERVICE_OBJECT,
252: serviceimpl);
253: return serviceimpl;
254: }
255: }
256:
257: public class AsyncMessageReceiverWorker implements Runnable {
258: private MessageContext messageCtx;
259:
260: public AsyncMessageReceiverWorker(MessageContext messageCtx) {
261: this .messageCtx = messageCtx;
262: }
263:
264: public void run() {
265: try {
266: ThreadContextDescriptor tc = setThreadContext(messageCtx);
267: try {
268: invokeBusinessLogic(messageCtx);
269: } finally {
270: restoreThreadContext(tc);
271: }
272: } catch (AxisFault e) {
273: // If we're IN-ONLY, swallow this. Otherwise, send it.
274: if (messageCtx.getAxisOperation() instanceof InOnlyAxisOperation) {
275: log.debug(e.getMessage(), e);
276: } else {
277: try {
278: MessageContext faultContext = MessageContextBuilder
279: .createFaultMessageContext(messageCtx,
280: e);
281:
282: AxisEngine.sendFault(faultContext);
283: } catch (AxisFault axisFault) {
284: log.error(e.getMessage(), e);
285: }
286: log.error(e.getMessage(), e);
287: }
288: }
289: }
290: }
291: }
|