View Javadoc

1   package org.codehaus.xfire.service.binding;
2   
3   import java.lang.reflect.InvocationTargetException;
4   import java.lang.reflect.Method;
5   import java.lang.reflect.Modifier;
6   
7   import org.apache.commons.logging.Log;
8   import org.apache.commons.logging.LogFactory;
9   import org.codehaus.xfire.MessageContext;
10  import org.codehaus.xfire.XFireRuntimeException;
11  import org.codehaus.xfire.fault.XFireFault;
12  import org.codehaus.xfire.service.Service;
13  import org.codehaus.xfire.transport.Session;
14  
15  /***
16   * An invoker which instantiates classes automatically based on the Service's scope.
17   * The default scope is SCOPE_APPLICATION, which creates once instance to use
18   * for the lifetime of the invoker.
19   * 
20   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
21   * @since Nov 16, 2004
22   */
23  public class ObjectInvoker
24          implements Invoker
25  {
26      private static final Log logger = LogFactory.getLog(ObjectInvoker.class.getName());
27  
28      /***
29       * Scope to denote that a single implementation instance should exist for the lifetime
30       * of this invoker and should be reused for every request.
31       */
32      public final static int SCOPE_APPLICATION = 1;
33  
34      /***
35       * Scope to denote that a new instance of the service implementation should be created
36       * on every call.
37       */
38      public final static int SCOPE_REQUEST = 3;
39  
40      /***
41       * Scope for storing one object per session. An example of a session implementation is
42       * an http session, whereby one object is created per session and stored in the session scope.
43       */
44      public final static int SCOPE_SESSION = 2;
45  
46      /***
47       * Constant to denote the implementation class for the service.
48       */
49      public static final String SERVICE_IMPL_CLASS = "xfire.serviceImplClass";
50  
51      private int scope = ObjectInvoker.SCOPE_APPLICATION;
52  
53      /***
54       * The object if the scope is SCOPE_APPLICATION.
55       */
56      private Object appObj;
57  
58      public Object invoke(final Method method, final Object[] params, final MessageContext context)
59              throws XFireFault
60      {
61          try
62          {
63              final Object serviceObject = getServiceObject(context);
64  
65              Object[] newParams = params;
66              for (int i = 0; i < method.getParameterTypes().length; i++)
67              {
68                  if (method.getParameterTypes()[i].equals(MessageContext.class))
69                  {
70                      newParams = new Object[params.length+1];
71                      
72                      for (int j = 0; j < newParams.length; j++)
73                      {
74                          if (j == i)
75                          {
76                              newParams[j] = context;
77                          }
78                          else if (j > i)
79                          {
80                              newParams[j] = params[j-1];
81                          }
82                          else
83                          {
84                              newParams[j] = params[j];
85                          }
86                      }
87                  }
88              }
89              
90              return method.invoke(serviceObject, newParams);
91          }
92          catch (IllegalArgumentException e)
93          {
94              throw new XFireFault("Illegal argument.", e, XFireFault.SENDER);
95          }
96          catch (InvocationTargetException e)
97          {
98              final Throwable t = e.getTargetException();
99  
100             if (t instanceof XFireFault)
101             {
102                 throw (XFireFault) t;
103             }
104             else if (t instanceof Exception)
105             {
106                 logger.warn("Error invoking service.", t);
107                 throw new XFireFault(t, XFireFault.SENDER);
108             }
109             else
110             {
111                 logger.warn("Error invoking service.", e);
112                 throw new XFireRuntimeException("Error invoking service.", e);
113             }
114         }
115         catch (IllegalAccessException e)
116         {
117             throw new XFireFault("Couldn't access service object.", e, XFireFault.RECEIVER);
118         }
119     }
120 
121     /***
122      * Creates and returns a service object depending on the scope.
123      */
124     public Object getServiceObject(final MessageContext context)
125             throws XFireFault
126     {
127         final Service service = context.getService();
128         
129         if (scope == ObjectInvoker.SCOPE_APPLICATION)
130         {
131             if (appObj == null)
132             {
133                 synchronized (Service.class)
134                 {
135                     appObj = createServiceObject(service);
136                 }
137             }
138             return appObj;
139         }
140         else if (scope == ObjectInvoker.SCOPE_SESSION)
141         {
142             final Session session = context.getSession();
143             final String key = "service." + service.getName();
144 
145             Object sessObj = session.get(key);
146             if (sessObj == null)
147             {
148                 synchronized (Service.class)
149                 {
150                     sessObj = createServiceObject(service);
151                     session.put(key, sessObj);
152                 }
153             }
154             return sessObj;
155         }
156         else if (scope == ObjectInvoker.SCOPE_REQUEST)
157         {
158             return createServiceObject(service);
159         }
160         else
161         {
162             throw new UnsupportedOperationException("Scope " + scope + " is invalid.");
163         }
164     }
165 
166     /***
167      * Override this method to control how XFire creates the service object.
168      *
169      * @param service
170      * @return
171      * @throws XFireFault
172      */
173     public Object createServiceObject(final Service service)
174             throws XFireFault
175     {
176         try
177         {
178             Class svcClass = (Class) service.getProperty(ObjectInvoker.SERVICE_IMPL_CLASS);
179 
180             if (svcClass == null)
181             {
182                 svcClass = service.getServiceInfo().getServiceClass();
183                 if(svcClass.isInterface())
184                 {
185                     throw new XFireFault("ObjectInvoker.SERVICE_IMPL_CLASS not set for interface '" + svcClass.getName() + "'", XFireFault.RECEIVER);
186                 }
187             }
188           
189             if(svcClass.isInterface())
190             {
191                 throw new XFireFault("Service class '" + svcClass.getName() + "' is an interface", XFireFault.RECEIVER);
192             }
193           
194           if(Modifier.isAbstract(svcClass.getModifiers()))
195           {
196               throw new XFireFault("Service class '" + svcClass.getName() + "' is abstract", XFireFault.RECEIVER);
197           }
198             return svcClass.newInstance();
199         }
200         catch (InstantiationException e)
201         {
202             throw new XFireFault("Couldn't instantiate service object.", e, XFireFault.RECEIVER);
203         }
204         catch (IllegalAccessException e)
205         {
206             throw new XFireFault("Couldn't access service object.", e, XFireFault.RECEIVER);
207         }
208     }
209 
210     public int getScope()
211     {
212         return scope;
213     }
214 
215     public void setScope(int scope)
216     {
217         this.scope = scope;
218     }
219 }