[jboss-cvs] JBossAS SVN: r58655 - trunk/system/src/main/org/jboss/deployers/plugins/scanner
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Tue Nov 21 03:02:23 EST 2006
Author: scott.stark at jboss.org
Date: 2006-11-21 03:02:21 -0500 (Tue, 21 Nov 2006)
New Revision: 58655
Added:
trunk/system/src/main/org/jboss/deployers/plugins/scanner/VFSDeploymentScannerImpl.java
Log:
Restore the hotdeployment vfs scanner
Added: trunk/system/src/main/org/jboss/deployers/plugins/scanner/VFSDeploymentScannerImpl.java
===================================================================
--- trunk/system/src/main/org/jboss/deployers/plugins/scanner/VFSDeploymentScannerImpl.java 2006-11-21 08:02:19 UTC (rev 58654)
+++ trunk/system/src/main/org/jboss/deployers/plugins/scanner/VFSDeploymentScannerImpl.java 2006-11-21 08:02:21 UTC (rev 58655)
@@ -0,0 +1,615 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * 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.deployers.plugins.scanner;
+
+import static org.jboss.deployers.spi.structure.StructureDetermined.PREDETERMINED;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import org.jboss.deployers.plugins.structure.AbstractDeploymentContext;
+import org.jboss.deployers.plugins.structure.BasicStructuredDeployers;
+import org.jboss.deployers.plugins.structure.StructureMetaDataImpl;
+import org.jboss.deployers.spi.DeploymentException;
+import org.jboss.deployers.spi.deployment.MainDeployer;
+import org.jboss.deployers.spi.structure.DeploymentContext;
+import org.jboss.deployers.spi.structure.vfs.StructureBuilder;
+import org.jboss.deployers.spi.structure.vfs.StructureDeployer;
+import org.jboss.deployers.spi.structure.vfs.StructureMetaData;
+import org.jboss.deployers.spi.structure.vfs.StructuredDeployers;
+import org.jboss.logging.Logger;
+import org.jboss.util.StringPropertyReplacer;
+import org.jboss.virtual.VFS;
+import org.jboss.virtual.VirtualFile;
+import org.jboss.virtual.VirtualFileFilter;
+
+
+/**
+ * A DeploymentScanner build on top of the VFS and MainDeployer. This is a
+ * first pass to flesh out the APIs/concepts.
+ *
+ * @author <a href="mailto:dimitris at jboss.org">Dimitris Andreadis</a>
+ * @author Scott.Stark at jboss.org
+ * @version $Revision$
+ */
+public class VFSDeploymentScannerImpl
+ implements Runnable
+{
+ private static final Logger log = Logger.getLogger(VFSDeploymentScannerImpl.class);
+ // Private Data --------------------------------------------------
+ private MainDeployer mainDeployer;
+ /** The structure builder that translates structure metadata to deployments */
+ private StructureBuilder structureBuilder;
+ private StructuredDeployers structureDeployers = new BasicStructuredDeployers();
+
+ /** */
+ private VirtualFileFilter filter;
+ /** The ExecutorService/ThreadPool for performing scans */
+ private ScheduledExecutorService scanExecutor;
+ private ScheduledFuture activeScan;
+
+ /** The URIfied ServerHomeURL */
+ private URI serverHomeURI;
+
+ /** The list of URIs to scan */
+ private List<URI> uriList = Collections.synchronizedList(new ArrayList<URI>());
+
+ /** The list of VirtualFiles to scan */
+ private List<VirtualFile> vdfList = Collections.synchronizedList(new ArrayList<VirtualFile>());
+
+ /** Whether to search for files inside directories whose names containing no dots */
+ private boolean doRecursiveSearch = true;
+ /** Period in ms between deployment scans */
+ private long scanPeriod = 5000;
+ private int scanCount;
+
+ /** A set of scanned VirtualFiles which have been deployed */
+ private Map<VirtualFile, DeploymentContext> deployedMap = new ConcurrentHashMap<VirtualFile, DeploymentContext>();
+
+ // Constructor ---------------------------------------------------
+
+ public VFSDeploymentScannerImpl()
+ {
+ // empty
+ }
+
+ // Attributes ----------------------------------------------------
+
+ public void setMainDeployer(MainDeployer deployer)
+ {
+ this.mainDeployer = deployer;
+ }
+
+ /**
+ * Get the structure deployers
+ *
+ * @return the structure deployers
+ */
+ public synchronized Set<StructureDeployer> getStructureDeployers()
+ {
+ SortedSet<StructureDeployer> sdeployers = structureDeployers.getDeployers();
+ return sdeployers;
+ }
+
+ public VirtualFileFilter getFilter()
+ {
+ return filter;
+ }
+ public void setFilter(VirtualFileFilter filter)
+ {
+ this.filter = filter;
+ }
+
+ /**
+ * @return Returns the scanExecutor.
+ */
+ public ScheduledExecutorService getScanExecutor()
+ {
+ return this.scanExecutor;
+ }
+
+ /**
+ * @param scanExecutor The scanExecutor to set.
+ */
+ public void setScanExecutor(ScheduledExecutorService scanExecutor)
+ {
+ this.scanExecutor = scanExecutor;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.deployment.scanner.VFSDeploymentScanner#getScanPeriod()
+ */
+ public long getScanPeriod()
+ {
+ return scanPeriod;
+ }
+ /* (non-Javadoc)
+ * @see org.jboss.deployment.scanner.VFSDeploymentScanner#setScanPeriod(long)
+ */
+ public void setScanPeriod(long period)
+ {
+ this.scanPeriod = period;
+ }
+
+ /** Are deployment scans enabled.
+ */
+ public boolean isScanEnabled()
+ {
+ return activeScan != null;
+ }
+
+ public synchronized int getScanCount()
+ {
+ return scanCount;
+ }
+ public synchronized void resetScanCount()
+ {
+ this.scanCount = 0;
+ }
+
+ /**
+ * Enable/disable deployment scans.
+ * @param scanEnabled true to enable scans, false to disable.
+ */
+ public synchronized void setScanEnabled(boolean scanEnabled)
+ {
+ if( scanEnabled == true && activeScan == null )
+ {
+ activeScan = this.scanExecutor.scheduleWithFixedDelay(this, 0,
+ scanPeriod, TimeUnit.MILLISECONDS);
+ }
+ else if( scanEnabled == false && activeScan != null )
+ {
+ activeScan.cancel(true);
+ activeScan = null;
+ }
+ }
+
+ /**
+ * @throws URISyntaxException
+ * @throws IOException
+ */
+ public void setURIs(final String listspec) throws URISyntaxException, IOException
+ {
+ if (listspec == null)
+ {
+ this.uriList.clear();
+ return;
+ }
+ List<URI> list = new LinkedList<URI>();
+
+ StringTokenizer stok = new StringTokenizer(listspec, ",");
+ while (stok.hasMoreTokens())
+ {
+ String urispec = stok.nextToken().trim();
+
+ log.debug("Adding URI from spec: " + urispec);
+
+ URI uri = makeURI(urispec);
+
+ log.debug("URI: " + uri);
+
+ list.add(uri);
+ }
+ setURIList(list);
+ }
+
+ /**
+ *
+ * @throws IOException
+ */
+ public void setURIList(final List<URI> list) throws IOException
+ {
+ if (list == null)
+ {
+ return;
+ }
+
+ // start out with a fresh list
+ uriList.clear();
+
+ for(int n = 0; n < list.size(); n ++)
+ {
+ URI uri = list.get(n);
+ if (uri == null)
+ {
+ throw new IllegalArgumentException("list element["+n+"] is null");
+ }
+ addURI(uri);
+ }
+ log.debug("URI list: " + uriList);
+ }
+
+ public List<URI> getURIList()
+ {
+ return new ArrayList<URI>(uriList);
+ }
+
+ public void setRecursiveSearch(boolean recurse)
+ {
+ doRecursiveSearch = recurse;
+ }
+
+ public boolean getRecursiveSearch()
+ {
+ return doRecursiveSearch;
+ }
+
+ // Operations ----------------------------------------------------
+
+ public void addURI(final URI uri) throws IOException
+ {
+ if (uri == null)
+ {
+ throw new NullPointerException("uri argument cannot be null");
+ }
+ if( uriList.add(uri) == true )
+ {
+ log.debug("Added URI: " + uri);
+ VirtualFile vf = VFS.getRoot(uri);
+ vdfList.add(vf);
+ }
+ }
+
+ public void removeURI(final URI uri)
+ throws IOException
+ {
+ if (uri == null)
+ {
+ throw new NullPointerException("uri argument cannot be null");
+ }
+ VirtualFile vf = VFS.getRoot(uri);
+ vdfList.remove(vf);
+ boolean success = uriList.remove(uri);
+
+ if (success)
+ {
+ log.debug("Removed URI: " + uri);
+ }
+ }
+
+ public boolean hasURI(final URI uri)
+ {
+ if (uri == null)
+ {
+ throw new NullPointerException("uri argument cannot be null");
+ }
+ return uriList.contains(uri);
+ }
+
+ public void start() throws Exception
+ {
+ // synchronize uriList and vdfList because only at this point
+ // setVirtualFileFactory() injection has been performed
+ vdfList.clear();
+ for (URI uri : uriList)
+ {
+ VirtualFile vf = VFS.getRoot(uri);
+ vdfList.add(vf);
+ }
+
+ // Default to a single thread executor
+ if( scanExecutor == null )
+ {
+ scanExecutor = Executors.newSingleThreadScheduledExecutor(
+ new ThreadFactory()
+ {
+ public Thread newThread(Runnable r)
+ {
+ return new Thread(r, "VFSDeploymentScanner");
+ }
+ }
+ );
+ }
+ activeScan = scanExecutor.scheduleWithFixedDelay(this, 0,
+ scanPeriod, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Executes scan
+ *
+ */
+ public void run()
+ {
+ try
+ {
+ scan();
+ }
+ catch(Throwable e)
+ {
+ log.warn("Scan failed", e);
+ }
+ finally
+ {
+ incScanCount();
+ }
+ }
+
+ public void stop()
+ {
+ if( activeScan != null )
+ {
+ activeScan.cancel(true);
+ activeScan = null;
+ }
+ }
+
+ public synchronized void scan() throws Exception
+ {
+ if (vdfList == null)
+ {
+ throw new IllegalStateException("not initialized");
+ }
+ boolean trace = log.isTraceEnabled();
+
+ // Scan for deployments
+ log.debug("Begin deployment scan");
+
+ // VirtualFiles to deploy
+ List<VirtualFile> toDeployList = new LinkedList<VirtualFile>();
+ synchronized (vdfList)
+ {
+ for (VirtualFile vf : vdfList)
+ {
+ if( trace )
+ log.trace("Checking file: "+vf);
+ if (vf.isLeaf())
+ {
+ // treat this as a deployable unit
+ toDeployList.add(vf);
+ }
+ else
+ {
+ // process (possibly recursively) the dir
+ addDeployments(toDeployList, vf);
+ }
+ }
+ }
+
+ if (trace)
+ {
+ log.trace("toDeployList: "+toDeployList);
+ }
+ LinkedList<VirtualFile> toRemoveList = new LinkedList<VirtualFile>();
+ LinkedList<VirtualFile> toCheckForUpdateList = new LinkedList<VirtualFile>();
+
+ synchronized (deployedMap)
+ {
+ // remove previously deployed URLs no longer needed
+ Iterator<VirtualFile> iter = deployedMap.keySet().iterator();
+ while( iter.hasNext() )
+ {
+ VirtualFile vf = iter.next();
+ if (toDeployList.contains(vf))
+ {
+ toCheckForUpdateList.add(vf);
+ }
+ else
+ {
+ toRemoveList.add(vf);
+ }
+ }
+ }
+
+ // ********
+ // Undeploy
+ // ********
+
+ for (VirtualFile vf : toRemoveList)
+ {
+ undeploy(vf);
+ }
+
+ // ********
+ // Redeploy
+ // ********
+
+ // compute the DeployedURL list to update
+ ArrayList<VirtualFile> toUpdateList = new ArrayList<VirtualFile>(toCheckForUpdateList.size());
+ for (VirtualFile vf : toUpdateList)
+ {
+ DeploymentContext context = deployedMap.get(vf);
+ long modified = vf.getLastModified();
+ Long prevLastDeployed = context.getTransientAttachments().getAttachment("deployedLastModified", Long.class);
+ if (prevLastDeployed != null && prevLastDeployed.compareTo(modified) < 0)
+ {
+ if (trace)
+ {
+ log.trace("Re-deploying " + vf);
+ }
+ toUpdateList.add(vf);
+ }
+ }
+
+ // sort to update list
+ //Collections.sort(toUpdateList, sorter);
+
+ // Undeploy in order
+ for (int i = toUpdateList.size() - 1; i >= 0; i--)
+ {
+ VirtualFile vf = toUpdateList.get(i);
+ undeploy(vf);
+ }
+
+ // Deploy in order
+ for (int i = 0; i < toUpdateList.size(); i++)
+ {
+ VirtualFile vf = toUpdateList.get(i);
+ deploy(vf);
+ }
+
+ // ******
+ // Deploy
+ // ******
+
+ //Collections.sort(toDeployList, sorter);
+ for (Iterator i = toDeployList.iterator(); i.hasNext();)
+ {
+ VirtualFile vf = (VirtualFile)i.next();
+
+ // if vf is not deployed already, deploy it
+ if (!deployedMap.containsKey(vf))
+ {
+ deploy(vf);
+ }
+
+ // vf must have been deployed by now, so remove it from list
+ i.remove();
+
+ }
+ log.debug("End deployment scan");
+ }
+
+ /**
+ * Inc the scanCount and to a notifyAll.
+ *
+ */
+ protected synchronized void incScanCount()
+ {
+ scanCount ++;
+ notifyAll();
+ }
+
+ // Private -------------------------------------------------------
+
+ /**
+ * A helper to make a URI from a full/partial urispec
+ */
+ private URI makeURI(String urispec) throws URISyntaxException
+ {
+ // First replace URI with appropriate properties
+ urispec = StringPropertyReplacer.replaceProperties(urispec);
+ return serverHomeURI.resolve(urispec);
+ }
+
+ /**
+ * A helper to find all deployments under a directory vf
+ * and add them to the supplied list.
+ *
+ * We may recurse.
+ */
+ private void addDeployments(List<VirtualFile> list, VirtualFile root)
+ throws IOException
+ {
+ List<VirtualFile> components = root.getChildren();
+
+ for (VirtualFile vf : components)
+ {
+ if (vf.isLeaf())
+ {
+ // the first arg in filter.accept is not used!
+ if (filter == null || filter.accepts(vf))
+ {
+ list.add(vf);
+ }
+ }
+ else
+ {
+ if (vf.getName().indexOf('.') == -1 && this.doRecursiveSearch)
+ {
+ // recurse if not '.' in name and recursive search is enabled
+ addDeployments(list, vf);
+ }
+ else
+ {
+ list.add(vf);
+ }
+ }
+ }
+ }
+
+ /**
+ * A helper to deploy the given vf using the deployer.
+ */
+ private void deploy(final VirtualFile vf)
+ {
+ // If the deployer is null simply ignore the request
+ log.debug("Deploying: " + vf);
+ DeploymentContext context = new AbstractDeploymentContext(vf);
+ try
+ {
+ mainDeployer.addDeploymentContext(context);
+ mainDeployer.process();
+ }
+ catch (Exception e)
+ {
+ log.warn("Failed to deploy: " + vf, e);
+ // TODO: somehow need to ignore bad deployments to avoid repeated errors
+ return;
+ }
+
+ /* TODO: this differs from the previous behavior. We would need a type to metainf location
+ if we want to watch the same file as jboss4. But since not all files have a deployment
+ descriptor, we need to be able to watch the deployment root anyway.
+ */
+ try
+ {
+ long deployedLastModified = vf.getLastModified();
+ context.getTransientAttachments().addAttachment("deployedLastModified", deployedLastModified);
+ if (!deployedMap.containsKey(vf))
+ {
+ deployedMap.put(vf, context);
+ }
+ }
+ catch(IOException e)
+ {
+ log.warn("Failed to obtain lastModified for: "+vf, e);
+ }
+ }
+
+ /**
+ * A helper to undeploy the given vf using the deployer.
+ */
+ private void undeploy(final VirtualFile vf)
+ {
+ try
+ {
+ log.debug("Undeploying: " + vf);
+ DeploymentContext deployment = deployedMap.remove(vf);
+ mainDeployer.removeDeploymentContext(deployment.getName());
+ }
+ catch (Exception e)
+ {
+ log.error("Failed to undeploy: " + vf, e);
+ }
+ }
+
+}
More information about the jboss-cvs-commits
mailing list