/* * JBoss, the OpenSource EJB server * * Distributable under LGPL license. * See terms of license at gnu.org. */ package org.jboss.ejb.plugins.jrmp.interfaces; import java.io.IOException; import java.io.ObjectOutput; import java.io.ObjectInput; import java.lang.reflect.Method; import java.rmi.MarshalledObject; import javax.naming.Name; import javax.ejb.EJBHome; import javax.ejb.EJBObject; import javax.ejb.Handle; import javax.ejb.HomeHandle; import javax.ejb.EJBMetaData; import javax.ejb.RemoveException; import org.jboss.ejb.CacheKey; import org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker; /** * The client-side proxy for an EJB Home object. * * @author Rickard Öberg (rickard.oberg@telkel.com) * @author Marc Fleury * @author Jason Dillon <jason@planet57.com> * @version $Revision: 1.23 $ */ public class HomeProxy extends GenericProxy { // Constants ----------------------------------------------------- /** Serial Version Identifier. */ private static final long serialVersionUID = 432426690456622923L; // Static -------------------------------------------------------- /** {@link EJBHome#getEJBMetaData} method reference. */ protected static final Method GET_EJB_META_DATA; /** {@link EJBHome#getHomeHandle} method reference. */ protected static final Method GET_HOME_HANDLE; /** {@link EJBHome#remove(Handle)} method reference. */ protected static final Method REMOVE_BY_HANDLE; /** {@link EJBHome#remove(Object)} method reference. */ protected static final Method REMOVE_BY_PRIMARY_KEY; /** {@link EJBObject#remove} method reference. */ protected static final Method REMOVE_OBJECT; /** * Initialize {@link EJBHome} and {@link EJBObject} method references. */ static { try { final Class empty[] = {}; final Class type = EJBHome.class; GET_EJB_META_DATA = type.getMethod("getEJBMetaData", empty); GET_HOME_HANDLE = type.getMethod("getHomeHandle", empty); REMOVE_BY_HANDLE = type.getMethod("remove", new Class[] { Handle.class }); REMOVE_BY_PRIMARY_KEY = type.getMethod("remove", new Class[] { Object.class }); // Get the "remove" method from the EJBObject REMOVE_OBJECT = EJBObject.class.getMethod("remove", empty); } catch (Exception e) { e.printStackTrace(); throw new ExceptionInInitializerError(e); } } // Attributes ---------------------------------------------------- /** The EJB meta-data for the {@link EJBHome} reference. */ protected EJBMetaData ejbMetaData; // Constructors -------------------------------------------------- /** * No-argument constructor for externalization. */ public HomeProxy() {} /** * Construct a HomeProxy. * * @param name The JNDI name of the container that we proxy for. * @param ejbMetaData ??? * @param container The remote interface of the invoker for which * this is a proxy for. * @param optimize True if the proxy will attempt to optimize * VM-local calls. */ public HomeProxy(final String name, final EJBMetaData ejbMetaData, final ContainerRemote container, final boolean optimize) { super(name, container, optimize); this.ejbMetaData = ejbMetaData; } // Public -------------------------------------------------------- /** * InvocationHandler implementation. * * @param proxy The proxy object. * @param m The method being invoked. * @param args The arguments for the method. * * @throws Throwable Any exception or error thrown while processing. */ public Object invoke(final Object proxy, final Method m, Object[] args) throws Throwable { // Normalize args to always be an array // Isn't this a bug in the proxy call?? if (args == null) args = EMPTY_ARGS; // Implement local methods if (m.equals(TO_STRING)) { return name + "Home"; } else if (m.equals(EQUALS)) { // equality of the proxy home is based on names... Object temp = invoke(proxy, TO_STRING, args); return new Boolean(temp.equals(name + "Home")); } else if (m.equals(HASH_CODE)) { return new Integer(this.hashCode()); } // Implement local EJB calls else if (m.equals(GET_HOME_HANDLE)) { return new HomeHandleImpl(initialContextHandle, name); } else if (m.equals(GET_EJB_META_DATA)) { return ejbMetaData; } else if (m.equals(REMOVE_BY_HANDLE)) { // First get the EJBObject EJBObject object = ((Handle) args[0]).getEJBObject(); // remove the object from here object.remove(); // Return Void return Void.TYPE; } else if (m.equals(REMOVE_BY_PRIMARY_KEY)) { // Session beans must throw RemoveException (EJB 1.1, 5.3.2) if (ejbMetaData.isSession()) throw new RemoveException("Session beans cannot be removed by primary key."); // The trick is simple we trick the container in believe it // is a remove() on the instance Object id = new CacheKey(args[0]); return invokeContainer(id, REMOVE_OBJECT, EMPTY_ARGS); } // If not taken care of, go on and call the container else { return invokeHome(m, args); } } /** * Externalization support. * * @param out * * @throws IOException */ public void writeExternal(final ObjectOutput out) throws IOException { super.writeExternal(out); out.writeObject(ejbMetaData); } /** * Externalization support. * * @param in * * @throws IOException * @throws ClassNotFoundException */ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); ejbMetaData = (EJBMetaData)in.readObject(); } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // Private ------------------------------------------------------- /** * Invoke the container to handle this EJBHome method * invocation. * * @param method The method to invoke. * @param args The arguments passed to the method. * * @throws Throwable Failed to invoke container. */ private Object invokeHome(final Method method, final Object[] args) throws Throwable { Object result; // Optimize if calling another bean in same EJB-application if (optimize && isLocal()) { result = container.invokeHome(method, args, getTransaction(), getPrincipal(), getCredential()); } else { MarshalledObject mo = createMarshalledObject(null, method, args); // Invoke on the remote server, enforce marshaling if (isLocal()) { // ensure marshaling of exceptions is done properly try { result = container.invokeHome(mo).get(); } catch (Throwable e) { throw (Throwable)new MarshalledObject(e).get(); } } else { // Marshaling is done by RMI return container.invokeHome(mo).get(); } } return result; } // Inner classes ------------------------------------------------- }