--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+ <classpathentry kind="src" path="src/main/java"/>\r
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>\r
+ <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+ <name>deployer</name>\r
+ <comment></comment>\r
+ <projects>\r
+ </projects>\r
+ <buildSpec>\r
+ <buildCommand>\r
+ <name>org.eclipse.jdt.core.javabuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ </buildSpec>\r
+ <natures>\r
+ <nature>org.eclipse.jdt.core.javanature</nature>\r
+ </natures>\r
+</projectDescription>\r
--- /dev/null
+ \8ed\97l\8f\91\r
+ ======\r
+\r
+\8aT\97v\r
+----\r
+\r
+\81@war\83t\83@\83C\83\8b\82Ì\82æ\82¤\82É\81A\83N\83\89\83X \83t\83@\83C\83\8b\81Ajar\83t\83@\83C\83\8b\81A\83\8a\83\\81[\83X\82ð\8ai\94[\82µ\82½\83A\81[\83J\83C\83u\82Ì\83z\83b\83g\83f\83v\83\8d\83C\82ð\8ds\82¢\81A\83N\83\89\83X\83\8d\81[\83_\81[\82ð\8d\\92z\82·\82é\8b@\94\\82ð\8e\9d\82¿\82Ü\82·\81B\r
+\r
+\83A\81[\83J\83C\83u\82Ì\8d\\91¢\r
+----------------\r
+\r
+\81@\83A\81[\83J\83C\83u\82Í\88È\89º\82Ì\97v\91f\82Å\8d\\90¬\82³\82ê\82Ü\82·\81B\r
+\r
+- \83N\83\89\83X \83t\83@\83C\83\8b\81B\r
+- jar \83t\83@\83C\83\8b\81B\r
+- \82»\82Ì\91¼\82Ì\83t\83@\83C\83\8b(\83\8a\83\\81[\83X)\81B\r
+\r
+\81@\83A\81[\83J\83C\83u\93à\82Ì\83f\83B\83\8c\83N\83g\83\8a\8d\\91¢\82Ídeployer.properties\90Ý\92è\83t\83@\83C\83\8b\82Å\8ew\92è\82Å\82«\82Ü\82·\81B\r
+\r
+\83f\83v\83\8d\83C\r
+--------\r
+\r
+\81@ArchiveClassLoader\82Í\81A\8ew\92è\82³\82ê\82½\83A\81[\83J\83C\83u \83t\83@\83C\83\8b\82©\82ç\83N\83\89\83X\83\8d\81[\83_\81[\82ð\8d\\92z\82µ\82Ü\82·\81B\83A\81[\83J\83C\83u \83t\83@\83C\83\8b\82Í\88ê\8e\9e\83f\83B\83\8c\83N\83g\83\8a(1)\82É\93W\8aJ\82³\82ê\81A\88È\8d~\82Í\93W\8aJ\82³\82ê\82½\83t\83@\83C\83\8b\82ð\8eQ\8fÆ\82µ\82Ü\82·(2)\81B\93Ç\82Ý\8d\9e\82Ý\8c³\82Ì\83A\81[\83J\83C\83u \83t\83@\83C\83\8b\82Í\92è\8aú\93I\82É\8aÄ\8e\8b\82³\82ê\82Ä\82¢\82Ü\82·(3)\81B\83t\83@\83C\83\8b\82ª\91¶\8dÝ\82µ\82È\82\82È\82Á\82½\8fê\8d\87\81A\83A\83\93\83f\83v\83\8d\83C\82µ\82Ü\82·\81B\83t\83@\83C\83\8b\82ª\95Ï\8dX\82³\82ê\82Ä\82¢\82½\8fê\8d\87(4)\81A\8dÄ\83f\83v\83\8d\83C\82³\82ê\82Ü\82·\81BArchiveClassLoader\82ÉArchiveClassLoaderListener\82ð\93o\98^\82·\82é\82±\82Æ\82Å\81A\83f\83v\83\8d\83C\81A\83A\83\93\83f\83v\83\8d\83C\8e\9e\82Ì\83C\83x\83\93\83g\82ð\8eó\82¯\8eæ\82é\82±\82Æ\82ª\82Å\82«\82Ü\82·\81B\r
+\81@ArchiveDirectoryMonitor\82Í\81A\8ew\92è\82³\82ê\82½\83f\83B\83\8c\83N\83g\83\8a\82ð\8aÄ\8e\8b\82µ\81A\83A\81[\83J\83C\83u \83t\83@\83C\83\8b\82ª\94z\92u\82³\82ê\82½\8fê\8d\87\82ÉArchiveClassLoader\82ð\8d\\92z\82µ\82Ü\82·\81B\r
+\r
+(1) \88ê\8e\9e\83f\83B\83\8c\83N\83g\83\8a\82ÍArchiveClassLoader\8f\89\8aú\89»\8e\9e\82É\8ew\92è\82·\82é\82±\82Æ\82ª\82Å\82«\82Ü\82·\81B\82Ü\82½\81Adeployer.properties\82É\8ew\92è\82·\82é\82±\82Æ\82à\82Å\82«\82Ü\82·\81B\r
+(2) \83A\81[\83J\83C\83u \83t\83@\83C\83\8b\82Í\81A\93W\8aJ\8e\9e\82¾\82¯\83t\83@\83C\83\8b \83\8d\83b\83N\82³\82ê\81A\93W\8aJ\82ª\8fI\97¹\82·\82é\82Æ\83\8d\83b\83N\82ª\89ð\8f\9c\82³\82ê\82Ü\82·\81B\r
+(3) \8aÄ\8e\8b\8aÔ\8au\82ÍArchiveClassLoader\8f\89\8aú\89»\8e\9e\82É\8ew\92è\82·\82é\82±\82Æ\82ª\82Å\82«\82Ü\82·\81B\82Ü\82½\81Adeployer.properties\82É\8ew\92è\82·\82é\82±\82Æ\82à\82Å\82«\82Ü\82·\81B\r
+(4) \95Ï\8dX\82Ì\8c\9f\92m\95û\96@\82Í\81A\83^\83C\83\80\83X\83^\83\93\83v\81A\83t\83@\83C\83\8b \83T\83C\83Y\81A\83t\83@\83C\83\8b\82Ì\93à\97e\81A\82Å\82·\81B\r
+\r
+\83N\83\89\83X\82Ì\8c\9f\8dõ\8f\87\8f\98\r
+----------------\r
+\r
+1) \90e\83N\83\89\83X\83\8d\81[\83_\81[\81B\r
+2) \83N\83\89\83X \83t\83@\83C\83\8b\82Ì\83f\83B\83\8c\83N\83g\83\8a\81B\r
+3) jar\83t\83@\83C\83\8b\81B\r
+\r
+\83\8a\83\\81[\83X\82Ì\8c\9f\8dõ\8f\87\8f\98\r
+------------------\r
+\r
+1) \90e\83N\83\89\83X\83\8d\81[\83_\81[\81B\r
+2) \83A\81[\83J\83C\83u\93à\82Ì\83t\83@\83C\83\8b\81B\r
+3) jar\83t\83@\83C\83\8b\81B\r
--- /dev/null
+\r
+package jp.gr.java_conf.uguu.deployer;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.nio.channels.FileLock;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.regex.Pattern;\r
+import java.util.zip.ZipEntry;\r
+import java.util.zip.ZipInputStream;\r
+\r
+public class Deployer {\r
+\r
+ private List<DeployerListener> listenerList = new ArrayList<DeployerListener>();\r
+\r
+ private File deployDirectory;\r
+\r
+ private Pattern filePattern;\r
+\r
+ private File workDirectory;\r
+\r
+ private FileMonitor fileMonitor;\r
+\r
+ public Deployer(File deployDirectory, Pattern filePattern, File workDirectory) {\r
+ if (deployDirectory == null) {\r
+ throw new IllegalArgumentException("deployDirectory is null.");\r
+ }\r
+ if (!deployDirectory.isDirectory()) {\r
+ throw new IllegalArgumentException("deployDirectory is not directory.");\r
+ }\r
+ if (filePattern == null) {\r
+ throw new IllegalArgumentException("filePattern is null.");\r
+ }\r
+ if (workDirectory == null) {\r
+ throw new IllegalArgumentException("workDirectory is null.");\r
+ }\r
+ if (!workDirectory.isDirectory()) {\r
+ throw new IllegalArgumentException("workDirectory is not directory.");\r
+ }\r
+\r
+ this.deployDirectory = deployDirectory;\r
+ this.filePattern = filePattern;\r
+ this.workDirectory = workDirectory;\r
+\r
+ // ディレクトリの監視を開始する。\r
+ this.fileMonitor = new FileMonitor(this.deployDirectory, this.filePattern);\r
+ this.fileMonitor.addListener(new FileMonitorListenerImpl());\r
+ }\r
+\r
+ public void addListener(DeployerListener listener) {\r
+ if (listener == null) {\r
+ throw new IllegalArgumentException("listener is null.");\r
+ }\r
+ synchronized (this.listenerList) {\r
+ this.listenerList.add(listener);\r
+ }\r
+ }\r
+\r
+ public void removeListener(DeployerListener listener) {\r
+ synchronized (this.listenerList) {\r
+ this.listenerList.remove(listener);\r
+ }\r
+ }\r
+\r
+ public void monitor() throws IOException {\r
+ this.fileMonitor.monitor();\r
+ }\r
+\r
+ private void deploy(File file) throws IOException {\r
+ // イベントを通知する。\r
+ synchronized (this.listenerList) {\r
+ for (DeployerListener l : this.listenerList) {\r
+ l.deployStart(this, file);\r
+ }\r
+ }\r
+ // デプロイ先のディレクトリを削除する。\r
+ File destDir = this.getDestDirectory(file, this.deployDirectory, this.workDirectory);\r
+ if (destDir.exists()) {\r
+ this.delete(destDir);\r
+ this.deleteWithParent(destDir.getParentFile());\r
+ }\r
+ // デプロイ先のディレクトリを作成する。\r
+ if (!destDir.mkdirs()) {\r
+ throw new IOException("ディレクトリ\"" + destDir.getAbsolutePath() + "\"の作成に失敗しました。");\r
+ }\r
+ // デプロイ先に展開する。\r
+ this.decompress(file, destDir);\r
+ // イベントを通知する。\r
+ synchronized (this.listenerList) {\r
+ for (DeployerListener l : this.listenerList) {\r
+ l.deployEnd(this, file, destDir);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void undeploy(File file) throws IOException {\r
+ File destDir = this.getDestDirectory(file, this.deployDirectory, this.workDirectory);\r
+ // イベントを通知する。\r
+ synchronized (this.listenerList) {\r
+ for (DeployerListener l : this.listenerList) {\r
+ l.undeployStart(this, file, destDir);\r
+ }\r
+ }\r
+ // デプロイ先のディレクトリを削除する。\r
+ this.delete(destDir);\r
+ this.deleteWithParent(destDir.getParentFile());\r
+ // イベントを通知する。\r
+ synchronized (this.listenerList) {\r
+ for (DeployerListener l : this.listenerList) {\r
+ l.undeployEnd(this, file);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void decompress(File file, File destDir) throws IOException {\r
+ FileInputStream fileIn = null;\r
+ while (fileIn == null) {\r
+ try {\r
+ fileIn = new FileInputStream(file);\r
+ } catch (FileNotFoundException e) {\r
+ fileIn = null;\r
+ try {\r
+ Thread.sleep(1000);\r
+ } catch (InterruptedException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ }\r
+ }\r
+ try {\r
+ ZipInputStream zipIn = new ZipInputStream(fileIn);\r
+ try {\r
+ FileLock lock = fileIn.getChannel().lock(0, Long.MAX_VALUE, true);\r
+ try {\r
+ ZipEntry zipEntry;\r
+ while ((zipEntry = zipIn.getNextEntry()) != null) {\r
+ if (!zipEntry.isDirectory()) {\r
+ File f = new File(destDir, zipEntry.getName().replace('/', File.separatorChar));\r
+ if (!f.createNewFile()) {\r
+ throw new IOException("ファイル\"" + f.getAbsolutePath() + "\"の作成に失敗しました。");\r
+ }\r
+ // ファイルを展開します。\r
+ FileOutputStream fileOut = new FileOutputStream(f);\r
+ try {\r
+ byte[] buf = new byte[1024];\r
+ int len;\r
+ while ((len = zipIn.read(buf)) != -1) {\r
+ fileOut.write(buf, 0, len);\r
+ }\r
+ } finally {\r
+ fileOut.close();\r
+ }\r
+ // イベントを通知します。\r
+ synchronized (this.listenerList) {\r
+ for (DeployerListener l : this.listenerList) {\r
+ l.deployFile(this, file, destDir, f);\r
+ }\r
+ }\r
+ } else {\r
+ File dir = new File(destDir, zipEntry.getName().replace('/', File.separatorChar));\r
+ if (!dir.mkdirs()) {\r
+ throw new IOException("ディレクトリ\"" + dir.getAbsolutePath() + "\"の作成に失敗しました。");\r
+ }\r
+ }\r
+ }\r
+ } finally {\r
+ lock.release();\r
+ }\r
+ } finally {\r
+ zipIn.close();\r
+ }\r
+ } finally {\r
+ fileIn.close();\r
+ }\r
+ }\r
+\r
+ private void delete(File dir) throws IOException {\r
+ for (File f : dir.listFiles()) {\r
+ if (!f.isDirectory()) {\r
+ if (!f.delete()) {\r
+ throw new IOException("ファイル\"" + f.getAbsolutePath() + "\"の削除に失敗しました。");\r
+ }\r
+ } else {\r
+ this.delete(f);\r
+ }\r
+ }\r
+ if (!dir.delete()) {\r
+ throw new IOException("ディレクトリ\"" + dir.getAbsolutePath() + "\"の削除に失敗しました。");\r
+ }\r
+ }\r
+\r
+ private void deleteWithParent(File dir) throws IOException {\r
+ if (this.workDirectory.getAbsolutePath().equals(dir.getAbsolutePath())) {\r
+ return;\r
+ }\r
+ if (dir.listFiles().length > 0) {\r
+ return;\r
+ }\r
+ File parentDir = dir.getParentFile();\r
+ if (!dir.delete()) {\r
+ throw new IOException("ディレクトリ\"" + dir.getAbsolutePath() + "\"の削除に失敗しました。");\r
+ }\r
+ this.deleteWithParent(parentDir);\r
+ }\r
+\r
+ private File getDestDirectory(File archiveFile, File deployDirectory, File workDirectory) {\r
+ String name = archiveFile.getAbsolutePath().substring(deployDirectory.getAbsolutePath().length());\r
+ File dir = new File(workDirectory, name);\r
+ return dir;\r
+ }\r
+\r
+ private class FileMonitorListenerImpl implements FileMonitorListener {\r
+\r
+ public void create(FileMonitor monitor, File file) {\r
+ try {\r
+ Deployer.this.deploy(file);\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ public void delete(FileMonitor monitor, File file) {\r
+ try {\r
+ Deployer.this.undeploy(file);\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ public void update(FileMonitor monitor, File file) {\r
+ try {\r
+ Deployer.this.undeploy(file);\r
+ Deployer.this.deploy(file);\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+\r
+package jp.gr.java_conf.uguu.deployer;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.net.MalformedURLException;\r
+import java.net.URL;\r
+import java.util.ArrayList;\r
+import java.util.Enumeration;\r
+import java.util.List;\r
+import java.util.Vector;\r
+import java.util.jar.JarEntry;\r
+import java.util.jar.JarFile;\r
+\r
+public class DeployerClassLoader extends ClassLoader {\r
+\r
+ private List<DeployerClassLoaderListener> listenerList = new ArrayList<DeployerClassLoaderListener>();\r
+\r
+ private File deployDirectory;\r
+\r
+ private String classDirectory;\r
+\r
+ private String jarDirectory;\r
+\r
+ public DeployerClassLoader(File deployDirectory, String classDirectory, String jarDirectory, ClassLoader parent) throws IOException {\r
+ super(parent);\r
+ this.initialize(deployDirectory, classDirectory, jarDirectory);\r
+ }\r
+\r
+ public DeployerClassLoader(File deployDirectory, String classDirectory, String jarDirectory) throws IOException {\r
+ super();\r
+ this.initialize(deployDirectory, classDirectory, jarDirectory);\r
+ }\r
+\r
+ private void initialize(File deployDirectory, String classDirectory, String jarDirectory) throws IOException {\r
+ if (deployDirectory == null) {\r
+ throw new IllegalArgumentException("deployDirectory is null.");\r
+ }\r
+ if (!deployDirectory.isDirectory()) {\r
+ throw new IllegalArgumentException("deployDirectory is not directory.");\r
+ }\r
+ if (classDirectory == null) {\r
+ throw new IllegalArgumentException("classDirectory is null.");\r
+ }\r
+ if (jarDirectory == null) {\r
+ throw new IllegalArgumentException("jarDirectory is null.");\r
+ }\r
+\r
+ this.deployDirectory = deployDirectory;\r
+ this.classDirectory = classDirectory;\r
+ this.jarDirectory = jarDirectory;\r
+ }\r
+\r
+ public void addListener(DeployerClassLoaderListener listener) {\r
+ if (listener == null) {\r
+ throw new IllegalArgumentException("listener is null.");\r
+ }\r
+ synchronized (this.listenerList) {\r
+ this.listenerList.add(listener);\r
+ }\r
+ }\r
+\r
+ public void removeListener(DeployerClassLoaderListener listener) {\r
+ synchronized (this.listenerList) {\r
+ this.listenerList.remove(listener);\r
+ }\r
+ }\r
+\r
+ public void dispose() {\r
+ // TODO 定義済みクラスをうまく解放する方法を考える。\r
+ }\r
+\r
+ @Override\r
+ protected Class<?> findClass(String name) throws ClassNotFoundException {\r
+// String resName = "/" + name.replace('.', '/') + ".class";\r
+ String resName = name.replace('.', '/') + ".class";\r
+ URL url = this.findResource(resName);\r
+ if (url == null) {\r
+ throw new ClassNotFoundException("\"" + name + "\"クラスが見つかりませんでした。");\r
+ }\r
+\r
+ try {\r
+ InputStream in = url.openStream();\r
+ try {\r
+ // classファイルを読み込む。\r
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream();\r
+ try {\r
+ byte[] buf = new byte[1024];\r
+ int len;\r
+ while ((len = in.read(buf)) != -1) {\r
+ byteOut.write(buf, 0, len);\r
+ }\r
+ } finally {\r
+ byteOut.close();\r
+ }\r
+ // クラスを定義する。\r
+ byte[] classData = byteOut.toByteArray();\r
+ Class<?> clazz = this.defineClass(name, classData, 0, classData.length);\r
+ // イベントを通知する。\r
+ synchronized (this.listenerList) {\r
+ for (DeployerClassLoaderListener l : this.listenerList) {\r
+ l.findClass(clazz, url);\r
+ }\r
+ }\r
+ return clazz;\r
+ } finally {\r
+ in.close();\r
+ }\r
+ } catch (IOException e) {\r
+ throw new ClassNotFoundException("\"" + name + "\"クラスの読み込みに失敗しました。", e);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected URL findResource(String name) {\r
+ URL url;\r
+ // クラス ディレクトリから探す。\r
+ try {\r
+ url = this.findResourceForClassDirectory(new File(this.deployDirectory, this.classDirectory), name);\r
+ } catch (MalformedURLException e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+ if (url != null) {\r
+ return url;\r
+ }\r
+ // jarディレクトリから探す。\r
+ List<File> jarFileList = this.getJarFileList(new File(this.deployDirectory, this.jarDirectory));\r
+ for (File jarFile : jarFileList) {\r
+ try {\r
+ url = this.findResourceForJarFile(jarFile, name);\r
+ } catch (IOException e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+ if (url != null) {\r
+ return url;\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ protected Enumeration<URL> findResources(String name) throws IOException {\r
+ Vector<URL> urlVector = new Vector<URL>();\r
+ URL url;\r
+ // クラス ディレクトリから探す。\r
+ try {\r
+ url = this.findResourceForClassDirectory(new File(this.deployDirectory, this.classDirectory), name);\r
+ } catch (MalformedURLException e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+ if (url != null) {\r
+ urlVector.add(url);\r
+ }\r
+ // jarディレクトリから探す。\r
+ List<File> jarFileList = this.getJarFileList(new File(this.deployDirectory, this.jarDirectory));\r
+ for (File jarFile : jarFileList) {\r
+ try {\r
+ url = this.findResourceForJarFile(jarFile, name);\r
+ } catch (IOException e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+ if (url != null) {\r
+ urlVector.add(url);\r
+ }\r
+ }\r
+ return urlVector.elements();\r
+ }\r
+\r
+ private URL findResourceForClassDirectory(File classDir, String resourceName) throws MalformedURLException {\r
+ String resName = resourceName.replace('/', File.separatorChar);\r
+ File resFile = new File(classDir, resName);\r
+ if (resFile.exists()) {\r
+ URL url = new URL("file:/" + resFile.getAbsolutePath().replace(File.separatorChar, '/'));\r
+ return url;\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+\r
+ private List<File> getJarFileList(File jarDir) {\r
+ List<File> jarFileList = new ArrayList<File>();\r
+\r
+ File[] files = jarDir.listFiles();\r
+ if (files == null) {\r
+ return new ArrayList<File>();\r
+ }\r
+ for (File file : files) {\r
+ if (file.isFile()) {\r
+ if (file.getName().endsWith(".jar")) {\r
+ jarFileList.add(file);\r
+ }\r
+ } else {\r
+ jarFileList.addAll(this.getJarFileList(file));\r
+ }\r
+ }\r
+\r
+ return jarFileList;\r
+ }\r
+\r
+ private URL findResourceForJarFile(File jarFile, String resourceName) throws IOException {\r
+ JarFile jar = new JarFile(jarFile);\r
+ try {\r
+ JarEntry entry = jar.getJarEntry(resourceName);\r
+ if (entry != null) {\r
+ URL url = new URL("jar:file:/" + jarFile.getAbsolutePath().replace(File.separatorChar, '/') + "!/" + entry.getName());\r
+ return url;\r
+ } else {\r
+ return null;\r
+ }\r
+ } finally {\r
+ jar.close();\r
+ }\r
+ }\r
+\r
+}\r
--- /dev/null
+\r
+package jp.gr.java_conf.uguu.deployer;\r
+\r
+import java.net.URL;\r
+\r
+public interface DeployerClassLoaderListener {\r
+\r
+ void findClass(Class clazz, URL url);\r
+\r
+}\r
--- /dev/null
+\r
+package jp.gr.java_conf.uguu.deployer;\r
+\r
+import java.io.File;\r
+\r
+public interface DeployerListener {\r
+\r
+ void deployStart(Deployer deployer, File file);\r
+\r
+ void deployFile(Deployer deployer, File file, File destDirectory, File deployFile);\r
+\r
+ void deployEnd(Deployer deployer, File file, File destDirectory);\r
+\r
+ void undeployStart(Deployer deployer, File file, File destDirectory);\r
+\r
+ void undeployEnd(Deployer deployer, File file);\r
+\r
+}\r
--- /dev/null
+\r
+package jp.gr.java_conf.uguu.deployer;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.regex.Pattern;\r
+\r
+public class FileMonitor {\r
+\r
+ private List<FileMonitorListener> listenerList = new ArrayList<FileMonitorListener>();\r
+\r
+ private File baseDirectory;\r
+\r
+ private Pattern filePattern;\r
+\r
+ private Map<String, MonitoringFileInfo> monitoringFileMap = new HashMap<String, MonitoringFileInfo>();\r
+\r
+ public FileMonitor(File baseDirectory, Pattern filePattern) {\r
+ if (baseDirectory == null) {\r
+ throw new IllegalArgumentException("baseDirectory is null.");\r
+ }\r
+ if (!baseDirectory.isDirectory()) {\r
+ throw new IllegalArgumentException("baseDirectory is not directory.");\r
+ }\r
+ if (filePattern == null) {\r
+ throw new IllegalArgumentException("filePattern is null.");\r
+ }\r
+ this.baseDirectory = baseDirectory;\r
+ this.filePattern = filePattern;\r
+ }\r
+\r
+ public FileMonitor(File baseDirectory) {\r
+ this(baseDirectory, Pattern.compile(".*"));\r
+ }\r
+\r
+ public void addListener(FileMonitorListener listener) {\r
+ if (listener == null) {\r
+ throw new IllegalArgumentException("listener is null.");\r
+ }\r
+ synchronized (this.listenerList) {\r
+ this.listenerList.add(listener);\r
+ }\r
+ }\r
+\r
+ public void removeListener(FileMonitorListener listener) {\r
+ synchronized (this.listenerList) {\r
+ this.listenerList.remove(listener);\r
+ }\r
+ }\r
+\r
+ private FileMonitorListener[] getListeners() {\r
+ synchronized (this.listenerList) {\r
+ return this.listenerList.toArray(new FileMonitorListener[0]);\r
+ }\r
+ }\r
+\r
+ public void monitor() throws IOException {\r
+ this.checkCreateOrUpdate(this.baseDirectory);\r
+ this.checkDelete();\r
+ this.checkClear();\r
+ }\r
+\r
+ private void checkCreateOrUpdate(File dir) throws IOException {\r
+ File[] files = dir.listFiles();\r
+ if (files == null) {\r
+ throw new IOException("ディレクトリ\"" + dir.getAbsolutePath() + "\"に格納されているファイルの一覧の取得に失敗しました。");\r
+ }\r
+ for (File f : dir.listFiles()) {\r
+ if (f.isFile()) {\r
+ this.checkFileCreateOrUpdate(f);\r
+ } else {\r
+ this.checkCreateOrUpdate(f);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void checkFileCreateOrUpdate(File file) {\r
+ if (this.filePattern.matcher(file.getAbsolutePath()).matches()) {\r
+ synchronized (this.monitoringFileMap) {\r
+ if (!this.monitoringFileMap.containsKey(file.getAbsolutePath())) {\r
+ // ファイルがマップに存在しない場合、新規のモニター対象。\r
+ MonitoringFileInfo info = new MonitoringFileInfo();\r
+ info.path = file.getAbsolutePath();\r
+ info.length = file.length();\r
+ info.lastModified = file.lastModified();\r
+ info.hashValue = ""; // TODO: ハッシュ値を算出し、格納する。\r
+ info.checked = true;\r
+ this.monitoringFileMap.put(file.getAbsolutePath(), info);\r
+ // イベントを通知する。\r
+ FileMonitorListener[] listeners = this.getListeners();\r
+ for (FileMonitorListener l : listeners) {\r
+ l.create(this, file);\r
+ }\r
+ } else {\r
+ // ファイルがマップに存在する場合、変更のモニター対象。\r
+ MonitoringFileInfo info = this.monitoringFileMap.get(file.getAbsolutePath());\r
+ if (info.length != file.length() || info.lastModified != file.lastModified()) { // TODO:\r
+ // ハッシュ値を比較する。\r
+ info.length = file.length();\r
+ info.lastModified = file.lastModified();\r
+ info.hashValue = ""; // TODO: ハッシュ値を算出し、格納する。\r
+ info.checked = true;\r
+ // イベントを通知する。\r
+ FileMonitorListener[] listeners = this.getListeners();\r
+ for (FileMonitorListener l : listeners) {\r
+ l.update(this, file);\r
+ }\r
+ }\r
+ info.checked = true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private void checkDelete() {\r
+ synchronized (this.monitoringFileMap) {\r
+ List<String> removeFileList = new ArrayList<String>();\r
+ for (MonitoringFileInfo info : this.monitoringFileMap.values()) {\r
+ if (!info.checked) {\r
+ File f = new File(info.path);\r
+ if (!f.exists()) {\r
+ removeFileList.add(info.path);\r
+ // イベントを通知する。\r
+ FileMonitorListener[] listeners = this.getListeners();\r
+ for (FileMonitorListener l : listeners) {\r
+ l.delete(this, f);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ for (String path : removeFileList) {\r
+ this.monitoringFileMap.remove(path);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void checkClear() {\r
+ synchronized (this.monitoringFileMap) {\r
+ for (MonitoringFileInfo info : this.monitoringFileMap.values()) {\r
+ info.checked = false;\r
+ }\r
+ }\r
+ }\r
+\r
+ private class MonitoringFileInfo {\r
+\r
+ String path;\r
+\r
+ long length;\r
+\r
+ long lastModified;\r
+\r
+ String hashValue;\r
+\r
+ boolean checked = false;\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+\r
+package jp.gr.java_conf.uguu.deployer;\r
+\r
+import java.io.File;\r
+\r
+public interface FileMonitorListener {\r
+\r
+ void create(FileMonitor monitor, File file);\r
+\r
+ void update(FileMonitor monitor, File file);\r
+\r
+ void delete(FileMonitor monitor, File file);\r
+\r
+}\r
--- /dev/null
+\r
+package jp.gr.java_conf.uguu.deployer;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.net.URL;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.regex.Pattern;\r
+\r
+public class Main implements DeployerListener, DeployerClassLoaderListener {\r
+\r
+ public static void main(String[] args) throws Exception {\r
+ new Main().execute();\r
+ }\r
+\r
+ private Map<String, DeployerClassLoader> classLoaderMap = new HashMap<String, DeployerClassLoader>();\r
+\r
+ public void execute() throws IOException {\r
+ Deployer deployer = new Deployer(new File("E:\\work\\deploy"), Pattern.compile(".*\\.zip|.*\\.jar"), new File("E:\\work\\work"));\r
+ deployer.addListener(this);\r
+ while (true) {\r
+ deployer.monitor();\r
+ try {\r
+ Thread.sleep(1000);\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ }\r
+\r
+ public void deployEnd(Deployer deployer, File file, File destDirectory) {\r
+ try {\r
+ final DeployerClassLoader cl = new DeployerClassLoader(destDirectory, "classes", "lib");\r
+ cl.addListener(this);\r
+ this.classLoaderMap.put(file.getAbsolutePath(), cl);\r
+\r
+ Runnable runnable = new Runnable() {\r
+\r
+ public void run() {\r
+ try {\r
+ Class<?> clazz = cl.loadClass("Main");\r
+ Object obj = clazz.newInstance();\r
+ clazz.getMethod("main").invoke(obj);\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ };\r
+ Thread t = new Thread(runnable);\r
+ t.start();\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ // ログ。\r
+ System.out.println("deployEnd: " + file.getAbsolutePath());\r
+ }\r
+\r
+ public void deployFile(Deployer deployer, File file, File destDirectory, File deployFile) {\r
+ // ログ。\r
+ System.out.println("deployFile: " + file.getAbsolutePath() + ", " + deployFile.getAbsolutePath());\r
+ }\r
+\r
+ public void deployStart(Deployer deployer, File file) {\r
+ // ログ。\r
+ System.out.println("deployStart: " + file.getAbsolutePath());\r
+ }\r
+\r
+ public void undeployEnd(Deployer deployer, File file) {\r
+ DeployerClassLoader cl = this.classLoaderMap.remove(file.getAbsolutePath());\r
+ cl.dispose();\r
+ // ログ。\r
+ System.out.println("undeployEnd: " + file.getAbsolutePath());\r
+ }\r
+\r
+ public void undeployStart(Deployer deployer, File file, File destDirectory) {\r
+ // ログ。\r
+ System.out.println("undeployStart: " + file.getAbsolutePath());\r
+ }\r
+\r
+ public void findClass(Class clazz, URL url) {\r
+ // ログ。\r
+ System.out.println("findClass: " + clazz.getName() + " [" + url.toExternalForm() + "]");\r
+ }\r
+\r
+}\r