KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > providers > java > JavaProvider


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.axis.providers.java;
18
19 import org.apache.axis.AxisEngine;
20 import org.apache.axis.AxisFault;
21 import org.apache.axis.Constants;
22 import org.apache.axis.Handler;
23 import org.apache.axis.Message;
24 import org.apache.axis.MessageContext;
25 import org.apache.axis.components.logger.LogFactory;
26 import org.apache.axis.description.JavaServiceDesc;
27 import org.apache.axis.description.OperationDesc;
28 import org.apache.axis.constants.Scope;
29 import org.apache.axis.handlers.soap.SOAPService;
30 import org.apache.axis.message.SOAPEnvelope;
31 import org.apache.axis.providers.BasicProvider;
32 import org.apache.axis.session.Session;
33 import org.apache.axis.utils.ClassUtils;
34 import org.apache.axis.utils.Messages;
35 import org.apache.axis.utils.XMLUtils;
36 import org.apache.axis.utils.cache.ClassCache;
37 import org.apache.axis.utils.cache.JavaClass;
38 import org.apache.commons.logging.Log;
39 import org.xml.sax.SAXException JavaDoc;
40
41 import javax.xml.rpc.holders.IntHolder JavaDoc;
42 import javax.xml.rpc.server.ServiceLifecycle JavaDoc;
43 import javax.xml.soap.SOAPMessage JavaDoc;
44 import javax.wsdl.OperationType;
45 import java.io.Serializable JavaDoc;
46 import java.util.ArrayList JavaDoc;
47 import java.util.StringTokenizer JavaDoc;
48
49 /**
50  * Base class for Java dispatching. Fetches various fields out of envelope,
51  * looks up service object (possibly using session state), and delegates
52  * envelope body processing to subclass via abstract processMessage method.
53  *
54  * @author Doug Davis (dug@us.ibm.com)
55  * @author Carl Woolf (cwoolf@macromedia.com)
56  */

57 public abstract class JavaProvider extends BasicProvider
58 {
59     protected static Log log =
60         LogFactory.getLog(JavaProvider.class.getName());
61
62     // The enterprise category is for stuff that an enterprise product might
63
// want to track, but in a simple environment (like the AXIS build) would
64
// be nothing more than a nuisance.
65
protected static Log entLog =
66         LogFactory.getLog(Constants.ENTERPRISE_LOG_CATEGORY);
67
68     public static final String JavaDoc OPTION_CLASSNAME = "className";
69     public static final String JavaDoc OPTION_ALLOWEDMETHODS = "allowedMethods";
70     public static final String JavaDoc OPTION_SCOPE = "scope";
71
72     /**
73      * Get the service object whose method actually provides the service.
74      * May look up in session table.
75      */

76     public Object JavaDoc getServiceObject (MessageContext msgContext,
77                                     Handler service,
78                                     String JavaDoc clsName,
79                                     IntHolder JavaDoc scopeHolder)
80         throws Exception JavaDoc
81     {
82         String JavaDoc serviceName = msgContext.getService().getName();
83
84         // scope can be "Request", "Session", "Application", "Factory"
85
Scope scope = Scope.getScope((String JavaDoc)service.getOption(OPTION_SCOPE), Scope.DEFAULT);
86
87         scopeHolder.value = scope.getValue();
88
89         if (scope == Scope.REQUEST) {
90             // make a one-off
91
return getNewServiceObject(msgContext, clsName);
92         } else if (scope == Scope.SESSION) {
93             // What do we do if serviceName is null at this point???
94
if (serviceName == null)
95                 serviceName = msgContext.getService().toString();
96
97             // look in incoming session
98
Session session = msgContext.getSession();
99             if (session != null) {
100                 return getSessionServiceObject(session, serviceName,
101                                                msgContext, clsName);
102             } else {
103                 // was no incoming session, sigh, treat as request scope
104
scopeHolder.value = Scope.DEFAULT.getValue();
105                 return getNewServiceObject(msgContext, clsName);
106             }
107         } else if (scope == Scope.APPLICATION) {
108             // MUST be AxisEngine here!
109
return getApplicationScopedObject(msgContext, serviceName, clsName, scopeHolder);
110         } else if (scope == Scope.FACTORY) {
111             String JavaDoc objectID = msgContext.getStrProp("objectID");
112             if (objectID == null) {
113                 return getApplicationScopedObject(msgContext, serviceName, clsName, scopeHolder);
114             }
115             SOAPService svc = (SOAPService)service;
116             Object JavaDoc ret = svc.serviceObjects.get(objectID);
117             if (ret == null) {
118                 throw new AxisFault("NoSuchObject", null, null, null);
119             }
120             return ret;
121         }
122
123         // NOTREACHED
124
return null;
125     }
126
127     private Object JavaDoc getApplicationScopedObject(MessageContext msgContext, String JavaDoc serviceName, String JavaDoc clsName, IntHolder JavaDoc scopeHolder) throws Exception JavaDoc {
128         AxisEngine engine = msgContext.getAxisEngine();
129         Session appSession = engine.getApplicationSession();
130         if (appSession != null) {
131             return getSessionServiceObject(appSession, serviceName,
132                                            msgContext, clsName);
133         } else {
134             // was no application session - log an error and
135
// treat as request scope
136
log.error(Messages.getMessage("noAppSession"));
137             scopeHolder.value = Scope.DEFAULT.getValue();
138             return getNewServiceObject(msgContext, clsName);
139         }
140     }
141
142     /**
143      * Simple utility class for dealing with synchronization issues.
144      */

145     class LockObject implements Serializable JavaDoc {
146         private boolean completed = false;
147
148         synchronized void waitUntilComplete() throws InterruptedException JavaDoc {
149             while (!completed) {
150                 wait();
151             }
152         }
153
154         synchronized void complete() {
155             completed = true;
156             notifyAll();
157         }
158     }
159
160     /**
161      * Get a service object from a session. Handles threading / locking
162      * issues when multiple threads might be accessing the same session
163      * object, and ensures only one thread gets to create the service
164      * object if there isn't one already.
165      */

166     private Object JavaDoc getSessionServiceObject(Session session,
167                                            String JavaDoc serviceName,
168                                            MessageContext msgContext,
169                                            String JavaDoc clsName) throws Exception JavaDoc {
170         Object JavaDoc obj = null;
171         boolean makeNewObject = false;
172
173         // This is a little tricky.
174
synchronized (session.getLockObject()) {
175             // store service objects in session, indexed by class name
176
obj = session.get(serviceName);
177
178             // If nothing there, put in a placeholder object so
179
// other threads wait for us to create the real
180
// service object.
181
if (obj == null) {
182                 obj = new LockObject();
183                 makeNewObject = true;
184                 session.set(serviceName, obj);
185                 msgContext.getService().addSession(session);
186             }
187         }
188
189         // OK, we DEFINITELY have something in obj at this point. Either
190
// it's the service object or it's a LockObject (ours or someone
191
// else's).
192

193         if (LockObject.class == obj.getClass()) {
194             LockObject lock = (LockObject)obj;
195
196             // If we were the lucky thread who got to install the
197
// placeholder, create a new service object and install it
198
// instead, then notify anyone waiting on the LockObject.
199
if (makeNewObject) {
200                 try {
201                   obj = getNewServiceObject(msgContext, clsName);
202                   session.set(serviceName, obj);
203                   msgContext.getService().addSession(session);
204                 } catch(final Exception JavaDoc e) {
205                     session.remove(serviceName);
206                     throw e;
207                 } finally {
208                   lock.complete();
209                 }
210             } else {
211                 // It's someone else's LockObject, so wait around until
212
// it's completed.
213
lock.waitUntilComplete();
214
215                 // Now we are guaranteed there is a service object in the
216
// session, so this next part doesn't need syncing
217
obj = session.get(serviceName);
218             }
219         }
220
221         return obj;
222     }
223
224     /**
225      * Return a new service object which, if it implements the ServiceLifecycle
226      * interface, has been init()ed.
227      *
228      * @param msgContext the MessageContext
229      * @param clsName the name of the class to instantiate
230      * @return an initialized service object
231      */

232     private Object JavaDoc getNewServiceObject(MessageContext msgContext,
233                                        String JavaDoc clsName) throws Exception JavaDoc
234     {
235         Object JavaDoc serviceObject = makeNewServiceObject(msgContext, clsName);
236         if (serviceObject != null &&
237                 serviceObject instanceof ServiceLifecycle JavaDoc) {
238             ((ServiceLifecycle JavaDoc)serviceObject).init(
239                   msgContext.getProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT));
240         }
241         return serviceObject;
242     }
243
244     /**
245      * Process the current message. Side-effect resEnv to create return value.
246      *
247      * @param msgContext self-explanatory
248      * @param reqEnv the request envelope
249      * @param resEnv the response envelope
250      * @param obj the service object itself
251      */

252     public abstract void processMessage (MessageContext msgContext,
253                                          SOAPEnvelope reqEnv,
254                                          SOAPEnvelope resEnv,
255                                          Object JavaDoc obj)
256         throws Exception JavaDoc;
257
258
259     /**
260      * Invoke the message by obtaining various common fields, looking up
261      * the service object (via getServiceObject), and actually processing
262      * the message (via processMessage).
263      */

264     public void invoke(MessageContext msgContext) throws AxisFault {
265         if (log.isDebugEnabled())
266             log.debug("Enter: JavaProvider::invoke (" + this + ")");
267
268         /* Find the service we're invoking so we can grab it's options */
269         /***************************************************************/
270         String JavaDoc serviceName = msgContext.getTargetService();
271         Handler service = msgContext.getService();
272
273         /* Now get the service (RPC) specific info */
274         /********************************************/
275         String JavaDoc clsName = getServiceClassName(service);
276
277         if ((clsName == null) || clsName.equals("")) {
278             throw new AxisFault("Server.NoClassForService",
279                 Messages.getMessage("noOption00", getServiceClassNameOptionName(), serviceName),
280                 null, null);
281         }
282
283         IntHolder JavaDoc scope = new IntHolder JavaDoc();
284         Object JavaDoc serviceObject = null;
285
286         try {
287             serviceObject = getServiceObject(msgContext, service, clsName, scope);
288
289             SOAPEnvelope resEnv = null;
290
291             // If there IS a response message AND this is a one-way operation,
292
// we delete the response message here. Note that this might
293
// cause confusing results in some cases - i.e. nothing fails,
294
// but your response headers don't go anywhere either. It might
295
// be nice if in the future there was a way to detect an error
296
// when trying to install a response message in a MessageContext
297
// associated with a one-way operation....
298
OperationDesc operation = msgContext.getOperation();
299             if (operation != null &&
300                     OperationType.ONE_WAY.equals(operation.getMep())) {
301                 msgContext.setResponseMessage(null);
302             } else {
303                 Message resMsg = msgContext.getResponseMessage();
304
305                 // If we didn't have a response message, make sure we set one up
306
// with the appropriate versions of SOAP and Schema
307
if (resMsg == null) {
308                     resEnv = new SOAPEnvelope(msgContext.getSOAPConstants(),
309                                                msgContext.getSchemaVersion());
310                     
311                     resMsg = new Message(resEnv);
312                     String JavaDoc encoding = XMLUtils.getEncoding(msgContext);
313                     resMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding);
314                     msgContext.setResponseMessage( resMsg );
315                 } else {
316                     resEnv = resMsg.getSOAPEnvelope();
317                 }
318             }
319             
320             Message reqMsg = msgContext.getRequestMessage();
321             SOAPEnvelope reqEnv = reqMsg.getSOAPEnvelope();
322
323             processMessage(msgContext, reqEnv, resEnv, serviceObject);
324         } catch( SAXException JavaDoc exp ) {
325             entLog.debug( Messages.getMessage("toAxisFault00"), exp);
326             Exception JavaDoc real = exp.getException();
327             if (real == null) {
328                 real = exp;
329             }
330             throw AxisFault.makeFault(real);
331         } catch( Exception JavaDoc exp ) {
332             entLog.debug( Messages.getMessage("toAxisFault00"), exp);
333             AxisFault fault = AxisFault.makeFault(exp);
334             //make a note if this was a runtime fault, for better logging
335
if (exp instanceof RuntimeException JavaDoc) {
336                 fault.addFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION,
337                         "true");
338             }
339             throw fault;
340         } finally {
341             // If this is a request scoped service object which implements
342
// ServiceLifecycle, let it know that it's being destroyed now.
343
if (serviceObject != null &&
344                 scope.value == Scope.REQUEST.getValue() &&
345                 serviceObject instanceof ServiceLifecycle JavaDoc)
346             {
347                 ((ServiceLifecycle JavaDoc)serviceObject).destroy();
348             }
349         }
350
351         if (log.isDebugEnabled())
352             log.debug("Exit: JavaProvider::invoke (" + this + ")");
353     }
354
355     private String JavaDoc getAllowedMethods(Handler service)
356     {
357         String JavaDoc val = (String JavaDoc)service.getOption(OPTION_ALLOWEDMETHODS);
358         if (val == null || val.length() == 0) {
359             // Try the old option for backwards-compatibility
360
val = (String JavaDoc)service.getOption("methodName");
361         }
362         return val;
363     }
364
365     ///////////////////////////////////////////////////////////////
366
///////////////////////////////////////////////////////////////
367
/////// Default methods for java classes. Override, eg, for
368
/////// ejbeans
369
///////////////////////////////////////////////////////////////
370
///////////////////////////////////////////////////////////////
371

372     /**
373      * Default java service object comes from simply instantiating the
374      * class wrapped in jc
375      *
376      */

377     protected Object JavaDoc makeNewServiceObject(MessageContext msgContext,
378                                              String JavaDoc clsName)
379         throws Exception JavaDoc
380     {
381         ClassLoader JavaDoc cl = msgContext.getClassLoader();
382         ClassCache cache = msgContext.getAxisEngine().getClassCache();
383         JavaClass jc = cache.lookup(clsName, cl);
384
385         return jc.getJavaClass().newInstance();
386     }
387
388     /**
389      * Return the class name of the service
390      */

391     protected String JavaDoc getServiceClassName(Handler service)
392     {
393         return (String JavaDoc) service.getOption( getServiceClassNameOptionName() );
394     }
395
396     /**
397      * Return the option in the configuration that contains the service class
398      * name
399      */

400     protected String JavaDoc getServiceClassNameOptionName()
401     {
402         return OPTION_CLASSNAME;
403     }
404
405     /**
406      * Returns the Class info about the service class.
407      */

408     protected Class JavaDoc getServiceClass(String JavaDoc clsName,
409                                     SOAPService service,
410                                     MessageContext msgContext)
411             throws AxisFault {
412         ClassLoader JavaDoc cl = null;
413         Class JavaDoc serviceClass = null;
414         AxisEngine engine = service.getEngine();
415
416         // If we have a message context, use that to get classloader
417
// otherwise get the current threads classloader
418
if (msgContext != null) {
419             cl = msgContext.getClassLoader();
420         } else {
421             cl = Thread.currentThread().getContextClassLoader();
422         }
423
424         // If we have an engine, use its class cache
425
if (engine != null) {
426             ClassCache cache = engine.getClassCache();
427             try {
428                 JavaClass jc = cache.lookup(clsName, cl);
429                 serviceClass = jc.getJavaClass();
430             } catch (ClassNotFoundException JavaDoc e) {
431                 log.error(Messages.getMessage("exception00"), e);
432                 throw new AxisFault(Messages.getMessage("noClassForService00", clsName), e);
433             }
434         } else {
435             // if no engine, we don't have a cache, use Class.forName instead.
436
try {
437                 serviceClass = ClassUtils.forName(clsName, true, cl);
438             } catch (ClassNotFoundException JavaDoc e) {
439                 log.error(Messages.getMessage("exception00"), e);
440                 throw new AxisFault(Messages.getMessage("noClassForService00", clsName), e);
441             }
442         }
443         return serviceClass;
444     }
445
446     /**
447      * Fill in a service description with the correct impl class
448      * and typemapping set. This uses methods that can be overridden by
449      * other providers (like the EJBProvider) to get the class from the
450      * right place.
451      */

452     public void initServiceDesc(SOAPService service, MessageContext msgContext)
453             throws AxisFault
454     {
455         // Set up the Implementation class for the service
456

457         String JavaDoc clsName = getServiceClassName(service);
458         if (clsName == null) {
459             throw new AxisFault(Messages.getMessage("noServiceClass"));
460         }
461         Class JavaDoc cls = getServiceClass(clsName, service, msgContext);
462         JavaServiceDesc serviceDescription = (JavaServiceDesc)service.getServiceDescription();
463
464         // And the allowed methods, if necessary
465
if (serviceDescription.getAllowedMethods() == null && service != null) {
466             String JavaDoc allowedMethods = getAllowedMethods(service);
467             if (allowedMethods != null && !"*".equals(allowedMethods)) {
468                 ArrayList JavaDoc methodList = new ArrayList JavaDoc();
469                 StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(allowedMethods, " ,");
470                 while (tokenizer.hasMoreTokens()) {
471                     methodList.add(tokenizer.nextToken());
472                 }
473                 serviceDescription.setAllowedMethods(methodList);
474             }
475         }
476
477         serviceDescription.loadServiceDescByIntrospection(cls);
478     }
479
480 }
481
Popular Tags