Adding jetty-deploy-manager-graph

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/sandbox/trunk@1076 7e9141cc-0065-0410-87d8-b60c137991c4
diff --git a/jetty-deploy-manager-graph/.gitignore b/jetty-deploy-manager-graph/.gitignore
new file mode 100644
index 0000000..796b602
--- /dev/null
+++ b/jetty-deploy-manager-graph/.gitignore
@@ -0,0 +1,9 @@
+target/
+.classpath
+.project
+.settings
+*/src/main/java/META-INF/
+*.log
+*.swp
+*.diff
+*.patch
diff --git a/jetty-deploy-manager-graph/pom.xml b/jetty-deploy-manager-graph/pom.xml
new file mode 100644
index 0000000..edefa9c
--- /dev/null
+++ b/jetty-deploy-manager-graph/pom.xml
@@ -0,0 +1,85 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty</groupId>
+    <artifactId>jetty-project</artifactId>
+    <version>7.0.1-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>jetty-deploy-manager-graph</artifactId>
+  <name>Jetty :: Deployment Manager Graph Based</name>
+  <description>Jetty Deployment Manager</description>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>${felix.bundle.version}</version>
+        <extensions>true</extensions>
+        <executions>
+          <execution>
+            <goals>
+              <goal>manifest</goal>
+            </goals>
+           </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <!--
+        Required for OSGI
+        -->
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+          </archive>
+        </configuration>
+      </plugin>
+      <!-- always include sources since jetty-xbean makes use of them -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-webapp</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-xml</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.7</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.5</version>
+        <configuration>
+          <docfilessubdirs>true</docfilessubdirs>
+          <detectLinks>true</detectLinks>
+          <detectJavaApiLink>true</detectJavaApiLink>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/App.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/App.java
new file mode 100644
index 0000000..924c8de
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/App.java
@@ -0,0 +1,73 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy;
+
+import java.io.File;
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+/**
+ * The information about an App that is managed by the {@link DeploymentManager}
+ */
+public interface App
+{
+    /**
+     * The raw id of the {@link App}
+     * 
+     * @return the generated Id for the App.
+     */
+    String getId();
+
+    /**
+     * Get the internally declared name of the App.
+     * 
+     * @return the internal name of the App.
+     */
+    String getName();
+
+    /**
+     * Get ContextHandler for the App.
+     * 
+     * Create it if needed.
+     * 
+     * @return the {@link ContextHandler} to use for the App when fully started. (Portions of which might be ignored
+     *         when App is in the {@link AppState#STAGED} state}
+     * @throws Exception
+     */
+    ContextHandler getContextHandler(DeploymentManager deployMgr) throws Exception;
+
+    /**
+     * Get the work dir for this App, as managed by the {@link DeploymentManager}
+     * 
+     * @return the App's work dir.
+     */
+    File getWorkDir();
+
+    /**
+     * Get the archive path to the App.
+     * 
+     * Might exist as a Directory (example: an exploded webapp, or a jetty:run) or a File (example: a WAR file)
+     * 
+     * @return the
+     */
+    File getDir();
+
+    /**
+     * The origin of this {@link App} as specified by the {@link AppProvider}
+     * 
+     * @return String representing the origin of this app.
+     */
+    String getOrigin();
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/AppLifecycle.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/AppLifecycle.java
new file mode 100644
index 0000000..bf28998
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/AppLifecycle.java
@@ -0,0 +1,269 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jetty.deploy.annotations.DeployLifecycleBinding;
+import org.eclipse.jetty.deploy.graph.Graph;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.util.log.Log;
+
+/**
+ * The lifecycle of an App in the {@link DeploymentManager}.
+ * 
+ * Setups a the default {@link Graph}, and manages the bindings to the life cycle via the {@link DeployLifecycleBinding}
+ * annotation.
+ * <p>
+ * <img src="doc-files/AppLifecycle.png">
+ */
+public class AppLifecycle extends Graph
+{
+    private static class BoundMethod
+    {
+        Object obj;
+        @SuppressWarnings("unused")
+        Node node;
+        Method method;
+    }
+
+    // Private string constants defined to avoid typos on repeatedly used strings 
+    private static final String NODE_UNDEPLOYED = "undeployed";
+    private static final String NODE_PRE_DEPLOYING = "pre-deploying";
+    private static final String NODE_DEPLOYING = "deploying";
+    private static final String NODE_DEPLOYED = "deployed";
+    private static final String NODE_PRE_STARTING = "pre-starting";
+    private static final String NODE_STARTING = "starting";
+    private static final String NODE_STARTED = "started";
+    private static final String NODE_PRE_STOPPING = "pre-stopping";
+    private static final String NODE_STOPPING = "stopping";
+    private static final String NODE_PRE_UNDEPLOYING = "pre-undeploying";
+    private static final String NODE_UNDEPLOYING = "undeploying";
+
+    public static void main(String[] args)
+    {
+        // Dump All Paths
+        AppLifecycle lifecycle = new AppLifecycle();
+
+        Set<Node> nodes = lifecycle.getNodes();
+
+        for (Node from : nodes)
+        {
+            for (Node to : nodes)
+            {
+                System.out.println();
+                System.out.printf("Paths %s -> %s:%n",from,to);
+                List<Node> path = lifecycle.findPath(from,to);
+                if (path.isEmpty())
+                {
+                    System.out.printf("  (no steps needed)%n");
+                    continue;
+                }
+
+                for (Node step : path)
+                {
+                    System.out.printf("  %s%n",step.getName());
+                }
+            }
+        }
+    }
+
+    private Map<Node, List<BoundMethod>> lifecyclebindings = new HashMap<Node, List<BoundMethod>>();
+
+    public AppLifecycle()
+    {
+        // Define Default Graph
+
+        // undeployed -> deployed
+        addEdge(NODE_UNDEPLOYED,NODE_PRE_DEPLOYING);
+        addEdge(NODE_PRE_DEPLOYING,NODE_DEPLOYING);
+        addEdge(NODE_DEPLOYING,NODE_DEPLOYED);
+
+        // deployed -> started
+        addEdge(NODE_DEPLOYED,NODE_PRE_STARTING);
+        addEdge(NODE_PRE_STARTING,NODE_STARTING);
+        addEdge(NODE_STARTING,NODE_STARTED);
+
+        // started -> deployed
+        addEdge(NODE_STARTED,NODE_PRE_STOPPING);
+        addEdge(NODE_PRE_STOPPING,NODE_STOPPING);
+        addEdge(NODE_STOPPING,NODE_DEPLOYED);
+
+        // deployed -> undeployed
+        addEdge(NODE_DEPLOYED,NODE_PRE_UNDEPLOYING);
+        addEdge(NODE_PRE_UNDEPLOYING,NODE_UNDEPLOYING);
+        addEdge(NODE_UNDEPLOYING,NODE_UNDEPLOYED);
+    }
+
+    public void addBinding(Object obj)
+    {
+        Class<?>[] expectedParams =
+        { Node.class, App.class, DeploymentManager.class };
+
+        for (Method method : obj.getClass().getDeclaredMethods())
+        {
+            // Does it have annotation?
+            if (!method.isAnnotationPresent(DeployLifecycleBinding.class))
+            {
+                continue; // skip
+            }
+
+            // Is it public?
+            if (!Modifier.isPublic(method.getModifiers()))
+            {
+                continue; // skip
+            }
+
+            // Does it return void?
+            if (method.getReturnType() != Void.TYPE)
+            {
+                continue; // skip
+            }
+
+            // Does it have specified parameters?
+            Class<?> params[] = method.getParameterTypes();
+            if (params == null)
+            {
+                continue; // skip
+            }
+            if (params.length != expectedParams.length)
+            {
+                continue; // skip
+            }
+            for (int i = 0; i < expectedParams.length; i++)
+            {
+                if (params[i].isAssignableFrom(expectedParams[i]) == false)
+                {
+                    continue; // Not a match. skip it
+                }
+            }
+
+            // Has to be a match at this point.
+            DeployLifecycleBinding bindingAnno = method.getAnnotation(DeployLifecycleBinding.class);
+
+            for (String nodeName : bindingAnno.nodes())
+            {
+                if (nodeName.equals("*"))
+                {
+                    // Special Case: Bind to all Nodes
+                    for (Node node : getNodes())
+                    {
+                        bindToNode(node,obj,method);
+                    }
+                }
+                else
+                {
+                    // Bind to specific node
+                    Node node = getNodeByName(nodeName);
+                    bindToNode(node,obj,method);
+                }
+            }
+        }
+    }
+
+    private void bindToNode(Node node, Object obj, Method method)
+    {
+        // Create Method -> Object binding reference.
+        BoundMethod bound = new BoundMethod();
+        bound.obj = obj;
+        bound.method = method;
+        bound.node = node;
+
+        // Assign to map
+        List<BoundMethod> bindings = lifecyclebindings.get(node);
+        if (bindings == null)
+        {
+            bindings = new ArrayList<BoundMethod>();
+        }
+        bindings.add(bound);
+
+        lifecyclebindings.put(node,bindings);
+    }
+
+    /**
+     * Get all {@link Node} bound objects.
+     * 
+     * @return Set of Object(s) for all lifecycle bindings. never null.
+     */
+    public Set<Object> getBindings()
+    {
+        Set<Object> boundset = new HashSet<Object>();
+
+        for (List<BoundMethod> bindings : lifecyclebindings.values())
+        {
+            for (BoundMethod bound : bindings)
+            {
+                boundset.add(bound.obj);
+            }
+        }
+
+        return boundset;
+    }
+
+    /**
+     * Get all objects bound to a specific {@link Node}
+     * 
+     * @return Set of Object(s) for specific lifecycle bindings. never null.
+     */
+    public Set<Object> getBindings(Node node)
+    {
+        Set<Object> boundset = new HashSet<Object>();
+
+        List<BoundMethod> bindings = lifecyclebindings.get(node);
+        if (bindings == null)
+        {
+            return boundset;
+        }
+
+        for (BoundMethod bound : bindings)
+        {
+            boundset.add(bound.obj);
+        }
+
+        return boundset;
+    }
+
+    public Set<Object> getBindings(String nodeName)
+    {
+        Node node = getNodeByName(nodeName);
+        return getBindings(node);
+    }
+
+    public void runBindings(Node node, App app, DeploymentManager deploymentManager) throws Throwable
+    {
+        List<BoundMethod> bindings = this.lifecyclebindings.get(node);
+        if (bindings == null)
+        {
+            return;
+        }
+
+        Object[] params =
+        { node, app, deploymentManager };
+
+        for (BoundMethod binding : bindings)
+        {
+            Log.debug("Calling " + binding.obj.getClass().getName() + "#" + binding.method.getName());
+            binding.method.invoke(binding.obj,params);
+        }
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/AppProvider.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/AppProvider.java
new file mode 100644
index 0000000..76ca1e6
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/AppProvider.java
@@ -0,0 +1,26 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy;
+
+/**
+ * Object responsible for providing {@link App}s to the {@link DeploymentManager}
+ */
+public interface AppProvider
+{
+    void startProvider(DeploymentManager deploymentManager) throws Exception;
+
+    void stopProvider() throws Exception;
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java
new file mode 100644
index 0000000..8b6fa1a
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java
@@ -0,0 +1,379 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.deploy.support.ConfigurationManager;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.util.AttributesMap;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+
+/**
+ * The Deployment Manager.
+ * <p>
+ * Responsibilities:
+ * <p>
+ * <img src="doc-files/DeploymentManager_Roles.png">
+ * <ol>
+ * <li>Tracking Apps and their Lifecycle Location</li>
+ * <li>Managing AppProviders and the Apps that they provide.</li>
+ * <li>Executing AppLifecycle on App based on current and desired Lifecycle Location.</li>
+ * </ol>
+ * <p>
+ * <img src="doc-files/DeploymentManager.png">
+ */
+public class DeploymentManager extends AbstractLifeCycle
+{
+    /**
+     * Represents a single tracked app within the deployment manager.
+     */
+    public class AppEntry
+    {
+        /**
+         * Version of the app.
+         * 
+         * Note: Auto-increments on each {@link DeploymentManager#addApp(App)}
+         */
+        private int version;
+
+        /**
+         * The app being tracked.
+         */
+        private App app;
+
+        /**
+         * The lifecycle node location of this App
+         */
+        private Node lifecyleNode;
+
+        /**
+         * Tracking the various AppState timestamps (in system milliseconds)
+         */
+        private Map<Node, Long> stateTimestamps = new HashMap<Node, Long>();
+
+        public App getApp()
+        {
+            return app;
+        }
+
+        public int getVersion()
+        {
+            return version;
+        }
+
+        public Node getLifecyleNode()
+        {
+            return lifecyleNode;
+        }
+
+        public Map<Node, Long> getStateTimestamps()
+        {
+            return stateTimestamps;
+        }
+
+        void setLifecycleNode(Node node)
+        {
+            this.lifecyleNode = node;
+            this.stateTimestamps.put(node,Long.valueOf(System.currentTimeMillis()));
+        }
+    }
+
+    private Map<String, AppEntry> appmap = new HashMap<String, AppEntry>();
+    private List<AppProvider> providers = new ArrayList<AppProvider>();
+    private AttributesMap contextAttributes = new AttributesMap();
+    private ConfigurationManager configurationManager;
+    private ContextHandlerCollection contexts;
+    private AppLifecycle lifecycle = new AppLifecycle();
+
+    /**
+     * Receive an app for processing.
+     * 
+     * Most commonly used by the various {@link AppProvider} implementations.
+     */
+    public void addApp(App app)
+    {
+        AppEntry entry = appmap.get(app.getId());
+        if (entry == null)
+        {
+            // New Entry
+            entry = new AppEntry();
+            entry.version = 0;
+            entry.setLifecycleNode(lifecycle.getNodeByName("undeployed"));
+        }
+        else
+        {
+            // Existing Entry
+            entry.version++;
+
+            // TODO: determine state change
+            // TODO: determine redeploy need?
+        }
+
+        entry.app = app;
+        appmap.put(app.getId(),entry);
+
+        // TODO: Should immediately attempt to start?
+        // this.requestAppGoal(app.getId(),AppState.STARTED);
+    }
+
+    public void addAppProvider(AppProvider provider)
+    {
+        providers.add(provider);
+        if (isStarted() || isStarting())
+        {
+            try
+            {
+                provider.startProvider(this);
+            }
+            catch (Exception e)
+            {
+                Log.warn("Unable to start AppProvider",e);
+            }
+        }
+    }
+
+    @Override
+    protected void doStart() throws Exception
+    {
+        Log.info("Starting all Providers: " + providers.size());
+        // Start all of the AppProviders
+        for (AppProvider provider : providers)
+        {
+            try
+            {
+                provider.startProvider(this);
+            }
+            catch (Exception e)
+            {
+                Log.warn("Unable to start AppProvider",e);
+            }
+        }
+        super.doStart();
+    }
+
+    @Override
+    protected void doStop() throws Exception
+    {
+        Log.info("Stopping all Providers: " + providers.size());
+
+        // Stop all of the AppProviders
+        for (AppProvider provider : providers)
+        {
+            try
+            {
+                provider.stopProvider();
+            }
+            catch (Exception e)
+            {
+                Log.warn("Unable to start AppProvider",e);
+            }
+        }
+        super.doStop();
+    }
+
+    public App getApp(String appId)
+    {
+        AppEntry entry = appmap.get(appId);
+        if (entry == null)
+        {
+            return null;
+        }
+        return entry.app;
+    }
+
+    public Collection<AppEntry> getAppEntries()
+    {
+        return appmap.values();
+    }
+
+    public AppEntry getAppEntry(String appId)
+    {
+        return appmap.get(appId);
+    }
+
+    public Collection<AppProvider> getAppProviders()
+    {
+        return providers;
+    }
+
+    public Collection<App> getApps()
+    {
+        List<App> apps = new ArrayList<App>();
+        for (AppEntry entry : appmap.values())
+        {
+            apps.add(entry.app);
+        }
+        return apps;
+    }
+
+    /**
+     * Get Set of {@link App}s by {@link Node}
+     * 
+     * @param state
+     *            the state to look for.
+     * @return
+     */
+    public Collection<App> getApps(Node node)
+    {
+        List<App> apps = new ArrayList<App>();
+        for (AppEntry entry : appmap.values())
+        {
+            if (entry.lifecyleNode == node)
+            {
+                apps.add(entry.app);
+            }
+        }
+        return apps;
+    }
+
+    /**
+     * Get a contextAttribute that will be set for every Context deployed by this provider.
+     * 
+     * @param name
+     * @return
+     */
+    public Object getAttribute(String name)
+    {
+        return contextAttributes.getAttribute(name);
+    }
+
+    public ConfigurationManager getConfigurationManager()
+    {
+        return configurationManager;
+    }
+
+    public AttributesMap getContextAttributes()
+    {
+        return contextAttributes;
+    }
+
+    public ContextHandlerCollection getContexts()
+    {
+        return contexts;
+    }
+
+    public Server getServer()
+    {
+        if (contexts == null)
+        {
+            return null;
+        }
+        return contexts.getServer();
+    }
+
+    public void removeAppProvider(AppProvider provider)
+    {
+        providers.remove(provider);
+        try
+        {
+            provider.stopProvider();
+        }
+        catch (Exception e)
+        {
+            Log.warn("Unable to stop Provider",e);
+        }
+    }
+
+    /**
+     * Remove a contextAttribute that will be set for every Context deployed by this provider.
+     * 
+     * @param name
+     */
+    public void removeAttribute(String name)
+    {
+        contextAttributes.removeAttribute(name);
+    }
+
+    /**
+     * Move an {@link App} through the {@link AppLifecycle} to the desired {@link Node}, executing each lifecycle step
+     * in the process to reach the desired state.
+     * 
+     * @param appId
+     *            the id of the app to move through the process
+     * @param nodeName
+     *            the name of the node to attain
+     */
+    public void requestAppGoal(String appId, String nodeName)
+    {
+        AppEntry appentry = getAppEntry(appId);
+
+        Node destinationNode = lifecycle.getNodeByName(nodeName);
+        // Compute lifecycle steps
+        List<Node> path = lifecycle.findPath(appentry.lifecyleNode,destinationNode);
+        if (path.isEmpty())
+        {
+            // nothing to do. already there.
+            return;
+        }
+
+        // Execute each Node binding.  Stopping at any thrown exception.
+        try
+        {
+            for (Node node : path)
+            {
+                Log.info("Executing Node: " + node);
+                lifecycle.runBindings(node,appentry.app,this);
+            }
+        }
+        catch (Throwable t)
+        {
+            Log.warn("Unable to reach node goal: " + nodeName,t);
+        }
+    }
+
+    /**
+     * Set a contextAttribute that will be set for every Context deployed by this provider.
+     * 
+     * @param name
+     * @param value
+     */
+    public void setAttribute(String name, Object value)
+    {
+        contextAttributes.setAttribute(name,value);
+    }
+
+    public void setConfigurationManager(ConfigurationManager configurationManager)
+    {
+        this.configurationManager = configurationManager;
+    }
+
+    public void setContextAttributes(AttributesMap contextAttributes)
+    {
+        this.contextAttributes = contextAttributes;
+    }
+
+    public void setContexts(ContextHandlerCollection contexts)
+    {
+        this.contexts = contexts;
+    }
+
+    public void addLifecycleBinding(Object binding)
+    {
+        lifecycle.addBinding(binding);
+    }
+
+    public AppLifecycle getLifecycle()
+    {
+        return lifecycle;
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/annotations/DeployLifecycleBinding.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/annotations/DeployLifecycleBinding.java
new file mode 100644
index 0000000..5e8df39
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/annotations/DeployLifecycleBinding.java
@@ -0,0 +1,30 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Documented
+public @interface DeployLifecycleBinding
+{
+    String[] nodes();
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultDeployer.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultDeployer.java
new file mode 100644
index 0000000..baed599
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultDeployer.java
@@ -0,0 +1,32 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.bindings;
+
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.DeploymentManager;
+import org.eclipse.jetty.deploy.annotations.DeployLifecycleBinding;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+public class DefaultDeployer
+{
+    @DeployLifecycleBinding(nodes = "deploying")
+    public void handleAppDeploy(DeploymentManager deployMgr, Node lifecycleNode, App app) throws Exception
+    {
+        ContextHandler handler = app.getContextHandler(deployMgr);
+        deployMgr.getContexts().addHandler(handler);
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultStarter.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultStarter.java
new file mode 100644
index 0000000..3e367cc
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultStarter.java
@@ -0,0 +1,35 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.bindings;
+
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.DeploymentManager;
+import org.eclipse.jetty.deploy.annotations.DeployLifecycleBinding;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+public class DefaultStarter
+{
+    @DeployLifecycleBinding(nodes = "starting")
+    public void handleAppStart(DeploymentManager deployMgr, Node lifecycleNode, App app) throws Exception
+    {
+        ContextHandler handler = app.getContextHandler(deployMgr);
+        if (!handler.isStarted())
+        {
+            handler.start();
+        }
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultStopper.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultStopper.java
new file mode 100644
index 0000000..53470ba
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultStopper.java
@@ -0,0 +1,35 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.bindings;
+
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.DeploymentManager;
+import org.eclipse.jetty.deploy.annotations.DeployLifecycleBinding;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+public class DefaultStopper
+{
+    @DeployLifecycleBinding(nodes = "stopping")
+    public void handleAppStop(DeploymentManager deployMgr, Node lifecycleNode, App app) throws Exception
+    {
+        ContextHandler handler = app.getContextHandler(deployMgr);
+        if (!handler.isStopped())
+        {
+            handler.stop();
+        }
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultUndeployer.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultUndeployer.java
new file mode 100644
index 0000000..25ab5d8
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/bindings/DefaultUndeployer.java
@@ -0,0 +1,32 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.bindings;
+
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.DeploymentManager;
+import org.eclipse.jetty.deploy.annotations.DeployLifecycleBinding;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+public class DefaultUndeployer
+{
+    @DeployLifecycleBinding(nodes = "undeploying")
+    public void handleAppUndeploy(DeploymentManager deployMgr, Node lifecycleNode, App app) throws Exception
+    {
+        ContextHandler handler = app.getContextHandler(deployMgr);
+        deployMgr.getContexts().removeHandler(handler);
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java
new file mode 100644
index 0000000..5e6d070
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java
@@ -0,0 +1,78 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.graph;
+
+/**
+ * Basic Graph Edge
+ */
+public class Edge
+{
+    private Node from;
+    private Node to;
+
+    public Edge(Node from, Node to)
+    {
+        this.from = from;
+        this.to = to;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((from == null)?0:from.hashCode());
+        result = prime * result + ((to == null)?0:to.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Edge other = (Edge)obj;
+        if (from == null)
+        {
+            if (other.from != null)
+                return false;
+        }
+        else if (!from.equals(other.from))
+            return false;
+        if (to == null)
+        {
+            if (other.to != null)
+                return false;
+        }
+        else if (!to.equals(other.to))
+            return false;
+        return true;
+    }
+
+    public Node getFrom()
+    {
+        return from;
+    }
+
+    public Node getTo()
+    {
+        return to;
+    }
+}
\ No newline at end of file
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java
new file mode 100644
index 0000000..1c0f644
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java
@@ -0,0 +1,385 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.graph;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Basic directed graph implementation
+ */
+public class Graph
+{
+    private class EdgeSearch
+    {
+        private Set<Edge> seenEdges = new HashSet<Edge>();
+        private List<NodePath> paths = new ArrayList<NodePath>();
+
+        public EdgeSearch(Node from)
+        {
+            NodePath path = new NodePath();
+            path.add(from);
+            paths.add(path);
+        }
+
+        public void breadthFirst(Node destination)
+        {
+            // Test existing edge endpoints
+            if (hasReachedDestination(destination))
+            {
+                // Found our destination!
+
+                // Now remove the other paths that do not end at the destination
+                ListIterator<NodePath> pathiter = paths.listIterator();
+                while (pathiter.hasNext())
+                {
+                    NodePath path = pathiter.next();
+                    if (path.lastNode() != destination)
+                    {
+                        pathiter.remove();
+                    }
+                }
+                return;
+            }
+
+            List<NodePath> extrapaths = null;
+
+            // Add next unseen segments to paths.
+            boolean pathsAdded = false;
+
+            for (NodePath path : paths)
+            {
+                List<Edge> next = nextUnseenEdges(path);
+                if (next.size() == 0)
+                {
+                    continue; // no new edges
+                }
+
+                pathsAdded = true;
+
+                // More than 1 path out? Split it.
+                if (next.size() > 1)
+                {
+                    if (extrapaths == null)
+                    {
+                        extrapaths = new ArrayList<NodePath>();
+                    }
+
+                    // Split path for other edges
+                    for (int i = 1, n = next.size(); i < n; i++)
+                    {
+                        NodePath split = path.forkPath();
+                        // Add segment to split'd path
+                        split.add(next.get(i).getTo());
+
+                        // Add to extra paths
+                        extrapaths.add(split);
+                    }
+                }
+
+                // Add edge to current path
+                Edge edge = next.get(0);
+                path.add(edge.getTo());
+
+                // Mark all edges as seen
+                for (Edge e : next)
+                {
+                    seenEdges.add(e);
+                }
+            }
+
+            // Do we have any extra paths?
+            if (extrapaths != null)
+            {
+                paths.addAll(extrapaths);
+            }
+
+            if (pathsAdded)
+            {
+                // recurse
+                breadthFirst(destination);
+            }
+        }
+
+        public NodePath getShortestPath()
+        {
+            NodePath shortest = null;
+            int shortestlen = Integer.MAX_VALUE;
+
+            for (NodePath path : paths)
+            {
+                if (shortest == null)
+                {
+                    shortest = path;
+                    continue;
+                }
+
+                int len = path.length();
+
+                if (len < shortestlen)
+                {
+                    shortest = path;
+                    shortestlen = len;
+                }
+            }
+
+            return shortest;
+        }
+
+        private boolean hasReachedDestination(Node destination)
+        {
+            for (NodePath path : paths)
+            {
+                if (path.lastNode() == destination)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private List<Edge> nextUnseenEdges(NodePath path)
+        {
+            List<Edge> next = new ArrayList<Edge>();
+
+            for (Edge edge : findEdgesFrom(path.lastNode()))
+            {
+                if (seenEdges.contains(edge) == false)
+                {
+                    next.add(edge);
+                }
+            }
+
+            return next;
+        }
+    }
+
+    private class NodePath implements Iterable<Node>
+    {
+        private Stack<Node> path;
+
+        public NodePath()
+        {
+            path = new Stack<Node>();
+        }
+
+        public void add(Node node)
+        {
+            path.push(node);
+        }
+
+        public NodePath forkPath()
+        {
+            NodePath ep = new NodePath();
+            for (Node node : this)
+            {
+                ep.add(node);
+            }
+            return ep;
+        }
+
+        public Collection<Node> getCollection()
+        {
+            return path;
+        }
+
+        public Iterator<Node> iterator()
+        {
+            return path.iterator();
+        }
+
+        public Node lastNode()
+        {
+            return path.peek();
+        }
+
+        public int length()
+        {
+            return path.size();
+        }
+    }
+
+    private Set<Node> nodes = new HashSet<Node>();
+    private Set<Edge> edges = new HashSet<Edge>();
+
+    public void addEdge(Edge edge)
+    {
+        this.edges.add(edge);
+    }
+
+    public void addEdge(String from, String to)
+    {
+        Node fromNode = null;
+        Node toNode = null;
+
+        try
+        {
+            fromNode = getNodeByName(from);
+        }
+        catch (NodeNotFoundException e)
+        {
+            fromNode = new Node(from);
+            addNode(fromNode);
+        }
+
+        try
+        {
+            toNode = getNodeByName(to);
+        }
+        catch (NodeNotFoundException e)
+        {
+            toNode = new Node(to);
+            addNode(toNode);
+        }
+
+        Edge edge = new Edge(fromNode,toNode);
+        addEdge(edge);
+    }
+
+    public void addNode(Node node)
+    {
+        this.nodes.add(node);
+    }
+
+    /**
+     * Find all edges that are connected to the specific node, both as an outgoing {@link Edge#getFrom()} or incoming
+     * {@link Edge#getTo()} end point.
+     * 
+     * @param node
+     *            the node with potential end points
+     * @return the set of edges connected to the node
+     */
+    public Set<Edge> findEdges(Node node)
+    {
+        Set<Edge> fromedges = new HashSet<Edge>();
+
+        for (Edge edge : this.edges)
+        {
+            if ((edge.getFrom() == node) || (edge.getTo() == node))
+            {
+                fromedges.add(edge);
+            }
+        }
+
+        return fromedges;
+    }
+
+    /**
+     * Find all edges that are connected {@link Edge#getFrom()} the specific node.
+     * 
+     * @param node
+     *            the node with potential edges from it
+     * @return the set of edges from the node
+     */
+    public Set<Edge> findEdgesFrom(Node from)
+    {
+        Set<Edge> fromedges = new HashSet<Edge>();
+
+        for (Edge edge : this.edges)
+        {
+            if (edge.getFrom() == from)
+            {
+                fromedges.add(edge);
+            }
+        }
+
+        return fromedges;
+    }
+
+    /**
+     * Using BFS (Breadth First Search) return the path from a any arbitrary node to any other.
+     * 
+     * @param from
+     *            the node from
+     * @param to
+     *            the node to
+     * @return the path to take
+     */
+    public List<Node> findPath(Node from, Node to)
+    {
+        if (from == to)
+        {
+            return Collections.emptyList();
+        }
+
+        // Perform a Breadth First Search (BFS) of the tree.
+        EdgeSearch search = new EdgeSearch(from);
+        search.breadthFirst(to);
+
+        NodePath nodepath = search.getShortestPath();
+        List<Node> path = new ArrayList<Node>();
+        path.addAll(nodepath.getCollection());
+        return path;
+    }
+
+    public Set<Edge> getEdges()
+    {
+        return edges;
+    }
+
+    public Node getNodeByName(String name)
+    {
+        for (Node node : nodes)
+        {
+            if (node.getName().equals(name))
+            {
+                return node;
+            }
+        }
+
+        throw new NodeNotFoundException("Unable to find node: " + name);
+    }
+
+    public Set<Node> getNodes()
+    {
+        return nodes;
+    }
+
+    public void removeEdge(Edge edge)
+    {
+        this.edges.remove(edge);
+    }
+
+    public void removeEdge(String fromNodeName, String toNodeName)
+    {
+        Node fromNode = getNodeByName(fromNodeName);
+        Node toNode = getNodeByName(toNodeName);
+        Edge edge = new Edge(fromNode,toNode);
+        removeEdge(edge);
+    }
+
+    public void removeNode(Node node)
+    {
+        this.nodes.remove(node);
+    }
+
+    public void setEdges(Set<Edge> edges)
+    {
+        this.edges = edges;
+    }
+
+    public void setNodes(Set<Node> nodes)
+    {
+        this.nodes = nodes;
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/ImpossiblePathException.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/ImpossiblePathException.java
new file mode 100644
index 0000000..7a9e871
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/ImpossiblePathException.java
@@ -0,0 +1,31 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.graph;
+
+public class ImpossiblePathException extends RuntimeException
+{
+    private static final long serialVersionUID = 8423437443748056467L;
+
+    public ImpossiblePathException(String message, Throwable cause)
+    {
+        super(message,cause);
+    }
+
+    public ImpossiblePathException(String message)
+    {
+        super(message);
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Node.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Node.java
new file mode 100644
index 0000000..ab80ea7
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/Node.java
@@ -0,0 +1,69 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.graph;
+
+/**
+ * Basic Graph Node
+ */
+public class Node
+{
+    private String name;
+
+    public Node(String name)
+    {
+        this.name = name;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Node[" + name + "]";
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((name == null)?0:name.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Node other = (Node)obj;
+        if (name == null)
+        {
+            if (other.name != null)
+                return false;
+        }
+        else if (!name.equals(other.name))
+            return false;
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/NodeNotFoundException.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/NodeNotFoundException.java
new file mode 100644
index 0000000..336adf9
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/graph/NodeNotFoundException.java
@@ -0,0 +1,34 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.graph;
+
+/**
+ * NodeNotFoundException for when a referenced node cannot be found.
+ */
+public class NodeNotFoundException extends RuntimeException
+{
+    private static final long serialVersionUID = -7126395440535048386L;
+
+    public NodeNotFoundException(String message, Throwable cause)
+    {
+        super(message,cause);
+    }
+
+    public NodeNotFoundException(String message)
+    {
+        super(message);
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/ConfiguredContextApp.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/ConfiguredContextApp.java
new file mode 100644
index 0000000..8ffb50d
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/ConfiguredContextApp.java
@@ -0,0 +1,94 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.providers;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.DeploymentManager;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.util.AttributesMap;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.xml.XmlConfiguration;
+
+public class ConfiguredContextApp implements App
+{
+    private String filename;
+    private ContextHandler handler;
+
+    public ConfiguredContextApp(String filename)
+    {
+        this.filename = filename;
+    }
+
+    public File getDir()
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public ContextHandler getContextHandler(DeploymentManager deploymgr) throws Exception
+    {
+        if (handler == null)
+        {
+            Resource resource = Resource.newResource(filename);
+            if (!resource.exists())
+            {
+                return null;
+            }
+
+            XmlConfiguration xmlc = new XmlConfiguration(resource.getURL());
+            Map props = new HashMap();
+            props.put("Server",deploymgr.getServer());
+            if (deploymgr.getConfigurationManager() != null)
+            {
+                props.putAll(deploymgr.getConfigurationManager().getProperties());
+            }
+
+            xmlc.setProperties(props);
+            this.handler = (ContextHandler)xmlc.configure();
+            this.handler.setAttributes(new AttributesMap(deploymgr.getContextAttributes()));
+        }
+        return handler;
+    }
+
+    public String getId()
+    {
+        return null;
+    }
+
+    public String getName()
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getOrigin()
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public File getWorkDir()
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/ContextsDirAppProvider.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/ContextsDirAppProvider.java
new file mode 100644
index 0000000..b5acb0e
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/ContextsDirAppProvider.java
@@ -0,0 +1,152 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.providers;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.Collections;
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.AppProvider;
+import org.eclipse.jetty.deploy.DeploymentManager;
+import org.eclipse.jetty.util.Scanner;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.resource.Resource;
+
+/**
+ * Backwards Compatible AppProvider for Monitoring a Contexts directory and deploying All Contexts.
+ * 
+ * Similar in scope to the original org.eclipse.jetty.deploy.ContextDeployer
+ */
+public class ContextsDirAppProvider implements AppProvider, Scanner.DiscreteListener
+{
+    private Resource contextsDir;
+    private Scanner scanner;
+    private int scanInterval = 10;
+    private boolean recursive = false;
+    private DeploymentManager deploymgr;
+
+    class XmlFilenameFilter implements FilenameFilter
+    {
+        public boolean accept(File dir, String name)
+        {
+            if (name.endsWith(".xml"))
+            {
+                return true;
+            }
+
+            return false;
+        }
+    }
+
+    public ContextsDirAppProvider()
+    {
+        scanner = new Scanner();
+    }
+
+    public void startProvider(DeploymentManager deploymentManager) throws Exception
+    {
+        Log.info(this.getClass().getSimpleName() + ".startProvider(" + deploymentManager + ")");
+        if (contextsDir == null)
+        {
+            throw new IllegalStateException("No configuration dir specified");
+        }
+
+        this.deploymgr = deploymentManager;
+
+        File scandir = contextsDir.getFile();
+        Log.info("ScanDir: " + scandir);
+        this.scanner.setScanDirs(Collections.singletonList(scandir));
+        this.scanner.setScanInterval(scanInterval);
+        this.scanner.setRecursive(recursive);
+        this.scanner.setFilenameFilter(new XmlFilenameFilter());
+        this.scanner.addListener(this);
+        this.scanner.scan();
+        this.scanner.start();
+    }
+
+    public Resource getContextsDir()
+    {
+        return contextsDir;
+    }
+
+    public void setContextsDir(Resource contextsDir)
+    {
+        this.contextsDir = contextsDir;
+    }
+
+    /**
+     * @param dir
+     *            Directory to scan for context descriptors
+     */
+    public void setContextsDir(String dir)
+    {
+        try
+        {
+            contextsDir = Resource.newResource(dir);
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    public int getScanInterval()
+    {
+        return scanInterval;
+    }
+
+    public void setScanInterval(int scanInterval)
+    {
+        this.scanInterval = scanInterval;
+    }
+
+    public boolean isRecursive()
+    {
+        return recursive;
+    }
+
+    public void setRecursive(boolean recursive)
+    {
+        this.recursive = recursive;
+    }
+
+    public void stopProvider()
+    {
+        this.scanner.removeListener(this);
+        this.scanner.stop();
+    }
+
+    public void fileAdded(String filename) throws Exception
+    {
+        Log.info("fileAdded(" + filename + ")");
+        App app = new ConfiguredContextApp(filename);
+        this.deploymgr.addApp(app);
+    }
+
+    public void fileChanged(String filename) throws Exception
+    {
+        Log.info("fileChanged(" + filename + ")");
+        App app = new ConfiguredContextApp(filename);
+        this.deploymgr.addApp(app);
+    }
+
+    public void fileRemoved(String filename) throws Exception
+    {
+        Log.info("fileRemoved(" + filename + ")");
+        App app = new ConfiguredContextApp(filename);
+        this.deploymgr.addApp(app);
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/WebappsDirAppProvider.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/WebappsDirAppProvider.java
new file mode 100644
index 0000000..7e526df
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/providers/WebappsDirAppProvider.java
@@ -0,0 +1,41 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.providers;
+
+import org.eclipse.jetty.deploy.AppProvider;
+import org.eclipse.jetty.deploy.DeploymentManager;
+
+/**
+ * Backwards Compatible AppProvider for Monitoring a Webapps directory and deploying All apps.
+ * 
+ * Similar in scope to the original org.eclipse.jetty.deploy.WebAppDeployer
+ */
+public class WebappsDirAppProvider implements AppProvider
+{
+
+    public void startProvider(DeploymentManager deploymentManager) throws Exception
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void stopProvider()
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/support/ConfigurationManager.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/support/ConfigurationManager.java
new file mode 100644
index 0000000..c9f7ad5
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/support/ConfigurationManager.java
@@ -0,0 +1,27 @@
+// ========================================================================
+// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+
+package org.eclipse.jetty.deploy.support;
+
+import java.util.Map;
+
+/**
+ * ConfigurationManager
+ *
+ * Type for allow injection of property values
+ * for replacement in jetty xml files during deployment.
+ */
+public interface ConfigurationManager
+{
+    public Map<?, ?> getProperties();
+}
diff --git a/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/support/FileConfigurationManager.java b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/support/FileConfigurationManager.java
new file mode 100644
index 0000000..e4dc398
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/java/org/eclipse/jetty/deploy/support/FileConfigurationManager.java
@@ -0,0 +1,66 @@
+// ========================================================================
+// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+
+package org.eclipse.jetty.deploy.support;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+import java.util.Properties;
+
+import org.eclipse.jetty.util.resource.Resource;
+
+/**
+ * FileConfigurationManager
+ * 
+ * Supplies properties defined in a file.
+ */
+public class FileConfigurationManager implements ConfigurationManager
+{
+    private Resource _file;
+    private Properties _properties = new Properties();
+
+    public FileConfigurationManager()
+    {
+    }
+
+    public void setFile(String filename) throws MalformedURLException, IOException
+    {
+        _file = Resource.newResource(filename);
+    }
+
+    /**
+     * @see org.eclipse.jetty.deploy.ConfigurationManager#getProperties()
+     */
+    public Map<?, ?> getProperties()
+    {
+        try
+        {
+            loadProperties();
+            return _properties;
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void loadProperties() throws FileNotFoundException, IOException
+    {
+        if (_properties.isEmpty())
+        {
+            _properties.load(_file.getInputStream());
+        }
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/AppLifecycle.png b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/AppLifecycle.png
new file mode 100644
index 0000000..071c747
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/AppLifecycle.png
Binary files differ
diff --git a/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/AppLifecycle.svg b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/AppLifecycle.svg
new file mode 100644
index 0000000..dc6974c
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/AppLifecycle.svg
@@ -0,0 +1,482 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by Graphviz version 2.20.2 (Mon Mar 30 10:11:53 UTC 2009)
+     For user: (joakim) Joakim Erdfelt,,, -->
+<!-- Title: G Pages: 1 -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="765"
+   height="900"
+   viewBox="0 0 327 590"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="AppLifecycle.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0"
+   inkscape:export-filename="/home/joakim/code/webtide/jetty7-git/sandbox/jetty-deploy-manager/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/AppLifecycle.png"
+   inkscape:export-xdpi="40"
+   inkscape:export-ydpi="40">
+  <metadata
+     id="metadata184">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs182">
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lstart"
+       style="overflow:visible">
+      <path
+         id="path4328"
+         style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3605"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutL"
+       style="overflow:visible">
+      <path
+         id="path3727"
+         d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.8,0.8)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible">
+      <path
+         id="path3587"
+         d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 368.75 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="408.75 : 368.75 : 1"
+       inkscape:persp3d-origin="204.375 : 245.83333 : 1"
+       id="perspective186" />
+    <title
+       id="title5">G</title>
+    <title
+       id="title10">incoming_app</title>
+    <title
+       id="title17">command_deploy</title>
+    <title
+       id="title33">state_deployed</title>
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-height="1151"
+     inkscape:window-width="1920"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="1"
+     guidetolerance="10"
+     gridtolerance="10.0"
+     objecttolerance="13"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     showgrid="false"
+     inkscape:zoom="0.92828283"
+     inkscape:cx="387.34766"
+     inkscape:cy="428.51283"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:current-layer="svg2"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:document-units="cm"
+     units="in"
+     inkscape:snap-guide="true"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="false"
+     inkscape:bbox-nodes="false"
+     inkscape:snap-intersection-line-segments="true"
+     inkscape:object-paths="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-center="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3514"
+       dotted="true"
+       visible="true"
+       enabled="true"
+       units="cm"
+       spacingx="0.25cm"
+       spacingy="0.25cm"
+       empspacing="5" />
+  </sodipodi:namedview>
+  <g
+     id="g3445"
+     transform="matrix(1.2491264,0,0,1.2491264,109.41031,84.061397)">
+    <polygon
+       style="fill:#ffa500;stroke:#ffa500;stroke-width:0.80055952"
+       points="228,-510 144,-510 144,-468 228,-468 228,-510 "
+       id="polygon3447"
+       transform="translate(4,586)" />
+    <text
+       x="190"
+       y="92.600006"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3449"
+       sodipodi:linespacing="125%">
+      <tspan
+         sodipodi:role="line"
+         id="tspan3451"
+         x="190"
+         y="92.600006">Phase</tspan>
+      <tspan
+         sodipodi:role="line"
+         id="tspan3453"
+         x="190"
+         y="110.60001">DEPLOY</tspan>
+    </text>
+  </g>
+  <g
+     id="g3917">
+    <polygon
+       transform="matrix(1.6111428,0,0,1.2491264,-118.06476,648.90074)"
+       id="polygon3491"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       style="fill:#00ffff;stroke:#00ffff;stroke-width:0.70490372" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text3493"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       y="130.01364"
+       x="178.38551">
+      <tspan
+         sodipodi:role="line"
+         id="tspan3503"
+         x="178.38551"
+         y="130.01364">State</tspan>
+      <tspan
+         sodipodi:role="line"
+         id="tspan3505"
+         x="178.38551"
+         y="152.49792">UNAVAILABLE</tspan>
+    </text>
+  </g>
+  <g
+     id="g3549"
+     transform="matrix(1.2491264,0,0,1.2491264,-227.0731,84.061397)">
+    <polygon
+       style="fill:#ffa500;stroke:#ffa500;stroke-width:0.80055952"
+       points="228,-510 144,-510 144,-468 228,-468 228,-510 "
+       id="polygon3551"
+       transform="translate(4,586)" />
+    <text
+       x="190"
+       y="92.600006"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3553"
+       sodipodi:linespacing="125%">
+      <tspan
+         sodipodi:role="line"
+         id="tspan3559"
+         x="190"
+         y="92.600006">Phase</tspan>
+      <tspan
+         sodipodi:role="line"
+         id="tspan3561"
+         x="190"
+         y="110.60001">UNDEPLOY</tspan>
+    </text>
+  </g>
+  <g
+     id="g3483"
+     transform="matrix(1.2491264,0,0,1.2491264,-102.88457,7.5836656)">
+    <ellipse
+       style="fill:#c1c1c1;fill-opacity:1;stroke:none"
+       cx="222"
+       cy="-564"
+       rx="96.784599"
+       ry="18"
+       id="ellipse3485"
+       sodipodi:cx="222"
+       sodipodi:cy="-564"
+       sodipodi:rx="96.784599"
+       sodipodi:ry="18"
+       transform="translate(4,586)" />
+    <text
+       x="226"
+       y="26.099976"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3487"
+       sodipodi:linespacing="125%">Incoming WebApp</text>
+  </g>
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.9988189;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Lend)"
+     d="M 180.40071,57.523395 L 180.40071,108.36997"
+     id="path2594"
+     sodipodi:nodetypes="cc" />
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3923"
+     d="M 252.49807,154.27312 L 294.28101,190.29424"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 294.28101,213.09705 L 236.46989,265.1469"
+     id="path3925"
+     sodipodi:nodetypes="cc" />
+  <g
+     id="g3469"
+     transform="matrix(1.2491264,0,0,1.2491264,-55.825685,55.721845)">
+    <polygon
+       style="fill:#00ffff;stroke:#00ffff;stroke-width:0.80055952"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       id="polygon3471"
+       transform="translate(4,586)" />
+    <text
+       x="188"
+       y="170.60001"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3473"
+       sodipodi:linespacing="125%">
+      <tspan
+         sodipodi:role="line"
+         id="tspan3475"
+         x="188"
+         y="170.60001">State</tspan>
+      <tspan
+         sodipodi:role="line"
+         id="tspan3477"
+         x="188"
+         y="188.60001">DEPLOYED</tspan>
+    </text>
+  </g>
+  <g
+     id="g5403"
+     transform="matrix(1.2491264,0,0,1.2491264,-56.840602,191.55677)">
+    <polygon
+       style="fill:#00ffff;stroke:#00ffff;stroke-width:0.80055952"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       id="polygon5405"
+       transform="translate(4,586)" />
+    <text
+       x="188"
+       y="170.60001"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text5407"
+       sodipodi:linespacing="125%">
+      <tspan
+         sodipodi:role="line"
+         id="tspan5417"
+         x="188"
+         y="170.60001">State</tspan>
+      <tspan
+         sodipodi:role="line"
+         id="tspan5419"
+         x="188"
+         y="188.60001">STAGED</tspan>
+    </text>
+  </g>
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3929"
+     d="M 120.53534,398.20562 L 62.724228,352.50272"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3935"
+     d="M 294.28101,355.83348 L 235.45498,398.20563"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <g
+     transform="matrix(1.2491264,0,0,1.2491264,109.41031,219.89633)"
+     id="g3535">
+    <polygon
+       transform="translate(4,586)"
+       id="polygon3537"
+       points="228,-510 144,-510 144,-468 228,-468 228,-510 "
+       style="fill:#ffa500;stroke:#ffa500;stroke-width:0.80055952" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text3539"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       y="92.600006"
+       x="190">
+      <tspan
+         sodipodi:role="line"
+         id="tspan3545"
+         x="190"
+         y="92.600006">Phase</tspan>
+      <tspan
+         sodipodi:role="line"
+         id="tspan3547"
+         x="190"
+         y="110.60001">STAGE</tspan>
+    </text>
+  </g>
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3927"
+     d="M 236.46989,284.21436 L 293.65647,330.6791"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3941"
+     d="M 62.724228,186.76323 L 104.27295,153.52683"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3943"
+     d="M 121.55027,263.8367 L 62.724228,212.94524"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <text
+     x="-10.835248"
+     y="23.769073"
+     style="font-size:20.46376419px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold Italic"
+     id="text2456"
+     sodipodi:linespacing="100%">
+    <tspan
+       sodipodi:role="line"
+       id="tspan2460"
+       x="-10.835244"
+       y="23.769073"
+       style="font-size:20.46376419px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold Italic">Deployment</tspan>
+    <tspan
+       sodipodi:role="line"
+       x="-10.835247"
+       y="44.232838"
+       id="tspan2464"
+       style="font-size:20.46376419px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold Italic">Lifecycle</tspan>
+  </text>
+  <g
+     id="g2472"
+     transform="matrix(1.2491264,0,0,1.2491264,109.41031,355.73126)">
+    <polygon
+       style="fill:#ffa500;stroke:#ffa500;stroke-width:0.80055952"
+       points="228,-510 144,-510 144,-468 228,-468 228,-510 "
+       id="polygon2474"
+       transform="translate(4,586)" />
+    <text
+       x="190"
+       y="92.600006"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text2476"
+       sodipodi:linespacing="125%">
+      <tspan
+         y="92.600006"
+         x="190"
+         id="tspan2478"
+         sodipodi:role="line">Phase</tspan>
+      <tspan
+         y="110.60001"
+         x="190"
+         id="tspan2480"
+         sodipodi:role="line">START</tspan>
+    </text>
+  </g>
+  <g
+     id="g2482"
+     transform="matrix(1.2491264,0,0,1.2491264,-227.0731,219.89633)">
+    <polygon
+       style="fill:#ffa500;stroke:#ffa500;stroke-width:0.80055952"
+       points="228,-510 144,-510 144,-468 228,-468 228,-510 "
+       id="polygon2484"
+       transform="translate(4,586)" />
+    <text
+       x="190"
+       y="92.600006"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text2486"
+       sodipodi:linespacing="125%">
+      <tspan
+         y="92.600006"
+         x="190"
+         id="tspan2488"
+         sodipodi:role="line">Phase</tspan>
+      <tspan
+         y="110.60001"
+         x="190"
+         id="tspan2490"
+         sodipodi:role="line">STOP</tspan>
+    </text>
+  </g>
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 236.46989,420.04929 L 293.65647,466.51403"
+     id="path2492"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 62.724228,326.37326 L 121.55027,286.42657"
+     id="path2494"
+     sodipodi:nodetypes="cc" />
+  <g
+     transform="matrix(1.2491264,0,0,1.2491264,-56.840602,327.3917)"
+     id="g2551">
+    <polygon
+       transform="translate(4,586)"
+       id="polygon2553"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       style="fill:#00ffff;stroke:#00ffff;stroke-width:0.80055952" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text2555"
+       style="font-size:14.39999962px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       y="170.60001"
+       x="188">
+      <tspan
+         y="170.60001"
+         x="188"
+         id="tspan2557"
+         sodipodi:role="line">State</tspan>
+      <tspan
+         y="188.60001"
+         x="188"
+         id="tspan2559"
+         sodipodi:role="line">STARTED</tspan>
+    </text>
+  </g>
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 120.53534,536.86536 L 23.883096,367.29325"
+     id="path2561"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 294.28101,491.66841 L 235.45498,545.3398"
+     id="path2563"
+     sodipodi:nodetypes="cc" />
+</svg>
diff --git a/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager.png b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager.png
new file mode 100644
index 0000000..b3c0a5b
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager.png
Binary files differ
diff --git a/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager.svg b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager.svg
new file mode 100644
index 0000000..68a51bf
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager.svg
@@ -0,0 +1,570 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by Graphviz version 2.20.2 (Mon Mar 30 10:11:53 UTC 2009)
+     For user: (joakim) Joakim Erdfelt,,, -->
+<!-- Title: G Pages: 1 -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="965.69556"
+   height="852.49811"
+   viewBox="0 0 327 590"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="DeploymentManager.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0"
+   inkscape:export-filename="/home/joakim/code/webtide/jetty7-git/sandbox/jetty-deploy-manager/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager.png"
+   inkscape:export-xdpi="59.964943"
+   inkscape:export-ydpi="59.964943">
+  <metadata
+     id="metadata184">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs182">
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart"
+       style="overflow:visible">
+      <path
+         id="path4328"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3605"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutL"
+       style="overflow:visible">
+      <path
+         id="path3727"
+         d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.8,0.8)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible">
+      <path
+         id="path3587"
+         d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 368.75 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="408.75 : 368.75 : 1"
+       inkscape:persp3d-origin="204.375 : 245.83333 : 1"
+       id="perspective186" />
+    <title
+       id="title5">G</title>
+    <title
+       id="title10">incoming_app</title>
+    <title
+       id="title17">command_deploy</title>
+    <title
+       id="title33">state_deployed</title>
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-height="1151"
+     inkscape:window-width="1920"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="1"
+     guidetolerance="10"
+     gridtolerance="10.0"
+     objecttolerance="13"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     showgrid="false"
+     inkscape:zoom="1"
+     inkscape:cx="474.19853"
+     inkscape:cy="442.53354"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:current-layer="svg2"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:document-units="cm"
+     units="cm"
+     inkscape:snap-guide="true"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="false"
+     inkscape:bbox-nodes="false"
+     inkscape:snap-intersection-line-segments="true"
+     inkscape:object-paths="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-center="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3514"
+       dotted="true"
+       visible="true"
+       enabled="true"
+       units="cm"
+       spacingx="0.25cm"
+       spacingy="0.25cm"
+       empspacing="5" />
+  </sodipodi:namedview>
+  <text
+     x="-78.66259"
+     y="28.720337"
+     style="font-size:20.46376419px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold Italic"
+     id="text2456"
+     sodipodi:linespacing="100%">
+    <tspan
+       sodipodi:role="line"
+       id="tspan2460"
+       x="-78.662582"
+       y="28.720337"
+       style="font-size:20.46376419px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold Italic">Deployment</tspan>
+    <tspan
+       sodipodi:role="line"
+       x="-78.66259"
+       y="49.184101"
+       id="tspan2464"
+       style="font-size:20.46376419px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold Italic">Management</tspan>
+  </text>
+  <g
+     id="g3282"
+     transform="translate(102.27151,-84.291492)">
+    <polygon
+       style="fill:#ffad70;fill-opacity:1;stroke:none;stroke-width:0.1850972"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       id="polygon3273"
+       transform="matrix(2.3250213,0,0,1.0137256,-252.78172,805.8122)" />
+    <text
+       x="174.1483"
+       y="394.13333"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3275"
+       sodipodi:linespacing="125%">
+      <tspan
+         y="394.13333"
+         x="174.1483"
+         id="tspan3277"
+         sodipodi:role="line">DeploymentManager</tspan>
+    </text>
+  </g>
+  <g
+     id="g3304"
+     transform="translate(129.1072,31.5257)">
+    <polygon
+       style="fill:#d5ff70;fill-opacity:1;stroke:none;stroke-width:0.1850972"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       id="polygon3289"
+       transform="matrix(1.5190294,0,0,1.4508985,-250.33457,723.80726)" />
+    <text
+       x="28.670605"
+       y="122.9516"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3291"
+       sodipodi:linespacing="125%">
+      <tspan
+         y="122.9516"
+         x="28.670605"
+         id="tspan3293"
+         sodipodi:role="line">AppProvider</tspan>
+      <tspan
+         id="tspan3300"
+         y="145.43587"
+         x="28.670603"
+         sodipodi:role="line">Contexts Dir</tspan>
+    </text>
+  </g>
+  <g
+     id="g3310"
+     transform="translate(300.00818,31.5257)">
+    <polygon
+       transform="matrix(1.5190294,0,0,1.4508985,-250.33457,723.80726)"
+       id="polygon3312"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       style="fill:#d5ff70;fill-opacity:1;stroke:none;stroke-width:0.1850972" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text3314"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       y="122.9516"
+       x="28.670605">
+      <tspan
+         sodipodi:role="line"
+         id="tspan3316"
+         x="28.670605"
+         y="122.9516">AppProvider</tspan>
+      <tspan
+         sodipodi:role="line"
+         x="28.670605"
+         y="145.43587"
+         id="tspan3318">Webapps Dir</tspan>
+    </text>
+  </g>
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 246.279,212.30268 L 216.9954,189.48254"
+     id="path3344"
+     sodipodi:nodetypes="cc" />
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3879"
+     d="M 246.279,212.30268 L 281.25982,189.48254"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3889"
+     d="M 338.25506,189.48254 L 338.25509,283.59126"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3891"
+     d="M 177.84916,189.48255 L 177.54883,283.59124"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <g
+     id="g3916"
+     transform="translate(105.09632,-15.083658)">
+    <polygon
+       transform="matrix(1.5190294,0,0,1.0137261,-95.187633,465.47084)"
+       id="polygon3903"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       style="fill:#70d9ff;fill-opacity:1;stroke:none;stroke-width:0.1850972" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text3905"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       y="53.791767"
+       x="184.1996">
+      <tspan
+         id="tspan3909"
+         sodipodi:role="line"
+         x="184.1996"
+         y="53.791767">File System</tspan>
+    </text>
+  </g>
+  <path
+     sodipodi:nodetypes="cc"
+     id="path3921"
+     d="M 204.70466,128.54481 L 240.721,55.034003"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 343.12033,128.54481 L 309.92883,55.034003"
+     id="path3923"
+     sodipodi:nodetypes="cc" />
+  <polygon
+     style="fill:#ff913e;fill-opacity:1;stroke:none;stroke-width:0.1850972"
+     points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+     id="polygon4134"
+     transform="matrix(0.4627878,0,0,-5.402269,346.01282,-1753.521)" />
+  <g
+     id="g3971"
+     transform="translate(328.9625,-22.190946)">
+    <polygon
+       style="fill:#ffad70;fill-opacity:1;stroke:none;stroke-width:0.1850972"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       id="polygon3958"
+       transform="matrix(1.8107217,0,0,1.0137258,-329.65122,830.47882)" />
+    <text
+       x="2.6476707"
+       y="418.79987"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3960"
+       sodipodi:linespacing="125%">
+      <tspan
+         id="tspan3964"
+         y="418.79987"
+         x="2.6476688"
+         sodipodi:role="line">DefaultDeployer</tspan>
+    </text>
+  </g>
+  <g
+     id="g3976"
+     transform="translate(328.58482,33.210928)">
+    <polygon
+       style="fill:#ffad70;fill-opacity:1;stroke:none;stroke-width:0.1850972"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       id="polygon3978"
+       transform="matrix(1.8107217,0,0,1.0137258,-329.65122,830.47882)" />
+    <text
+       x="2.6476707"
+       y="418.79987"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3980"
+       sodipodi:linespacing="125%">
+      <tspan
+         id="tspan3982"
+         y="418.79987"
+         x="2.6476722"
+         sodipodi:role="line">DefaultStarter</tspan>
+    </text>
+  </g>
+  <g
+     id="g3984"
+     transform="translate(329.29103,86.176108)">
+    <polygon
+       style="fill:#ffad70;fill-opacity:1;stroke:none;stroke-width:0.1850972"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       id="polygon3986"
+       transform="matrix(1.8107217,0,0,1.0137258,-329.65122,830.47882)" />
+    <text
+       x="2.6476707"
+       y="418.79987"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3988"
+       sodipodi:linespacing="125%">
+      <tspan
+         id="tspan3990"
+         y="418.79987"
+         x="2.6476693"
+         sodipodi:role="line">DefaultStopper</tspan>
+    </text>
+  </g>
+  <g
+     id="g4003"
+     transform="translate(148.88088,-17.953732)">
+    <polygon
+       style="fill:#ffad70;fill-opacity:1;stroke:none;stroke-width:0.1850972"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       id="polygon3994"
+       transform="matrix(2.102414,0,0,1.0137258,-216.3303,986.86761)" />
+    <text
+       x="169.63997"
+       y="575.18866"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       id="text3996"
+       sodipodi:linespacing="125%">
+      <tspan
+         id="tspan3998"
+         y="575.18866"
+         x="169.63997"
+         sodipodi:role="line">DefaultUndeployer</tspan>
+    </text>
+  </g>
+  <g
+     id="g4136"
+     transform="translate(163.00492,-10.846444)">
+    <polygon
+       transform="matrix(2.309669,0,0,3.2368503,-636.87384,1707.8548)"
+       id="polygon3927"
+       points="230,-432 138,-432 138,-390 230,-390 230,-432 "
+       style="fill:#70d9ff;fill-opacity:1;stroke:none;stroke-width:0.1850972" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text3929"
+       style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+       y="331.32928"
+       x="-211.42046">
+      <tspan
+         id="tspan3933"
+         sodipodi:role="line"
+         x="-211.42046"
+         y="331.32928">Jetty Server</tspan>
+    </text>
+    <g
+       transform="translate(3.6339138,14.123438)"
+       id="g4042">
+      <rect
+         style="opacity:1;fill:#ffffff;fill-opacity:0.57352941;stroke:none;stroke-width:1.52362204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect4033"
+         width="135.59087"
+         height="42.576458"
+         x="-282.93228"
+         y="367.66122"
+         ry="0" />
+      <text
+         x="-216.01076"
+         y="395.65521"
+         style="font-size:17.98741913px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+         id="text4038"
+         sodipodi:linespacing="125%">
+        <tspan
+           y="395.65521"
+           x="-216.01076"
+           sodipodi:role="line"
+           id="tspan4040">Handler</tspan>
+      </text>
+    </g>
+  </g>
+  <path
+     sodipodi:nodetypes="cc"
+     id="path4027"
+     d="M 249.19086,394.86412 L 19.29742,380.32317"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 248.81318,455.59753 L 19.29742,388.44449"
+     id="path4047"
+     sodipodi:nodetypes="cc" />
+  <path
+     sodipodi:nodetypes="cc"
+     id="path4049"
+     d="M 249.5194,508.56271 L 19.29742,398.33131"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 236.80775,555.87827 L 19.29742,408.92435"
+     id="path4051"
+     sodipodi:nodetypes="cc" />
+  <text
+     transform="matrix(0.9979899,6.3372504e-2,-6.3372504e-2,0.9979899,0,0)"
+     id="text4053"
+     y="375.59882"
+     x="71.124741"
+     style="font-size:13.11166096px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     xml:space="preserve"><tspan
+       y="375.59882"
+       x="71.124741"
+       id="tspan4055"
+       sodipodi:role="line">Create/Add ContextHandler</tspan></text>
+  <text
+     transform="matrix(0.960082,0.2797186,-0.2797186,0.960082,0,0)"
+     id="text4061"
+     y="363.9259"
+     x="239.78268"
+     style="font-size:13.1116581px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     xml:space="preserve"><tspan
+       y="363.9259"
+       x="239.78268"
+       id="tspan4063"
+       sodipodi:role="line">Start Handler</tspan></text>
+  <text
+     transform="matrix(0.9021783,0.4313632,-0.4313632,0.9021783,0,0)"
+     id="text4065"
+     y="346.85672"
+     x="305.1987"
+     style="font-size:13.11165524px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     xml:space="preserve"><tspan
+       y="346.85672"
+       x="305.1987"
+       id="tspan4067"
+       sodipodi:role="line">Stop Handler</tspan></text>
+  <text
+     transform="matrix(0.8286045,0.5598344,-0.5598344,0.8286045,0,0)"
+     id="text4069"
+     y="324.38153"
+     x="358.96548"
+     style="font-size:13.1116581px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     xml:space="preserve"
+     inkscape:transform-center-x="50.663071"
+     inkscape:transform-center-y="-52.951508"><tspan
+       y="324.38153"
+       x="358.96548"
+       id="tspan4071"
+       sodipodi:role="line">Remove Handler</tspan></text>
+  <path
+     sodipodi:nodetypes="cc"
+     id="path4073"
+     d="M 384.24468,305.40822 C 415.02857,303.94581 422.97175,327.74882 428.85613,353.36389"
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99881887;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  <text
+     transform="matrix(0.8492228,0.5280347,-0.5280347,0.8492228,0,0)"
+     id="text4075"
+     y="38.223793"
+     x="494.58685"
+     style="font-size:13.11166382px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     xml:space="preserve"
+     inkscape:transform-center-x="-244.6352"
+     inkscape:transform-center-y="-504.72461"><tspan
+       y="38.223793"
+       x="494.58685"
+       sodipodi:role="line"
+       id="tspan4079">Process Phases</tspan></text>
+  <text
+     sodipodi:linespacing="125%"
+     id="text4094"
+     style="font-size:24.99049759px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+     y="-423.87344"
+     x="420.23651"
+     transform="matrix(0,1,-1,0,0,0)">
+    <tspan
+       sodipodi:role="line"
+       id="tspan4096"
+       x="420.23651"
+       y="-423.87344">Lifecycle</tspan>
+  </text>
+  <text
+     transform="matrix(1,1.6038357e-4,-1.6038357e-4,1,0,0)"
+     id="text2579"
+     y="228.70334"
+     x="180.83775"
+     style="font-size:13.11166191px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     xml:space="preserve"
+     inkscape:transform-center-x="-17.522216"
+     inkscape:transform-center-y="1.6854193"><tspan
+       y="228.70334"
+       x="180.83775"
+       sodipodi:role="line"
+       id="tspan3922">App</tspan></text>
+  <path
+     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00542861;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     d="M 246.54365,283.59124 L 246.279,212.30268"
+     id="path2583"
+     sodipodi:nodetypes="cc" />
+  <text
+     transform="matrix(1,1.6038357e-4,-1.6038357e-4,1,0,0)"
+     id="text3912"
+     y="228.69254"
+     x="248.14288"
+     style="font-size:13.11166191px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     xml:space="preserve"
+     inkscape:transform-center-x="-17.522216"
+     inkscape:transform-center-y="1.6854193"><tspan
+       y="228.69254"
+       x="248.14288"
+       sodipodi:role="line"
+       id="tspan3916">Start</tspan><tspan
+       y="245.08211"
+       x="248.14288"
+       sodipodi:role="line"
+       id="tspan3920">Stop</tspan></text>
+  <text
+     transform="matrix(1,1.6038357e-4,-1.6038357e-4,1,0,0)"
+     id="text3926"
+     y="228.6776"
+     x="341.29437"
+     style="font-size:13.11166191px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+     xml:space="preserve"
+     inkscape:transform-center-x="-17.522216"
+     inkscape:transform-center-y="1.6854193"><tspan
+       y="228.6776"
+       x="341.29437"
+       sodipodi:role="line"
+       id="tspan3928">App</tspan></text>
+</svg>
diff --git a/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager_Roles.png b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager_Roles.png
new file mode 100644
index 0000000..4b96a6b
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager_Roles.png
Binary files differ
diff --git a/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager_Roles.svg b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager_Roles.svg
new file mode 100644
index 0000000..7185759
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager_Roles.svg
@@ -0,0 +1,389 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by Graphviz version 2.20.2 (Mon Mar 30 10:11:53 UTC 2009)
+     For user: (joakim) Joakim Erdfelt,,, -->
+<!-- Title: G Pages: 1 -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="439.37006"
+   height="729.92126"
+   viewBox="0 0 327 590"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="DeploymentManager Roles.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0"
+   inkscape:export-filename="/home/joakim/code/webtide/jetty7-git/sandbox/jetty-deploy-manager/src/main/javadoc/org/eclipse/jetty/deploy/doc-files/DeploymentManager_Roles.png"
+   inkscape:export-xdpi="40"
+   inkscape:export-ydpi="40">
+  <metadata
+     id="metadata184">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs182">
+    <linearGradient
+       id="linearGradient3424">
+      <stop
+         style="stop-color:#ff7107;stop-opacity:1;"
+         offset="0"
+         id="stop3426" />
+      <stop
+         style="stop-color:#ffeee0;stop-opacity:1;"
+         offset="1"
+         id="stop3428" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart"
+       style="overflow:visible">
+      <path
+         id="path4328"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3605"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutL"
+       style="overflow:visible">
+      <path
+         id="path3727"
+         d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.8,0.8)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible">
+      <path
+         id="path3587"
+         d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 368.75 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="408.75 : 368.75 : 1"
+       inkscape:persp3d-origin="204.375 : 245.83333 : 1"
+       id="perspective186" />
+    <title
+       id="title5">G</title>
+    <title
+       id="title10">incoming_app</title>
+    <title
+       id="title17">command_deploy</title>
+    <title
+       id="title33">state_deployed</title>
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-height="1151"
+     inkscape:window-width="1920"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="1"
+     guidetolerance="10"
+     gridtolerance="10.0"
+     objecttolerance="13"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     showgrid="false"
+     inkscape:zoom="1"
+     inkscape:cx="261.1181"
+     inkscape:cy="392.53714"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:current-layer="svg2"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:document-units="cm"
+     units="cm"
+     inkscape:snap-guide="true"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="false"
+     inkscape:bbox-nodes="false"
+     inkscape:snap-intersection-line-segments="true"
+     inkscape:object-paths="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-center="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3514"
+       dotted="true"
+       visible="true"
+       enabled="true"
+       units="cm"
+       spacingx="0.25cm"
+       spacingy="0.25cm"
+       empspacing="5" />
+  </sodipodi:namedview>
+  <g
+     id="g4043"
+     transform="matrix(1.1578745,0,0,1.1578745,-22.605787,-30.429653)">
+    <g
+       transform="translate(6.2287521,5.1906208)"
+       id="g3432">
+      <rect
+         style="opacity:1;fill:#ff984b;fill-opacity:1;stroke:none;stroke-width:1.52362204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect2582"
+         width="271.29678"
+         height="108.65714"
+         x="18.959866"
+         y="223.19566"
+         ry="46.920952"
+         rx="50.806107" />
+      <text
+         sodipodi:linespacing="125%"
+         id="text3275"
+         style="font-size:25.83806229px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold"
+         y="268.40268"
+         x="153.72513">
+        <tspan
+           sodipodi:role="line"
+           id="tspan3277"
+           x="153.72513"
+           y="268.40268">Deployment</tspan>
+        <tspan
+           sodipodi:role="line"
+           x="153.72513"
+           y="300.70026"
+           id="tspan3378">Manager</tspan>
+      </text>
+    </g>
+    <g
+       transform="translate(62.97961,2.9413488)"
+       id="g3418">
+      <rect
+         rx="20.920155"
+         ry="46.920952"
+         y="347.77072"
+         x="-37.790993"
+         height="47.75378"
+         width="119.23236"
+         id="rect3380"
+         style="opacity:1;fill:#ffd7b9;fill-opacity:1;stroke:none;stroke-width:1.52362204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <text
+         x="21.438501"
+         y="366.92834"
+         style="font-size:17.21594238px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:110.00000238%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+         id="text3382"
+         sodipodi:linespacing="110%">
+        <tspan
+           id="tspan3386"
+           y="366.92834"
+           x="21.438501"
+           sodipodi:role="line">Bind</tspan>
+        <tspan
+           y="385.86588"
+           x="21.438503"
+           sodipodi:role="line"
+           id="tspan3390">Lifecycle</tspan>
+      </text>
+    </g>
+    <g
+       transform="translate(2.1078682,5.3948095)"
+       id="g3412">
+      <rect
+         style="opacity:1;fill:#ffd7b9;fill-opacity:1;stroke:none;stroke-width:1.52362204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect3392"
+         width="119.23236"
+         height="47.75378"
+         x="175.14517"
+         y="345.31726"
+         ry="46.920952"
+         rx="20.920155" />
+      <text
+         sodipodi:linespacing="110%"
+         id="text3394"
+         style="font-size:17.21594238px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:110.00000238%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+         y="364.21011"
+         x="234.37466">
+        <tspan
+           sodipodi:role="line"
+           x="234.37466"
+           y="364.21011"
+           id="tspan3396">Use</tspan>
+        <tspan
+           id="tspan3398"
+           sodipodi:role="line"
+           x="234.37466"
+           y="383.14764">Lifecycle</tspan>
+      </text>
+    </g>
+    <rect
+       style="opacity:1;fill:#ffd970;fill-opacity:1;stroke:none;stroke-width:1.52362204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect3400"
+       width="271.29678"
+       height="108.65714"
+       x="25.188618"
+       y="412.13449"
+       ry="46.920952"
+       rx="50.806107" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text3402"
+       style="font-size:25.83806229px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold"
+       y="458.72568"
+       x="159.2618">
+      <tspan
+         sodipodi:role="line"
+         x="159.2618"
+         y="458.72568"
+         id="tspan3406">Deployment</tspan>
+      <tspan
+         id="tspan3410"
+         sodipodi:role="line"
+         x="159.2618"
+         y="491.02325">Lifecycle</tspan>
+    </text>
+    <g
+       transform="translate(6.2287521,-178.55759)"
+       id="g3438">
+      <rect
+         rx="50.806107"
+         ry="46.920952"
+         y="223.19566"
+         x="18.959866"
+         height="108.65714"
+         width="271.29678"
+         id="rect3440"
+         style="opacity:1;fill:#d5ff70;fill-opacity:1;stroke:none;stroke-width:1.52362204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <text
+         x="153.72513"
+         y="268.40268"
+         style="font-size:25.83806229px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans Bold"
+         id="text3442"
+         sodipodi:linespacing="125%">
+        <tspan
+           id="tspan3446"
+           y="268.40268"
+           x="153.72513"
+           sodipodi:role="line">App</tspan>
+        <tspan
+           id="tspan3450"
+           y="300.70026"
+           x="153.72513"
+           sodipodi:role="line">Provider</tspan>
+      </text>
+    </g>
+    <g
+       id="g3452"
+       transform="translate(62.97961,-180.80686)">
+      <rect
+         style="opacity:1;fill:#ffd7b9;fill-opacity:1;stroke:none;stroke-width:1.52362204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect3454"
+         width="119.23236"
+         height="47.75378"
+         x="-37.790993"
+         y="347.77072"
+         ry="46.920952"
+         rx="20.920155" />
+      <text
+         sodipodi:linespacing="110%"
+         id="text3456"
+         style="font-size:17.21594238px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:110.00000238%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+         y="366.92834"
+         x="21.438501">
+        <tspan
+           id="tspan3478"
+           sodipodi:role="line"
+           x="21.438499"
+           y="366.92834">Manage</tspan>
+        <tspan
+           id="tspan3482"
+           sodipodi:role="line"
+           x="21.438501"
+           y="385.86588">Provider</tspan>
+      </text>
+    </g>
+    <g
+       transform="translate(215.04403,-180.80686)"
+       id="g3462">
+      <rect
+         rx="20.920155"
+         ry="46.920952"
+         y="347.77072"
+         x="-37.790993"
+         height="47.75378"
+         width="119.23236"
+         id="rect3464"
+         style="opacity:1;fill:#ffd7b9;fill-opacity:1;stroke:none;stroke-width:1.52362204;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <text
+         x="21.438501"
+         y="366.92834"
+         style="font-size:17.21594238px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:110.00000238%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
+         id="text3466"
+         sodipodi:linespacing="110%">
+        <tspan
+           y="366.92834"
+           x="21.438503"
+           sodipodi:role="line"
+           id="tspan3470">Process</tspan>
+        <tspan
+           id="tspan3474"
+           y="385.86588"
+           x="21.438499"
+           sodipodi:role="line">App</tspan>
+      </text>
+    </g>
+    <path
+       style="opacity:0.61261262;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.86833984;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 195.13829,151.79607 L 195.13829,229.04598"
+       id="path4023"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="opacity:0.61261262;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.86833984;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 127.84895,230.68829 L 127.84895,153.43838"
+       id="path4037"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="opacity:0.61261262;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.86833984;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 195.13829,335.87758 L 195.13829,413.12749"
+       id="path4039"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="opacity:0.61261262;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.86833984;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 127.84895,335.87758 L 127.84895,413.12749"
+       id="path4041"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
diff --git a/jetty-deploy-manager-graph/src/main/javadoc/overview.html b/jetty-deploy-manager-graph/src/main/javadoc/overview.html
new file mode 100644
index 0000000..689d4f4
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/javadoc/overview.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+  <HEAD>
+    <TITLE>Jetty DeploymentManager API Overview</TITLE>
+  </HEAD>
+  <BODY>
+    Short overview of the API.
+  </BODY>
+</HTML>
diff --git a/jetty-deploy-manager-graph/src/main/resources/org/eclipse/jetty/deploy/lifecycle-bindings.txt b/jetty-deploy-manager-graph/src/main/resources/org/eclipse/jetty/deploy/lifecycle-bindings.txt
new file mode 100644
index 0000000..ed00104
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/main/resources/org/eclipse/jetty/deploy/lifecycle-bindings.txt
@@ -0,0 +1 @@
+# Default Bindings
\ No newline at end of file
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/AppLifecycleTest.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/AppLifecycleTest.java
new file mode 100644
index 0000000..7451db4
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/AppLifecycleTest.java
@@ -0,0 +1,217 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.deploy.graph.Node;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Just an overly picky test case to validate the potential paths.
+ */
+public class AppLifecycleTest
+{
+    private void assertNoPath(String from, String to)
+    {
+        assertPath(from,to,new ArrayList<String>());
+    }
+
+    private void assertPath(AppLifecycle lifecycle, String from, String to, List<String> expected)
+    {
+        Node fromNode = lifecycle.getNodeByName(from);
+        Node toNode = lifecycle.getNodeByName(to);
+        List<Node> actual = lifecycle.findPath(fromNode,toNode);
+        String msg = "Lifecycle.path from " + from + " to " + to;
+        Assert.assertNotNull(msg + " should never be null",actual);
+
+        if (expected.size() != actual.size())
+        {
+            System.out.println();
+            System.out.printf("/* from '%s' -> '%s' */%n",from,to);
+            System.out.println("/* Expected Path */");
+            for (String path : expected)
+            {
+                System.out.println(path);
+            }
+            System.out.println("/* Actual Path */");
+            for (Node path : actual)
+            {
+                System.out.println(path.getName());
+            }
+
+            Assert.assertEquals(msg + " / count",expected.size(),actual.size());
+        }
+
+        for (int i = 0, n = expected.size(); i < n; i++)
+        {
+            Assert.assertEquals(msg + "[" + i + "]",expected.get(i),actual.get(i).getName());
+        }
+    }
+
+    private void assertPath(String from, String to, List<String> expected)
+    {
+        AppLifecycle lifecycle = new AppLifecycle();
+        assertPath(lifecycle,from,to,expected);
+    }
+
+    @Test
+    public void testFindPath_Deployed_Deployed()
+    {
+        assertNoPath("deployed","deployed");
+    }
+
+    @Test
+    public void testFindPath_Deployed_Started()
+    {
+        List<String> expected = new ArrayList<String>();
+        expected.add("deployed");
+        expected.add("pre-starting");
+        expected.add("starting");
+        expected.add("started");
+        assertPath("deployed","started",expected);
+    }
+
+    @Test
+    public void testFindPath_Deployed_Undeployed()
+    {
+        List<String> expected = new ArrayList<String>();
+        expected.add("deployed");
+        expected.add("pre-undeploying");
+        expected.add("undeploying");
+        expected.add("undeployed");
+        assertPath("deployed","undeployed",expected);
+    }
+
+    @Test
+    public void testFindPath_Started_Deployed()
+    {
+        List<String> expected = new ArrayList<String>();
+        expected.add("started");
+        expected.add("pre-stopping");
+        expected.add("stopping");
+        expected.add("deployed");
+        assertPath("started","deployed",expected);
+    }
+
+    @Test
+    public void testFindPath_Started_Started()
+    {
+        assertNoPath("started","started");
+    }
+
+    @Test
+    public void testFindPath_Started_Undeployed()
+    {
+        List<String> expected = new ArrayList<String>();
+        expected.add("started");
+        expected.add("pre-stopping");
+        expected.add("stopping");
+        expected.add("deployed");
+        expected.add("pre-undeploying");
+        expected.add("undeploying");
+        expected.add("undeployed");
+        assertPath("started","undeployed",expected);
+    }
+
+    @Test
+    public void testFindPath_Undeployed_Deployed()
+    {
+        List<String> expected = new ArrayList<String>();
+        expected.add("undeployed");
+        expected.add("pre-deploying");
+        expected.add("deploying");
+        expected.add("deployed");
+        assertPath("undeployed","deployed",expected);
+    }
+
+    @Test
+    public void testFindPath_Undeployed_Started()
+    {
+        List<String> expected = new ArrayList<String>();
+        expected.add("undeployed");
+        expected.add("pre-deploying");
+        expected.add("deploying");
+        expected.add("deployed");
+        expected.add("pre-starting");
+        expected.add("starting");
+        expected.add("started");
+        assertPath("undeployed","started",expected);
+    }
+
+    @Test
+    public void testFindPath_Undeployed_Uavailable()
+    {
+        assertNoPath("undeployed","undeployed");
+    }
+
+    /**
+     * Request multiple lifecycle paths with a single lifecycle instance. Just to ensure that there is no state
+     * maintained between {@link AppLifecycle#findPath(Node, Node)} requests.
+     */
+    @Test
+    public void testFindPathMultiple()
+    {
+        AppLifecycle lifecycle = new AppLifecycle();
+        List<String> expected = new ArrayList<String>();
+
+        lifecycle.removeEdge("deployed","pre-starting");
+        lifecycle.addEdge("deployed","staging");
+        lifecycle.addEdge("staging","staged");
+        lifecycle.addEdge("staged","pre-starting");
+
+        // Deployed -> Deployed
+        expected.clear();
+        assertPath(lifecycle,"deployed","deployed",expected);
+
+        // Deployed -> Staged
+        expected.clear();
+        expected.add("deployed");
+        expected.add("staging");
+        expected.add("staged");
+        assertPath(lifecycle,"deployed","staged",expected);
+
+        // Staged -> Undeployed
+        expected.clear();
+        expected.add("staged");
+        expected.add("pre-starting");
+        expected.add("starting");
+        expected.add("started");
+        expected.add("pre-stopping");
+        expected.add("stopping");
+        expected.add("deployed");
+        expected.add("pre-undeploying");
+        expected.add("undeploying");
+        expected.add("undeployed");
+        assertPath(lifecycle,"staged","undeployed",expected);
+
+        // Undeployed -> Started
+        expected.clear();
+        expected.add("undeployed");
+        expected.add("pre-deploying");
+        expected.add("deploying");
+        expected.add("deployed");
+        expected.add("staging");
+        expected.add("staged");
+        expected.add("pre-starting");
+        expected.add("starting");
+        expected.add("started");
+        assertPath(lifecycle,"undeployed","started",expected);
+    }
+
+}
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerLifecyclePathTest.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerLifecyclePathTest.java
new file mode 100644
index 0000000..bebc413
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerLifecyclePathTest.java
@@ -0,0 +1,66 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.junit.Test;
+
+public class DeploymentManagerLifecyclePathTest
+{
+    @Test
+    public void testStateTransition_NewToDeployed()
+    {
+        LifecycleOrderTracker pathtracker = new LifecycleOrderTracker();
+        DeploymentManager depman = new DeploymentManager();
+        depman.addLifecycleBinding(pathtracker);
+        App app = new MockApp();
+
+        // Pretend to AppProvider ...
+        depman.addApp(app);
+
+        // Request Deploy of App
+        depman.requestAppGoal(app.getId(),"deployed");
+
+        // Setup Expectations.
+        List<Node> expectedOrder = new ArrayList<Node>();
+        expectedOrder.add(new Node("pre-deploying"));
+        expectedOrder.add(new Node("deploying"));
+        expectedOrder.add(new Node("deployed"));
+
+        pathtracker.assertExpected("Test StateTransition / New -> Deployed",expectedOrder);
+    }
+
+    @Test
+    public void testStateTransition_Receive()
+    {
+        LifecycleOrderTracker pathtracker = new LifecycleOrderTracker();
+        DeploymentManager depman = new DeploymentManager();
+        depman.addLifecycleBinding(pathtracker);
+        App app = new MockApp();
+
+        // Pretend to AppProvider
+        depman.addApp(app);
+
+        // Perform no goal request.
+
+        // Setup Expectations.
+        List<Node> expectedOrder = new ArrayList<Node>();
+
+        pathtracker.assertExpected("Test StateTransition / New only",expectedOrder);
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerTest.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerTest.java
new file mode 100644
index 0000000..d334fd2
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerTest.java
@@ -0,0 +1,81 @@
+package org.eclipse.jetty.deploy;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.eclipse.jetty.deploy.test.XmlConfiguredJetty;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class DeploymentManagerTest
+{
+    @Test
+    public void testReceiveApp()
+    {
+        LifecycleOrderTracker pathtracker = new LifecycleOrderTracker();
+        DeploymentManager depman = new DeploymentManager();
+        depman.addLifecycleBinding(pathtracker);
+        App app = new MockApp();
+
+        // Pretend to be AppProvider ...
+        depman.addApp(app);
+
+        // Test app tracking
+        Collection<App> apps = depman.getApps();
+        Assert.assertNotNull("Should never be null",apps);
+        Assert.assertEquals("Expected App Count",1,apps.size());
+
+        // Test app get
+        App actual = depman.getApp("mock-app");
+        Assert.assertNotNull("Should have gotten app (by id)",actual);
+        Assert.assertEquals("Should have gotten app (by id)",app.getId(),actual.getId());
+    }
+
+    @Test
+    public void testBinding()
+    {
+        LifecycleOrderTracker pathtracker = new LifecycleOrderTracker();
+        DeploymentManager depman = new DeploymentManager();
+        depman.addLifecycleBinding(pathtracker);
+
+        Set<Object> allbindings = depman.getLifecycle().getBindings();
+        Assert.assertNotNull("All Bindings should never be null",allbindings);
+        Assert.assertEquals("All Bindings.size",1,allbindings.size());
+
+        Set<Object> deploybindings = depman.getLifecycle().getBindings("deploying");
+        Assert.assertNotNull("'deploying' Bindings should not be null",deploybindings);
+        Assert.assertEquals("'deploying' Bindings.size",1,deploybindings.size());
+    }
+
+    @Test
+    public void testXmlConfigured() throws Exception
+    {
+        XmlConfiguredJetty jetty = null;
+        try
+        {
+            jetty = new XmlConfiguredJetty();
+            jetty.addConfiguration("jetty.xml");
+            jetty.addConfiguration("jetty-deploymgr-contexts.xml");
+
+            // Should not throw an Exception
+            jetty.load();
+
+            // Start it
+            jetty.start();
+        }
+        finally
+        {
+            if (jetty != null)
+            {
+                try
+                {
+                    jetty.stop();
+                }
+                catch (Exception ignore)
+                {
+                    // ignore
+                }
+            }
+        }
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/LifecycleOrderTracker.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/LifecycleOrderTracker.java
new file mode 100644
index 0000000..f8cbd65
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/LifecycleOrderTracker.java
@@ -0,0 +1,71 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.deploy.annotations.DeployLifecycleBinding;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.junit.Assert;
+
+/**
+ * Binds to all lifecycle nodes, and tracks the order of the lifecycle nodes for testing purposes.
+ */
+public class LifecycleOrderTracker
+{
+    List<Node> actualOrder = new ArrayList<Node>();
+
+    public void clear()
+    {
+        actualOrder.clear();
+    }
+
+    public List<Node> getCapturedPath()
+    {
+        return actualOrder;
+    }
+
+    @DeployLifecycleBinding(nodes = "*")
+    public void handleAppDeploy(Node node, App app, DeploymentManager depmgr)
+    {
+        actualOrder.add(node);
+    }
+
+    public void assertExpected(String msg, List<Node> expectedOrder)
+    {
+        if (expectedOrder.size() != actualOrder.size())
+        {
+            System.out.println("/* Expected Path */");
+            for (Node path : expectedOrder)
+            {
+                System.out.println(path);
+            }
+            System.out.println("/* Actual Path */");
+            for (Node path : actualOrder)
+            {
+                System.out.println(path);
+            }
+
+            Assert.assertEquals(msg + " / count",0,actualOrder.size());
+        }
+
+        for (int i = 0, n = expectedOrder.size(); i < n; i++)
+        {
+            Assert.assertEquals(msg + "[" + i + "]",expectedOrder.get(i),actualOrder.get(i));
+        }
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/MockApp.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/MockApp.java
new file mode 100644
index 0000000..123b66d
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/MockApp.java
@@ -0,0 +1,53 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy;
+
+import java.io.File;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+public class MockApp implements App
+{
+    public ContextHandler getContextHandler(DeploymentManager deployMgr)
+    {
+        return null;
+    }
+
+    public File getDir()
+    {
+        return null;
+    }
+
+    public String getId()
+    {
+        return "mock-app";
+    }
+
+    public String getName()
+    {
+        return "Mock App";
+    }
+
+    public String getOrigin()
+    {
+        return "Test Cases";
+    }
+
+    public File getWorkDir()
+    {
+        return null;
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/providers/ContextsDirAppProviderTest.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/providers/ContextsDirAppProviderTest.java
new file mode 100644
index 0000000..743edb9
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/providers/ContextsDirAppProviderTest.java
@@ -0,0 +1,75 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.providers;
+
+import org.eclipse.jetty.deploy.test.XmlConfiguredJetty;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ContextsDirAppProviderTest
+{
+    private static XmlConfiguredJetty jetty;
+
+    @BeforeClass
+    public static void setupEnvironment() throws Exception
+    {
+        jetty = new XmlConfiguredJetty();
+        jetty.addConfiguration("jetty.xml");
+        jetty.addConfiguration("jetty-deploymgr-contexts.xml");
+
+        // Should not throw an Exception
+        jetty.load();
+
+        // Start it
+        jetty.start();
+    }
+
+    @AfterClass
+    public static void teardownEnvironment() throws Exception
+    {
+        // Stop jetty.
+        jetty.stop();
+    }
+
+    @Test
+    public void testFindContext()
+    {
+        // Check Server for Handlers
+        Server server = jetty.getServer();
+        Handler handler = server.getHandler();
+        System.out.println("handler: " + handler);
+
+        if (handler instanceof HandlerCollection)
+        {
+            System.out.printf("Handler Collection (child-handlers:%s - handlers:%d)%n",((HandlerCollection)handler).getChildHandlers().length,
+                    ((HandlerCollection)handler).getHandlers().length);
+            System.out.println("is a HandlerCollection: " + ((HandlerCollection)handler).dump());
+        }
+
+        // TODO: verify that handler was created for context.
+    }
+
+    // TODO: write test that adds new app (after startup).
+
+    // TODO: write test that adds new app (after startup), then removes it from filesystem (resulting in removed from handlers).
+
+    // TODO: write test that adds new app (after startup), then updates it (redeploy).
+
+}
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/MavenTestingUtils.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/MavenTestingUtils.java
new file mode 100644
index 0000000..b8339c7
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/MavenTestingUtils.java
@@ -0,0 +1,219 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.test;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jetty.util.IO;
+
+/**
+ * Common utility methods for working with JUnit tests cases in a maven friendly way.
+ */
+public class MavenTestingUtils
+{
+    private static File basedir;
+    private static File testResourcesDir;
+    private static File targetDir;
+
+    // private static Boolean surefireRunning;
+
+    public static File getBasedir()
+    {
+        if (basedir == null)
+        {
+            String cwd = System.getProperty("basedir");
+
+            if (cwd == null)
+            {
+                cwd = System.getProperty("user.dir");
+            }
+
+            basedir = new File(cwd);
+        }
+
+        return basedir;
+    }
+
+    /**
+     * Get the directory to the /target directory for this project.
+     * 
+     * @return the directory path to the target directory.
+     */
+    public static File getTargetDir()
+    {
+        if (targetDir == null)
+        {
+            targetDir = new File(basedir,"target");
+            PathAssert.assertDirExists("Target Dir",targetDir);
+        }
+        return targetDir;
+    }
+
+    /**
+     * Create a {@link File} object for a path in the /target directory.
+     * 
+     * @param path
+     *            the path desired, no validation of existence is performed.
+     * @return the File to the path.
+     */
+    public static File getTargetFile(String path)
+    {
+        return new File(getTargetDir(),path.replace("/",File.separator));
+    }
+
+    public static File getTargetTestingDir()
+    {
+        File dir = new File(getTargetDir(),"testing");
+        if (!dir.exists())
+        {
+            dir.mkdirs();
+        }
+        return dir;
+    }
+
+    /**
+     * Get a dir in /target/ that uses the JUnit 3.x {@link TestCase#getName()} to make itself unique.
+     * 
+     * @param test
+     *            the junit 3.x testcase to base this new directory on.
+     * @return
+     */
+    public static File getTargetTestingDir(TestCase test)
+    {
+        return getTargetTestingDir(test.getName());
+    }
+
+    /**
+     * Get a dir in /target/ that uses the an arbitrary name.
+     * 
+     * @param testname
+     *            the testname to create directory against.
+     * @return
+     */
+    public static File getTargetTestingDir(String testname)
+    {
+        File dir = new File(getTargetDir(),"test-" + testname);
+        if (!dir.exists())
+        {
+            dir.mkdirs();
+        }
+        return dir;
+    }
+
+    /**
+     * Get a dir from the src/test/resource directory.
+     * 
+     * @param name
+     *            the name of the path to get (it must exist as a dir)
+     * @return the dir in src/test/resource
+     */
+    public static File getTestResourceDir(String name)
+    {
+        File dir = new File(getTestResourcesDir(),name);
+        PathAssert.assertDirExists("Test Resource Dir",dir);
+        return dir;
+    }
+
+    /**
+     * Get a file from the src/test/resource directory.
+     * 
+     * @param name
+     *            the name of the path to get (it must exist as a file)
+     * @return the file in src/test/resource
+     */
+    public static File getTestResourceFile(String name)
+    {
+        File file = new File(getTestResourcesDir(),name);
+        PathAssert.assertFileExists("Test Resource File",file);
+        return file;
+    }
+
+    /**
+     * Get a path resource (File or Dir) from the src/test/resource directory.
+     * 
+     * @param name
+     *            the name of the path to get (it must exist)
+     * @return the path in src/test/resource
+     */
+    public static File getTestResourcePath(String name)
+    {
+        File path = new File(getTestResourcesDir(),name);
+        PathAssert.assertExists("Test Resource Path",path);
+        return path;
+    }
+
+    /**
+     * Get the directory to the src/test/resource directory
+     * 
+     * @return the directory {@link File} to the src/test/resources directory
+     */
+    public static File getTestResourcesDir()
+    {
+        if (testResourcesDir == null)
+        {
+            testResourcesDir = new File(basedir,"src/test/resources".replace("/",File.separator));
+            PathAssert.assertDirExists("Test Resources Dir",testResourcesDir);
+        }
+        return testResourcesDir;
+    }
+
+    /**
+     * Read the contents of a file into a String and return it.
+     * 
+     * @param file
+     *            the file to read.
+     * @return the contents of the file.
+     * @throws IOException
+     *             if unable to read the file.
+     */
+    public static String readToString(File file) throws IOException
+    {
+        FileReader reader = null;
+        try
+        {
+            reader = new FileReader(file);
+            return IO.toString(reader);
+        }
+        finally
+        {
+            IO.close(reader);
+        }
+    }
+
+    /*
+    public static boolean isSurefireExecuting()
+    {
+        if (surefireRunning == null)
+        {
+            String val = System.getProperty("surefire.test.class.path");
+            if (val != null)
+            {
+                surefireRunning = Boolean.TRUE;
+            }
+            else
+            {
+                surefireRunning = Boolean.FALSE;
+            }
+        }
+        
+        return surefireRunning;
+    }
+    */
+}
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/PathAssert.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/PathAssert.java
new file mode 100644
index 0000000..7b4af5e
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/PathAssert.java
@@ -0,0 +1,40 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+package org.eclipse.jetty.deploy.test;
+
+import java.io.File;
+
+import junit.framework.Assert;
+
+public class PathAssert
+{
+    public static void assertDirExists(String msg, File path)
+    {
+        assertExists(msg,path);
+        Assert.assertTrue(msg + " path should be a Dir : " + path.getAbsolutePath(),path.isDirectory());
+    }
+
+    public static void assertFileExists(String msg, File path)
+    {
+        assertExists(msg,path);
+        Assert.assertTrue(msg + " path should be a File : " + path.getAbsolutePath(),path.isFile());
+    }
+
+    public static void assertExists(String msg, File path)
+    {
+        Assert.assertTrue(msg + " path should exist: " + path.getAbsolutePath(),path.exists());
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java
new file mode 100644
index 0000000..90fc9e4
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java
@@ -0,0 +1,215 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.deploy.test;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.jetty.http.HttpSchemes;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.xml.XmlConfiguration;
+import org.junit.Assert;
+
+/**
+ * Allows for setting up a Jetty server for testing based on XML configuration files.
+ */
+public class XmlConfiguredJetty
+{
+    private List<URL> xmlConfigurations;
+    private Properties properties = new Properties();
+    private Server server;
+    private int serverPort;
+    private String scheme = HttpSchemes.HTTP;
+
+    public XmlConfiguredJetty() throws IOException
+    {
+        String testname = new Throwable().getStackTrace()[1].getClassName();
+
+        xmlConfigurations = new ArrayList<URL>();
+        properties = new Properties();
+
+        File jettyHome = MavenTestingUtils.getTargetTestingDir(testname);
+        // Prepare Jetty.Home (Test) dir
+        jettyHome.mkdirs();
+
+        File logsDir = new File(jettyHome,"logs");
+        logsDir.mkdirs();
+
+        File etcDir = new File(jettyHome,"etc");
+        etcDir.mkdirs();
+        IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/realm.properties"),new File(etcDir,"realm.properties"));
+
+        File webappsDir = new File(jettyHome,"webapps");
+        webappsDir.mkdirs();
+        File tmpDir = new File(MavenTestingUtils.getTargetTestingDir(testname),"tmp");
+        tmpDir.mkdirs();
+
+        // Setup properties
+        System.setProperty("java.io.tmpdir",tmpDir.getAbsolutePath());
+        properties.setProperty("jetty.home",jettyHome.getAbsolutePath());
+        System.setProperty("jetty.home",jettyHome.getAbsolutePath());
+        properties.setProperty("test.basedir",MavenTestingUtils.getBasedir().getAbsolutePath());
+        properties.setProperty("test.resourcesdir",MavenTestingUtils.getTestResourcesDir().getAbsolutePath());
+        properties.setProperty("test.webapps",MavenTestingUtils.getTestResourceDir("webapps").getAbsolutePath());
+        properties.setProperty("test.targetdir",MavenTestingUtils.getTargetDir().getAbsolutePath());
+
+        // Write out configuration for use by ConfigurationManager.
+        File testConfig = MavenTestingUtils.getTargetFile("xml-configured-jetty.properties");
+        FileOutputStream out = new FileOutputStream(testConfig);
+        properties.store(out,"Generated by " + XmlConfiguredJetty.class.getName());
+    }
+
+    public void addConfiguration(File xmlConfigFile) throws MalformedURLException
+    {
+        xmlConfigurations.add(xmlConfigFile.toURI().toURL());
+    }
+
+    public void addConfiguration(String testConfigName) throws MalformedURLException
+    {
+        addConfiguration(MavenTestingUtils.getTestResourceFile(testConfigName));
+    }
+
+    public void addConfiguration(URL xmlConfig)
+    {
+        xmlConfigurations.add(xmlConfig);
+    }
+
+    public String getScheme()
+    {
+        return scheme;
+    }
+
+    public Server getServer()
+    {
+        return server;
+    }
+
+    public int getServerPort()
+    {
+        return serverPort;
+    }
+
+    public URI getServerURI() throws UnknownHostException
+    {
+        StringBuffer uri = new StringBuffer();
+        uri.append(this.scheme).append("://");
+        uri.append(InetAddress.getLocalHost().getHostAddress());
+        uri.append(":").append(this.serverPort);
+        return URI.create(uri.toString());
+    }
+
+    @SuppressWarnings("unchecked")
+    public void load() throws Exception
+    {
+        XmlConfiguration last = null;
+        Object[] obj = new Object[this.xmlConfigurations.size()];
+
+        // Configure everything
+        for (int i = 0; i < this.xmlConfigurations.size(); i++)
+        {
+            URL configURL = this.xmlConfigurations.get(i);
+            XmlConfiguration configuration = new XmlConfiguration(configURL);
+            if (last != null)
+            {
+                configuration.getIdMap().putAll(last.getIdMap());
+            }
+            configuration.setProperties(properties);
+            obj[i] = configuration.configure();
+            last = configuration;
+        }
+
+        // Test for Server Instance.
+        Server foundServer = null;
+        int serverCount = 0;
+        for (int i = 0; i < this.xmlConfigurations.size(); i++)
+        {
+            if (obj[i] instanceof Server)
+            {
+                if (obj[i].equals(foundServer))
+                {
+                    // Identical server instance found
+                    break;
+                }
+                foundServer = (Server)obj[i];
+                serverCount++;
+            }
+        }
+
+        if (serverCount <= 0)
+        {
+            throw new Exception("Load failed to configure a " + Server.class.getName());
+        }
+
+        Assert.assertEquals("Server load count",1,serverCount);
+
+        this.server = foundServer;
+        this.server.setGracefulShutdown(10);
+
+    }
+
+    public void setProperty(String key, String value)
+    {
+        properties.setProperty(key,value);
+    }
+
+    public void setScheme(String scheme)
+    {
+        this.scheme = scheme;
+    }
+
+    public void start() throws Exception
+    {
+        Assert.assertNotNull("Server should not be null (failed load?)",server);
+
+        server.start();
+
+        // Find the active server port.
+        this.serverPort = (-1);
+        Connector connectors[] = server.getConnectors();
+        for (int i = 0; i < connectors.length; i++)
+        {
+            Connector connector = connectors[i];
+            if (connector.getLocalPort() > 0)
+            {
+                this.serverPort = connector.getLocalPort();
+                break;
+            }
+        }
+
+        Assert.assertTrue("Server Port is between 1 and 65535. Actually <" + serverPort + ">",(1 <= this.serverPort) && (this.serverPort <= 65535));
+
+        // Uncomment to have server start and continue to run (without exiting)
+        // System.out.printf("Listening to port %d%n",this.serverPort);
+        // server.join();
+    }
+
+    public void stop() throws Exception
+    {
+        server.stop();
+    }
+}
diff --git a/jetty-deploy-manager-graph/src/test/resources/contexts/logcommon.xml b/jetty-deploy-manager-graph/src/test/resources/contexts/logcommon.xml
new file mode 100644
index 0000000..6da9c12
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/resources/contexts/logcommon.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"  encoding="ISO-8859-1"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Set name="contextPath">/logcommon</Set>
+    <Set name="war">
+        <Property name="test.webapps" default="." />/logcommon.war
+    </Set>
+</Configure>
diff --git a/jetty-deploy-manager-graph/src/test/resources/etc/realm.properties b/jetty-deploy-manager-graph/src/test/resources/etc/realm.properties
new file mode 100644
index 0000000..cbf905d
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/resources/etc/realm.properties
@@ -0,0 +1,21 @@
+#
+# This file defines users passwords and roles for a HashUserRealm
+#
+# The format is
+#  <username>: <password>[,<rolename> ...]
+#
+# Passwords may be clear text, obfuscated or checksummed.  The class 
+# org.eclipse.util.Password should be used to generate obfuscated
+# passwords or password checksums
+#
+# If DIGEST Authentication is used, the password must be in a recoverable
+# format, either plain text or OBF:.
+#
+jetty: MD5:164c88b302622e17050af52c89945d44,user
+admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin
+other: OBF:1xmk1w261u9r1w1c1xmq,user
+plain: plain,user
+user: password,user
+
+# This entry is for digest auth.  The credential is a MD5 hash of username:realmname:password
+digest: MD5:6e120743ad67abfbc385bc2bb754e297,user
diff --git a/jetty-deploy-manager-graph/src/test/resources/etc/webdefault.xml b/jetty-deploy-manager-graph/src/test/resources/etc/webdefault.xml
new file mode 100644
index 0000000..35a5a9b
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/resources/etc/webdefault.xml
@@ -0,0 +1,404 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!-- ===================================================================== -->
+<!-- This file contains the default descriptor for web applications.       -->
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<!-- The intent of this descriptor is to include jetty specific or common  -->
+<!-- configuration for all webapps.   If a context has a webdefault.xml    -->
+<!-- descriptor, it is applied before the contexts own web.xml file        -->
+<!--                                                                       -->
+<!-- A context may be assigned a default descriptor by:                    -->
+<!--  + Calling WebApplicationContext.setDefaultsDescriptor                -->
+<!--  + Passed an arg to addWebApplications                                -->
+<!--                                                                       -->
+<!-- This file is used both as the resource within the jetty.jar (which is -->
+<!-- used as the default if no explicit defaults descriptor is set) and it -->
+<!-- is copied to the etc directory of the Jetty distro and explicitly     -->
+<!-- by the jetty.xml file.                                                -->
+<!--                                                                       -->
+<!-- ===================================================================== -->
+<web-app 
+   xmlns="http://java.sun.com/xml/ns/javaee" 
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
+   metadata-complete="true"
+   version="2.5"> 
+
+  <description>
+    Default web.xml file.  
+    This file is applied to a Web application before it's own WEB_INF/web.xml file
+  </description>
+
+
+  <!-- ==================================================================== -->
+  <!-- Context params to control Session Cookies                            -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!-- UNCOMMENT TO ACTIVATE
+  <context-param>
+    <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
+    <param-value>127.0.0.1</param-value>
+  </context-param>
+
+  <context-param>
+    <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
+    <param-value>/</param-value>
+  </context-param>
+
+  <context-param>
+    <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
+    <param-value>-1</param-value>
+  </context-param>
+  -->
+
+
+  <!-- ==================================================================== -->
+  <!-- The default servlet.                                                 -->
+  <!-- This servlet, normally mapped to /, provides the handling for static -->
+  <!-- content, OPTIONS and TRACE methods for the context.                  -->
+  <!-- The following initParameters are supported:                          -->
+  <!--                                                                      -->
+  <!--   acceptRanges     If true, range requests and responses are         -->
+  <!--                    supported                                         -->
+  <!--                                                                      -->
+  <!--   dirAllowed       If true, directory listings are returned if no    -->
+  <!--                    welcome file is found. Else 403 Forbidden.        -->
+  <!--                                                                      -->
+  <!--   welcomeServlets  If true, attempt to dispatch to welcome files     -->
+  <!--                    that are servlets, if no matching static          -->
+  <!--                    resources can be found.                           -->
+  <!--                                                                      -->
+  <!--   redirectWelcome  If true, redirect welcome file requests           -->
+  <!--                    else use request dispatcher forwards              -->
+  <!--                                                                      -->
+  <!--   gzip             If set to true, then static content will be served--> 
+  <!--                    as gzip content encoded if a matching resource is -->
+  <!--                    found ending with ".gz"                           -->
+  <!--                                                                      -->
+  <!--   resoureBase      Can be set to replace the context resource base   -->
+  <!--                                                                      -->
+  <!--   relativeResourceBase                                               -->
+  <!--                    Set with a pathname relative to the base of the   -->
+  <!--                    servlet context root. Useful for only serving     -->
+  <!--                    static content from only specific subdirectories. -->
+  <!--                                                                      -->
+  <!--   useFileMappedBuffer                                                -->
+  <!--                    If set to true (the default), a  memory mapped    -->
+  <!--                    file buffer will be used to serve static content  -->
+  <!--                    when using an NIO connector. Setting this value   -->
+  <!--                    to false means that a direct buffer will be used  -->
+  <!--                    instead. If you are having trouble with Windows   -->
+  <!--                    file locking, set this to false.                  -->
+  <!--                                                                      -->
+  <!--  cacheControl      If set, all static content will have this value   -->
+  <!--                    set as the cache-control header.                  -->
+  <!--                                                                      -->
+  <!--  maxCacheSize      Maximum size of the static resource cache         -->
+  <!--                                                                      -->
+  <!--  maxCachedFileSize Maximum size of any single file in the cache      -->
+  <!--                                                                      -->
+  <!--  maxCachedFiles    Maximum number of files in the cache              -->
+  <!--                                                                      -->
+  <!--  cacheType         "nio", "bio" or "both" to determine the type(s)   -->
+  <!--                    of resource cache. A bio cached buffer may be used-->
+  <!--                    by nio but is not as efficient as a nio buffer.   -->
+  <!--                    An nio cached buffer may not be used by bio.      -->
+  <!--                                                                      -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <servlet>
+    <servlet-name>default</servlet-name>
+    <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
+    <init-param>
+      <param-name>acceptRanges</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>dirAllowed</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>welcomeServlets</param-name>
+ 	    <param-value>false</param-value>
+ 	  </init-param>
+    <init-param>
+      <param-name>redirectWelcome</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>maxCacheSize</param-name>
+      <param-value>256000000</param-value>
+    </init-param>
+    <init-param>
+      <param-name>maxCachedFileSize</param-name>
+      <param-value>10000000</param-value>
+    </init-param>
+    <init-param>
+      <param-name>maxCachedFiles</param-name>
+      <param-value>1000</param-value>
+    </init-param>
+    <init-param>
+      <param-name>cacheType</param-name>
+      <param-value>both</param-value>
+    </init-param>
+    <init-param>
+      <param-name>gzip</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>useFileMappedBuffer</param-name>
+      <param-value>true</param-value>
+    </init-param>  
+    <!--
+    <init-param>
+      <param-name>cacheControl</param-name>
+      <param-value>max-age=3600,public</param-value>
+    </init-param>
+    -->
+    <load-on-startup>0</load-on-startup>
+  </servlet> 
+
+  <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
+  
+
+  <!-- ==================================================================== -->
+  <!-- JSP Servlet                                                          -->
+  <!-- This is the jasper JSP servlet from the jakarta project              -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!-- The JSP page compiler and execution servlet, which is the mechanism  -->
+  <!-- used by Glassfish to support JSP pages.  Traditionally, this servlet -->
+  <!-- is mapped to URL patterh "*.jsp".  This servlet supports the         -->
+  <!-- following initialization parameters (default values are in square    -->
+  <!-- brackets):                                                           -->
+  <!--                                                                      -->
+  <!--   checkInterval       If development is false and reloading is true, -->
+  <!--                       background compiles are enabled. checkInterval -->
+  <!--                       is the time in seconds between checks to see   -->
+  <!--                       if a JSP page needs to be recompiled. [300]    -->
+  <!--                                                                      -->
+  <!--   compiler            Which compiler Ant should use to compile JSP   -->
+  <!--                       pages.  See the Ant documenation for more      -->
+  <!--                       information. [javac]                           -->
+  <!--                                                                      -->
+  <!--   classdebuginfo      Should the class file be compiled with         -->
+  <!--                       debugging information?  [true]                 -->
+  <!--                                                                      -->
+  <!--   classpath           What class path should I use while compiling   -->
+  <!--                       generated servlets?  [Created dynamically      -->
+  <!--                       based on the current web application]          -->
+  <!--                       Set to ? to make the container explicitly set  -->
+  <!--                       this parameter.                                -->
+  <!--                                                                      -->
+  <!--   development         Is Jasper used in development mode (will check -->
+  <!--                       for JSP modification on every access)?  [true] -->
+  <!--                                                                      -->
+  <!--   enablePooling       Determines whether tag handler pooling is      -->
+  <!--                       enabled  [true]                                -->
+  <!--                                                                      -->
+  <!--   fork                Tell Ant to fork compiles of JSP pages so that -->
+  <!--                       a separate JVM is used for JSP page compiles   -->
+  <!--                       from the one Tomcat is running in. [true]      -->
+  <!--                                                                      -->
+  <!--   ieClassId           The class-id value to be sent to Internet      -->
+  <!--                       Explorer when using <jsp:plugin> tags.         -->
+  <!--                       [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93]   -->
+  <!--                                                                      -->
+  <!--   javaEncoding        Java file encoding to use for generating java  -->
+  <!--                       source files. [UTF-8]                          -->
+  <!--                                                                      -->
+  <!--   keepgenerated       Should we keep the generated Java source code  -->
+  <!--                       for each page instead of deleting it? [true]   -->
+  <!--                                                                      -->
+  <!--   logVerbosityLevel   The level of detailed messages to be produced  -->
+  <!--                       by this servlet.  Increasing levels cause the  -->
+  <!--                       generation of more messages.  Valid values are -->
+  <!--                       FATAL, ERROR, WARNING, INFORMATION, and DEBUG. -->
+  <!--                       [WARNING]                                      -->
+  <!--                                                                      -->
+  <!--   mappedfile          Should we generate static content with one     -->
+  <!--                       print statement per input line, to ease        -->
+  <!--                       debugging?  [false]                            -->
+  <!--                                                                      -->
+  <!--                                                                      -->
+  <!--   reloading           Should Jasper check for modified JSPs?  [true] -->
+  <!--                                                                      -->
+  <!--   suppressSmap        Should the generation of SMAP info for JSR45   -->
+  <!--                       debugging be suppressed?  [false]              -->
+  <!--                                                                      -->
+  <!--   dumpSmap            Should the SMAP info for JSR45 debugging be    -->
+  <!--                       dumped to a file? [false]                      -->
+  <!--                       False if suppressSmap is true                  -->
+  <!--                                                                      -->
+  <!--   scratchdir          What scratch directory should we use when      -->
+  <!--                       compiling JSP pages?  [default work directory  -->
+  <!--                       for the current web application]               -->
+  <!--                                                                      -->
+  <!--   tagpoolMaxSize      The maximum tag handler pool size  [5]         -->
+  <!--                                                                      -->
+  <!--   xpoweredBy          Determines whether X-Powered-By response       -->
+  <!--                       header is added by generated servlet  [false]  -->
+  <!--                                                                      -->
+  <!-- If you wish to use Jikes to compile JSP pages:                       -->
+  <!--   Set the init parameter "compiler" to "jikes".  Define              -->
+  <!--   the property "-Dbuild.compiler.emacs=true" when starting Jetty     -->
+  <!--   to cause Jikes to emit error messages in a format compatible with  -->
+  <!--   Jasper.                                                            -->
+  <!--   If you get an error reporting that jikes can't use UTF-8 encoding, -->
+  <!--   try setting the init parameter "javaEncoding" to "ISO-8859-1".     -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <servlet id="jsp">
+    <servlet-name>jsp</servlet-name>
+    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+    <init-param>
+        <param-name>logVerbosityLevel</param-name>
+        <param-value>DEBUG</param-value>
+    </init-param>
+    <init-param>
+        <param-name>fork</param-name>
+        <param-value>false</param-value>
+    </init-param>
+    <init-param>
+        <param-name>xpoweredBy</param-name>
+        <param-value>false</param-value>
+    </init-param>
+    <!--  
+    <init-param>
+        <param-name>classpath</param-name>
+        <param-value>?</param-value>
+    </init-param>
+    -->
+    <load-on-startup>0</load-on-startup>
+  </servlet>
+
+  <servlet-mapping> 
+    <servlet-name>jsp</servlet-name> 
+    <url-pattern>*.jsp</url-pattern> 
+    <url-pattern>*.jspf</url-pattern>
+    <url-pattern>*.jspx</url-pattern>
+    <url-pattern>*.xsp</url-pattern>
+    <url-pattern>*.JSP</url-pattern> 
+    <url-pattern>*.JSPF</url-pattern>
+    <url-pattern>*.JSPX</url-pattern>
+    <url-pattern>*.XSP</url-pattern>
+  </servlet-mapping>
+  
+  <!-- ==================================================================== -->
+  <!-- Dynamic Servlet Invoker.                                             -->
+  <!-- This servlet invokes anonymous servlets that have not been defined   -->
+  <!-- in the web.xml or by other means. The first element of the pathInfo  -->
+  <!-- of a request passed to the envoker is treated as a servlet name for  -->
+  <!-- an existing servlet, or as a class name of a new servlet.            -->
+  <!-- This servlet is normally mapped to /servlet/*                        -->
+  <!-- This servlet support the following initParams:                       -->
+  <!--                                                                      -->
+  <!--  nonContextServlets       If false, the invoker can only load        -->
+  <!--                           servlets from the contexts classloader.    -->
+  <!--                           This is false by default and setting this  -->
+  <!--                           to true may have security implications.    -->
+  <!--                                                                      -->
+  <!--  verbose                  If true, log dynamic loads                 -->
+  <!--                                                                      -->
+  <!--  *                        All other parameters are copied to the     -->
+  <!--                           each dynamic servlet as init parameters    -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!-- Uncomment for dynamic invocation
+  <servlet>
+    <servlet-name>invoker</servlet-name>
+    <servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class>
+    <init-param>
+      <param-name>verbose</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>nonContextServlets</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>dynamicParam</param-name>
+      <param-value>anyValue</param-value>
+    </init-param>
+    <load-on-startup>0</load-on-startup>
+  </servlet>
+
+  <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping>
+  -->
+
+
+
+  <!-- ==================================================================== -->
+  <session-config>
+    <session-timeout>30</session-timeout>
+  </session-config>
+
+  <!-- ==================================================================== -->
+  <!-- Default MIME mappings                                                -->
+  <!-- The default MIME mappings are provided by the mime.properties        -->
+  <!-- resource in the org.eclipse.jetty.server.jar file.  Additional or modified  -->
+  <!-- mappings may be specified here                                       -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!-- UNCOMMENT TO ACTIVATE
+  <mime-mapping>
+    <extension>mysuffix</extension>
+    <mime-type>mymime/type</mime-type>
+  </mime-mapping>
+  -->
+
+  <!-- ==================================================================== -->
+  <welcome-file-list>
+    <welcome-file>index.html</welcome-file>
+    <welcome-file>index.htm</welcome-file>
+    <welcome-file>index.jsp</welcome-file>
+  </welcome-file-list>
+
+  <!-- ==================================================================== -->
+  <locale-encoding-mapping-list>
+    <locale-encoding-mapping><locale>ar</locale><encoding>ISO-8859-6</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>be</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>bg</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ca</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>cs</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>da</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>de</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>el</locale><encoding>ISO-8859-7</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>en</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>es</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>et</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>fi</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>fr</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>hr</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>hu</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>is</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>it</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>iw</locale><encoding>ISO-8859-8</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ja</locale><encoding>Shift_JIS</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ko</locale><encoding>EUC-KR</encoding></locale-encoding-mapping>     
+    <locale-encoding-mapping><locale>lt</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>lv</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>mk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>nl</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>no</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>pl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>pt</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ro</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ru</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sh</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sk</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sq</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sr</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sv</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>tr</locale><encoding>ISO-8859-9</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>uk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>zh</locale><encoding>GB2312</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>zh_TW</locale><encoding>Big5</encoding></locale-encoding-mapping>   
+  </locale-encoding-mapping-list>
+  
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>Disable TRACE</web-resource-name>
+      <url-pattern>/</url-pattern>
+      <http-method>TRACE</http-method>
+    </web-resource-collection>
+    <auth-constraint/>
+  </security-constraint>
+  
+</web-app>
+
diff --git a/jetty-deploy-manager-graph/src/test/resources/jetty-deploymgr-contexts.xml b/jetty-deploy-manager-graph/src/test/resources/jetty-deploymgr-contexts.xml
new file mode 100644
index 0000000..e917ca9
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/resources/jetty-deploymgr-contexts.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <Call name="addLifeCycle">
+    <Arg>
+      <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
+        <Set name="contexts">
+          <Ref id="Contexts" />
+        </Set>
+        <Set name="configurationManager">
+          <New class="org.eclipse.jetty.deploy.support.FileConfigurationManager">
+            <Set name="file">
+              <Property name="test.targetdir" default="target" />/xml-configured-jetty.properties
+            </Set>
+          </New>
+        </Set>
+        
+        <!-- Lifecycle Bindings -->
+        <Call name="addLifecycleBinding">
+          <Arg>
+            <New class="org.eclipse.jetty.deploy.bindings.DefaultDeployer" />
+          </Arg>
+        </Call>
+        <Call name="addLifecycleBinding">
+          <Arg>
+            <New class="org.eclipse.jetty.deploy.bindings.DefaultUndeployer" />
+          </Arg>
+        </Call>
+        <Call name="addLifecycleBinding">
+          <Arg>
+            <New class="org.eclipse.jetty.deploy.bindings.DefaultStarter" />
+          </Arg>
+        </Call>
+        <Call name="addLifecycleBinding">
+          <Arg>
+            <New class="org.eclipse.jetty.deploy.bindings.DefaultStopper" />
+          </Arg>
+        </Call>
+
+        <!-- Providers of Apps -->
+        <Call name="addAppProvider">
+          <Arg>
+            <New class="org.eclipse.jetty.deploy.providers.ContextsDirAppProvider">
+              <Set name="contextsDir">
+                <Property name="test.resourcesdir" default="src/test/resources" />/contexts
+              </Set>
+              <Set name="scanInterval">0</Set>
+              <Set name="recursive">false</Set>
+            </New>
+          </Arg>
+        </Call>
+
+      </New>
+    </Arg>
+  </Call>
+
+</Configure>
diff --git a/jetty-deploy-manager-graph/src/test/resources/jetty.xml b/jetty-deploy-manager-graph/src/test/resources/jetty.xml
new file mode 100644
index 0000000..d0cb501
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/resources/jetty.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+
+<!-- =============================================================== -->
+<!-- Configure the Jetty Server                                      -->
+<!--                                                                 -->
+<!-- Documentation of this file format can be found at:              -->
+<!-- http://docs.codehaus.org/display/JETTY/jetty.xml                -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+    <!-- =========================================================== -->
+    <!-- Server Thread Pool                                          -->
+    <!-- =========================================================== -->
+    <Set name="ThreadPool">
+      <!-- Default queued blocking threadpool 
+      -->
+      <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
+        <Set name="minThreads">10</Set>
+        <Set name="maxThreads">200</Set>
+      </New>
+
+      <!-- Optional Java 5 bounded threadpool with job queue 
+      <New class="org.eclipse.thread.concurrent.ThreadPool">
+        <Set name="corePoolSize">50</Set>
+        <Set name="maximumPoolSize">50</Set>
+      </New>
+      -->
+    </Set>
+
+    <!-- =========================================================== -->
+    <!-- Set connectors                                              -->
+    <!-- =========================================================== -->
+
+    <Call name="addConnector">
+      <Arg>
+          <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
+            <Set name="host"></Set>
+            <Set name="port">0</Set>
+            <Set name="maxIdleTime">300000</Set>
+            <Set name="Acceptors">2</Set>
+            <Set name="statsOn">false</Set>
+            <Set name="confidentialPort">8443</Set>
+        <Set name="lowResourcesConnections">20000</Set>
+        <Set name="lowResourcesMaxIdleTime">5000</Set>
+          </New>
+      </Arg>
+    </Call>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <!-- To add a HTTPS SSL connector                                    -->
+    <!-- mixin jetty-ssl.xml:                                            -->
+    <!--   java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml           -->
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <!-- To add a HTTP blocking connector                                -->
+    <!-- mixin jetty-bio.xml:                                            -->
+    <!--   java -jar start.jar etc/jetty.xml etc/jetty-bio.xml           -->
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+    <!-- To allow Jetty to be started from xinetd                        -->
+    <!-- mixin jetty-xinetd.xml:                                         -->
+    <!--   java -jar start.jar etc/jetty.xml etc/jetty-xinetd.xml        -->
+    <!--                                                                 -->
+    <!-- See jetty-xinetd.xml for further instructions.                  -->
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <!-- =========================================================== -->
+    <!-- Set handler Collection Structure                            --> 
+    <!-- =========================================================== -->
+    <Set name="handler">
+      <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
+        <Set name="handlers">
+         <Array type="org.eclipse.jetty.server.Handler">
+           <Item>
+             <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
+           </Item>
+           <Item>
+             <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
+           </Item>
+           <Item>
+             <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
+           </Item>
+         </Array>
+        </Set>
+      </New>
+    </Set>
+    
+    <!-- =========================================================== -->
+    <!-- Configure Authentication Login Service                      -->
+    <!-- Realms may be configured for the entire server here, or     -->
+    <!-- they can be configured for a specific web app in a context  -->
+    <!-- configuration (see $(jetty.home)/contexts/test.xml for an   -->
+    <!-- example).                                                   -->
+    <!-- =========================================================== -->
+    <Call name="addBean">
+      <Arg>
+        <New class="org.eclipse.jetty.security.HashLoginService">
+          <Set name="name">Test Realm</Set>
+          <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
+          <Set name="refreshInterval">0</Set>
+        </New>
+      </Arg>
+    </Call>
+
+    <!-- =========================================================== -->
+    <!-- Configure Request Log                                       -->
+    <!-- Request logs  may be configured for the entire server here, -->
+    <!-- or they can be configured for a specific web app in a       -->
+    <!-- contexts configuration (see $(jetty.home)/contexts/test.xml -->
+    <!-- for an example).                                            -->
+    <!-- =========================================================== -->
+    <Ref id="RequestLog">
+      <Set name="requestLog">
+        <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
+          <Set name="filename"><SystemProperty name="jetty.home" default="."/>/logs/yyyy_mm_dd.request.log</Set>
+          <Set name="filenameDateFormat">yyyy_MM_dd</Set>
+          <Set name="retainDays">90</Set>
+          <Set name="append">true</Set>
+          <Set name="extended">false</Set>
+          <Set name="logCookies">false</Set>
+          <Set name="LogTimeZone">GMT</Set>
+        </New>
+      </Set>
+    </Ref>
+
+    <!-- =========================================================== -->
+    <!-- extra options                                               -->
+    <!-- =========================================================== -->
+    <Set name="stopAtShutdown">true</Set>
+    <Set name="sendServerVersion">true</Set>
+    <Set name="sendDateHeader">true</Set>
+    <Set name="gracefulShutdown">1000</Set>
+
+</Configure>
diff --git a/jetty-deploy-manager-graph/src/test/resources/webapps/logcommon.war b/jetty-deploy-manager-graph/src/test/resources/webapps/logcommon.war
new file mode 100644
index 0000000..bac25eb
--- /dev/null
+++ b/jetty-deploy-manager-graph/src/test/resources/webapps/logcommon.war
Binary files differ