001: package org.mockejb;
002:
003: import java.io.Serializable;
004: import java.lang.reflect.*;
005: import java.rmi.RemoteException;
006:
007: import javax.ejb.*;
008:
009: import org.mockejb.interceptor.*;
010:
011: /**
012: * Base class for concrete Home implementations.
013: * Creates proxy for home interface and calls "create" method.
014: * "create" must be defined by the subclasses.
015: *
016: * @author Alexander Ananiev
017: */
018: abstract class BasicEjbHome implements InvocationHandler, Serializable {
019:
020: private static MethodContainer standardMethods;
021:
022: /**
023: * Standard methods required by EJBHome and EJBLocalHome implemented by
024: * this class.
025: */
026: static {
027: standardMethods = new MethodContainer(SessionBeanHome.class);
028: standardMethods.add("getEJBMetaData");
029: standardMethods.add("getHomeHandle");
030:
031: Class objectArg[] = { Object.class };
032: standardMethods.add("remove", objectArg);
033:
034: // Object methods
035: standardMethods.add("toString");
036:
037: // equals is a convenience method
038: standardMethods.add("equals", objectArg);
039: standardMethods.add("hashCode");
040:
041: // another convenience method
042: standardMethods.add("toString");
043:
044: }
045:
046: private BasicEjbDescriptor descriptor;
047: //private MockEjbObject ejbObject;
048:
049: private Object proxy;
050:
051: private MockEjbMetaData ejbMetaData;
052:
053: protected InterceptorInvoker interceptorInvoker = new InterceptorInvoker();
054:
055: BasicEjbHome(BasicEjbDescriptor descriptor) {
056: this .descriptor = descriptor;
057: interceptorInvoker.setContext("descriptor", descriptor);
058: ejbMetaData = new MockEjbMetaData(descriptor);
059:
060: }
061:
062: /** Creates a new instance */
063: public Object createProxy() {
064:
065: Class homeClass = descriptor.getHomeClass();
066:
067: proxy = Proxy.newProxyInstance(homeClass.getClassLoader(),
068: new Class[] { homeClass, GenericHome.class }, this );
069:
070: ejbMetaData.setHomeProxy(proxy);
071:
072: return proxy;
073:
074: }
075:
076: protected Object getHomeProxy() {
077: return proxy;
078: }
079:
080: /**
081: * Handles calls to Home methods
082: */
083: public Object invoke(Object this Proxy, Method homeMethod,
084: Object[] paramVals) throws Throwable {
085:
086: Object returnValue = null;
087: // if this is one of the standard methods
088: Method method = standardMethods.find(homeMethod);
089: if (method != null) {
090: returnValue = interceptorInvoker.invoke(proxy, homeMethod,
091: this , method, paramVals);
092: }
093: // Handle create methods, this also includes genericCreate from the GenericHome iface
094: else if (homeMethod.getName().startsWith("create")
095: || homeMethod.getDeclaringClass().equals(
096: GenericHome.class)) {
097: // Create MockEjbObject
098: MockEjbObject ejbObject = new MockEjbObject(descriptor
099: .getIfaceClass());
100: ejbObject.setHomeImpl(this );
101: ejbObject.setHomeProxy(proxy);
102: // create returns the proxy to the newly created object
103: returnValue = create(descriptor, ejbObject, homeMethod,
104: paramVals);
105: } else
106: returnValue = invokeHomeMethod(descriptor, homeMethod,
107: paramVals);
108:
109: return returnValue;
110:
111: }
112:
113: /**
114: * Implementors of this method must create an instance of a bean (if needed)
115: * and call the required EJB lifecycle methods.
116: * @param descriptor
117: * @param ejbObject
118: * @param homeMethod
119: * @param paramVals
120: * @return Proxy created by the EjbObject ready to be returned to the client.
121: */
122: public abstract Object create(BasicEjbDescriptor descriptor,
123: MockEjbObject ejbObject, Method homeMethod,
124: Object[] paramVals) throws Exception;
125:
126: /**
127: * Implementors of this method can invoke home methods other than create and remove
128: * suitable for their EJB type, such as ejbFind for entity bean.
129: * If the EJB type only supports create and remove methods, this method must
130: * throw exception.
131: * @param descriptor
132: * @param ejbObject
133: * @param homeMethod
134: * @param paramVals
135: * @return return value of the home method
136: */
137: public abstract Object invokeHomeMethod(
138: BasicEjbDescriptor descriptor, Method homeMethod,
139: Object[] paramVals) throws Exception;
140:
141: /**
142: * Helper method to create a bean instance. If the bean object is passed in the
143: * descriptor simply returns it, otherwise calls newInstance.
144: * @param descriptor EJB descriptor
145: * @return bean object
146: */
147: protected Object createBean(BasicEjbDescriptor descriptor) {
148:
149: Object bean;
150: if (descriptor.getBean() == null) {
151: bean = invokeNewInstance(descriptor.getBeanClass());
152: } else {
153: bean = descriptor.getBean();
154: }
155:
156: return bean;
157:
158: }
159:
160: // *** Helper methods to call bean's methods
161:
162: /**
163: * Finds a method of the bean using reflection and calls InterceptorInvoker to
164: * find interceptors and call the target.
165: *
166: * @param bean target bean object
167: * @param homeMethod home method being callese
168: * @param methodName name of the method of the target bean to call
169: * @param paramTypes types of the parameters of the target method
170: * @param paramVals parameters of the target method
171: * @return
172: */
173: protected Object invokeBeanMethod(Object bean, Method homeMethod,
174: String methodName, Class[] paramTypes, Object[] paramVals)
175: throws Exception {
176:
177: Method method;
178:
179: try {
180:
181: method = bean.getClass().getMethod(methodName, paramTypes);
182:
183: } catch (NoSuchMethodException noSuchMethodEx) {
184: throw new MockEjbSystemException("EJB "
185: + bean.getClass().getName()
186: + " does not implement method " + methodName,
187: noSuchMethodEx);
188: }
189: return interceptorInvoker.invoke(getHomeProxy(), homeMethod,
190: bean, method, paramVals);
191:
192: }
193:
194: Object invokeBeanMethod(Object bean, Method homeMethod,
195: String methodName) throws Exception {
196:
197: Class paramTypes[] = {};
198: Object args[] = {};
199:
200: return invokeBeanMethod(bean, homeMethod, methodName,
201: paramTypes, args);
202: }
203:
204: /**
205: * Invokes "ejbCreate" method of a bean. Translate the name of the home
206: * create method to the appropriate "ejbCreate".
207: * @param bean target bean object
208: * @param createMethod create method of the home interface
209: * @param paramVals parameters of the create method (for entity and stateful beans)
210: *
211: */
212: protected Object invokeBeanCreateMethod(Object bean,
213: Method createMethod, Object[] paramVals) throws Exception {
214:
215: Object returnVal = null;
216: if (createMethod.getName().startsWith("create")) {
217: returnVal = invokeBeanMethodWithPrefix("ejb", bean,
218: createMethod, paramVals);
219: } else {
220: // genericCreate
221: returnVal = invokeBeanMethod(bean, createMethod,
222: "ejbCreate", createMethod.getParameterTypes(),
223: paramVals);
224: }
225:
226: return returnVal;
227: }
228:
229: protected Object invokeBeanMethodWithPrefix(String prefix,
230: Object bean, Method homeMethod, Object[] paramVals)
231: throws Exception {
232:
233: String methodName = prefix
234: + homeMethod.getName().substring(0, 1).toUpperCase()
235: + homeMethod.getName().substring(1);
236:
237: return invokeBeanMethod(bean, homeMethod, methodName,
238: homeMethod.getParameterTypes(), paramVals);
239:
240: }
241:
242: /**
243: * Create an instance of a bean
244: */
245: protected Object invokeNewInstance(Class beanClass) {
246:
247: Object bean = null;
248: try {
249: bean = beanClass.newInstance();
250: } catch (IllegalAccessException iae) {
251: throw new MockEjbSystemException(
252: "Error instantiating a bean " + beanClass.getName(),
253: iae);
254: } catch (InstantiationException ie) {
255: throw new MockEjbSystemException(
256: "Error instantiating a bean " + beanClass.getName(),
257: ie);
258: }
259:
260: return bean;
261:
262: }
263:
264: // Implementation of methods required by the EJBHome and EJBLocalHome interfaces
265:
266: /**
267: * This method is not implemented by this class.
268: */
269: public void remove(Object obj) throws RemoveException {
270: throwMethodNotImplemented("remove( obj )");
271: }
272:
273: /**
274: *
275: */
276: public EJBMetaData getEJBMetaData() throws RemoteException {
277: return ejbMetaData;
278: }
279:
280: /**
281: *
282: */
283: public HomeHandle getHomeHandle() throws RemoteException {
284: throwMethodNotImplemented("getHomeHandle()");
285: return null;
286: }
287:
288: /**
289: * If the object is a proxy, the pointer equality is used.
290: * Otherwise, super.equals is called.
291: *
292: */
293: public boolean equals(Object obj) {
294: // if the object is proxy
295: if (descriptor.getHomeClass().isInstance(obj))
296: return (proxy == obj);
297: else
298: return super .equals(obj);
299: }
300:
301: public int hashCode() {
302: return descriptor.getHomeClass().hashCode();
303: }
304:
305: public String toString() {
306: return "Home object: HomeIface: "
307: + descriptor.getHomeClass().getName()
308: + " BusinessIface: "
309: + descriptor.getIfaceClass().getName();
310:
311: }
312:
313: /**
314: * Helper method to throw NotImplementedException for this class
315: * @param methodName
316: */
317: protected void throwMethodNotImplemented(String methodName) {
318:
319: throw new MethodNotImplementedException(methodName, this
320: .getClass().getName());
321:
322: }
323:
324: }
|