package org.jboss.seam.deployment; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.servlet.ServletContext; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; /** * A {@link DeploymentStrategy} coordinates the deployment of resources for a Seam * application. * * @author Pete Muir * */ public abstract class DeploymentStrategy { private static final LogProvider log = Logging.getLogProvider(DeploymentStrategy.class); private Scanner scanner; private List<File> files = new ArrayList<File>(); private Map<String, DeploymentHandler> deploymentHandlers; /** * The key under which to list possible scanners. System properties take * precedence over /META-INF/seam-scanner.properties. Entries will be tried * in sequential order until a Scanner can be loaded. * * This can be specified as a System property or in * /META-INF/seam-deployment.properties */ public static final String SCANNERS_KEY = "org.jboss.seam.deployment.scanners"; /** * Do the scan for resources * * Should only be called by Seam * */ public abstract void scan(); /** * Get the scanner being used * */ protected Scanner getScanner() { if (scanner == null) { initScanner(); } return scanner; } /** * Get the classloader to use */ public abstract ClassLoader getClassLoader(); /** * Get the ServletContext to use */ public abstract ServletContext getServletContext(); /** * Get (or modify) any registered {@link DeploymentHandler}s * * Implementations of {@link DeploymentStrategy} may add default * {@link DeploymentHandler}s */ public Map<String, DeploymentHandler> getDeploymentHandlers() { if (deploymentHandlers == null) { initDeploymentHandlers(); } return this.deploymentHandlers; } private void initDeploymentHandlers() { this.deploymentHandlers = new HashMap<String, DeploymentHandler>(); List<String> deploymentHandlersClassNames = new SeamDeploymentProperties(getClassLoader()).getPropertyValues(getDeploymentHandlersKey()); addHandlers(deploymentHandlersClassNames); } protected abstract String getDeploymentHandlersKey(); protected void initScanner() { List<String> scanners = new SeamDeploymentProperties(getClassLoader()).getPropertyValues(SCANNERS_KEY); for ( String className : scanners ) { Scanner scanner = instantiateScanner(className); if (scanner != null) { log.trace("Using " + scanner.toString()); this.scanner = scanner; return; } } log.trace("Using default URLScanner"); this.scanner = new URLScanner(this); } private Scanner instantiateScanner(String className) { try { Class<Scanner> scannerClass = (Class<Scanner>) getClassLoader().loadClass(className); Constructor<Scanner> constructor = scannerClass.getConstructor(new Class[] {DeploymentStrategy.class}); return constructor.newInstance( new Object[] {this} ); } catch (ClassNotFoundException e) { log.trace("Unable to use " + className + " as scanner (class not found)", e); } catch (NoClassDefFoundError e) { log.trace("Unable to use " + className + " as scanner (dependency not found)", e); } catch (ClassCastException e) { log.trace("Unable to use " + className + " as scanner (class does not implement org.jboss.seam.deployment.Scanner)"); } catch (InstantiationException e) { log.trace("Unable to instantiate scanner " + className, e); } catch (IllegalAccessException e) { log.trace("Unable to instantiate scanner " + className, e); } catch (SecurityException e) { log.trace(className + " must declare public " + className + "( ClassLoader classLoader, String ... resourceNames )", e); } catch (NoSuchMethodException e) { log.trace(className + " must declare public " + className + "( ClassLoader classLoader, String ... resourceNames )", e); } catch (IllegalArgumentException e) { log.trace(className + " must declare public " + className + "( ClassLoader classLoader, String ... resourceNames )", e); } catch (InvocationTargetException e) { log.trace(className + " must declare public " + className + "( ClassLoader classLoader, String ... resourceNames )", e); } return null; } private void addHandlers(List<String> handlers) { for (String handler : handlers) { addHandler(handler); } } private void addHandler(String className) { DeploymentHandler deploymentHandler = instantiateDeploymentHandler(className); if (deploymentHandler != null) { log.trace("Adding " + deploymentHandler + " as a deployment handler"); deploymentHandlers.put(deploymentHandler.getName(), deploymentHandler); } } private DeploymentHandler instantiateDeploymentHandler(String className) { try { Class<DeploymentHandler> clazz = (Class<DeploymentHandler>) getClassLoader().loadClass(className); return clazz.newInstance(); } catch (ClassNotFoundException e) { log.trace("Unable to use " + className + " as a deployment handler (class not found)", e); } catch (NoClassDefFoundError e) { log.trace("Unable to use " + className + " as a deployment handler (dependency not found)", e); } catch (InstantiationException e) { log.trace("Unable to instantiate deployment handler " + className, e); } catch (IllegalAccessException e) { log.trace("Unable to instantiate deployment handler " + className, e); } return null; } public List<File> getFiles() { return files; } public void setFiles(List<File> files) { this.files = files; } public long getTimestamp() { return getScanner().getTimestamp(); } protected void postScan() { for (Entry<String, DeploymentHandler> entry : getDeploymentHandlers().entrySet()) { entry.getValue().postProcess(getClassLoader()); } } }