/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.openejb.client; import org.apache.openejb.client.proxy.ProxyManager; import javax.ejb.EJBException; import javax.ejb.EJBHome; import javax.ejb.Handle; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.lang.reflect.Method; import java.rmi.RemoteException; import java.util.concurrent.ThreadPoolExecutor; @SuppressWarnings("NullArgumentToVariableArgMethod") public abstract class EJBHomeHandler extends EJBInvocationHandler implements Externalizable { private static final long serialVersionUID = 4212515330775330214L; protected static final Method GETEJBMETADATA = getMethod(EJBHome.class, "getEJBMetaData", null); protected static final Method GETHOMEHANDLE = getMethod(EJBHome.class, "getHomeHandle", null); @SuppressWarnings("RedundantArrayCreation") protected static final Method REMOVE_W_KEY = getMethod(EJBHome.class, "remove", new Class[]{Object.class}); @SuppressWarnings("RedundantArrayCreation") protected static final Method REMOVE_W_HAND = getMethod(EJBHome.class, "remove", new Class[]{Handle.class}); protected static final Method GETHANDLER = getMethod(EJBHomeProxy.class, "getEJBHomeHandler", null); protected ThreadPoolExecutor executor; public EJBHomeHandler() { } public EJBHomeHandler(final ThreadPoolExecutor executor, final EJBMetaDataImpl ejb, final ServerMetaData server, final ClientMetaData client, final JNDIContext.AuthenticationInfo auth) { super(ejb, server, client, auth); this.executor = executor; } public static EJBHomeHandler createEJBHomeHandler(final ThreadPoolExecutor executor, final EJBMetaDataImpl ejb, final ServerMetaData server, final ClientMetaData client, final JNDIContext.AuthenticationInfo auth) { switch (ejb.type) { case EJBMetaDataImpl.BMP_ENTITY: case EJBMetaDataImpl.CMP_ENTITY: return new EntityEJBHomeHandler(executor, ejb, server, client, auth); case EJBMetaDataImpl.STATEFUL: return new StatefulEJBHomeHandler(executor, ejb, server, client, auth); case EJBMetaDataImpl.STATELESS: return new StatelessEJBHomeHandler(executor, ejb, server, client, auth); case EJBMetaDataImpl.SINGLETON: return new SingletonEJBHomeHandler(executor, ejb, server, client, auth); } throw new IllegalStateException("Uknown bean type code '" + ejb.type + "' : " + ejb.toString()); } // protected abstract EJBObjectHandler newEJBObjectHandler(); public EJBHomeProxy createEJBHomeProxy() { try { // Interface class must be listed first otherwise the proxy code will select // the openejb system class loader for proxy creation instead of the // application class loader final Class[] interfaces = new Class[]{ejb.homeClass, EJBHomeProxy.class}; return (EJBHomeProxy) ProxyManager.newProxyInstance(interfaces, this); } catch (IllegalAccessException e) { throw new ClientRuntimeException("Unable to create proxy for " + ejb.homeClass, e); } } @Override protected Object _invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { final String methodName = method.getName(); try { if (method.getDeclaringClass() == Object.class) { if (method.equals(TOSTRING)) { return "proxy=" + this; } else if (method.equals(EQUALS)) { return Boolean.FALSE; } else if (method.equals(HASHCODE)) { return this.hashCode(); } else { throw new UnsupportedOperationException("Unkown method: " + method); } } else if (method.getDeclaringClass() == EJBHomeProxy.class) { if (method.equals(GETHANDLER)) { return this; } else if (methodName.equals("writeReplace")) { return new EJBHomeProxyHandle(this); } else if (methodName.equals("readResolve")) { throw new UnsupportedOperationException("Unkown method: " + method); } else { throw new UnsupportedOperationException("Unkown method: " + method); } } /*-------------------------------------------------------*/ /*-- CREATE ------------- <HomeInterface>.create(<x>) ---*/ if (methodName.startsWith("create")) { return create(method, args, proxy); /*-- FIND X --------------- <HomeInterface>.find<x>() ---*/ } else if (methodName.startsWith("find")) { return findX(method, args, proxy); /*-- GET EJB METADATA ------ EJBHome.getEJBMetaData() ---*/ } else if (method.equals(GETEJBMETADATA)) { return getEJBMetaData(method, args, proxy); /*-- GET HOME HANDLE -------- EJBHome.getHomeHandle() ---*/ } else if (method.equals(GETHOMEHANDLE)) { return getHomeHandle(method, args, proxy); /*-- REMOVE ------------------------ EJBHome.remove() ---*/ } else if (method.equals(REMOVE_W_HAND)) { return removeWithHandle(method, args, proxy); } else if (method.equals(REMOVE_W_KEY)) { return removeByPrimaryKey(method, args, proxy); /*-- UNKOWN ---------------------------------------------*/ } else { return homeMethod(method, args, proxy); } } catch (SystemException e) { invalidateReference(); throw convertException(getCause(e), method); /* * Application exceptions must be reported dirctly to the client. They * do not impact the viability of the proxy. */ } catch (ApplicationException ae) { throw convertException(getCause(ae), method); /* * A system exception would be highly unusual and would indicate a sever * problem with the container system. */ } catch (SystemError se) { invalidateReference(); if (remote) { throw new RemoteException("Container has suffered a SystemException", getCause(se)); } else { throw new EJBException("Container has suffered a SystemException").initCause(getCause(se)); } } catch (Throwable oe) { if (remote) { throw new RemoteException("Unknown Client Exception", oe); } else { throw new EJBException("Unknown Client Exception").initCause(oe); } } } public Object homeMethod(final Method method, final Object[] args, final Object proxy) throws Throwable { final EJBRequest req = new EJBRequest(RequestMethodCode.EJB_HOME_METHOD, ejb, method, args, null, client.getSerializer()); final EJBResponse res = request(req); switch (res.getResponseCode()) { case ResponseCodes.EJB_ERROR: throw new SystemError((ThrowableArtifact) res.getResult()); case ResponseCodes.EJB_SYS_EXCEPTION: throw new SystemException((ThrowableArtifact) res.getResult()); case ResponseCodes.EJB_APP_EXCEPTION: throw new ApplicationException((ThrowableArtifact) res.getResult()); case ResponseCodes.EJB_OK: return res.getResult(); default: throw new RemoteException("Received invalid response code from server: " + res.getResponseCode()); } } /*-------------------------------------------------*/ /* Home interface methods */ /*-------------------------------------------------*/ protected Object create(final Method method, final Object[] args, final Object proxy) throws Throwable { final EJBRequest req = new EJBRequest(RequestMethodCode.EJB_HOME_CREATE, ejb, method, args, null, client.getSerializer()); final EJBResponse res = request(req); switch (res.getResponseCode()) { case ResponseCodes.EJB_ERROR: throw new SystemError((ThrowableArtifact) res.getResult()); case ResponseCodes.EJB_SYS_EXCEPTION: throw new SystemException((ThrowableArtifact) res.getResult()); case ResponseCodes.EJB_APP_EXCEPTION: throw new ApplicationException((ThrowableArtifact) res.getResult()); case ResponseCodes.EJB_OK: final Object primKey = res.getResult(); final EJBObjectHandler handler = EJBObjectHandler.createEJBObjectHandler(executor, ejb, server, client, primKey, authenticationInfo); handler.setEJBHomeProxy((EJBHomeProxy) proxy); return handler.createEJBObjectProxy(); default: throw new RemoteException("Received invalid response code from server: " + res.getResponseCode()); } } protected abstract Object findX(Method method, Object[] args, Object proxy) throws Throwable; /*-------------------------------------------------*/ /* EJBHome methods */ /*-------------------------------------------------*/ protected Object getEJBMetaData(final Method method, final Object[] args, final Object proxy) throws Throwable { return ejb; } protected Object getHomeHandle(final Method method, final Object[] args, final Object proxy) throws Throwable { return new EJBHomeHandle((EJBHomeProxy) proxy); } protected abstract Object removeWithHandle(Method method, Object[] args, Object proxy) throws Throwable; protected abstract Object removeByPrimaryKey(Method method, Object[] args, Object proxy) throws Throwable; @Override public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { } @Override public void writeExternal(final ObjectOutput out) throws IOException { } }