1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20
21 package org.apache.axis2.receivers;
22
23 import org.apache.axiom.om.OMAbstractFactory;
24 import org.apache.axiom.soap.SOAP11Constants;
25 import org.apache.axiom.soap.SOAP12Constants;
26 import org.apache.axiom.soap.SOAPFactory;
27 import org.apache.axis2.AxisFault;
28 import org.apache.axis2.Constants;
29 import org.apache.axis2.addressing.EndpointReference;
30 import org.apache.axis2.classloader.MultiParentClassLoader;
31 import org.apache.axis2.clustering.ClusteringFault;
32 import org.apache.axis2.clustering.context.Replicator;
33 import org.apache.axis2.context.MessageContext;
34 import org.apache.axis2.context.ServiceContext;
35 import org.apache.axis2.description.AxisService;
36 import org.apache.axis2.description.InOnlyAxisOperation;
37 import org.apache.axis2.description.Parameter;
38 import org.apache.axis2.description.WSDL2Constants;
39 import org.apache.axis2.engine.AxisEngine;
40 import org.apache.axis2.engine.DependencyManager;
41 import org.apache.axis2.engine.MessageReceiver;
42 import org.apache.axis2.i18n.Messages;
43 import org.apache.axis2.util.JavaUtils;
44 import org.apache.axis2.util.Loader;
45 import org.apache.axis2.util.MessageContextBuilder;
46 import org.apache.axis2.wsdl.WSDLUtil;
47 import org.apache.commons.logging.Log;
48 import org.apache.commons.logging.LogFactory;
49
50 import java.lang.reflect.Method;
51 import java.lang.reflect.InvocationTargetException;
52 import java.net.URL;
53 import java.security.AccessController;
54 import java.security.PrivilegedAction;
55 import java.security.PrivilegedExceptionAction;
56
57 public abstract class AbstractMessageReceiver implements MessageReceiver {
58 protected static final Log log = LogFactory.getLog(AbstractMessageReceiver.class);
59
60 public static final String SCOPE = "scope";
61 protected String serviceTCCL = null;
62 public static final String SAVED_TCCL = "_SAVED_TCCL_";
63 public static final String SAVED_MC = "_SAVED_MC_";
64 public static final String DO_ASYNC = "messageReceiver.invokeOnSeparateThread";
65
66 // Place to store previous values
67 public static class ThreadContextDescriptor {
68 public ClassLoader oldClassLoader;
69 public MessageContext oldMessageContext;
70 }
71
72 protected void replicateState(MessageContext messageContext) throws ClusteringFault {
73 Replicator.replicate(messageContext);
74 }
75
76 /**
77 * Do the actual work of the MessageReceiver. Must be overridden by concrete subclasses.
78 *
79 * @param messageCtx active MessageContext
80 * @throws AxisFault if a problem occurred
81 */
82 protected abstract void invokeBusinessLogic(MessageContext messageCtx) throws AxisFault;
83
84 /**
85 *
86 * @param messageCtx active MessageContext
87 * @throws AxisFault if a problem occurred
88 */
89 public void receive(final MessageContext messageCtx) throws AxisFault {
90 if (messageCtx.isPropertyTrue(DO_ASYNC)
91 || ((messageCtx.getParameter(DO_ASYNC) != null) &&
92 JavaUtils.isTrueExplicitly(messageCtx.getParameter(DO_ASYNC).getValue()))) {
93
94 String mep = messageCtx.getAxisOperation()
95 .getMessageExchangePattern();
96 EndpointReference replyTo = messageCtx.getReplyTo();
97 // In order to invoke the service in the ASYNC mode, the request
98 // should contain ReplyTo header if the MEP of the service is not
99 // InOnly type
100 if ((!WSDLUtil.isOutputPresentForMEP(mep))
101 || (replyTo != null && !replyTo.hasAnonymousAddress())) {
102 AsyncMessageReceiverWorker worker = new AsyncMessageReceiverWorker(
103 messageCtx);
104 messageCtx.getEnvelope().build();
105 messageCtx.getConfigurationContext().getThreadPool().execute(
106 worker);
107 return;
108 }
109 }
110
111
112 ThreadContextDescriptor tc = setThreadContext(messageCtx);
113 try {
114 invokeBusinessLogic(messageCtx);
115 } catch (AxisFault fault) {
116 // If we're in-only, eat this. Otherwise, toss it upwards!
117 if ((messageCtx.getAxisOperation() instanceof InOnlyAxisOperation) &&
118 !WSDL2Constants.MEP_URI_ROBUST_IN_ONLY.equals(messageCtx.getAxisOperation().getMessageExchangePattern())) {
119 log.error(fault);
120 } else {
121 fault.setFaultType(Constants.APPLICATION_FAULT);
122 throw fault;
123 }
124 } finally {
125 restoreThreadContext(tc);
126 }
127 }
128
129 /**
130 * Several pieces of information need to be available to the service
131 * implementation class. For one, the ThreadContextClassLoader needs
132 * to be correct, and for another we need to give the service code
133 * access to the MessageContext (getCurrentContext()). So we toss these
134 * things in TLS.
135 *
136 * @param msgContext the current MessageContext
137 * @return a ThreadContextDescriptor containing the old values
138 */
139 protected ThreadContextDescriptor setThreadContext(final MessageContext msgContext) {
140 ThreadContextDescriptor tc = new ThreadContextDescriptor();
141 tc.oldMessageContext = (MessageContext) MessageContext.currentMessageContext.get();
142 final ClassLoader contextClassLoader = getContextClassLoader_doPriv();
143 tc.oldClassLoader = contextClassLoader;
144
145 AxisService service = msgContext.getAxisService();
146 String serviceTCCL = (String) service.getParameterValue(Constants.SERVICE_TCCL);
147 if (serviceTCCL != null) {
148 serviceTCCL = serviceTCCL.trim().toLowerCase();
149
150 if (serviceTCCL.equals(Constants.TCCL_COMPOSITE)) {
151 final ClassLoader loader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
152 public Object run() {
153 return new MultiParentClassLoader(new URL[]{},
154 new ClassLoader[]{
155 msgContext.getAxisService().getClassLoader(),
156 contextClassLoader
157 });
158 }
159 });
160 org.apache.axis2.java.security.AccessController.doPrivileged(
161 new PrivilegedAction() {
162 public Object run() {
163 Thread.currentThread().setContextClassLoader(
164 loader);
165 return null;
166 }
167 }
168 );
169 } else if (serviceTCCL.equals(Constants.TCCL_SERVICE)) {
170 org.apache.axis2.java.security.AccessController.doPrivileged(
171 new PrivilegedAction() {
172 public Object run() {
173 Thread.currentThread().setContextClassLoader(
174 msgContext.getAxisService().getClassLoader()
175 );
176 return null;
177 }
178 }
179 );
180 }
181 }
182 MessageContext.setCurrentMessageContext(msgContext);
183 return tc;
184 }
185
186 private ClassLoader getContextClassLoader_doPriv() {
187 return (ClassLoader) org.apache.axis2.java.security.AccessController.doPrivileged(
188 new PrivilegedAction() {
189 public Object run() {
190 return Thread.currentThread().getContextClassLoader();
191 }
192 }
193 );
194 }
195
196 protected void restoreThreadContext(final ThreadContextDescriptor tc) {
197 org.apache.axis2.java.security.AccessController.doPrivileged(
198 new PrivilegedAction() {
199 public Object run() {
200 Thread.currentThread().setContextClassLoader(tc.oldClassLoader);
201 return null;
202 }
203 }
204 );
205 MessageContext.currentMessageContext.set(tc.oldMessageContext);
206 }
207
208 /**
209 * Create a new service object. Override if you want to customize how
210 * this happens in your own MessageReceiver.
211 *
212 * @param msgContext
213 * @return Returns Object.
214 * @throws AxisFault
215 */
216 protected Object makeNewServiceObject(MessageContext msgContext) throws AxisFault {
217 try {
218 final AxisService service = msgContext.getAxisService();
219 ClassLoader classLoader = service.getClassLoader();
220
221 // allow alternative definition of makeNewServiceObject
222 if (service.getParameter(Constants.SERVICE_OBJECT_SUPPLIER) != null) {
223 Parameter serviceObjectParam =
224 service.getParameter(Constants.SERVICE_OBJECT_SUPPLIER);
225 final Class serviceObjectMaker = Loader.loadClass(classLoader, ((String)
226 serviceObjectParam.getValue()).trim());
227
228 // Find static getServiceObject() method, call it if there
229 final Method method = (Method) org.apache.axis2.java.security.AccessController.doPrivileged(
230 new PrivilegedExceptionAction() {
231 public Object run() throws NoSuchMethodException {
232 return serviceObjectMaker.getMethod("getServiceObject",
233 new Class[]{AxisService.class});
234 }
235 }
236 );
237 if (method != null) {
238 return org.apache.axis2.java.security.AccessController.doPrivileged(
239 new PrivilegedExceptionAction() {
240 public Object run() throws InvocationTargetException, IllegalAccessException, InstantiationException {
241 return method.invoke(serviceObjectMaker.newInstance(), new Object[]{service});
242 }
243 }
244 );
245 }
246 }
247
248 Parameter implInfoParam = service.getParameter(Constants.SERVICE_CLASS);
249 if (implInfoParam != null) {
250 final Class implClass = Loader.loadClass(
251 classLoader,
252 ((String) implInfoParam.getValue()).trim());
253 return org.apache.axis2.java.security.AccessController.doPrivileged(
254 new PrivilegedExceptionAction() {
255 public Object run() throws InstantiationException, IllegalAccessException {
256 return implClass.newInstance();
257 }
258 }
259 );
260 } else {
261 throw new AxisFault(
262 Messages.getMessage("paramIsNotSpecified", "SERVICE_OBJECT_SUPPLIER"));
263 }
264 } catch (Exception e) {
265 throw AxisFault.makeFault(e);
266 }
267 }
268
269 public SOAPFactory getSOAPFactory(MessageContext msgContext) throws AxisFault {
270 String nsURI = msgContext.getEnvelope().getNamespace().getNamespaceURI();
271 if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(nsURI)) {
272 return OMAbstractFactory.getSOAP12Factory();
273 } else if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(nsURI)) {
274 return OMAbstractFactory.getSOAP11Factory();
275 } else {
276 throw new AxisFault(Messages.getMessage("invalidSOAPversion"));
277 }
278 }
279
280 /**
281 * Retrieve the implementation object. This will either return a cached
282 * object if present in the ServiceContext, or create a new one via
283 * makeNewServiceObject() (and then cache that).
284 *
285 * @param msgContext the active MessageContext
286 * @return the appropriate back-end service object.
287 * @throws AxisFault if there's a problem
288 */
289 protected Object getTheImplementationObject(MessageContext msgContext) throws AxisFault {
290 ServiceContext serviceContext = msgContext.getServiceContext();
291 Object serviceimpl = serviceContext.getProperty(ServiceContext.SERVICE_OBJECT);
292 if (serviceimpl != null) {
293 // since service impl is there in service context , take that from there
294 return serviceimpl;
295 } else {
296 // create a new service impl class for that service
297 serviceimpl = makeNewServiceObject(msgContext);
298 //Service initialization
299 DependencyManager.initServiceObject(serviceimpl, msgContext.getServiceContext());
300 serviceContext.setProperty(ServiceContext.SERVICE_OBJECT, serviceimpl);
301 return serviceimpl;
302 }
303 }
304
305 public class AsyncMessageReceiverWorker implements Runnable {
306 private MessageContext messageCtx;
307
308 public AsyncMessageReceiverWorker(MessageContext messageCtx){
309 this.messageCtx = messageCtx;
310 }
311
312 public void run() {
313 try {
314 ThreadContextDescriptor tc = setThreadContext(messageCtx);
315 try {
316 invokeBusinessLogic(messageCtx);
317 } finally {
318 restoreThreadContext(tc);
319 }
320 } catch (AxisFault e) {
321 // If we're IN-ONLY, swallow this. Otherwise, send it.
322 if (messageCtx.getAxisOperation() instanceof InOnlyAxisOperation) {
323 log.debug(e.getMessage(), e);
324 } else {
325 try {
326 MessageContext faultContext =
327 MessageContextBuilder.createFaultMessageContext(messageCtx, e);
328
329 AxisEngine.sendFault(faultContext);
330 } catch (AxisFault axisFault) {
331 log.error(e.getMessage(), e);
332 }
333 log.error(e.getMessage(), e);
334 }
335 }
336 }
337 }
338 }