/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.kernel.plugins.dependency;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.beans.info.spi.BeanInfo;
import org.jboss.beans.metadata.spi.BeanMetaData;
import org.jboss.beans.metadata.spi.LifecycleMetaData;
import org.jboss.dependency.plugins.AbstractControllerContextActions;
import org.jboss.dependency.plugins.AbstractDependencyItem;
import org.jboss.dependency.plugins.spi.action.ControllerContextAction;
import org.jboss.dependency.spi.ControllerContext;
import org.jboss.dependency.spi.ControllerState;
import org.jboss.dependency.spi.DependencyInfo;
import org.jboss.joinpoint.spi.Joinpoint;
import org.jboss.joinpoint.spi.JoinpointException;
import org.jboss.joinpoint.spi.MethodJoinpoint;
import org.jboss.joinpoint.spi.TargettedJoinpoint;
import org.jboss.kernel.Kernel;
import org.jboss.kernel.plugins.config.Configurator;
import org.jboss.kernel.spi.config.KernelConfigurator;
import org.jboss.kernel.spi.dependency.KernelController;
import org.jboss.kernel.spi.dependency.KernelControllerContext;
import org.jboss.kernel.spi.dependency.KernelControllerContextAware;
import org.jboss.kernel.spi.registry.KernelRegistry;
import org.jboss.logging.Logger;
/**
* The KernelControllerActions.<p>
*
* When there is a security manager and we are using a native context
* we switch to our privileges to run the actions and switch back to callout to beans.<p>
*
* Otherwise, we just use the caller's privileges.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @version $Revision: 1.12 $
*/
public class KernelControllerContextActions extends AbstractControllerContextActions
{
/** The single instance */
private static KernelControllerContextActions instance;
/**
* Dispatch a joinpoint
*
* @param context the context
* @param joinpoint the joinpoint
* @return the result
* @throws Throwable for any error
*/
protected static Object dispatchJoinPoint(final KernelControllerContext context, final Joinpoint joinpoint) throws Throwable
{
AccessControlContext access = null;
if (context instanceof AbstractKernelControllerContext)
{
AbstractKernelControllerContext theContext = (AbstractKernelControllerContext) context;
access = theContext.getAccessControlContext();
}
if (access == null)
{
return joinpoint.dispatch();
}
else
{
DispatchJoinPoint action = new DispatchJoinPoint(joinpoint);
try
{
return AccessController.doPrivileged(action, access);
}
catch (PrivilegedActionException e)
{
throw e.getCause();
}
}
}
/**
* Get the instance
*
* @return the actions
*/
public static KernelControllerContextActions getInstance()
{
if (instance == null)
{
Map actions = new HashMap();
actions.put(ControllerState.DESCRIBED, new DescribeAction());
actions.put(ControllerState.INSTANTIATED, new InstantiateAction());
actions.put(ControllerState.CONFIGURED, new ConfigureAction());
actions.put(ControllerState.CREATE, new CreateDestroyLifecycleAction());
actions.put(ControllerState.START, new StartStopLifecycleAction());
actions.put(ControllerState.INSTALLED, new InstallAction());
instance = new KernelControllerContextActions(actions);
}
return instance;
}
/**
* Create a new KernelControllerContextActions.
*/
protected KernelControllerContextActions(Map actions)
{
super(actions);
}
/**
* Abstract action
*/
public static class KernelControllerContextAction implements ControllerContextAction
{
protected Logger log = Logger.getLogger(getClass());
public void install(final ControllerContext context) throws Throwable
{
if (System.getSecurityManager() == null || context instanceof AbstractKernelControllerContext == false)
installAction((KernelControllerContext) context);
else
{
PrivilegedExceptionAction action = new PrivilegedExceptionAction()
{
public Object run() throws Exception
{
try
{
installAction((KernelControllerContext) context);
return null;
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
catch (Error e)
{
throw e;
}
catch (Throwable t)
{
throw new RuntimeException(t);
}
}
};
try
{
AccessController.doPrivileged(action);
}
catch (PrivilegedActionException e)
{
throw e.getCause();
}
}
}
public void uninstall(final ControllerContext context)
{
if (System.getSecurityManager() == null || context instanceof AbstractKernelControllerContext == false)
uninstallAction((KernelControllerContext) context);
else
{
PrivilegedAction action = new PrivilegedAction()
{
public Object run()
{
uninstallAction((KernelControllerContext) context);
return null;
}
};
AccessController.doPrivileged(action);
}
}
public void installAction(KernelControllerContext context) throws Throwable
{
}
public void uninstallAction(KernelControllerContext context)
{
}
}
/**
* The describe action
*/
public static class DescribeAction extends KernelControllerContextAction
{
public void installAction(KernelControllerContext context) throws Throwable
{
KernelController controller = (KernelController) context.getController();
Kernel kernel = controller.getKernel();
KernelConfigurator configurator = kernel.getConfigurator();
BeanMetaData metaData = context.getBeanMetaData();
BeanInfo info = configurator.getBeanInfo(metaData);
context.setBeanInfo(info);
// add custom dependencies (e.g. AOP layer).
DependencyInfo depends = context.getDependencyInfo();
List dependencies = info.getDependencies();
if (dependencies != null)
{
Iterator it = dependencies.iterator();
while (it.hasNext())
{
AbstractDependencyItem dependency = new AbstractDependencyItem(metaData.getName(), it.next(), ControllerState.INSTANTIATED, ControllerState.INSTALLED);
depends.addIDependOn(dependency);
}
}
}
public void uninstallAction(KernelControllerContext context)
{
context.setBeanInfo(null);
}
}
/**
* The instantiate action
*/
public static class InstantiateAction extends KernelControllerContextAction
{
public void installAction(KernelControllerContext context) throws Throwable
{
KernelController controller = (KernelController) context.getController();
Kernel kernel = controller.getKernel();
KernelConfigurator configurator = kernel.getConfigurator();
BeanMetaData metaData = context.getBeanMetaData();
BeanInfo info = context.getBeanInfo();
final Joinpoint joinPoint = configurator.getConstructorJoinPoint(info, metaData.getConstructor(), metaData);
Object object = dispatchJoinPoint(context, joinPoint);
context.setTarget(object);
try
{
if (object != null && object instanceof KernelControllerContextAware)
((KernelControllerContextAware) object).setKernelControllerContext(context);
}
catch (Throwable t)
{
uninstall(context);
throw t;
}
}
public void uninstallAction(KernelControllerContext context)
{
try
{
Object object = context.getTarget();
if (object != null && object instanceof KernelControllerContextAware)
((KernelControllerContextAware) object).unsetKernelControllerContext(context);
}
catch (Throwable ignored)
{
log.debug("Ignored error unsetting context ", ignored);
}
finally
{
context.setTarget(null);
}
}
}
/**
* The configure action
*/
public static class ConfigureAction extends KernelControllerContextAction
{
public void installAction(KernelControllerContext context) throws Throwable
{
KernelController controller = (KernelController) context.getController();
Kernel kernel = controller.getKernel();
KernelConfigurator configurator = kernel.getConfigurator();
Object object = context.getTarget();
BeanInfo info = context.getBeanInfo();
BeanMetaData metaData = context.getBeanMetaData();
Set joinPoints = configurator.getPropertySetterJoinPoints(info, metaData);
setAttributes(context, object, joinPoints, false);
}
public void uninstallAction(KernelControllerContext context)
{
KernelController controller = (KernelController) context.getController();
Kernel kernel = controller.getKernel();
KernelConfigurator configurator = kernel.getConfigurator();
Object object = context.getTarget();
BeanInfo info = context.getBeanInfo();
BeanMetaData metaData = context.getBeanMetaData();
try
{
Set joinPoints = configurator.getPropertyNullerJoinPoints(info, metaData);
setAttributes(context, object, joinPoints, true);
}
catch (Throwable t)
{
log.warn("Error unconfiguring bean " + context, t);
}
}
/**
* Set the attributes
*
* @param context the context
* @param target the target
* @param joinPoints the attribute setter joinpoints
* @param ignoreErrors whether to ignore errors
* @throws Throwable for any unignored error
*/
protected void setAttributes(KernelControllerContext context, Object target, Set joinPoints, boolean ignoreErrors) throws Throwable
{
if (joinPoints.isEmpty() == false)
{
boolean trace = log.isTraceEnabled();
for (Iterator i = joinPoints.iterator(); i.hasNext();)
{
TargettedJoinpoint joinPoint = (TargettedJoinpoint) i.next();
joinPoint.setTarget(target);
try
{
dispatchJoinPoint(context, joinPoint);
}
catch (Throwable t)
{
if (ignoreErrors)
{
if (trace)
log.trace("Ignored for " + joinPoint, t);
}
else
{
throw t;
}
}
}
}
}
}
/**
* A lifecycle action
*/
public static abstract class LifecycleAction extends KernelControllerContextAction
{
/**
* Create a new AbstractLifecycleAction.
*/
public LifecycleAction()
{
}
/**
* Get the install method
*
* @param context the context
* @return the method
*/
public abstract String getInstallMethod(KernelControllerContext context);
/**
* Get the install parameters
*
* @param context the context
* @return the parameters
*/
public abstract List getInstallParameters(KernelControllerContext context);
/**
* Get the uninstall method
*
* @param context the context
* @return the method
*/
public abstract String getUninstallMethod(KernelControllerContext context);
/**
* Get the uninstall parameters
*
* @param context the context
* @return the parameters
*/
public abstract List getUninstallParameters(KernelControllerContext context);
public void installAction(KernelControllerContext context) throws Throwable
{
boolean trace = log.isTraceEnabled();
KernelController controller = (KernelController) context.getController();
Kernel kernel = controller.getKernel();
KernelConfigurator configurator = kernel.getConfigurator();
Object target = context.getTarget();
BeanInfo info = context.getBeanInfo();
BeanMetaData metaData = context.getBeanMetaData();
String method = getInstallMethod(context);
List parameters = getInstallParameters(context);
MethodJoinpoint joinpoint = null;
try
{
ClassLoader cl = Configurator.getClassLoader(metaData);
joinpoint = configurator.getMethodJoinPoint(info, cl, method, parameters, false, true);
}
catch (JoinpointException ignored)
{
if (trace)
{
if (parameters == null)
log.trace("No " + method + " method for " + context);
else
log.trace("No " + method + parameters + " method for " + context);
}
return;
}
joinpoint.setTarget(target);
dispatchJoinPoint(context, joinpoint);
}
public void uninstallAction(KernelControllerContext context)
{
boolean trace = log.isTraceEnabled();
KernelController controller = (KernelController) context.getController();
Kernel kernel = controller.getKernel();
KernelConfigurator configurator = kernel.getConfigurator();
Object target = context.getTarget();
BeanInfo info = context.getBeanInfo();
BeanMetaData metaData = context.getBeanMetaData();
String method = getUninstallMethod(context);
List parameters = getUninstallParameters(context);
MethodJoinpoint joinpoint = null;
try
{
ClassLoader cl = Configurator.getClassLoader(metaData);
joinpoint = configurator.getMethodJoinPoint(info, cl, method, parameters, false, true);
joinpoint.setTarget(target);
dispatchJoinPoint(context, joinpoint);
}
catch (JoinpointException ignored)
{
if (trace)
{
if (parameters == null)
log.trace("No " + method + " method for " + context);
else
log.trace("No " + method + parameters + " method for " + context);
}
return;
}
catch (Throwable throwable)
{
log.warn("Error during " + method, throwable);
}
}
}
/**
* A CreateDestroyLifecycleAction.
*/
public static class CreateDestroyLifecycleAction extends LifecycleAction
{
public String getInstallMethod(KernelControllerContext context)
{
BeanMetaData metaData = context.getBeanMetaData();
LifecycleMetaData lifecycle = metaData.getCreate();
if (lifecycle != null)
return lifecycle.getMethodName();
return "create";
}
public List getInstallParameters(KernelControllerContext context)
{
BeanMetaData metaData = context.getBeanMetaData();
LifecycleMetaData lifecycle = metaData.getCreate();
if (lifecycle != null)
return lifecycle.getParameters();
return null;
}
public String getUninstallMethod(KernelControllerContext context)
{
BeanMetaData metaData = context.getBeanMetaData();
LifecycleMetaData lifecycle = metaData.getDestroy();
if (lifecycle != null)
return lifecycle.getMethodName();
return "destroy";
}
public List getUninstallParameters(KernelControllerContext context)
{
BeanMetaData metaData = context.getBeanMetaData();
LifecycleMetaData lifecycle = metaData.getDestroy();
if (lifecycle != null)
return lifecycle.getParameters();
return null;
}
}
/**
* A StartStopLifecycleAction.
*/
public static class StartStopLifecycleAction extends LifecycleAction
{
public String getInstallMethod(KernelControllerContext context)
{
BeanMetaData metaData = context.getBeanMetaData();
LifecycleMetaData lifecycle = metaData.getStart();
if (lifecycle != null)
return lifecycle.getMethodName();
return "start";
}
public List getInstallParameters(KernelControllerContext context)
{
BeanMetaData metaData = context.getBeanMetaData();
LifecycleMetaData lifecycle = metaData.getStart();
if (lifecycle != null)
return lifecycle.getParameters();
return null;
}
public String getUninstallMethod(KernelControllerContext context)
{
BeanMetaData metaData = context.getBeanMetaData();
LifecycleMetaData lifecycle = metaData.getStop();
if (lifecycle != null)
return lifecycle.getMethodName();
return "stop";
}
public List getUninstallParameters(KernelControllerContext context)
{
BeanMetaData metaData = context.getBeanMetaData();
LifecycleMetaData lifecycle = metaData.getStop();
if (lifecycle != null)
return lifecycle.getParameters();
return null;
}
}
/**
* The install action
*/
public static class InstallAction extends KernelControllerContextAction
{
public void installAction(KernelControllerContext context) throws Throwable
{
KernelController controller = (KernelController) context.getController();
Kernel kernel = controller.getKernel();
KernelRegistry registry = kernel.getRegistry();
BeanMetaData metaData = context.getBeanMetaData();
Object name = metaData.getName();
registry.registerEntry(name, context);
controller.addSupplies(context);
}
public void uninstallAction(KernelControllerContext context)
{
KernelController controller = (KernelController) context.getController();
Kernel kernel = controller.getKernel();
KernelRegistry registry = kernel.getRegistry();
BeanMetaData metaData = context.getBeanMetaData();
Object name = metaData.getName();
try
{
controller.removeSupplies(context);
registry.unregisterEntry(name);
}
catch (Throwable t)
{
log.warn("Ignoring unregistered entry at uninstall " + name);
}
}
}
/**
* Dispatches a joinpoint as a privileged action
*/
private static class DispatchJoinPoint implements PrivilegedExceptionAction
{
private Joinpoint joinpoint;
public DispatchJoinPoint(Joinpoint joinpoint)
{
this.joinpoint = joinpoint;
}
public Object run() throws Exception
{
try
{
return joinpoint.dispatch();
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
catch (Error e)
{
throw e;
}
catch (Throwable t)
{
throw new RuntimeException(t);
}
}
}
}