You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2012/12/04 06:51:32 UTC

svn commit: r1416785 - in /openejb/trunk/openejb/container: openejb-core/src/main/java/org/apache/openejb/assembler/classic/ openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ openejb-core/src/main/java/org/apache/openejb/config/ op...

Author: dblevins
Date: Tue Dec  4 05:51:30 2012
New Revision: 1416785

URL: http://svn.apache.org/viewvc?rev=1416785&view=rev
Log:
TOMEE-626 - Alternate unpack directory for apps/
TOMEE-620 - <Deployments autoDeploy="true"/> hot deploy

Added:
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPostCreate.java   (with props)
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPreDestroy.java   (with props)
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AutoDeployer.java   (contents, props changed)
      - copied, changed from r1416249, openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AutoDeployer.java
    openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java   (contents, props changed)
      - copied, changed from r1416249, openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/AutoDeployerTest.java
Removed:
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AutoDeployer.java
    openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/AutoDeployerTest.java
Modified:
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentModule.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/JarExtractor.java
    openejb/trunk/openejb/container/openejb-core/src/test/resources/altddPU1/META-INF/persistence.xml
    openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/Files.java

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java?rev=1416785&r1=1416784&r2=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java Tue Dec  4 05:51:30 2012
@@ -17,6 +17,8 @@
 package org.apache.openejb.assembler.classic;
 
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
@@ -30,6 +32,7 @@ public class AppInfo extends InfoObject 
 
     public String appId;
     public String path;
+    public Set<String> paths = new LinkedHashSet<String>();
     public boolean autoDeploy = true;
     public boolean delegateFirst = true;
     public boolean standaloneModule;

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java?rev=1416785&r1=1416784&r2=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java Tue Dec  4 05:51:30 2012
@@ -40,6 +40,8 @@ import org.apache.openejb.assembler.clas
 import org.apache.openejb.assembler.classic.event.AssemblerBeforeApplicationDestroyed;
 import org.apache.openejb.assembler.classic.event.AssemblerCreated;
 import org.apache.openejb.assembler.classic.event.AssemblerDestroyed;
+import org.apache.openejb.assembler.classic.event.ContainerSystemPostCreate;
+import org.apache.openejb.assembler.classic.event.ContainerSystemPreDestroy;
 import org.apache.openejb.assembler.monitoring.JMXContainer;
 import org.apache.openejb.async.AsynchronousPool;
 import org.apache.openejb.cdi.CdiAppContextsService;
@@ -444,9 +446,7 @@ public class Assembler extends Assembler
             }
         }
 
-//        final AutoDeployer autoDeployer = new AutoDeployer(containerSystemInfo.autoDeploy);
-//        SystemInstance.get().setComponent(AutoDeployer.class, autoDeployer);
-//        autoDeployer.start();
+        SystemInstance.get().fireEvent(new ContainerSystemPostCreate());
     }
 
     public boolean isDeployed(final String path) {
@@ -1104,10 +1104,7 @@ public class Assembler extends Assembler
     @Override
     public synchronized void destroy() {
 
-        final AutoDeployer autoDeployer = SystemInstance.get().getComponent(AutoDeployer.class);
-        if (autoDeployer != null) {
-            autoDeployer.stop();
-        }
+        SystemInstance.get().fireEvent(new ContainerSystemPreDestroy());
 
         try {
             EjbTimerServiceImpl.shutdown();

Added: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPostCreate.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPostCreate.java?rev=1416785&view=auto
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPostCreate.java (added)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPostCreate.java Tue Dec  4 05:51:30 2012
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.assembler.classic.event;
+
+import org.apache.openejb.observer.Event;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Event
+public class ContainerSystemPostCreate {
+
+    @Override
+    public String toString() {
+        return "ContainerSystemPostCreate{}";
+    }
+
+}

Propchange: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPostCreate.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPreDestroy.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPreDestroy.java?rev=1416785&view=auto
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPreDestroy.java (added)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPreDestroy.java Tue Dec  4 05:51:30 2012
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.assembler.classic.event;
+
+import org.apache.openejb.observer.Event;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Event
+public class ContainerSystemPreDestroy {
+
+    @Override
+    public String toString() {
+        return "ContainerSystemPreDestroy{}";
+    }
+}

Propchange: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/event/ContainerSystemPreDestroy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AutoDeployer.java (from r1416249, openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AutoDeployer.java)
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AutoDeployer.java?p2=openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AutoDeployer.java&p1=openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AutoDeployer.java&r1=1416249&r2=1416785&rev=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AutoDeployer.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AutoDeployer.java Tue Dec  4 05:51:30 2012
@@ -14,21 +14,27 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package org.apache.openejb.assembler.classic;
+package org.apache.openejb.config;
 
 import org.apache.openejb.NoSuchApplicationException;
 import org.apache.openejb.OpenEJBException;
 import org.apache.openejb.UndeployException;
-import org.apache.openejb.assembler.Deployer;
 import org.apache.openejb.assembler.DeployerEjb;
+import org.apache.openejb.assembler.classic.AppInfo;
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.event.ContainerSystemPostCreate;
+import org.apache.openejb.assembler.classic.event.ContainerSystemPreDestroy;
+import org.apache.openejb.config.sys.Deployments;
 import org.apache.openejb.loader.FileUtils;
+import org.apache.openejb.loader.Files;
+import org.apache.openejb.loader.Options;
 import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.observer.Observes;
 import org.apache.openejb.util.Duration;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
 
 import java.io.File;
-import java.io.IOException;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -40,68 +46,68 @@ import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.TimeUnit;
 
+import static org.apache.openejb.loader.ProvisioningUtil.realLocation;
+
 /**
  * @version $Rev$ $Date$
  */
 public class AutoDeployer {
 
     private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, AutoDeployer.class);
-    private final Deployer deployer = new DeployerEjb();
-    private List<DirectoryMonitor> monitors = new ArrayList<DirectoryMonitor>();
 
-    public AutoDeployer(List<String> locations) {
-        final SystemInstance systemInstance = SystemInstance.get();
-        final FileUtils base = systemInstance.getBase();
+    private final ConfigurationFactory factory;
+    private final long pollIntervalMillis;
+    private final Map<String, FileInfo> files = new HashMap<String, FileInfo>();
+    private final Timer timer;
+    private final List<Deployments> deployments = new ArrayList<Deployments>();
+
+    public AutoDeployer(ConfigurationFactory factory, List<Deployments> deployments) {
+        final Options options = SystemInstance.get().getOptions();
+        final Duration interval = options.get("openejb.autodeploy.interval", new Duration(2, TimeUnit.SECONDS));
 
-        final Duration interval = systemInstance.getOptions().get("openejb.autodeploy.interval", new Duration(5, TimeUnit.SECONDS));
         if (interval.getUnit() == null) interval.setUnit(TimeUnit.SECONDS);
-        final long time = interval.getUnit().toMillis(interval.getTime());
-
-        for (String location : locations) {
-            try {
-                final File directory = base.getDirectory(location, false);
-                monitors.add(new DirectoryMonitor(directory, this, time));
-            } catch (IOException e) {
-                logger.error("AutoDeploy impossible for location: " + location, e);
-            }
-        }
-    }
-
-    public void start() {
-        for (DirectoryMonitor monitor : monitors) {
-            monitor.start();
-        }
-    }
 
-    public void stop() {
-        for (DirectoryMonitor monitor : monitors) {
-            monitor.stop();
-        }
+        this.factory = factory;
+        this.deployments.addAll(deployments);
+        this.pollIntervalMillis = interval.getUnit().toMillis(interval.getTime());
+        this.timer = new Timer(this.getClass().getSimpleName());
     }
 
-
     public synchronized boolean fileAdded(File file) {
         logger.info("Auto-Deploying: " + file.getAbsolutePath());
         try {
-            deployer.deploy(file.getAbsolutePath());
-        } catch (OpenEJBException e) {
+            final AppInfo appInfo = factory.configureApplication(file);
+            appInfo.paths.add(file.getAbsolutePath());
+            appInfo.paths.add(appInfo.path);
+            for (String path : appInfo.paths) {
+                logger.info("Auto-Deploy: Path " + path);
+            }
+            getAssembler().createApplication(appInfo);
+        } catch (Exception e) {
             logger.error("Auto-Deploy Failed: " + file.getAbsolutePath(), e);
         }
         return true;
     }
 
+    private Assembler getAssembler() {
+        return SystemInstance.get().getComponent(Assembler.class);
+    }
+
     public synchronized boolean fileRemoved(File file) {
         final String path = file.getAbsolutePath();
-        final Collection<AppInfo> apps = deployer.getDeployedApps();
+        final Collection<AppInfo> apps = getAssembler().getDeployedApplications();
         for (AppInfo app : apps) {
-            if (path.equals(app.path)) {
+            if (app.paths.contains(path)) {
                 logger.info("Auto-Undeploying: " + app.appId + " - " + file.getAbsolutePath());
                 try {
-                    deployer.undeploy(app.appId);
-                } catch (UndeployException e) {
-                    logger.error("Auto-undeploy Failed: " + file.getAbsolutePath(), e);
-                } catch (NoSuchApplicationException e) {
-                    logger.error("Auto-undeploy Failed.  No Such Application: " + file.getAbsolutePath());
+                    getAssembler().destroyApplication(app);
+                    for (String location : app.paths) {
+                        final File delete = new File(location);
+                        Files.remove(delete);
+                        logger.info("Auto-Undeploy: Delete " + location);
+                    }
+                } catch (Exception e) {
+                    logger.error("Auto-Undeploy Failed: " + file.getAbsolutePath(), e);
                 }
                 break;
             }
@@ -114,283 +120,255 @@ public class AutoDeployer {
         fileAdded(file);
     }
 
-    public static class DirectoryMonitor {
-
-        public static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_DEPLOY, DirectoryMonitor.class.getPackage().getName());
-
-        private final long pollIntervalMillis;
+    private Logger getLogger() {
+        return logger;
+    }
 
-        private final File target;
+    public void observe(@Observes ContainerSystemPostCreate postCreate) {
+        start();
+    }
 
-        private final AutoDeployer listener;
+    public void observe(@Observes ContainerSystemPreDestroy preDestroy) {
+        stop();
+    }
 
-        private final Map<String, FileInfo> files = new HashMap<String, FileInfo>();
+    public synchronized void stop() {
+        timer.cancel();
+    }
 
-        private final Timer timer;
+    public void start() {
+        initialize();
 
-        public DirectoryMonitor(final File target, final AutoDeployer listener, final long pollIntervalMillis) {
-            assert listener == null : "No listener specified";
-            assert target.isDirectory() : "File specified is not a directory. " + target.getAbsolutePath();
-            assert target.canRead() : "Directory specified cannot be read. " + target.getAbsolutePath();
-            assert pollIntervalMillis > 0 : "Poll Interval must be above zero.";
+        getLogger().debug("Scanner running.  Polling every " + pollIntervalMillis + " milliseconds.");
 
+        timer.scheduleAtFixedRate(new TimerTask() {
+            public void run() {
+                try {
+                    scan();
+                } catch (Exception e) {
+                    getLogger().error("Scan failed.", e);
+                }
+            }
+        }, pollIntervalMillis, pollIntervalMillis);
 
-            this.target = target;
-            this.listener = listener;
-            this.pollIntervalMillis = pollIntervalMillis;
+    }
 
-            this.timer = new Timer(this.getClass().getSimpleName());
-        }
+    private void initialize() {
+        getLogger().debug("Doing initial scan of Deployments");
 
-        private Logger getLogger() {
-            return logger;
-        }
+        for (final File file : list()) {
 
-        public long getPollIntervalMillis() {
-            return pollIntervalMillis;
-        }
+            if (!file.canRead()) {
+                continue;
+            }
 
-        public File getTarget() {
-            return target;
+            final FileInfo now = newInfo(file);
+            now.setChanging(false);
         }
+    }
 
-        public AutoDeployer getAutoDeployer() {
-            return listener;
-        }
+    private FileInfo newInfo(final File child) {
+        final FileInfo fileInfo = child.isDirectory() ? new DirectoryInfo(child) : new FileInfo(child);
+        files.put(fileInfo.getPath(), fileInfo);
+        return fileInfo;
+    }
 
-        public synchronized void stop() {
-            timer.cancel();
-        }
+    /**
+     * Looks for changes to the immediate contents of the directory we're watching.
+     */
+    public void scan() {
 
-        public void start() {
-            initialize();
+        final List<File> files = list();
 
-            getLogger().debug("Scanner running.  Polling every " + pollIntervalMillis + " milliseconds.");
+        final HashSet<String> missingFilesList = new HashSet<String>(this.files.keySet());
 
-            timer.scheduleAtFixedRate(new TimerTask(){
-                public void run() {
-                    try {
-                        scan();
-                    }
-                    catch (Exception e) {
-                        getLogger().error("Scan failed.", e);
-                    }
-                }
-            }, pollIntervalMillis, pollIntervalMillis);
+        for (final File file : files) {
 
-        }
+            missingFilesList.remove(file.getAbsolutePath());
 
-        private void initialize() {
-            getLogger().debug("Doing initial scan of " + target.getAbsolutePath());
+            if (!file.canRead()) {
+                getLogger().debug("not readable " + file.getName());
+                continue;
+            }
 
-            final File[] files = (target.isDirectory()) ? target.listFiles(): new File[]{target};
+            final FileInfo oldStatus = oldInfo(file);
+            final FileInfo newStatus = newInfo(file);
 
-            if (files != null) {
-                for (final File file : files) {
+            newStatus.diff(oldStatus);
 
-                    if (!file.canRead()) {
-                        continue;
-                    }
+            if (oldStatus == null) {
+                // Brand new, but assume it's changing and
+                // wait a bit to make sure it's not still changing
+                getLogger().debug("File Discovered: " + newStatus);
+            } else if (newStatus.isChanging()) {
+                // The two records are different -- record the latest as a file that's changing
+                // and later when it stops changing we'll do the add or update as appropriate.
+                getLogger().debug("File Changing: " + newStatus);
+            } else if (oldStatus.isNewFile()) {
+                // Used to be changing, now in (hopefully) its final state
+                getLogger().info("New File: " + newStatus);
+                newStatus.setNewFile(!fileAdded(file));
+            } else if (oldStatus.isChanging()) {
+                getLogger().info("Updated File: " + newStatus);
+                fileUpdated(file);
 
-                    final FileInfo now = newInfo(file);
-                    now.setChanging(false);
-                }
+                missingFilesList.remove(oldStatus.getPath());
             }
+            // else it's just totally unchanged and we ignore it this pass
         }
 
-        private FileInfo newInfo(final File child) {
-            final FileInfo fileInfo = child.isDirectory() ? new DirectoryInfo(child) : new FileInfo(child);
-            files.put(fileInfo.getPath(), fileInfo);
-            return fileInfo;
-        }
+        // Look for any files we used to know about but didn't find in this pass
+        for (final String path : missingFilesList) {
+            getLogger().info("File removed: " + path);
 
-        /**
-         * Looks for changes to the immediate contents of the directory we're watching.
-         */
-        public void scan() {
+            if (fileRemoved(new File(path))) {
+                this.files.remove(path);
+            }
+        }
+    }
 
-            final File[] files = (target.isDirectory()) ? target.listFiles(): new File[]{target};
+    private List<File> list() {
+        final List<File> files = new ArrayList<File>();
 
-            final HashSet<String> missingFilesList = new HashSet<String>(this.files.keySet());
+        { // list all the files associated with hot deploy locations
 
-            if (files != null) {
-                for (final File file : files) {
+            final FileUtils base = SystemInstance.get().getBase();
+            for (Deployments deployment : deployments) {
+                DeploymentsResolver.loadFrom(deployment, base, files);
+            }
+        }
+        return files;
+    }
 
-                    missingFilesList.remove(file.getAbsolutePath());
+    private FileInfo oldInfo(final File file) {
+        return (FileInfo) files.get(file.getAbsolutePath());
+    }
 
-                    if (!file.canRead()) {
-                        getLogger().debug("not readable " + file.getName());
+    /**
+     * Provides details about a directory.
+     */
+    private static class DirectoryInfo extends FileInfo {
+        public DirectoryInfo(final File dir) {
+            //
+            // We don't pay attention to the size of the directory or files in the
+            // directory, only the highest last modified time of anything in the
+            // directory.  Hopefully this is good enough.
+            //
+            super(dir.getAbsolutePath(), 0, getLastModifiedInDir(dir));
+        }
+
+        private static long getLastModifiedInDir(final File dir) {
+            assert dir != null;
+
+            long value = dir.lastModified();
+            final File[] children = dir.listFiles();
+            long test;
+
+            if (children != null) {
+                for (final File child : children) {
+                    if (!child.canRead()) {
                         continue;
                     }
 
-                    final FileInfo oldStatus = oldInfo(file);
-                    final FileInfo newStatus = newInfo(file);
-
-                    newStatus.diff(oldStatus);
-
-                    if (oldStatus == null) {
-                        // Brand new, but assume it's changing and
-                        // wait a bit to make sure it's not still changing
-                        getLogger().debug("File Discovered: " + newStatus);
-                    } else if (newStatus.isChanging()) {
-                        // The two records are different -- record the latest as a file that's changing
-                        // and later when it stops changing we'll do the add or update as appropriate.
-                        getLogger().debug("File Changing: " + newStatus);
-                    } else if (oldStatus.isNewFile()) {
-                        // Used to be changing, now in (hopefully) its final state
-                        getLogger().info("New File: " + newStatus);
-                        newStatus.setNewFile(!listener.fileAdded(file));
-                    } else if (oldStatus.isChanging()) {
-                        getLogger().info("Updated File: " + newStatus);
-                        listener.fileUpdated(file);
+                    if (child.isDirectory()) {
+                        test = getLastModifiedInDir(child);
+                    } else {
+                        test = child.lastModified();
+                    }
 
-                        missingFilesList.remove(oldStatus.getPath());
+                    if (test > value) {
+                        value = test;
                     }
-                    // else it's just totally unchanged and we ignore it this pass
                 }
             }
 
-            // Look for any files we used to know about but didn't find in this pass
-            for (final String path : missingFilesList) {
-                getLogger().info("File removed: " + path);
-
-                if (listener.fileRemoved(new File(path))) {
-                    this.files.remove(path);
-                }
-            }
+            return value;
         }
+    }
 
-        private FileInfo oldInfo(final File file) {
-            return (FileInfo) files.get(file.getAbsolutePath());
-        }
+    /**
+     * Provides details about a file.
+     */
+    private static class FileInfo implements Serializable {
+        private String path;
 
-        /**
-         * Provides details about a directory.
-         */
-        private static class DirectoryInfo extends FileInfo {
-            public DirectoryInfo(final File dir) {
-                //
-                // We don't pay attention to the size of the directory or files in the
-                // directory, only the highest last modified time of anything in the
-                // directory.  Hopefully this is good enough.
-                //
-                super(dir.getAbsolutePath(), 0, getLastModifiedInDir(dir));
-            }
-
-            private static long getLastModifiedInDir(final File dir) {
-                assert dir != null;
-
-                long value = dir.lastModified();
-                final File[] children = dir.listFiles();
-                long test;
-
-                if (children != null) {
-                    for (final File child : children) {
-                        if (!child.canRead()) {
-                            continue;
-                        }
-
-                        if (child.isDirectory()) {
-                            test = getLastModifiedInDir(child);
-                        } else {
-                            test = child.lastModified();
-                        }
-
-                        if (test > value) {
-                            value = test;
-                        }
-                    }
-                }
-
-                return value;
-            }
-        }
+        private long size;
 
-        /**
-         * Provides details about a file.
-         */
-        private static class FileInfo implements Serializable {
-            private String path;
+        private long modified;
 
-            private long size;
+        private boolean newFile;
 
-            private long modified;
+        private boolean changing;
 
-            private boolean newFile;
+        public FileInfo(final File file) {
+            this(file.getAbsolutePath(), file.length(), file.lastModified());
+        }
 
-            private boolean changing;
+        public FileInfo(final String path, final long size, final long modified) {
+            assert path != null;
 
-            public FileInfo(final File file) {
-                this(file.getAbsolutePath(), file.length(), file.lastModified());
-            }
+            this.path = path;
+            this.size = size;
+            this.modified = modified;
+            this.newFile = true;
+            this.changing = true;
+        }
 
-            public FileInfo(final String path, final long size, final long modified) {
-                assert path != null;
+        public String getPath() {
+            return path;
+        }
 
-                this.path = path;
-                this.size = size;
-                this.modified = modified;
-                this.newFile = true;
-                this.changing = true;
-            }
+        public long getSize() {
+            return size;
+        }
 
-            public String getPath() {
-                return path;
-            }
+        public void setSize(final long size) {
+            this.size = size;
+        }
 
-            public long getSize() {
-                return size;
-            }
+        public long getModified() {
+            return modified;
+        }
 
-            public void setSize(final long size) {
-                this.size = size;
-            }
+        public void setModified(final long modified) {
+            this.modified = modified;
+        }
 
-            public long getModified() {
-                return modified;
-            }
+        public boolean isNewFile() {
+            return newFile;
+        }
 
-            public void setModified(final long modified) {
-                this.modified = modified;
-            }
+        public void setNewFile(final boolean newFile) {
+            this.newFile = newFile;
+        }
 
-            public boolean isNewFile() {
-                return newFile;
-            }
+        public boolean isChanging() {
+            return changing;
+        }
 
-            public void setNewFile(final boolean newFile) {
-                this.newFile = newFile;
-            }
+        public void setChanging(final boolean changing) {
+            this.changing = changing;
+        }
 
-            public boolean isChanging() {
-                return changing;
-            }
+        public boolean isSame(final FileInfo info) {
+            assert info != null;
 
-            public void setChanging(final boolean changing) {
-                this.changing = changing;
+            if (!path.equals(info.path)) {
+                throw new IllegalArgumentException("Should only be used to compare two files representing the same path!");
             }
 
-            public boolean isSame(final FileInfo info) {
-                assert info != null;
-
-                if (!path.equals(info.path)) {
-                    throw new IllegalArgumentException("Should only be used to compare two files representing the same path!");
-                }
-
-                return size == info.size && modified == info.modified;
-            }
+            return size == info.size && modified == info.modified;
+        }
 
-            public String toString() {
-                return path;
-            }
+        public String toString() {
+            return path;
+        }
 
-            public void diff(final FileInfo old) {
-                if (old != null) {
-                    this.changing = !isSame(old);
-                    this.newFile = old.newFile;
-                }
+        public void diff(final FileInfo old) {
+            if (old != null) {
+                this.changing = !isSame(old);
+                this.newFile = old.newFile;
             }
         }
     }
-
 }

Propchange: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AutoDeployer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java?rev=1416785&r1=1416784&r2=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java Tue Dec  4 05:51:30 2012
@@ -563,14 +563,21 @@ public class ConfigurationFactory implem
 
         final FileUtils base = SystemInstance.get().getBase();
 
+        final List<Deployments> autoDeploy = new ArrayList<Deployments>();
+
         final List<File> declaredAppsUrls = new ArrayList<File>();
         try {
             for (final Deployments deployment : deployments) {
                 DeploymentsResolver.loadFrom(deployment, base, declaredAppsUrls);
+                if (deployment.isAutoDeploy()) autoDeploy.add(deployment);
             }
         } catch (SecurityException ignored) {
         }
 
+        if (autoDeploy.size() > 0) {
+            SystemInstance.get().addObserver(new AutoDeployer(this, autoDeploy));
+        }
+
         return declaredAppsUrls;
     }
 
@@ -690,7 +697,12 @@ public class ConfigurationFactory implem
 
         try {
             final AppModule appModule = deploymentLoader.load(jarFile);
-            return configureApplication(appModule);
+            final AppInfo appInfo = configureApplication(appModule);
+
+            // TODO This is temporary -- we need to do this in AppInfoBuilder
+            appInfo.paths.add(appInfo.path);
+            appInfo.paths.add(jarFile.getAbsolutePath());
+            return appInfo;
         } catch (ValidationFailedException e) {
             logger.warning("configureApplication.loadFailed", jarFile.getAbsolutePath(), e.getMessage()); // DO not include the stacktrace in the message
             throw e;

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentModule.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentModule.java?rev=1416785&r1=1416784&r2=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentModule.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentModule.java Tue Dec  4 05:51:30 2012
@@ -22,6 +22,7 @@ import org.apache.openejb.loader.SystemI
 import java.io.File;
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -60,10 +61,20 @@ public interface DeploymentModule {
         private final URI uri;
         private boolean overriden = false;
 
+        /**
+         * The intention of this is to hold the extracted and archived versions
+         */
+        private final Set<String> locations = new LinkedHashSet<String>();
+
         public ID(NamedModule vendorDd, NamedModule specDd, String name, File location, URI uri, DeploymentModule module) {
             this.name = name(vendorDd, specDd, uri, location, name, module);
             this.location = location(location, uri);
             this.uri = uri(uri, location, this.name);
+            this.locations.add(location.getAbsolutePath());
+        }
+
+        public Set<String> getLocations() {
+            return locations;
         }
 
         private URI uri(URI uri, File location, String name) {

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/JarExtractor.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/JarExtractor.java?rev=1416785&r1=1416784&r2=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/JarExtractor.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/JarExtractor.java Tue Dec  4 05:51:30 2012
@@ -16,8 +16,10 @@
  */
 package org.apache.openejb.util;
 
+import org.apache.openejb.loader.FileUtils;
 import org.apache.openejb.loader.Files;
 import org.apache.openejb.loader.IO;
+import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.loader.Zips;
 
 import java.io.BufferedOutputStream;
@@ -27,6 +29,9 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.channels.FileChannel;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
 
 /**
  * @version $Rev$ $Date$
@@ -45,7 +50,19 @@ public class JarExtractor {
      *                                  during expansion
      */
     public static File extract(File file, String pathname) throws IOException {
-        File docBase = new File(file.getParentFile(), pathname);
+
+        final Properties properties = SystemInstance.get().getProperties();
+        final String key = "tomee.unpack.dir";
+
+        File unpackDir = file.getParentFile();
+
+        if (properties.containsKey(key)) {
+            final FileUtils base = SystemInstance.get().getBase();
+            unpackDir = base.getDirectory(properties.getProperty(key), true);
+        }
+
+        final File docBase = new File(unpackDir, pathname);
+
         extract(file, docBase);
         return docBase;
     }
@@ -148,13 +165,7 @@ public class JarExtractor {
      * @param dir File object representing the directory to be deleted
      */
     public static boolean delete(File dir) {
-        if (dir == null) return true;
-
-        if (dir.isDirectory()) {
-            return deleteDir(dir);
-        } else {
-            return dir.delete();
-        }
+        return deleteDir(dir);
     }
 
 
@@ -167,20 +178,13 @@ public class JarExtractor {
     public static boolean deleteDir(File dir) {
         if (dir == null) return true;
 
-        String fileNames[] = dir.list();
-        if (fileNames == null) {
-            fileNames = new String[0];
-        }
-        for (String fileName : fileNames) {
-            File file = new File(dir, fileName);
-            if (file.isDirectory()) {
+        if (dir.isDirectory()) {
+            for (File file : dir.listFiles()) {
                 deleteDir(file);
-            } else {
-                file.delete();
             }
         }
-        return dir.delete();
 
+        return dir.delete();
     }
 
 

Copied: openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java (from r1416249, openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/AutoDeployerTest.java)
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java?p2=openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java&p1=openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/AutoDeployerTest.java&r1=1416249&r2=1416785&rev=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/AutoDeployerTest.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java Tue Dec  4 05:51:30 2012
@@ -14,8 +14,10 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package org.apache.openejb.assembler.classic;
+package org.apache.openejb.config;
 
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.OpenEjbConfiguration;
 import org.apache.openejb.config.ConfigurationFactory;
 import org.apache.openejb.loader.Files;
 import org.apache.openejb.loader.IO;
@@ -46,7 +48,6 @@ import java.util.concurrent.locks.Reentr
 public class AutoDeployerTest extends Assert {
 
     @Test
-    @Ignore
     public void test() throws Exception {
         final File tmpdir = Files.tmpdir();
         final File apps = Files.mkdir(tmpdir, "myapps");
@@ -54,6 +55,65 @@ public class AutoDeployerTest extends As
 
         final Properties properties = new Properties();
         properties.setProperty("openejb.deployments.classpath", "false");
+        properties.setProperty("openejb.deployment.unpack.location", "false");
+        properties.setProperty("openejb.home", tmpdir.getAbsolutePath());
+        properties.setProperty("openejb.base", tmpdir.getAbsolutePath());
+
+        SystemInstance.init(properties);
+
+        { // Setup the configuration location
+            final File config = new File(conf, "openejb.xml");
+            IO.writeString(config, "<openejb><Deployments autoDeploy=\"true\" dir=\"myapps\"/> </openejb>");
+            SystemInstance.get().setProperty("openejb.configuration", config.getAbsolutePath());
+        }
+
+        final ConfigurationFactory configurationFactory = new ConfigurationFactory();
+        configurationFactory.init(properties);
+        final OpenEjbConfiguration configuration = configurationFactory.getOpenEjbConfiguration();
+
+        { // Check the ContainerSystemInfo
+
+            final List<String> autoDeploy = configuration.containerSystem.autoDeploy;
+            assertEquals(1, autoDeploy.size());
+            assertEquals("myapps", autoDeploy.get(0));
+        }
+
+        final Assembler assembler = new Assembler();
+        assembler.buildContainerSystem(configuration);
+
+        /// start with the testing...
+
+        assertFalse(Yellow.deployed);
+        assertFalse(Orange.deployed);
+
+        final File deployed = Files.path(apps, "colors.ear");
+
+        // Hot deploy the EAR
+        final File ear = createEar(tmpdir, Orange.class, State.class);
+        IO.copy(ear, deployed);
+
+        Orange.state.waitForChange(1, TimeUnit.MINUTES);
+
+        assertFalse(Yellow.deployed);
+        assertTrue(Orange.deployed);
+
+        Files.delete(deployed);
+
+        Orange.state.waitForChange(1, TimeUnit.MINUTES);
+
+        assertFalse(Yellow.deployed);
+        assertFalse(Orange.deployed);
+    }
+
+    @Test
+    public void testAltUnpackDir() throws Exception {
+        final File tmpdir = Files.tmpdir();
+        final File apps = Files.mkdir(tmpdir, "myapps");
+        final File conf = Files.mkdir(tmpdir, "conf");
+
+        final Properties properties = new Properties();
+        properties.setProperty("openejb.deployments.classpath", "false");
+        properties.setProperty("tomee.unpack.dir", "work");
         properties.setProperty("openejb.home", tmpdir.getAbsolutePath());
         properties.setProperty("openejb.base", tmpdir.getAbsolutePath());
 

Propchange: openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/config/AutoDeployerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openejb/trunk/openejb/container/openejb-core/src/test/resources/altddPU1/META-INF/persistence.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/test/resources/altddPU1/META-INF/persistence.xml?rev=1416785&r1=1416784&r2=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/test/resources/altddPU1/META-INF/persistence.xml (original)
+++ openejb/trunk/openejb/container/openejb-core/src/test/resources/altddPU1/META-INF/persistence.xml Tue Dec  4 05:51:30 2012
@@ -1,29 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!--
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
 
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
+  <persistence-unit name="unit">
+    <jta-data-source>movieDatabase</jta-data-source>
+    <properties>
+      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+    </properties>
+  </persistence-unit>
 
-       http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<!-- START SNIPPET: code -->
-<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
-
-    <persistence-unit name="unit">
-        <jta-data-source>movieDatabase</jta-data-source>
-        <properties>
-            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>            
-        </properties>
-    </persistence-unit>
 </persistence>
-<!-- END SNIPPET: code -->

Modified: openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/Files.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/Files.java?rev=1416785&r1=1416784&r2=1416785&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/Files.java (original)
+++ openejb/trunk/openejb/container/openejb-loader/src/main/java/org/apache/openejb/loader/Files.java Tue Dec  4 05:51:30 2012
@@ -204,6 +204,20 @@ public class Files {
         }
     }
 
+    public static void remove(File file) {
+        if (file == null) return;
+        if (!file.exists()) return;
+
+        if (file.isDirectory()) {
+            for (File child : file.listFiles()) {
+                remove(child);
+            }
+        }
+        if (!file.delete()) {
+            throw new IllegalStateException("Could not delete file: " + file.getAbsolutePath());
+        }
+    }
+
     public static File select(File dir, String pattern) {
         final List<File> matches = collect(dir, pattern);
         if (matches.size() == 0) throw new IllegalStateException(String.format("Missing '%s'", pattern));