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 }