Procházet zdrojové kódy

PUT and MKCOL support. Simplified paths (utilizing a servlet filter to make sure, directory paths always end on "/" while file paths don't).

Sebastian Stenzel před 9 roky
rodič
revize
389c49d846

+ 38 - 0
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/filters/AcceptRangeFilter.java

@@ -0,0 +1,38 @@
+package org.cryptomator.webdav.filters;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Adds an <code>Accept-Range: bytes</code> header to all <code>GET</code> requests.
+ */
+public class AcceptRangeFilter implements HttpFilter {
+
+	private static final String METHOD_GET = "GET";
+	private static final String HEADER_ACCEPT_RANGES = "Accept-Ranges";
+	private static final String HEADER_ACCEPT_RANGE_VALUE = "bytes";
+
+	@Override
+	public void init(FilterConfig filterConfig) throws ServletException {
+		// no-op
+	}
+
+	@Override
+	public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
+		if (METHOD_GET.equalsIgnoreCase(request.getMethod())) {
+			response.addHeader(HEADER_ACCEPT_RANGES, HEADER_ACCEPT_RANGE_VALUE);
+		}
+		chain.doFilter(request, response);
+	}
+
+	@Override
+	public void destroy() {
+		// no-op
+	}
+
+}

+ 26 - 0
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/filters/HttpFilter.java

@@ -0,0 +1,26 @@
+package org.cryptomator.webdav.filters;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+interface HttpFilter extends Filter {
+
+	@Override
+	default void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+		if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
+			doFilterHttp((HttpServletRequest) request, (HttpServletResponse) response, chain);
+		} else {
+			chain.doFilter(request, response);
+		}
+	}
+
+	void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException;
+
+}

+ 77 - 0
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/filters/UriNormalizationFilter.java

@@ -0,0 +1,77 @@
+package org.cryptomator.webdav.filters;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Depending on the HTTP method a "/" is added to or removed from the end of an URI.
+ * For example <code>MKCOL</code> creates a directory (ending on "/"), while <code>PUT</code> creates a file (not ending on "/").
+ */
+public class UriNormalizationFilter implements HttpFilter {
+
+	private static final String[] FILE_METHODS = {"PUT"};
+	private static final String[] DIRECTORY_METHODS = {"MKCOL"};
+
+	@Override
+	public void init(FilterConfig filterConfig) throws ServletException {
+		// no-op
+	}
+
+	@Override
+	public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
+		if (ArrayUtils.contains(FILE_METHODS, request.getMethod().toUpperCase())) {
+			chain.doFilter(new FileUriRequest(request), response);
+		} else if (ArrayUtils.contains(DIRECTORY_METHODS, request.getMethod().toUpperCase())) {
+			chain.doFilter(new DirectoryUriRequest(request), response);
+		} else {
+			chain.doFilter(request, response);
+		}
+	}
+
+	@Override
+	public void destroy() {
+		// no-op
+	}
+
+	/**
+	 * HTTP request, whose URI never ends on "/".
+	 */
+	private static class FileUriRequest extends HttpServletRequestWrapper {
+
+		public FileUriRequest(HttpServletRequest request) {
+			super(request);
+		}
+
+		@Override
+		public String getRequestURI() {
+			return StringUtils.removeEnd(super.getRequestURI(), "/");
+		}
+
+	}
+
+	/**
+	 * HTTP request, whose URI always ends on "/".
+	 */
+	private static class DirectoryUriRequest extends HttpServletRequestWrapper {
+
+		public DirectoryUriRequest(HttpServletRequest request) {
+			super(request);
+		}
+
+		@Override
+		public String getRequestURI() {
+			return StringUtils.appendIfMissing(super.getRequestURI(), "/");
+		}
+
+	}
+
+}

+ 3 - 3
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbit/DavFile.java

@@ -17,7 +17,6 @@ import java.time.Instant;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.DavResource;
 import org.apache.jackrabbit.webdav.DavResourceIterator;
-import org.apache.jackrabbit.webdav.DavResourceLocator;
 import org.apache.jackrabbit.webdav.DavSession;
 import org.apache.jackrabbit.webdav.io.InputContext;
 import org.apache.jackrabbit.webdav.io.OutputContext;
@@ -25,11 +24,12 @@ import org.apache.jackrabbit.webdav.lock.LockManager;
 import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.ReadableFile;
 import org.cryptomator.filesystem.WritableFile;
+import org.cryptomator.webdav.jackrabbit.DavPathFactory.DavPath;
 
 class DavFile extends DavNode<File> {
 
-	public DavFile(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavResourceLocator locator, File node) {
-		super(factory, lockManager, session, locator, node);
+	public DavFile(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavPath path, File node) {
+		super(factory, lockManager, session, path, node);
 	}
 
 	@Override

+ 35 - 8
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbit/DavFolder.java

@@ -9,6 +9,11 @@
 package org.cryptomator.webdav.jackrabbit;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
 import java.time.Instant;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -17,7 +22,6 @@ import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.DavResource;
 import org.apache.jackrabbit.webdav.DavResourceIterator;
 import org.apache.jackrabbit.webdav.DavResourceIteratorImpl;
-import org.apache.jackrabbit.webdav.DavResourceLocator;
 import org.apache.jackrabbit.webdav.DavSession;
 import org.apache.jackrabbit.webdav.io.InputContext;
 import org.apache.jackrabbit.webdav.io.OutputContext;
@@ -27,11 +31,14 @@ import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
 import org.apache.jackrabbit.webdav.property.ResourceType;
 import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.Folder;
+import org.cryptomator.filesystem.FolderCreateMode;
+import org.cryptomator.filesystem.WritableFile;
+import org.cryptomator.webdav.jackrabbit.DavPathFactory.DavPath;
 
 class DavFolder extends DavNode<Folder> {
 
-	public DavFolder(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavResourceLocator locator, Folder folder) {
-		super(factory, lockManager, session, locator, folder);
+	public DavFolder(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavPath path, Folder folder) {
+		super(factory, lockManager, session, path, folder);
 		properties.add(new ResourceType(ResourceType.COLLECTION));
 		properties.add(new DefaultDavProperty<Integer>(DavPropertyName.ISCOLLECTION, 1));
 	}
@@ -48,8 +55,30 @@ class DavFolder extends DavNode<Folder> {
 
 	@Override
 	public void addMember(DavResource resource, InputContext inputContext) throws DavException {
-		// TODO Auto-generated method stub
+		if (resource instanceof DavFolder) {
+			addMemberFolder((DavFolder) resource);
+		} else if (resource instanceof DavFile) {
+			addMemberFile((DavFile) resource, inputContext.getInputStream());
+		} else {
+			throw new IllegalArgumentException("Unsupported resource type: " + resource.getClass().getName());
+		}
+	}
+
+	private void addMemberFolder(DavFolder memberFolder) {
+		node.folder(memberFolder.getDisplayName()).create(FolderCreateMode.FAIL_IF_PARENT_IS_MISSING);
+	}
 
+	private void addMemberFile(DavFile memberFile, InputStream inputStream) {
+		try (ReadableByteChannel src = Channels.newChannel(inputStream); WritableFile dst = node.file(memberFile.getDisplayName()).openWritable()) {
+			ByteBuffer buf = ByteBuffer.allocate(1337);
+			while (src.read(buf) != -1) {
+				buf.flip();
+				dst.write(buf);
+				buf.clear();
+			}
+		} catch (IOException e) {
+			throw new UncheckedIOException(e);
+		}
 	}
 
 	@Override
@@ -60,14 +89,12 @@ class DavFolder extends DavNode<Folder> {
 	}
 
 	private DavFolder getMemberFolder(Folder memberFolder) {
-		final String subFolderResourcePath = locator.getResourcePath() + memberFolder.name() + '/';
-		final DavResourceLocator subFolderLocator = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), subFolderResourcePath);
+		final DavPath subFolderLocator = path.getChild(memberFolder.name() + '/');
 		return factory.createFolder(memberFolder, subFolderLocator, session);
 	}
 
 	private DavFile getMemberFile(File memberFile) {
-		final String subFolderResourcePath = locator.getResourcePath() + memberFile.name();
-		final DavResourceLocator subFolderLocator = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), subFolderResourcePath);
+		final DavPath subFolderLocator = path.getChild(memberFile.name());
 		return factory.createFile(memberFile, subFolderLocator, session);
 	}
 

+ 11 - 12
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbit/DavNode.java

@@ -14,7 +14,6 @@ import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 import java.util.List;
 
-import org.apache.commons.io.FilenameUtils;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.DavResource;
 import org.apache.jackrabbit.webdav.DavResourceLocator;
@@ -31,6 +30,7 @@ import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import org.apache.jackrabbit.webdav.property.PropEntry;
 import org.cryptomator.filesystem.Node;
+import org.cryptomator.webdav.jackrabbit.DavPathFactory.DavPath;
 
 abstract class DavNode<T extends Node> implements DavResource {
 
@@ -41,15 +41,15 @@ abstract class DavNode<T extends Node> implements DavResource {
 	protected final FilesystemResourceFactory factory;
 	protected final LockManager lockManager;
 	protected final DavSession session;
-	protected final DavResourceLocator locator;
+	protected final DavPath path;
 	protected final T node;
 	protected final DavPropertySet properties;
 
-	public DavNode(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavResourceLocator locator, T node) {
+	public DavNode(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, DavPath path, T node) {
 		this.factory = factory;
 		this.lockManager = lockManager;
 		this.session = session;
-		this.locator = locator;
+		this.path = path;
 		this.node = node;
 		this.properties = new DavPropertySet();
 	}
@@ -76,17 +76,17 @@ abstract class DavNode<T extends Node> implements DavResource {
 
 	@Override
 	public DavResourceLocator getLocator() {
-		return locator;
+		return path;
 	}
 
 	@Override
 	public String getResourcePath() {
-		return locator.getResourcePath();
+		return path.getResourcePath();
 	}
 
 	@Override
 	public String getHref() {
-		return locator.getHref(this.isCollection());
+		return path.getHref();
 	}
 
 	@Override
@@ -157,16 +157,15 @@ abstract class DavNode<T extends Node> implements DavResource {
 
 	@Override
 	public DavResource getCollection() {
-		if (locator.isRootLocation()) {
+		if (path.isRootLocation()) {
 			return null;
 		}
 
-		final String parentResource = FilenameUtils.getPathNoEndSeparator(locator.getResourcePath());
-		final DavResourceLocator parentLocator = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), parentResource);
+		final DavPath parentPath = path.getParent();
 		try {
-			return factory.createResource(parentLocator, session);
+			return factory.createResource(parentPath, session);
 		} catch (DavException e) {
-			throw new IllegalStateException("Unable to get parent resource with path " + parentLocator.getResourcePath(), e);
+			throw new IllegalStateException("Unable to get parent resource with path " + parentPath, e);
 		}
 	}
 

+ 59 - 19
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbit/IdentityLocatorFactory.java

@@ -19,45 +19,78 @@ import org.apache.jackrabbit.webdav.util.EncodeUtil;
 /**
  * A LocatorFactory constructing Locators, whose {@link DavResourceLocator#getResourcePath() resourcePath} and {@link DavResourceLocator#getRepositoryPath() repositoryPath} are equal.
  * These paths will be plain, case-sensitive, absolute, unencoded Strings with Unix-style path separators.
+ * 
+ * Paths ending on "/" are treated as directory paths and all others as file paths.
  */
-class IdentityLocatorFactory implements DavLocatorFactory {
+class DavPathFactory implements DavLocatorFactory {
 
 	private final String pathPrefix;
 
-	public IdentityLocatorFactory(URI contextRootUri) {
+	public DavPathFactory(URI contextRootUri) {
 		this.pathPrefix = StringUtils.removeEnd(contextRootUri.toString(), "/");
 	}
 
 	@Override
-	public DavResourceLocator createResourceLocator(String prefix, String href) {
+	public DavPath createResourceLocator(String prefix, String href) {
 		final String fullPrefix = StringUtils.removeEnd(prefix, "/");
 		final String remainingHref = StringUtils.removeStart(href, fullPrefix);
 		final String unencodedRemaingingHref = EncodeUtil.unescape(remainingHref);
-		assert unencodedRemaingingHref.startsWith("/");
-		return new IdentityLocator(unencodedRemaingingHref);
+		return new DavPath(unencodedRemaingingHref);
 	}
 
 	@Override
-	public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
-		assert resourcePath.startsWith("/");
-		return new IdentityLocator(resourcePath);
+	public DavPath createResourceLocator(String prefix, String workspacePath, String resourcePath) {
+		return createResourceLocator(prefix, workspacePath, resourcePath, true);
 	}
 
 	@Override
-	public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
-		assert path.startsWith("/");
-		return new IdentityLocator(path);
+	public DavPath createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
+		return new DavPath(path);
 	}
 
-	private class IdentityLocator implements DavResourceLocator {
+	public class DavPath implements DavResourceLocator {
 
 		private final String absPath;
 
-		private IdentityLocator(String absPath) {
+		private DavPath(String absPath) {
 			assert absPath.startsWith("/");
 			this.absPath = FilenameUtils.normalize(absPath, true);
 		}
 
+		/**
+		 * @return <code>true</code> if the path ends on "/".
+		 */
+		public boolean isDirectory() {
+			return absPath.endsWith("/");
+		}
+
+		/**
+		 * @return Parent DavPath or <code>null</code> if this is the root node.
+		 */
+		public DavPath getParent() {
+			if (isRootLocation()) {
+				return null;
+			} else {
+				final String parentPath = FilenameUtils.getFullPath(FilenameUtils.normalizeNoEndSeparator(absPath, true));
+				return createResourceLocator(getPrefix(), getWorkspacePath(), parentPath);
+			}
+		}
+
+		/**
+		 * Get the path of a child resource, consisting of curren path + child path.
+		 * If the child path ends on "/", the returned DavPath will be a directory path.
+		 * 
+		 * @return Child path
+		 */
+		public DavPath getChild(String relativeChildPath) {
+			if (isDirectory()) {
+				final String absChildPath = absPath + StringUtils.removeStart(relativeChildPath, "/");
+				return createResourceLocator(getPrefix(), getWorkspacePath(), absChildPath);
+			} else {
+				throw new UnsupportedOperationException("Can only resolve subpaths of a path representing a directory");
+			}
+		}
+
 		@Override
 		public String getPrefix() {
 			return pathPrefix;
@@ -88,13 +121,20 @@ class IdentityLocatorFactory implements DavLocatorFactory {
 			return false;
 		}
 
+		/**
+		 * @see #getHref(boolean)
+		 */
+		public String getHref() {
+			return getHref(isDirectory());
+		}
+
 		@Override
 		public String getHref(boolean isCollection) {
 			final String encodedResourcePath = EncodeUtil.escapePath(absPath);
 			if (isRootLocation()) {
 				return pathPrefix + "/";
 			} else {
-				assert isCollection ? encodedResourcePath.endsWith("/") : true;
+				assert isCollection ? isDirectory() : true;
 				return pathPrefix + encodedResourcePath;
 			}
 		}
@@ -105,8 +145,8 @@ class IdentityLocatorFactory implements DavLocatorFactory {
 		}
 
 		@Override
-		public DavLocatorFactory getFactory() {
-			return IdentityLocatorFactory.this;
+		public DavPathFactory getFactory() {
+			return DavPathFactory.this;
 		}
 
 		@Override
@@ -116,7 +156,7 @@ class IdentityLocatorFactory implements DavLocatorFactory {
 
 		@Override
 		public String toString() {
-			return "Locator: " + absPath + " (Prefix: " + pathPrefix + ")";
+			return "[" + pathPrefix + "]" + absPath;
 		}
 
 		@Override
@@ -126,8 +166,8 @@ class IdentityLocatorFactory implements DavLocatorFactory {
 
 		@Override
 		public boolean equals(Object obj) {
-			if (obj instanceof IdentityLocator) {
-				final IdentityLocator other = (IdentityLocator) obj;
+			if (obj instanceof DavPath) {
+				final DavPath other = (DavPath) obj;
 				final boolean samePrefix = this.getPrefix() == null && other.getPrefix() == null || this.getPrefix().equals(other.getPrefix());
 				final boolean sameRelativeCleartextPath = this.absPath == null && other.absPath == null || this.absPath.equals(other.absPath);
 				return samePrefix && sameRelativeCleartextPath;

+ 18 - 10
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbit/FilesystemResourceFactory.java

@@ -26,6 +26,7 @@ import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.FileSystem;
 import org.cryptomator.filesystem.Folder;
 import org.cryptomator.filesystem.Node;
+import org.cryptomator.webdav.jackrabbit.DavPathFactory.DavPath;
 
 class FilesystemResourceFactory implements DavResourceFactory {
 
@@ -47,22 +48,29 @@ class FilesystemResourceFactory implements DavResourceFactory {
 
 	@Override
 	public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException {
-		final String path = locator.getResourcePath();
-		if (path.endsWith("/")) {
-			Folder folder = this.resolve(path, FOLDER);
-			return createFolder(folder, locator, session);
+		if (locator instanceof DavPath) {
+			return createResource((DavPath) locator, session);
 		} else {
-			File file = this.resolve(path, FILE);
-			return createFile(file, locator, session);
+			throw new IllegalArgumentException("Unsupported locator type " + locator.getClass().getName());
 		}
 	}
 
-	DavFolder createFolder(Folder folder, DavResourceLocator locator, DavSession session) {
-		return new DavFolder(this, lockManager, session, locator, folder);
+	private DavResource createResource(DavPath path, DavSession session) throws DavException {
+		if (path.isDirectory()) {
+			Folder folder = this.resolve(path.getResourcePath(), FOLDER);
+			return createFolder(folder, path, session);
+		} else {
+			File file = this.resolve(path.getResourcePath(), FILE);
+			return createFile(file, path, session);
+		}
+	}
+
+	DavFolder createFolder(Folder folder, DavPath path, DavSession session) {
+		return new DavFolder(this, lockManager, session, path, folder);
 	}
 
-	public DavFile createFile(File file, DavResourceLocator locator, DavSession session) {
-		return new DavFile(this, lockManager, session, locator, file);
+	DavFile createFile(File file, DavPath path, DavSession session) {
+		return new DavFile(this, lockManager, session, path, file);
 	}
 
 	private <T extends Node> T resolve(String path, Class<T> expectedNodeType) {

+ 1 - 1
main/jackrabbit-filesystem-adapter/src/main/java/org/cryptomator/webdav/jackrabbit/WebDavServlet.java

@@ -28,7 +28,7 @@ public class WebDavServlet extends AbstractWebdavServlet {
 
 	public WebDavServlet(URI contextRootUri, FileSystem filesystem) {
 		davSessionProvider = new DavSessionProviderImpl();
-		davLocatorFactory = new IdentityLocatorFactory(contextRootUri);
+		davLocatorFactory = new DavPathFactory(contextRootUri);
 		davResourceFactory = new FilesystemResourceFactory(filesystem);
 	}
 

+ 7 - 0
main/jackrabbit-filesystem-adapter/src/test/java/org/cryptomator/webdav/jackrabbit/InMemoryWebDavServer.java

@@ -11,13 +11,18 @@ package org.cryptomator.webdav.jackrabbit;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.ByteBuffer;
+import java.util.EnumSet;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 
+import javax.servlet.DispatcherType;
+
 import org.cryptomator.filesystem.FileSystem;
 import org.cryptomator.filesystem.FolderCreateMode;
 import org.cryptomator.filesystem.WritableFile;
 import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
+import org.cryptomator.webdav.filters.AcceptRangeFilter;
+import org.cryptomator.webdav.filters.UriNormalizationFilter;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
@@ -52,6 +57,8 @@ public class InMemoryWebDavServer {
 		final ServletContextHandler servletContext = new ServletContextHandler(servletCollection, "/", ServletContextHandler.SESSIONS);
 		final ServletHolder servletHolder = new ServletHolder("InMemory-WebDAV-Servlet", new WebDavServlet(servletContextRootUri, inMemoryFileSystem));
 		servletContext.addServlet(servletHolder, "/*");
+		servletContext.addFilter(AcceptRangeFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
+		servletContext.addFilter(UriNormalizationFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
 		servletCollection.mapContexts();
 
 		server.setConnectors(new Connector[] {localConnector});