Merge branch 'release-9.3.7' into jetty-9.3.x
diff --git a/jetty-distribution/src/main/resources/bin/jetty.sh b/jetty-distribution/src/main/resources/bin/jetty.sh
index 21c2c97..9dd1a49 100755
--- a/jetty-distribution/src/main/resources/bin/jetty.sh
+++ b/jetty-distribution/src/main/resources/bin/jetty.sh
@@ -527,6 +527,7 @@
 
   restart)
     JETTY_SH=$0
+    > "$JETTY_STATE"
     if [ ! -f $JETTY_SH ]; then
       if [ ! -f $JETTY_HOME/bin/jetty.sh ]; then
         echo "$JETTY_HOME/bin/jetty.sh does not exist."
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java
new file mode 100644
index 0000000..8494386
--- /dev/null
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java
@@ -0,0 +1,157 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 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.quickstart;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Path;
+
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+
+/**
+ * Normalize Attribute to String.
+ * <p>Replaces and expands:
+ * <ul>
+ * <li>${WAR}</li>
+ * <li>${jetty.base}</li>
+ * <li>${jetty.home}</li>
+ * <li>${user.home}</li>
+ * <li>${user.dir}</li>
+ * </ul>
+ */
+public class AttributeNormalizer
+{
+    private static final Logger LOG = Log.getLogger(AttributeNormalizer.class);
+    private final Path _warPath;
+    private final Path _jettyBasePath;
+    private final Path _jettyHomePath;
+    private final Path _userHomePath;
+    private final Path _userDirPath;
+    
+    
+    public AttributeNormalizer(Resource baseResource)
+    {
+        try
+        {
+            _warPath=baseResource==null?null:baseResource.getFile().toPath();
+            _jettyBasePath=systemPath("jetty.base");
+            _jettyHomePath=systemPath("jetty.home");
+            _userHomePath=systemPath("user.home");
+            _userDirPath=systemPath("user.dir");
+        }
+        catch(Exception e)
+        {
+            throw new IllegalArgumentException(e);
+        }
+    }
+    
+    private static Path systemPath(String property) throws Exception
+    {
+        String p=System.getProperty(property);
+        if (p!=null)
+            return new File(p).getAbsoluteFile().getCanonicalFile().toPath();
+        return null;
+    }
+   
+    public String normalize(Object o)
+    {
+        try
+        {
+            // Find a URI
+            URI uri=null;
+            if (o instanceof URI)
+                uri=(URI)o;
+            else if (o instanceof URL)
+                uri = ((URL)o).toURI();
+            else if (o instanceof File)
+                uri = ((File)o).toURI();
+            else
+            {
+                String s=o.toString();
+                uri=new URI(s);
+                if (uri.getScheme()==null)
+                    return s;
+            }
+            
+            if ("jar".equalsIgnoreCase(uri.getScheme()))
+            {
+                String raw = uri.getRawSchemeSpecificPart();
+                int bang=raw.indexOf("!/");
+                String normal=normalize(raw.substring(0,bang));
+                String suffix=raw.substring(bang);
+                return "jar:"+normal+suffix;
+            }
+            else if ("file".equalsIgnoreCase(uri.getScheme()))
+            {
+                return "file:"+normalizePath(new File(uri).toPath());
+            }
+            
+        }
+        catch(Exception e)
+        {
+            LOG.warn(e);
+        }
+        return String.valueOf(o);
+    }
+    
+    public String normalizePath(Path path)
+    {
+        if (_warPath!=null && path.startsWith(_warPath))
+            return URIUtil.addPaths("${WAR}",_warPath.relativize(path).toString());
+        if (_jettyBasePath!=null && path.startsWith(_jettyBasePath))
+            return URIUtil.addPaths("${jetty.base}",_jettyBasePath.relativize(path).toString());
+        if (_jettyHomePath!=null && path.startsWith(_jettyHomePath))
+            return URIUtil.addPaths("${jetty.home}",_jettyHomePath.relativize(path).toString());
+        if (_userHomePath!=null && path.startsWith(_userHomePath))
+            return URIUtil.addPaths("${user.home}",_userHomePath.relativize(path).toString());
+        if (_userDirPath!=null && path.startsWith(_userDirPath))
+            return URIUtil.addPaths("${user.dir}",_userDirPath.relativize(path).toString());
+        
+        return path.toString();
+    }
+    
+    
+    public String expand(String s)
+    {
+        int i=s.indexOf("${");
+        if (i<0)
+            return s;
+        int e=s.indexOf('}',i+3);
+        String prop=s.substring(i+2,e);
+        switch(prop)
+        {
+            case "WAR":
+                return s.substring(0,i)+_warPath+expand(s.substring(e+1));
+            case "jetty.base":
+                return s.substring(0,i)+_jettyBasePath+expand(s.substring(e+1));
+            case "jetty.home":
+                return s.substring(0,i)+_jettyHomePath+expand(s.substring(e+1));
+            case "user.home":
+                return s.substring(0,i)+_userHomePath+expand(s.substring(e+1));
+            case "user.dir":
+                return s.substring(0,i)+_userDirPath+expand(s.substring(e+1));
+            default:
+                return s;
+        }
+    }
+}
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java
index 5db988d..34c4012 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java
@@ -22,6 +22,9 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EventListener;
@@ -55,6 +58,7 @@
 import org.eclipse.jetty.util.QuotedStringTokenizer;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.security.Constraint;
 import org.eclipse.jetty.webapp.MetaData;
 import org.eclipse.jetty.webapp.MetaData.OriginInfo;
@@ -128,16 +132,16 @@
         // Set some special context parameters
 
         // The location of the war file on disk
-        String resourceBase = _webApp.getBaseResource().getFile().getCanonicalFile().getAbsoluteFile().toURI().toString();
+        AttributeNormalizer normalizer = new AttributeNormalizer(_webApp.getBaseResource());
 
         // The library order
         addContextParamFromAttribute(out,ServletContext.ORDERED_LIBS);
         //the servlet container initializers
         addContextParamFromAttribute(out,AnnotationConfiguration.CONTAINER_INITIALIZERS);
         //the tlds discovered
-        addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_TLDS,resourceBase);
+        addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_TLDS,normalizer);
         //the META-INF/resources discovered
-        addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_RESOURCES,resourceBase);
+        addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_RESOURCES,normalizer);
 
 
         // init params
@@ -515,7 +519,27 @@
      */
     private void addContextParamFromAttribute(XmlAppendable out, String attribute) throws IOException
     {
-        addContextParamFromAttribute(out,attribute,null);
+        Object o = _webApp.getAttribute(attribute);
+        if (o == null)
+            return;
+                
+        Collection<?> c =  (o instanceof Collection)? (Collection<?>)o:Collections.singletonList(o);
+        StringBuilder v=new StringBuilder();
+        for (Object i:c)
+        {
+            if (i!=null)
+            {
+                if (v.length()>0)
+                    v.append(",\n    ");
+                else
+                    v.append("\n    ");
+                QuotedStringTokenizer.quote(v,i.toString());
+            }
+        }
+        out.openTag("context-param")
+        .tag("param-name",attribute)
+        .tagCDATA("param-value",v.toString())
+        .closeTag();        
     }
     
     /**
@@ -526,7 +550,7 @@
      * @param resourceBase
      * @throws IOException
      */
-    private void addContextParamFromAttribute(XmlAppendable out, String attribute, String resourceBase) throws IOException
+    private void addContextParamFromAttribute(XmlAppendable out, String attribute, AttributeNormalizer normalizer) throws IOException
     {
         Object o = _webApp.getAttribute(attribute);
         if (o == null)
@@ -542,16 +566,14 @@
                     v.append(",\n    ");
                 else
                     v.append("\n    ");
-                if (resourceBase==null)
-                    QuotedStringTokenizer.quote(v,i.toString());
-                else
-                    QuotedStringTokenizer.quote(v,i.toString().replace(resourceBase,"${WAR}/"));
+                QuotedStringTokenizer.quote(v,normalizer.normalize(i));
             }
         }
         out.openTag("context-param")
         .tag("param-name",attribute)
         .tagCDATA("param-value",v.toString())
-        .closeTag();        
+        .closeTag();  
+        
     }
 
     /**
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java
index 924b0dd..35d41ea 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java
@@ -99,6 +99,7 @@
                 values.add(value);
         }
 
+        AttributeNormalizer normalizer = new AttributeNormalizer(context.getBaseResource());
         // handle values
         switch(name)
         {
@@ -125,15 +126,14 @@
             case MetaInfConfiguration.METAINF_TLDS:
             {
                 List<Object> tlds = new ArrayList<>();
-                String war=context.getBaseResource().getURI().toString();
                 Object o=context.getAttribute(MetaInfConfiguration.METAINF_TLDS);
                 if (o instanceof Collection<?>)
                     tlds.addAll((Collection<?>)o);
                 for (String i : values)
                 {
-                    Resource r = Resource.newResource(i.replace("${WAR}/",war));
+                    Resource r = Resource.newResource(normalizer.expand(i));
                     if (r.exists())
-                        tlds.add(r.getURL());
+                        tlds.add(r.getURI().toURL());
                     else
                         throw new IllegalArgumentException("TLD not found: "+r);                    
                 }
@@ -145,10 +145,9 @@
             
             case MetaInfConfiguration.METAINF_RESOURCES:
             {
-                String war=context.getBaseResource().getURI().toString();
                 for (String i : values)
                 {
-                    Resource r = Resource.newResource(i.replace("${WAR}/",war));
+                    Resource r = Resource.newResource(normalizer.expand(i));
                     if (r.exists())
                         visitMetaInfResource(context,r); 
                     else
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java
index a54cac0..68e5227 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java
@@ -182,8 +182,13 @@
             _saveTask=null;
             if (_task!=null)
                 _task.cancel();
-
+            
             _task=null;
+            
+            //if we're managing our own timer, remove it
+            if (isManaged(_timer))
+               removeBean(_timer);
+
             _timer=null;
         }
        
@@ -192,7 +197,6 @@
         super.doStop();
 
         _sessions.clear();
-
     }
 
     /* ------------------------------------------------------------ */
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
index 57ff712..586445c 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
@@ -235,7 +235,20 @@
         response.addHeader("Content-Type","application/json");
         response.getWriter();
         assertEquals("application/json",response.getContentType());
+    }
 
+    @Test
+    public void testStrangeContentType() throws Exception
+    {
+        Response response = newResponse();
+
+        assertEquals(null, response.getContentType());
+
+        response.recycle();
+        response.setContentType("text/html;charset=utf-8;charset=UTF-8");
+        response.getWriter();
+        assertEquals("text/html;charset=utf-8;charset=UTF-8",response.getContentType());
+        assertEquals("utf-8",response.getCharacterEncoding().toLowerCase());
     }
 
     @Test
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java
index c1ad7da..d776f40 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java
@@ -25,6 +25,7 @@
 import org.eclipse.jetty.toolchain.test.FS;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.thread.Scheduler;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -80,7 +81,25 @@
         Server server = new Server();
         SessionHandler handler = new SessionHandler();
         handler.setServer(server);
-        HashSessionManager manager = new HashSessionManager();
+        HashSessionManager manager = new HashSessionManager()
+        {
+            @Override
+            public void doStart() throws Exception
+            {
+                super.doStart();
+                Scheduler timerBean = getBean(Scheduler.class);
+                Assert.assertNotNull(timerBean);
+            }
+
+            @Override
+            public void doStop() throws Exception
+            {
+                super.doStop();
+                Scheduler timerBean = getBean(Scheduler.class);
+                Assert.assertNull(timerBean);
+            }
+
+        };
         manager.setStoreDirectory(testDir);
         manager.setMaxInactiveInterval(5);
         Assert.assertTrue(testDir.exists());
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/PathWatcher.java b/jetty-util/src/main/java/org/eclipse/jetty/util/PathWatcher.java
index 1bc2762..335f30c 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/PathWatcher.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/PathWatcher.java
@@ -18,7 +18,9 @@
 
 package org.eclipse.jetty.util;
 
-import static java.nio.file.StandardWatchEventKinds.*;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
 
 import java.io.File;
 import java.io.IOException;
@@ -1244,7 +1246,7 @@
             LOG.debug("Starting java.nio file watching with {}",watchService);
         }
 
-        while (watchService != null)
+        while (watchService != null  && thread == Thread.currentThread())
         {
             WatchKey key = null;
 
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java
index 25418ee..392524c 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java
@@ -222,7 +222,7 @@
     @Test
     public void testAddPath() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         
         Path subdir = dir.resolve("sub");
         FS.ensureDirExists(subdir.toFile());
@@ -240,7 +240,7 @@
     @Test
     public void testAddRootPath() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Path subdir = dir.resolve("sub");
         Files.createDirectories(subdir);
 
@@ -288,7 +288,7 @@
     @Test
     public void testIsContainedIn() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         Path foo = dir.resolve("foo");
         Files.createFile(foo);
@@ -303,7 +303,7 @@
     @Test
     public void testIsDirectory() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         Path foo = dir.resolve("foo");
         Files.createFile(foo);
@@ -324,7 +324,7 @@
     @Test
     public void testLastModified() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         File file = testdir.getFile("foo");
         file.createNewFile();
 
@@ -340,7 +340,7 @@
     @Test
     public void testLastModified_NotExists() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         
         try (Resource base = newResource(dir.toFile()))
         {
@@ -352,7 +352,7 @@
     @Test
     public void testLength() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Path file = dir.resolve("foo");
@@ -375,7 +375,7 @@
     @Test
     public void testLength_NotExists() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         try (Resource base = newResource(dir.toFile()))
@@ -388,7 +388,7 @@
     @Test
     public void testDelete() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         Path file = dir.resolve("foo");
         Files.createFile(file);
@@ -408,7 +408,7 @@
     @Test
     public void testDelete_NotExists() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         try (Resource base = newResource(dir.toFile()))
@@ -426,7 +426,7 @@
     @Test
     public void testName() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         String expected = dir.toAbsolutePath().toString();
@@ -440,7 +440,7 @@
     @Test
     public void testInputStream() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Path file = dir.resolve("foo");
@@ -466,7 +466,7 @@
     @Test
     public void testReadableByteChannel() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
 
         Path file = dir.resolve("foo");
@@ -495,7 +495,7 @@
     @Test
     public void testGetURI() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
 
         Path file = dir.resolve("foo");
@@ -514,7 +514,7 @@
     @Test
     public void testGetURL() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
 
         Path file = dir.resolve("foo");
@@ -532,7 +532,7 @@
     @Test
     public void testList() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Files.createFile(dir.resolve("foo"));
@@ -561,7 +561,7 @@
     @Test
     public void testSymlink() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         
         Path foo = dir.resolve("foo");
         Path bar = dir.resolve("bar");
@@ -601,7 +601,7 @@
     @Test
     public void testNonExistantSymlink() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Path foo = dir.resolve("foo");
@@ -644,7 +644,7 @@
     @Test
     public void testCaseInsensitiveAlias() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         Path path = dir.resolve("file");
         Files.createFile(path);
@@ -681,7 +681,7 @@
     @Test
     public void testCase8dot3Alias() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Path path = dir.resolve("TextFile.Long.txt");
@@ -718,7 +718,7 @@
     @Test
     public void testNTFSFileStreamAlias() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
 
         Path path = dir.resolve("testfile");
@@ -761,7 +761,7 @@
     @Test
     public void testNTFSFileDataStreamAlias() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
 
         Path path = dir.resolve("testfile");
@@ -806,7 +806,7 @@
     @Test
     public void testNTFSFileEncodedDataStreamAlias() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
 
         Path path = dir.resolve("testfile");
@@ -843,7 +843,7 @@
     @Test
     public void testSemicolon() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         
         try
         {
@@ -868,7 +868,7 @@
     @Test
     public void testSingleQuote() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         try
@@ -894,7 +894,7 @@
     @Test
     public void testSingleBackTick() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         try
@@ -923,7 +923,7 @@
     @Test
     public void testBrackets() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         try
@@ -949,7 +949,7 @@
     @Test
     public void testBraces() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         try
@@ -978,7 +978,7 @@
     @Test
     public void testCaret() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         try
@@ -1007,7 +1007,7 @@
     @Test
     public void testPipe() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         try
@@ -1040,13 +1040,13 @@
     @Test
     public void testExist_Normal() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Path path = dir.resolve("a.jsp");
         Files.createFile(path);
 
-        URI ref = testdir.getDir().toURI().resolve("a.jsp");
+        URI ref = testdir.getPath().toUri().resolve("a.jsp");
         try (Resource fileres = newResource(ref))
         {
             assertThat("Resource: " + fileres,fileres.exists(),is(true));
@@ -1056,7 +1056,7 @@
     @Test
     public void testSingleQuoteInFileName() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Path fooA = dir.resolve("foo's.txt");
@@ -1121,7 +1121,7 @@
     @Test
     public void testExist_BadURINull() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Path path = dir.resolve("a.jsp");
@@ -1130,7 +1130,7 @@
         try
         {
             // request with null at end
-            URI uri = testdir.getDir().toURI().resolve("a.jsp%00");
+            URI uri = testdir.getPath().toUri().resolve("a.jsp%00");
             assertThat("Null URI",uri,notNullValue());
 
             Resource r = newResource(uri);
@@ -1147,7 +1147,7 @@
     @Test
     public void testExist_BadURINullX() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
         
         Path path = dir.resolve("a.jsp");
@@ -1156,7 +1156,7 @@
         try
         {
             // request with null and x at end
-            URI uri = testdir.getDir().toURI().resolve("a.jsp%00x");
+            URI uri = testdir.getPath().toUri().resolve("a.jsp%00x");
             assertThat("NullX URI",uri,notNullValue());
 
             Resource r = newResource(uri);
@@ -1173,7 +1173,7 @@
     @Test
     public void testEncoding() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Files.createDirectories(dir);
 
         Path specials = dir.resolve("a file with,spe#ials");
@@ -1192,7 +1192,7 @@
     @Test
     public void testUtf8Dir() throws Exception
     {
-        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path dir = testdir.getPath().normalize().toRealPath();
         Path utf8Dir = dir.resolve("bãm");
         Files.createDirectories(utf8Dir);
         
@@ -1209,4 +1209,6 @@
             assertThat("Alias: " + r,r,hasNoAlias());
         }
     }
+    
+    
 }
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java
index 13c30b7..87e4e76 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java
@@ -53,8 +53,6 @@
 import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
 import org.eclipse.jetty.websocket.client.WebSocketClient;
 import org.eclipse.jetty.websocket.client.io.UpgradeListener;
-import org.eclipse.jetty.websocket.common.SessionFactory;
-import org.eclipse.jetty.websocket.common.SessionListener;
 import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
 import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
@@ -73,7 +71,7 @@
  * <p>
  * This should be specific to a JVM if run in a standalone mode. or specific to a WebAppContext if running on the Jetty server.
  */
-public class ClientContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketContainerScope, SessionListener
+public class ClientContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketContainerScope
 {
     private static final Logger LOG = Log.getLogger(ClientContainer.class);
     
@@ -105,8 +103,7 @@
         this.scopeDelegate = scope;
         client = new WebSocketClient(scope, new SslContextFactory(trustAll));
         client.setEventDriverFactory(new JsrEventDriverFactory(client.getPolicy()));
-        SessionFactory sessionFactory = new JsrSessionFactory(this,this,client);
-        client.setSessionFactory(sessionFactory);
+        client.setSessionFactory(new JsrSessionFactory(this));
         addBean(client);
 
         this.endpointClientMetadataCache = new ConcurrentHashMap<>();
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java
index bb44774..82db0bd 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java
@@ -44,7 +44,6 @@
 import org.eclipse.jetty.websocket.api.BatchMode;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
-import org.eclipse.jetty.websocket.common.SessionListener;
 import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
 import org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver;
@@ -74,9 +73,9 @@
     private JsrAsyncRemote asyncRemote;
     private JsrBasicRemote basicRemote;
 
-    public JsrSession(ClientContainer container, String id, URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners)
+    public JsrSession(ClientContainer container, String id, URI requestURI, EventDriver websocket, LogicalConnection connection)
     {
-        super(container, requestURI, websocket, connection, sessionListeners);
+        super(container, requestURI, websocket, connection);
         if (!(websocket instanceof AbstractJsrEventDriver))
         {
             throw new IllegalArgumentException("Cannot use, not a JSR WebSocket: " + websocket);
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java
index f17734d..15cde46 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java
@@ -19,36 +19,32 @@
 package org.eclipse.jetty.websocket.jsr356;
 
 import java.net.URI;
-import java.util.concurrent.atomic.AtomicLong;
 
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
 import org.eclipse.jetty.websocket.common.SessionFactory;
-import org.eclipse.jetty.websocket.common.SessionListener;
 import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
 import org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver;
 
 public class JsrSessionFactory implements SessionFactory
 {
-    private AtomicLong idgen = new AtomicLong(0);
+    private static final Logger LOG = Log.getLogger(JsrSessionFactory.class);
     private final ClientContainer container;
-    private final SessionListener[] listeners;
 
-    public JsrSessionFactory(ClientContainer container, SessionListener... sessionListeners)
+    public JsrSessionFactory(ClientContainer container)
     {
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("Container: {}", container);
+        }
         this.container = container;
-        this.listeners = sessionListeners;
     }
 
     @Override
     public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
     {
-        return new JsrSession(container,getNextId(),requestURI,websocket,connection,listeners);
-    }
-
-    public String getNextId()
-    {
-        return String.format("websocket-%d",idgen.incrementAndGet());
+        return new JsrSession(container,connection.getId(),requestURI,websocket,connection);
     }
 
     @Override
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
index 2128e8e..8d114c3 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
@@ -30,6 +30,7 @@
 import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
 import org.eclipse.jetty.websocket.jsr356.ClientContainer;
 import org.eclipse.jetty.websocket.jsr356.JsrSessionFactory;
@@ -56,7 +57,7 @@
         EventDriverFactory eventDriverFactory = this.webSocketServerFactory.getEventDriverFactory();
         eventDriverFactory.addImplementation(new JsrServerEndpointImpl());
         eventDriverFactory.addImplementation(new JsrServerExtendsEndpointImpl());
-        this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this,this));
+        this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this));
         addBean(webSocketServerFactory);
     }
     
@@ -240,4 +241,16 @@
         // incoming streaming buffer size
         webSocketServerFactory.getPolicy().setMaxTextMessageBufferSize(max);
     }
+
+    @Override
+    public void onSessionClosed(WebSocketSession session)
+    {
+        webSocketServerFactory.onSessionClosed(session);
+    }
+
+    @Override
+    public void onSessionOpened(WebSocketSession session)
+    {
+        webSocketServerFactory.onSessionOpened(session);
+    }
 }
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java
index f98c536..9e1090f 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java
@@ -23,6 +23,8 @@
 
 import javax.servlet.ServletContainerInitializer;
 import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
 import javax.servlet.ServletException;
 import javax.servlet.annotation.HandlesTypes;
 import javax.websocket.DeploymentException;
@@ -47,6 +49,39 @@
     public static final String ENABLE_KEY = "org.eclipse.jetty.websocket.jsr356";
     private static final Logger LOG = Log.getLogger(WebSocketServerContainerInitializer.class);
 
+    
+    /**
+     * DestroyListener
+     *
+     *
+     */
+    public static class ContextDestroyListener implements ServletContextListener
+    {
+        @Override
+        public void contextInitialized(ServletContextEvent sce)
+        {
+            //noop
+        }
+
+        @Override
+        public void contextDestroyed(ServletContextEvent sce)
+        {
+            //remove any ServerContainer beans
+            if (sce.getServletContext() instanceof ContextHandler.Context)
+            {
+                ContextHandler handler = ((ContextHandler.Context)sce.getServletContext()).getContextHandler();
+                ServerContainer bean = handler.getBean(ServerContainer.class);
+                if (bean != null)
+                    handler.removeBean(bean);
+            }
+            
+            //remove reference in attributes
+            sce.getServletContext().removeAttribute(javax.websocket.server.ServerContainer.class.getName());
+        }
+    }
+    
+    
+    
     /**
      * Jetty Native approach.
      * <p>
@@ -63,7 +98,7 @@
 
         // Create the Jetty ServerContainer implementation
         ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),context.getServer().getThreadPool());
-        context.addBean(jettyContainer);
+        context.addBean(jettyContainer, true);
 
         // Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
         context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
@@ -88,7 +123,7 @@
 
         // Create the Jetty ServerContainer implementation
         ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),jettyContext.getServer().getThreadPool());
-        jettyContext.addBean(jettyContainer);
+        jettyContext.addBean(jettyContainer, true);
 
         // Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
         context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
@@ -171,9 +206,8 @@
 
             // Create the Jetty ServerContainer implementation
             ServerContainer jettyContainer = configureContext(context,jettyContext);
-
-            // Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
-            context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
+            
+            context.addListener(new ContextDestroyListener()); //make sure context is cleaned up when the context stops
             
             // Establish the DecoratedObjectFactory thread local 
             // for various ServiceLoader initiated components to use.
@@ -278,7 +312,9 @@
                     throw new ServletException(e);
                 }
             }
-        } finally {
+        }
+        finally
+        {
             Thread.currentThread().setContextClassLoader(old);
         }
     }
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTrackingTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTrackingTest.java
new file mode 100644
index 0000000..22733ea
--- /dev/null
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTrackingTest.java
@@ -0,0 +1,183 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 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.websocket.jsr356.server;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.websocket.CloseReason;
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.OnMessage;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.websocket.common.WebSocketSession;
+import org.eclipse.jetty.websocket.jsr356.ClientContainer;
+import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
+import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SessionTrackingTest
+{
+    public static class ClientSocket extends Endpoint
+    {
+        public Session session;
+        public CountDownLatch openLatch = new CountDownLatch(1);
+        public CountDownLatch closeLatch = new CountDownLatch(1);
+
+        @Override
+        public void onOpen(Session session, EndpointConfig config)
+        {
+            this.session = session;
+            openLatch.countDown();
+        }
+
+        @Override
+        public void onClose(Session session, CloseReason closeReason)
+        {
+            closeLatch.countDown();
+        }
+
+        public void waitForOpen(long timeout, TimeUnit unit) throws InterruptedException
+        {
+            assertThat("ClientSocket opened",openLatch.await(timeout,unit),is(true));
+        }
+
+        public void waitForClose(long timeout, TimeUnit unit) throws InterruptedException
+        {
+            assertThat("ClientSocket opened",closeLatch.await(timeout,unit),is(true));
+        }
+    }
+
+    @ServerEndpoint("/test")
+    public static class EchoSocket
+    {
+        @OnMessage
+        public String echo(String msg)
+        {
+            return msg;
+        }
+    }
+
+    private static Server server;
+    private static WebSocketServerFactory wsServerFactory;
+    private static URI serverURI;
+
+    @BeforeClass
+    public static void startServer() throws Exception
+    {
+        Server server = new Server();
+        ServerConnector serverConnector = new ServerConnector(server);
+        serverConnector.setPort(0);
+        server.addConnector(serverConnector);
+        ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
+        servletContextHandler.setContextPath("/");
+        server.setHandler(servletContextHandler);
+
+        ServerContainer serverContainer = WebSocketServerContainerInitializer.configureContext(servletContextHandler);
+        serverContainer.addEndpoint(EchoSocket.class);
+
+        wsServerFactory = serverContainer.getBean(WebSocketServerFactory.class);
+
+        server.start();
+
+        String host = serverConnector.getHost();
+        if (StringUtil.isBlank(host))
+        {
+            host = "localhost";
+        }
+        serverURI = new URI("ws://" + host + ":" + serverConnector.getLocalPort());
+    }
+
+    @AfterClass
+    public static void stopServer() throws Exception
+    {
+        if (server == null)
+        {
+            return;
+        }
+
+        server.stop();
+    }
+
+    @Test
+    public void testAddRemoveSessions() throws Exception
+    {
+        // Create Client
+        ClientContainer clientContainer = new ClientContainer();
+        try
+        {
+            clientContainer.start();
+
+            // Establish connections
+            ClientSocket cli1 = new ClientSocket();
+            clientContainer.connectToServer(cli1,serverURI.resolve("/test"));
+            cli1.waitForOpen(1,TimeUnit.SECONDS);
+
+            // Assert open connections
+            assertServerOpenConnectionCount(1);
+
+            // Establish new connection
+            ClientSocket cli2 = new ClientSocket();
+            clientContainer.connectToServer(cli2,serverURI.resolve("/test"));
+            cli2.waitForOpen(1,TimeUnit.SECONDS);
+
+            // Assert open connections
+            assertServerOpenConnectionCount(2);
+
+            // Establish close both connections
+            cli1.session.close();
+            cli2.session.close();
+
+            cli1.waitForClose(1,TimeUnit.SECONDS);
+            cli2.waitForClose(1,TimeUnit.SECONDS);
+
+            // Assert open connections
+            assertServerOpenConnectionCount(0);
+        }
+        finally
+        {
+            clientContainer.stop();
+        }
+    }
+
+    private void assertServerOpenConnectionCount(int expectedCount)
+    {
+        Collection<WebSocketSession> sessions = wsServerFactory.getBeans(WebSocketSession.class);
+        int openCount = 0;
+        for (WebSocketSession session : sessions)
+        {
+            assertThat("Session.isopen: " + session,session.isOpen(),is(true));
+            openCount++;
+        }
+        assertThat("Open Session Count",openCount,is(expectedCount));
+    }
+}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties b/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties
index c5a50f6..9681d91 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties
@@ -6,6 +6,9 @@
 # org.eclipse.jetty.websocket.LEVEL=WARN
 # org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG
 
+org.eclipse.jetty.websocket.common.WebSocketSession.LEVEL=DEBUG
+org.eclipse.jetty.websocket.jsr356.LEVEL=DEBUG
+
 ### Show state changes on BrowserDebugTool
 # -- LEAVE THIS AT DEBUG LEVEL --
 org.eclipse.jetty.websocket.jsr356.server.browser.LEVEL=DEBUG
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java
index bdd37a2..b552d30 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java
@@ -53,7 +53,6 @@
 import org.eclipse.jetty.websocket.client.masks.Masker;
 import org.eclipse.jetty.websocket.client.masks.RandomMasker;
 import org.eclipse.jetty.websocket.common.SessionFactory;
-import org.eclipse.jetty.websocket.common.SessionListener;
 import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.WebSocketSessionFactory;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
@@ -64,7 +63,7 @@
 /**
  * WebSocketClient provides a means of establishing connections to remote websocket endpoints.
  */
-public class WebSocketClient extends ContainerLifeCycle implements SessionListener, WebSocketContainerScope
+public class WebSocketClient extends ContainerLifeCycle implements WebSocketContainerScope
 {
     private static final Logger LOG = Log.getLogger(WebSocketClient.class);
 
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
index 4eda6fd..6e4c2ec 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
@@ -22,7 +22,6 @@
 import java.util.concurrent.Executor;
 
 import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.api.SuspendToken;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
@@ -155,4 +154,10 @@
      * @return the suspend token
      */
     SuspendToken suspend();
+
+    /**
+     * Get Unique ID for the Connection
+     * @return the unique ID for the connection
+     */
+    public String getId();
 }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/SessionListener.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/SessionListener.java
deleted file mode 100644
index c62face..0000000
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/SessionListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 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.websocket.common;
-
-/**
- * Basic listener interface for Session open/close.
- * <p>
- * Used primarily for tracking open sessions.
- */
-public interface SessionListener
-{
-    public void onSessionOpened(WebSocketSession session);
-    
-    public void onSessionClosed(WebSocketSession session);
-}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
index 33356b2..e32a52c 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
@@ -67,7 +67,6 @@
     private final URI requestURI;
     private final LogicalConnection connection;
     private final EventDriver websocket;
-    private final SessionListener[] sessionListeners;
     private final Executor executor;
     private ClassLoader classLoader;
     private ExtensionFactory extensionFactory;
@@ -80,7 +79,7 @@
     private UpgradeRequest upgradeRequest;
     private UpgradeResponse upgradeResponse;
 
-    public WebSocketSession(WebSocketContainerScope containerScope, URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners)
+    public WebSocketSession(WebSocketContainerScope containerScope, URI requestURI, EventDriver websocket, LogicalConnection connection)
     {
         Objects.requireNonNull(containerScope,"Container Scope cannot be null");
         Objects.requireNonNull(requestURI,"Request URI cannot be null");
@@ -90,11 +89,11 @@
         this.requestURI = requestURI;
         this.websocket = websocket;
         this.connection = connection;
-        this.sessionListeners = sessionListeners;
         this.executor = connection.getExecutor();
         this.outgoingHandler = connection;
         this.incomingHandler = websocket;
         this.connection.getIOState().addListener(this);
+        this.policy = containerScope.getPolicy();
         
         addBean(this.connection);
         addBean(this.websocket);
@@ -435,36 +434,28 @@
                 CloseInfo close = ioState.getCloseInfo();
                 // confirmed close of local endpoint
                 notifyClose(close.getStatusCode(),close.getReason());
-                
-                // notify session listeners
-                for (SessionListener listener : sessionListeners)
+                try
                 {
-                    try
-                    {
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("{}.onSessionClosed()",listener.getClass().getSimpleName());
-                        listener.onSessionClosed(this);
-                    }
-                    catch (Throwable t)
-                    {
-                        LOG.ignore(t);
-                    }
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{}.onSessionClosed()",containerScope.getClass().getSimpleName());
+                    containerScope.onSessionClosed(this);
+                }
+                catch (Throwable t)
+                {
+                    LOG.ignore(t);
                 }
                 break;
             case CONNECTED:
                 // notify session listeners
-                for (SessionListener listener : sessionListeners)
+                try
                 {
-                    try
-                    {
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("{}.onSessionOpen()", listener.getClass().getSimpleName());
-                        listener.onSessionOpened(this);
-                    }
-                    catch (Throwable t)
-                    {
-                        LOG.ignore(t);
-                    }
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{}.onSessionOpened()",containerScope.getClass().getSimpleName());
+                    containerScope.onSessionOpened(this);
+                }
+                catch (Throwable t)
+                {
+                    LOG.ignore(t);
                 }
                 break;
         }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java
index 8494a26..e46a231 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java
@@ -31,26 +31,10 @@
 public class WebSocketSessionFactory implements SessionFactory
 {
     private final WebSocketContainerScope containerScope;
-    private final SessionListener[] listeners;
 
-    public WebSocketSessionFactory(WebSocketContainerScope containerScope, SessionListener... sessionListeners)
+    public WebSocketSessionFactory(WebSocketContainerScope containerScope)
     {
         this.containerScope = containerScope;
-        if ((sessionListeners != null) && (sessionListeners.length > 0))
-        {
-            this.listeners = sessionListeners;
-        }
-        else
-        {
-            if (this.containerScope instanceof SessionListener)
-            {
-                this.listeners = new SessionListener[] { (SessionListener)containerScope };
-            }
-            else
-            {
-                this.listeners = new SessionListener[0];
-            }
-        }
    }
 
     @Override
@@ -62,6 +46,6 @@
     @Override
     public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
     {
-        return new WebSocketSession(containerScope, requestURI,websocket,connection,listeners);
+        return new WebSocketSession(containerScope, requestURI,websocket,connection);
     }
 }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
index a3a0ed3..027e8e6 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
@@ -214,6 +214,7 @@
     private final WebSocketPolicy policy;
     private final AtomicBoolean suspendToken;
     private final FrameFlusher flusher;
+    private final String id;
     private List<ExtensionConfig> extensions;
     private boolean isFilling;
     private ByteBuffer prefillBuffer;
@@ -224,6 +225,11 @@
     public AbstractWebSocketConnection(EndPoint endp, Executor executor, Scheduler scheduler, WebSocketPolicy policy, ByteBufferPool bufferPool)
     {
         super(endp,executor);
+        this.id = String.format("%s:%d->%s:%d",
+                endp.getLocalAddress().getAddress().getHostAddress(),
+                endp.getLocalAddress().getPort(),
+                endp.getRemoteAddress().getAddress().getHostAddress(),
+                endp.getRemoteAddress().getPort());
         this.policy = policy;
         this.bufferPool = bufferPool;
         this.generator = new Generator(policy,bufferPool);
@@ -347,6 +353,12 @@
     {
         return generator;
     }
+    
+    @Override
+    public String getId()
+    {
+        return id;
+    }
 
     @Override
     public long getIdleTimeout()
@@ -747,6 +759,43 @@
         return String.format("%s@%X{endp=%s,ios=%s,f=%s,g=%s,p=%s}",getClass().getSimpleName(),hashCode(),getEndPoint(),ioState,flusher,generator,parser);
     }
 
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        
+        EndPoint endp = getEndPoint();
+        if(endp != null)
+        {
+            result = prime * result + endp.getLocalAddress().hashCode();
+            result = prime * result + endp.getRemoteAddress().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;
+        AbstractWebSocketConnection other = (AbstractWebSocketConnection)obj;
+        EndPoint endp = getEndPoint();
+        EndPoint otherEndp = other.getEndPoint();
+        if (endp == null)
+        {
+            if (otherEndp != null)
+                return false;
+        }
+        else if (!endp.equals(otherEndp))
+            return false;
+        return true;
+    }
+
     /**
      * Extra bytes from the initial HTTP upgrade that need to
      * be processed by the websocket parser before starting
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java
index a68574c..0e8e0dd 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java
@@ -27,6 +27,7 @@
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.common.WebSocketSession;
 
 public class SimpleContainerScope extends ContainerLifeCycle implements WebSocketContainerScope
 {
@@ -105,4 +106,14 @@
     {
         this.sslContextFactory = sslContextFactory;
     }
+
+    @Override
+    public void onSessionOpened(WebSocketSession session)
+    {
+    }
+
+    @Override
+    public void onSessionClosed(WebSocketSession session)
+    {
+    }
 }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java
index 0717cfc..9e1f5e0 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java
@@ -24,6 +24,7 @@
 import org.eclipse.jetty.util.DecoratedObjectFactory;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.common.WebSocketSession;
 
 /**
  * Defined Scope for a WebSocketContainer.
@@ -64,4 +65,19 @@
      * @return the SslContextFactory in use by the container (can be null if no SSL context is defined)
      */
     public SslContextFactory getSslContextFactory();
+
+    /**
+     * A Session has been opened
+     * 
+     * @param the session that was opened
+     */
+    public void onSessionOpened(WebSocketSession session);
+    
+    /**
+     * A Session has been closed
+     * 
+     * @param the session that was closed
+     */
+    public void onSessionClosed(WebSocketSession session);
+
 }
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
index 71b8e3d..9c067f5 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
@@ -108,6 +108,12 @@
     }
 
     @Override
+    public String getId()
+    {
+        return this.id;
+    }
+
+    @Override
     public long getIdleTimeout()
     {
         return 0;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
index a5a1ba6..b0ea466 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
@@ -71,6 +71,12 @@
     }
 
     @Override
+    public String getId()
+    {
+        return "dummy";
+    }
+
+    @Override
     public long getIdleTimeout()
     {
         return 0;
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
index c8f9ef4..baebd44 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
@@ -39,7 +39,7 @@
             endp.setIdleTimeout(policy.getIdleTimeout());
         }
     }
-
+    
     @Override
     public InetSocketAddress getLocalAddress()
     {
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
index ec2dd3a..e30b4ca 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
@@ -58,7 +58,6 @@
 import org.eclipse.jetty.websocket.api.util.QuoteUtil;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
 import org.eclipse.jetty.websocket.common.SessionFactory;
-import org.eclipse.jetty.websocket.common.SessionListener;
 import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.WebSocketSessionFactory;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
@@ -75,7 +74,7 @@
 /**
  * Factory to create WebSocket connections
  */
-public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketContainerScope, WebSocketServletFactory, SessionListener
+public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketContainerScope, WebSocketServletFactory
 {
     private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);
 
diff --git a/pom.xml b/pom.xml
index eb942f9..0015f2a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -584,7 +584,7 @@
       <dependency>
         <groupId>org.eclipse.jetty.toolchain</groupId>
         <artifactId>jetty-schemas</artifactId>
-        <version>3.1.M0</version>
+        <version>3.1</version>
       </dependency>
 
       <dependency>
diff --git a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartTest.java b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartTest.java
index 61b853b..54b0caa 100644
--- a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartTest.java
+++ b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartTest.java
@@ -21,8 +21,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 
+import java.io.File;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
+import java.net.URI;
 import java.net.URL;
 
 import org.eclipse.jetty.server.NetworkConnector;
@@ -33,6 +35,7 @@
 import org.eclipse.jetty.xml.XmlConfiguration;
 import org.eclipse.jetty.xml.XmlParser.Node;
 import org.hamcrest.Matchers;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class QuickStartTest
@@ -176,4 +179,73 @@
       
         server.stop();
     }
+    
+    @Test
+    public void testNormalize() throws Exception
+    {
+        String jetty_base=System.getProperty("jetty.base");
+        String jetty_home=System.getProperty("jetty.home");
+        String user_home=System.getProperty("user.home");
+        String user_dir=System.getProperty("user.dir");
+        try
+        {
+            System.setProperty("jetty.home","/opt/jetty-distro");
+            System.setProperty("jetty.base","/opt/jetty-distro/demo.base");
+            System.setProperty("user.home","/home/user");
+            System.setProperty("user.dir","/etc/init.d");
+            AttributeNormalizer normalizer = new AttributeNormalizer(Resource.newResource("/opt/jetty-distro/demo.base/webapps/root"));
+
+            String[][] tests = { 
+                    { "WAR", "/opt/jetty-distro/demo.base/webapps/root" },
+                    { "jetty.home", "/opt/jetty-distro" },
+                    { "jetty.base", "/opt/jetty-distro/demo.base" },
+                    { "user.home", "/home/user" },
+                    { "user.dir", "/etc/init.d" },
+            };
+
+            for (String[] test : tests)
+            {
+                Assert.assertEquals("file:${"+test[0]+"}",normalizer.normalize("file:"+test[1]));
+                Assert.assertEquals("file:${"+test[0]+"}",normalizer.normalize("file:"+test[1]+"/"));
+                Assert.assertEquals("file:${"+test[0]+"}/file",normalizer.normalize("file:"+test[1]+"/file"));
+                Assert.assertEquals("file:${"+test[0]+"}",normalizer.normalize(new URI("file:"+test[1])));
+                Assert.assertEquals("file:${"+test[0]+"}",normalizer.normalize(new URI("file:"+test[1]+"/")));
+                Assert.assertEquals("file:${"+test[0]+"}/file",normalizer.normalize(new URI("file:"+test[1]+"/file")));
+                Assert.assertEquals("file:${"+test[0]+"}",normalizer.normalize(new URL("file:"+test[1])));
+                Assert.assertEquals("file:${"+test[0]+"}",normalizer.normalize(new URL("file:"+test[1]+"/")));
+                Assert.assertEquals("file:${"+test[0]+"}/file",normalizer.normalize(new URL("file:"+test[1]+"/file")));
+                Assert.assertEquals("jar:file:${"+test[0]+"}!/file",normalizer.normalize("jar:file:"+test[1]+"!/file"));
+                Assert.assertEquals("jar:file:${"+test[0]+"}!/file",normalizer.normalize("jar:file:"+test[1]+"/!/file"));
+                Assert.assertEquals("jar:file:${"+test[0]+"}/file!/file",normalizer.normalize("jar:file:"+test[1]+"/file!/file"));
+                Assert.assertEquals("jar:file:${"+test[0]+"}!/file",normalizer.normalize(new URI("jar:file:"+test[1]+"!/file")));
+                Assert.assertEquals("jar:file:${"+test[0]+"}!/file",normalizer.normalize(new URI("jar:file:"+test[1]+"/!/file")));
+                Assert.assertEquals("jar:file:${"+test[0]+"}/file!/file",normalizer.normalize(new URI("jar:file:"+test[1]+"/file!/file")));
+                Assert.assertEquals("jar:file:${"+test[0]+"}!/file",normalizer.normalize(new URL("jar:file:"+test[1]+"!/file")));
+                Assert.assertEquals("jar:file:${"+test[0]+"}!/file",normalizer.normalize(new URL("jar:file:"+test[1]+"/!/file")));
+                Assert.assertEquals("jar:file:${"+test[0]+"}/file!/file",normalizer.normalize(new URL("jar:file:"+test[1]+"/file!/file")));
+            }
+        }
+        finally
+        {
+            if (user_dir==null)
+                System.clearProperty("user.dir");
+            else
+                System.setProperty("user.dir",user_dir);
+
+            if (user_home==null)
+                System.clearProperty("user.home");
+            else
+                System.setProperty("user.home",user_home);
+
+            if (jetty_home==null)
+                System.clearProperty("jetty.home");
+            else
+                System.setProperty("jetty.home",jetty_home);
+
+            if (jetty_base==null)
+                System.clearProperty("jetty.base");
+            else
+                System.setProperty("jetty.base",jetty_base);
+        }
+    }
 }