blob: fe3935d4eeef249c254d220dbfd4c3a54299c2a3 [file] [log] [blame]
/*
* 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.core.ivm;
import org.apache.openejb.ApplicationException;
import org.apache.openejb.BeanContext;
import org.apache.openejb.InterfaceType;
import org.apache.openejb.InvalidateReferenceException;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.OpenEJBRuntimeException;
import org.apache.openejb.ProxyInfo;
import org.apache.openejb.SystemException;
import org.apache.openejb.async.AsynchronousPool;
import org.apache.openejb.core.ServerFederation;
import org.apache.openejb.core.ThreadContext;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.spi.ApplicationServer;
import org.apache.openejb.spi.SecurityService;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import javax.ejb.AccessLocalException;
import javax.ejb.EJBAccessException;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import java.io.ObjectStreamException;
import java.lang.reflect.Method;
import java.rmi.AccessException;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
public abstract class EjbObjectProxyHandler extends BaseEjbProxyHandler {
private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources");
static final Map<String, Integer> dispatchTable;
static {
dispatchTable = new HashMap<String, Integer>();
dispatchTable.put("getHandle", 1);
dispatchTable.put("getPrimaryKey", 2);
dispatchTable.put("isIdentical", 3);
dispatchTable.put("remove", 4);
dispatchTable.put("getEJBHome", 5);
dispatchTable.put("getEJBLocalHome", 6);
}
public EjbObjectProxyHandler(final BeanContext beanContext, final Object pk, final InterfaceType interfaceType, final List<Class> interfaces, final Class mainInterface) {
super(beanContext, pk, interfaceType, interfaces, mainInterface);
}
public abstract Object getRegistryId();
@Override
public Object _invoke(final Object p, final Class interfce, final Method m, final Object[] a) throws Throwable {
Object retValue = null;
Throwable exc = null;
final String methodName = m.getName();
try {
if (logger.isDebugEnabled()) {
logger.debug("EjbObjectProxyHandler: invoking method " + methodName + " on " + deploymentID + " with identity " + primaryKey);
}
Integer operation = dispatchTable.get(methodName);
if (operation != null) {
if (operation == 3) {
if (m.getParameterTypes()[0] != EJBObject.class && m.getParameterTypes()[0] != EJBLocalObject.class) {
operation = null;
}
} else {
operation = m.getParameterTypes().length == 0 ? operation : null;
}
}
if (operation == null || !interfaceType.isComponent()) {
retValue = businessMethod(interfce, m, a, p);
} else {
switch (operation) {
case 1:
retValue = getHandle(m, a, p);
break;
case 2:
retValue = getPrimaryKey(m, a, p);
break;
case 3:
retValue = isIdentical(m, a, p);
break;
case 4:
retValue = remove(interfce, m, a, p);
break;
case 5:
retValue = getEJBHome(m, a, p);
break;
case 6:
retValue = getEJBLocalHome(m, a, p);
break;
default:
throw new OpenEJBRuntimeException("Inconsistent internal state");
}
}
return retValue;
/*
* The ire is thrown by the container system and propagated by
* the server to the stub.
*/
} catch (final InvalidateReferenceException ire) {
invalidateAllHandlers(getRegistryId());
exc = ire.getRootCause() != null ? ire.getRootCause() : new RemoteException("InvalidateReferenceException: " + ire);
throw exc;
/*
* Application exceptions must be reported dirctly to the client. They
* do not impact the viability of the proxy.
*/
} catch (final ApplicationException ae) {
exc = ae.getRootCause() != null ? ae.getRootCause() : ae;
if (exc instanceof EJBAccessException) {
if (interfaceType.isBusiness()) {
throw exc;
} else {
if (interfaceType.isLocal()) {
throw new AccessLocalException(exc.getMessage()).initCause(exc.getCause());
} else {
throw new AccessException(exc.getMessage());
}
}
}
throw exc;
/*
* A system exception would be highly unusual and would indicate a sever
* problem with the container system.
*/
} catch (final SystemException se) {
try {
invalidateReference();
} catch (final IllegalStateException ignore) {
logger.debug("Tried to invalidate reference before processing system error: " +ignore.getMessage());
}
exc = se.getRootCause() != null ? se.getRootCause() : se;
logger.debug("The container received an unexpected exception: ", exc);
throw new RemoteException("Container has suffered a SystemException", exc);
} catch (final OpenEJBException oe) {
exc = oe.getRootCause() != null ? oe.getRootCause() : oe;
logger.debug("The container received an unexpected exception: ", exc);
throw new RemoteException("Unknown Container Exception", oe.getRootCause());
} finally {
if (logger.isDebugEnabled()) {
if (exc == null) {
String ret = "void";
if (null != retValue) {
try {
ret = retValue.toString();
} catch (final Exception e) {
ret = "toString() failed on (" + e.getMessage() + ")";
}
}
logger.debug("EjbObjectProxyHandler: finished invoking method " + methodName + ". Return value:" + ret);
} else {
logger.debug("EjbObjectProxyHandler: finished invoking method " + methodName + " with exception " + exc);
}
}
}
}
protected Object getEJBHome(final Method method, final Object[] args, final Object proxy) throws Throwable {
checkAuthorization(method);
return getBeanContext().getEJBHome();
}
protected Object getEJBLocalHome(final Method method, final Object[] args, final Object proxy) throws Throwable {
checkAuthorization(method);
return getBeanContext().getEJBLocalHome();
}
protected Object getHandle(final Method method, final Object[] args, final Object proxy) throws Throwable {
checkAuthorization(method);
return new IntraVmHandle(proxy);
}
@Override
public ProxyInfo getProxyInfo() {
return new ProxyInfo(getBeanContext(), primaryKey, getInterfaces(), interfaceType, getMainInterface());
}
@Override
protected Object _writeReplace(final Object proxy) throws ObjectStreamException {
/*
* If the proxy is being copied between bean instances in a RPC
* call we use the IntraVmArtifact
*/
if (IntraVmCopyMonitor.isIntraVmCopyOperation()) {
return new IntraVmArtifact(proxy);
/*
* If the proxy is referenced by a stateful bean that is being
* passivated by the container we allow this object to be serialized.
*/
} else if (IntraVmCopyMonitor.isStatefulPassivationOperation()) {
return proxy;
/*
* If the proxy is being copied between class loaders
* we allow this object to be serialized.
*/
} else if (IntraVmCopyMonitor.isCrossClassLoaderOperation()) {
return proxy;
/*
* If the proxy is serialized outside the core container system,
* we allow the application server to handle it.
*/
} else if (!interfaceType.isRemote()) {
return proxy;
} else {
final ApplicationServer applicationServer = ServerFederation.getApplicationServer();
if (interfaceType.isBusiness()) {
return applicationServer.getBusinessObject(this.getProxyInfo());
} else {
return applicationServer.getEJBObject(this.getProxyInfo());
}
}
}
protected abstract Object getPrimaryKey(Method method, Object[] args, Object proxy) throws Throwable;
protected abstract Object isIdentical(Method method, Object[] args, Object proxy) throws Throwable;
protected abstract Object remove(Class interfce, Method method, Object[] args, Object proxy) throws Throwable;
protected Object businessMethod(final Class<?> interfce, final Method method, final Object[] args, final Object proxy) throws Throwable {
final BeanContext beanContext = getBeanContext();
if (beanContext.isAsynchronous(method)) {
final SecurityService securityService = SystemInstance.get().getComponent(SecurityService.class);
if(null == securityService){
throw new OpenEJBRuntimeException("SecurityService has not been initialized");
}
Object stateTmp = securityService.currentState();
final boolean associate;
if (stateTmp == null) {
stateTmp = ClientSecurity.getIdentity();
associate = stateTmp != null;
} else {
associate = false;
}
final Object securityState = stateTmp;
final ThreadContext threadContext = ThreadContext.getThreadContext();
final AsynchronousPool asynchronousPool = beanContext.getModuleContext().getAppContext().getAsynchronousPool();
return asynchronousPool.invoke(new Callable<Object>() {
@Override
public Object call() throws Exception {
final Object threadState;
if (associate) {
//noinspection unchecked
securityService.associate(securityState);
threadState = null;
} else {
threadState = securityService.currentState();
securityService.setState(securityState);
}
final ThreadContext oldCtx; // ensure context is the same as for the caller
if (threadContext != null) {
oldCtx = ThreadContext.enter(new ThreadContext(threadContext));
} else {
oldCtx = null;
}
try {
return synchronizedBusinessMethod(interfce, method, args);
} catch (final ApplicationException ae) {
logger.error("EjbObjectProxyHandler: Asynchronous call to '" + interfce.getSimpleName() + "' on '" + method.getName() + "' failed", ae);
throw ae;
} finally {
if (threadContext != null) {
ThreadContext.exit(oldCtx);
}
if (!associate) {
securityService.setState(threadState);
} else {
securityService.disassociate();
}
}
}
}, method.getReturnType() == Void.TYPE);
} else {
return synchronizedBusinessMethod(interfce, method, args);
}
}
protected Object synchronizedBusinessMethod(final Class<?> interfce, final Method method, final Object[] args) throws OpenEJBException {
return container.invoke(deploymentID, interfaceType, interfce, method, args, primaryKey);
}
public static Object createProxy(final BeanContext beanContext, final Object primaryKey, final InterfaceType interfaceType, final Class mainInterface) {
return createProxy(beanContext, primaryKey, interfaceType, null, mainInterface);
}
public static Object createProxy(final BeanContext beanContext, final Object primaryKey, InterfaceType interfaceType, final List<Class> interfaces, final Class mainInterface) {
if (!interfaceType.isHome()) {
interfaceType = interfaceType.getCounterpart();
}
final EjbHomeProxyHandler homeHandler = EjbHomeProxyHandler.createHomeHandler(beanContext, interfaceType, interfaces, mainInterface);
return homeHandler.createProxy(primaryKey, mainInterface);
}
}