package org.jboss.deployment.scanner;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.jboss.deployment.Deployer;
import org.jboss.deployment.DeploymentException;
import org.jboss.system.server.ServerConfigLocator;
public class URLDirectoryScanner extends AbstractDeploymentScanner
implements DeploymentScanner, URLDirectoryScannerMBean
{
private FileFilter defaultFilter;
private Comparator defaultComparator;
private ArrayList scanners = new ArrayList();
private HashMap urlScannerMap = new HashMap();
private File serverHome;
public void addScanURL(URL url)
{
Scanner scanner = new Scanner(url);
addScanner(scanner);
}
public void addScanURL(String url) throws MalformedURLException
{
addScanURL(toUrl(url));
}
public void addScanDir(URL url, Comparator comp, FileFilter filter)
{
Scanner scanner = new DirScanner(url, comp, filter);
addScanner(scanner);
}
public void addScanDir(String urlSpec, String compClassName, String filterClassName)
throws MalformedURLException
{
URL url = toUrl(urlSpec);
Comparator comp = null;
if (compClassName != null)
{
try
{
Class compClass = Thread.currentThread().getContextClassLoader().loadClass("compClassName");
comp = (Comparator)compClass.newInstance();
} catch (Exception e)
{
log.warn("Unable to create instance of Comparator. Ignoring.", e);
}
}
FileFilter filter = null;
if (filterClassName != null)
{
try
{
Class filterClass = Thread.currentThread().getContextClassLoader().loadClass(filterClassName);
filter = (FileFilter)filterClass.newInstance();
} catch (Exception e)
{
log.warn("Unable to create instance of Filter. Ignoring.", e);
}
}
addScanDir(url, comp, filter);
}
private void addScanner(Scanner scanner)
{
synchronized (scanners)
{
if (isScanEnabled())
{
ArrayList localScanners = new ArrayList(scanners);
HashMap localMap = new HashMap(urlScannerMap);
localScanners.add(scanner);
localMap.put(scanner.url, scanner);
scanners = localScanners;
urlScannerMap = localMap;
} else
{
scanners.add(scanner);
urlScannerMap.put(scanner.url, scanner);
}
}
}
public void removeScanURL(URL url)
{
synchronized (scanners)
{
if (isScanEnabled())
{
ArrayList localScanners = new ArrayList(scanners);
HashMap localMap = new HashMap(urlScannerMap);
Scanner scanner = (Scanner)localMap.remove(url);
if (scanner != null)
{
localScanners.remove(scanner);
}
scanners = localScanners;
urlScannerMap = localMap;
} else
{
Scanner scanner = (Scanner)urlScannerMap.remove(url);
if (scanner != null)
{
scanners.remove(scanner);
}
}
}
}
public void setURLs(Element elem)
{
ArrayList localScanners = new ArrayList();
HashMap localMap = new HashMap();
NodeList list = elem.getChildNodes();
synchronized (scanners)
{
scanners.clear();
urlScannerMap.clear();
for (int i = 0; i < list.getLength(); i++)
{
Node node = list.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
NamedNodeMap nodeMap = node.getAttributes();
String name = getNodeValue(nodeMap.getNamedItem("name"));
if (name == null)
{
log.warn("No name specified in URLDirectoryScanner config: " +
node + ". Ignoring");
continue;
}
try
{
if (node.getNodeName().equals("dir"))
{
String filter = getNodeValue(nodeMap.getNamedItem("filter"));
String comp = getNodeValue(nodeMap.getNamedItem("comparator"));
addScanDir(name, comp, filter);
} else if (node.getNodeName().equals("url"))
{
addScanURL(name);
}
} catch (MalformedURLException e)
{
log.warn("Invalid url in DeploymentScanner. Ignoring.", e);
}
}
}
}
}
private String getNodeValue(Node node)
{
if (node == null)
{
return null;
}
String val = node.getNodeValue();
if (val == null)
{
return null;
}
if ((val = val.trim()).length() == 0)
{
return null;
}
return val;
}
private URL toUrl(String value) throws MalformedURLException
{
try
{
return new URL(value);
} catch (MalformedURLException e)
{
File file = new File(value);
if (!file.isAbsolute())
{
file = new File(serverHome, value);
}
try
{
file = file.getCanonicalFile();
} catch (IOException ioe)
{
throw new MalformedURLException("Can not obtain file: " + ioe);
}
return file.toURL();
}
}
public void setURLComparator(String comparatorClassName)
{
log.debug("Setting Comparator: " + comparatorClassName);
try
{
defaultComparator = (Comparator)Thread.currentThread().getContextClassLoader().loadClass(comparatorClassName).newInstance();
} catch (Exception e)
{
log.warn("Unable to create URLComparator.", e);
}
}
public String getURLComparator()
{
if (defaultComparator == null)
{
return null;
}
return defaultComparator.getClass().getName();
}
public void setFilter(String filterClassName)
{
log.debug("Setting Filter: " + filterClassName);
try
{
defaultFilter = (FileFilter)Thread.currentThread().getContextClassLoader().loadClass(filterClassName).newInstance();
} catch (Exception e)
{
log.warn("Unable to create URLComparator.", e);
}
}
public String getFilter()
{
if (defaultFilter == null)
{
return null;
}
return defaultFilter.getClass().getName();
}
Deployer getDeployerObj()
{
return deployer;
}
private class Scanner
{
protected URL url;
private URL watchUrl;
private long lastModified;
private boolean deployed;
public Scanner(URL url)
{
this.url = url;
}
public void scan()
{
if (getLog().isTraceEnabled()) {
getLog().trace("Scanning url: " + url);
}
if (lastModified != getLastModified())
{
if (exists())
{
try
{
getLog().debug("Deploying Modified (or new) url: " + url);
deploy();
} catch (DeploymentException e)
{
getLog().error("Failed to (re)deploy url: " + url, e);
}
} else
{
try
{
getLog().debug("Undeploying url: " + url);
undeploy();
} catch (DeploymentException e)
{
getLog().error("Failed to undeploy url: " + url, e);
}
}
}
}
private boolean exists()
{
try
{
if (url.getProtocol().equals("file")) {
File file = new File(url.getPath());
return file.exists();
} else {
url.openStream().close();
return true;
}
} catch (IOException e)
{
return false;
}
}
private long getLastModified()
{
try
{
URL lmUrl = watchUrl == null ? url : watchUrl;
return lmUrl.openConnection().getLastModified();
} catch (IOException e)
{
return 0L;
}
}
private void deploy() throws DeploymentException
{
if (deployed)
{
getDeployerObj().undeploy(url);
}
getDeployerObj().deploy(url);
try
{
Object o = getServer().invoke(getDeployer(), "getWatchUrl",
new Object[]
{ url },
new String[]
{ URL.class.getName() });
watchUrl = o == null ? url : (URL)o;
getLog().debug("Watch URL for: " + url + " -> " + watchUrl);
} catch (Exception e)
{
watchUrl = url;
getLog().debug("Unable to obtain watchUrl from deployer. " +
"Use url: " + url, e);
}
lastModified = getLastModified();
deployed = true;
}
private void undeploy() throws DeploymentException
{
if (!deployed)
{
return;
}
getDeployerObj().undeploy(url);
deployed = false;
lastModified = 0L;
watchUrl = null;
}
}
private class DirScanner extends Scanner
{
private File dir;
private FileFilter filter;
private Comparator comp;
private ArrayList deployed = new ArrayList();
public DirScanner(URL url, Comparator comp, FileFilter filter)
{
super(url);
if (!url.getProtocol().equals("file"))
{
throw new IllegalArgumentException("Urls for directory " +
"scanning must use the file: protocol.");
}
dir = new File(url.getPath()).getAbsoluteFile();
this.filter = filter == null ? defaultFilter : filter;
this.comp = new FileComparator(comp == null ? defaultComparator : comp);
}
public void scan()
{
if (!dir.exists())
{
getLog().warn("The director to scan does not exist: " + dir);
return;
}
if (!dir.isDirectory())
{
getLog().warn("The directory to scan is not a directory: " + dir);
return;
}
File[] files;
if (filter == null)
{
files = dir.listFiles();
} else
{
files = dir.listFiles(filter);
}
Arrays.sort(files, comp);
int deployedIndex = 0;
int fileIndex = 0;
while (true)
{
Scanner scanner = null;
if (deployedIndex < deployed.size())
{
scanner = (Scanner)deployed.get(deployedIndex);
}
File file = null;
if (fileIndex < files.length)
{
file = files[fileIndex];
}
if (scanner == null && file == null)
{
break;
}
switch (comp.compare(file, scanner == null ? null : scanner.url))
{
case -1: getLog().debug("Found new deployable application in directory " +
dir + ": " + file);
try {
scanner = new Scanner(file.toURL());
deployed.add(deployedIndex, scanner);
} catch (MalformedURLException e) {
getLog().warn("Unable to obtain URL for file: " + file, e);
fileIndex++;
}
case 0: scanner.scan();
deployedIndex++;
fileIndex++;
break;
case 1: getLog().debug("Deployed application removed from directory " +
dir + ": " + file);
scanner.scan();
if (!scanner.deployed)
{
deployed.remove(deployedIndex);
} else
{
deployedIndex++;
}
break;
}
}
}
}
private static class FileComparator implements Comparator
{
private Comparator urlComparator;
public FileComparator(Comparator urlComparator)
{
this.urlComparator = urlComparator;
}
public int compare(Object o1, Object o2)
{
if (o1 == o2)
{
return 0;
}
if (o1 == null)
{
return 1;
}
if (o2 == null)
{
return -1;
}
File file1;
File file2;
URL url1;
URL url2;
if (o1 instanceof URL)
{
url1 = (URL)o1;
file1 = new File(url1.getPath());
} else
{
file1 = (File)o1;
try
{
url1 = file1.toURL();
} catch (MalformedURLException e)
{
throw new IllegalStateException("Unable to create file url: " +
file1 + ": " + e);
}
}
if (o2 instanceof URL)
{
url2 = (URL)o2;
file2 = new File(url2.getPath());
} else
{
file2 = (File)o2;
try
{
url2 = file2.toURL();
} catch (MalformedURLException e)
{
throw new IllegalStateException("Unable to create file url: " +
file2 + ": " + e);
}
}
int comp = 0;
if (urlComparator != null)
{
comp = urlComparator.compare(url1, url2);
}
if (comp == 0)
{
comp = file1.compareTo(file2);
}
return comp < 0 ? -1 : comp > 0 ? 1 : 0;
}
}
public void scan()
{
log.trace("Scanning urls...");
for (Iterator iter = scanners.iterator(); iter.hasNext(); )
{
((Scanner)iter.next()).scan();
}
}
public ObjectName preRegister(MBeanServer server, ObjectName name)
throws Exception
{
serverHome = ServerConfigLocator.locate().getServerHomeDir();
return super.preRegister(server, name);
}
}