diff --git a/pom.xml b/pom.xml index 00d2720e091bd909bd1ed0dd9336827cf77aad08..1cd34c9c595e1f17ba157ce34a26cce1d9f9ed4b 100644 --- a/pom.xml +++ b/pom.xml @@ -2049,48 +2049,6 @@ <version>1.1.1</version> <scope>test</scope> </dependency> - <dependency> - <groupId>com.sun.jersey</groupId> - <artifactId>jersey-server</artifactId> - <version>${com.sun.jersey.version}</version> - <scope>test</scope> - <exclusions> - <exclusion> - <groupId>org.springframework</groupId> - <artifactId>spring-core</artifactId> - </exclusion> - <exclusion> - <groupId>org.springframework</groupId> - <artifactId>spring</artifactId> - </exclusion> - <exclusion> - <groupId>org.springframework</groupId> - <artifactId>spring-beans</artifactId> - </exclusion> - <exclusion> - <groupId>org.springframework</groupId> - <artifactId>spring-context</artifactId> - </exclusion> - <exclusion> - <groupId>org.springframework</groupId> - <artifactId>spring-web</artifactId> - </exclusion> - <exclusion> - <groupId>org.springframework</groupId> - <artifactId>spring-aop</artifactId> - </exclusion> - <exclusion> - <groupId>org.springframework</groupId> - <artifactId>spring-jca</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>com.sun.jersey.jersey-test-framework</groupId> - <artifactId>jersey-test-framework-grizzly</artifactId> - <version>${com.sun.jersey.version}</version> - <scope>test</scope> - </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> @@ -2134,6 +2092,18 @@ <version>4.8.2</version> <scope>test</scope> </dependency> + <dependency> + <groupId>io.undertow</groupId> + <artifactId>undertow-core</artifactId> + <version>1.0.0.Beta21</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.undertow</groupId> + <artifactId>undertow-servlet</artifactId> + <version>1.0.0.Beta21</version> + <scope>test</scope> + </dependency> <!-- Start test dependencies for Arquillian and Selenium --> <dependency> diff --git a/src/main/java/org/olat/core/commons/services/webdav/manager/VFSResourceRoot.java b/src/main/java/org/olat/core/commons/services/webdav/manager/VFSResourceRoot.java index dfc61b2c32c847d44d7eeb83ba08e8991eea0081..21cf66cf35eda15f58a97c3b709b19a9ac3e33c3 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/manager/VFSResourceRoot.java +++ b/src/main/java/org/olat/core/commons/services/webdav/manager/VFSResourceRoot.java @@ -170,7 +170,7 @@ public class VFSResourceRoot implements WebResourceRoot { } @Override - public boolean write(String path, InputStream is, boolean overwrite) { + public boolean write(String path, InputStream is, boolean overwrite, WebResource movedFrom) { VFSLeaf childLeaf; VFSItem file = resolveFile(path); if (file instanceof VFSLeaf) { @@ -235,6 +235,15 @@ public class VFSResourceRoot implements WebResourceRoot { } } + if(movedFrom instanceof VFSResource) { + VFSResource vfsResource = (VFSResource)movedFrom; + if(vfsResource.getItem() instanceof Versionable + && ((Versionable)vfsResource.getItem()).getVersions().isVersioned()) { + VFSLeaf currentVersion = (VFSLeaf)vfsResource.getItem(); + VersionsManager.getInstance().move(currentVersion, childLeaf, identity); + } + } + return true; } diff --git a/src/main/java/org/olat/core/commons/services/webdav/servlets/DefaultDispatcher.java b/src/main/java/org/olat/core/commons/services/webdav/servlets/DefaultDispatcher.java index 67a6bbb0b1deb96b975bb712842ee3f39d45fcd4..30fa8961e2fe91a5f8bca8e2b70516e985ec53e8 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/servlets/DefaultDispatcher.java +++ b/src/main/java/org/olat/core/commons/services/webdav/servlets/DefaultDispatcher.java @@ -39,7 +39,6 @@ import javax.servlet.http.HttpServletResponse; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; -import org.olat.core.util.WebappHelper; import org.olat.core.util.servlets.URLEncoder; @@ -365,7 +364,7 @@ public abstract class DefaultDispatcher implements Serializable { // Find content type. String contentType = resource.getMimeType(); if (contentType == null) { - contentType = WebappHelper.getMimeType(resource.getName()); + contentType = request.getServletContext().getMimeType(resource.getName()); resource.setMimeType(contentType); } diff --git a/src/main/java/org/olat/core/commons/services/webdav/servlets/WebDAVDispatcherImpl.java b/src/main/java/org/olat/core/commons/services/webdav/servlets/WebDAVDispatcherImpl.java index 873332b0657d8a1e11f17c00422bad764cdb4c19..b50f6da04146dd4a485f43c3e1177a27330f80ef 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/servlets/WebDAVDispatcherImpl.java +++ b/src/main/java/org/olat/core/commons/services/webdav/servlets/WebDAVDispatcherImpl.java @@ -910,7 +910,7 @@ public class WebDAVDispatcherImpl resourceInputStream = req.getInputStream(); } - if (resources.write(path, resourceInputStream, true)) { + if (resources.write(path, resourceInputStream, true, null)) { if (resource.exists()) { resp.setStatus(HttpServletResponse.SC_NO_CONTENT); } else { @@ -1000,7 +1000,7 @@ public class WebDAVDispatcherImpl String path = getRelativePath(req); WebResourceRoot resources = getResources(req); if (resources.canWrite(path)) { - copyResource(req, resp); + copyResource(req, resp, false); } else { resp.sendError(WebdavStatus.SC_FORBIDDEN); } @@ -1025,7 +1025,7 @@ public class WebDAVDispatcherImpl return; } - if (copyResource(req, resp)) { + if (copyResource(req, resp, true)) { deleteResource(path, req, resp, false); } } @@ -1645,7 +1645,7 @@ public class WebDAVDispatcherImpl * @param resp Servlet response * @return boolean true if the copy is successful */ - private boolean copyResource(HttpServletRequest req, HttpServletResponse resp) + private boolean copyResource(HttpServletRequest req, HttpServletResponse resp, boolean moved) throws IOException { // Parsing destination header @@ -1718,7 +1718,7 @@ public class WebDAVDispatcherImpl Hashtable<String,Integer> errorList = new Hashtable<String,Integer>(); - boolean result = copyResource(req, errorList, path, destinationPath); + boolean result = copyResource(req, errorList, path, destinationPath, moved); if ((!result) || (!errorList.isEmpty())) { if (errorList.size() == 1) { @@ -1807,7 +1807,7 @@ public class WebDAVDispatcherImpl * @param dest Destination path */ private boolean copyResource(HttpServletRequest req, Hashtable<String,Integer> errorList, - String source, String dest) { + String source, String dest, boolean moved) { if (log.isDebug()) log.debug("Copy: " + source + " To: " + dest); @@ -1835,10 +1835,11 @@ public class WebDAVDispatcherImpl childSrc += "/"; } childSrc += entry.getName(); - copyResource(req, errorList, childSrc, childDest); + copyResource(req, errorList, childSrc, childDest, moved); } } else if (sourceResource.isFile()) { - if (!resources.write(dest, sourceResource.getInputStream(), false)) { + WebResource movedFrom = moved ? sourceResource : null; + if (!resources.write(dest, sourceResource.getInputStream(), false, movedFrom)) { errorList.put(source, new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); return false; } @@ -2111,8 +2112,7 @@ public class WebDAVDispatcherImpl generatedXML.writeProperty ("D", "getcontentlength", String.valueOf(resource.getContentLength())); - String contentType = req.getServletContext().getMimeType( - resource.getName()); + String contentType = req.getServletContext().getMimeType(resource.getName()); if (contentType != null) { generatedXML.writeProperty("D", "getcontenttype", contentType); diff --git a/src/main/java/org/olat/core/commons/services/webdav/servlets/WebResourceRoot.java b/src/main/java/org/olat/core/commons/services/webdav/servlets/WebResourceRoot.java index 9a700945bb3c5cd3720bcd32638098191cae6cdd..96fa17d96ca1db5b6971f14162e0cf8a3588910e 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/servlets/WebResourceRoot.java +++ b/src/main/java/org/olat/core/commons/services/webdav/servlets/WebResourceRoot.java @@ -82,7 +82,7 @@ public interface WebResourceRoot { * * @return <code>true</code> if and only if the new Resource is written */ - boolean write(String path, InputStream is, boolean overwrite); + boolean write(String path, InputStream is, boolean overwrite, WebResource movedFrom); public boolean delete(WebResource resourceo); diff --git a/src/main/java/org/olat/core/servlets/OpenOLATServlet.java b/src/main/java/org/olat/core/servlets/OpenOLATServlet.java index 3597b56b2a1a0de2df90fc4140f7afbc234ab203..251bdfc12e482eae8f81c080b56dce38d50be426 100644 --- a/src/main/java/org/olat/core/servlets/OpenOLATServlet.java +++ b/src/main/java/org/olat/core/servlets/OpenOLATServlet.java @@ -178,7 +178,7 @@ public class OpenOLATServlet extends HttpServlet { String subContext = DispatcherModule.getFirstPath(req); if("/".equals(subContext)) { webDAVDispatcher.doRootOptions(req, resp); - } else if("webdav".equals(subContext)) { + } else if("/webdav".equals(subContext) || "/webdav/".equals(subContext)) { webDAVDispatcher.doWebdavOptions(req, resp); } else { super.doOptions(req, resp); @@ -252,9 +252,8 @@ public class OpenOLATServlet extends HttpServlet { Dispatcher dispatcher = dispatchers.get(dispatcherName); dispatcher.execute(request, response); } else { - String uri = request.getRequestURI(); //root -> redirect to dmz - if("/".equals(uri)) { + if("/".equals(dispatcherName) || "/dmz".equals(dispatcherName)) { String dmzUri = WebappHelper.getServletContextPath() + DispatcherModule.getPathDefault(); response.sendRedirect(dmzUri); } else { diff --git a/src/main/webapp-tomcat/WEB-INF/web.xml b/src/main/webapp-tomcat/WEB-INF/web.xml index f135f9c9379607f1e5a0205920d32be0dcab8d7d..842a692ca156da1d86eab1f3140567c7b0a7e2f4 100644 --- a/src/main/webapp-tomcat/WEB-INF/web.xml +++ b/src/main/webapp-tomcat/WEB-INF/web.xml @@ -32,14 +32,7 @@ <param-name>contextInitializerClasses</param-name> <param-value>org.olat.core.CoreSpringInitializer</param-value> </context-param> - <!-- - <filter> - <filter-name>SpyFilter</filter-name> - <filter-class>org.olat.core.servlets.SpyFilter</filter-class> - </filter> - --> - - + <!-- 2. Filters --> <filter> <filter-name>OnyxHttpsFilter</filter-name> diff --git a/src/test/java/org/olat/core/commons/services/webdav/HttpCopy.java b/src/test/java/org/olat/core/commons/services/webdav/HttpCopy.java new file mode 100644 index 0000000000000000000000000000000000000000..2ef53479a87e5e1f2bc73be1b78030a45d8863b0 --- /dev/null +++ b/src/test/java/org/olat/core/commons/services/webdav/HttpCopy.java @@ -0,0 +1,57 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpRequestBase; + +/** + * + * Initial date: 11.11.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class HttpCopy extends HttpRequestBase { + + public final static String METHOD_NAME = "COPY"; + + public HttpCopy() { + super(); + } + + public HttpCopy(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpCopy(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/core/commons/services/webdav/HttpLock.java b/src/test/java/org/olat/core/commons/services/webdav/HttpLock.java new file mode 100644 index 0000000000000000000000000000000000000000..b17973109454a2a2a6735f102a58d68ed7e2d688 --- /dev/null +++ b/src/test/java/org/olat/core/commons/services/webdav/HttpLock.java @@ -0,0 +1,57 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; + +/** + * + * Initial date: 11.11.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class HttpLock extends HttpEntityEnclosingRequestBase { + + public final static String METHOD_NAME = "LOCK"; + + public HttpLock() { + super(); + } + + public HttpLock(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpLock(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/core/commons/services/webdav/HttpMkcol.java b/src/test/java/org/olat/core/commons/services/webdav/HttpMkcol.java new file mode 100644 index 0000000000000000000000000000000000000000..be8117f19087d9daf67b92dcca581a7e163ea9a5 --- /dev/null +++ b/src/test/java/org/olat/core/commons/services/webdav/HttpMkcol.java @@ -0,0 +1,57 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpRequestBase; + +/** + * + * Initial date: 11.11.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class HttpMkcol extends HttpRequestBase { + + public final static String METHOD_NAME = "MKCOL"; + + public HttpMkcol() { + super(); + } + + public HttpMkcol(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpMkcol(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/core/commons/services/webdav/HttpMove.java b/src/test/java/org/olat/core/commons/services/webdav/HttpMove.java new file mode 100644 index 0000000000000000000000000000000000000000..70c6f2d26ef355e70d1f48f8e8d65d49861922da --- /dev/null +++ b/src/test/java/org/olat/core/commons/services/webdav/HttpMove.java @@ -0,0 +1,57 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpRequestBase; + +/** + * + * Initial date: 11.11.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class HttpMove extends HttpRequestBase { + + public final static String METHOD_NAME = "MOVE"; + + public HttpMove() { + super(); + } + + public HttpMove(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpMove(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/core/commons/services/webdav/HttpUnlock.java b/src/test/java/org/olat/core/commons/services/webdav/HttpUnlock.java new file mode 100644 index 0000000000000000000000000000000000000000..619d1254b5a11b9f35fa2c7e0141e560bd96b5ad --- /dev/null +++ b/src/test/java/org/olat/core/commons/services/webdav/HttpUnlock.java @@ -0,0 +1,57 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.webdav; + +import java.net.URI; + +import org.apache.http.client.methods.HttpRequestBase; + +/** + * + * Initial date: 11.11.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class HttpUnlock extends HttpRequestBase { + + public final static String METHOD_NAME = "UNLOCK"; + + public HttpUnlock() { + super(); + } + + public HttpUnlock(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpUnlock(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/core/commons/services/webdav/WebDAVCommandsTest.java b/src/test/java/org/olat/core/commons/services/webdav/WebDAVCommandsTest.java index 91085ef34ed461ae5ee56ba19686f33b11977d94..75d71d62cb910b5940bd7ad8d95cceb320fee780 100644 --- a/src/test/java/org/olat/core/commons/services/webdav/WebDAVCommandsTest.java +++ b/src/test/java/org/olat/core/commons/services/webdav/WebDAVCommandsTest.java @@ -22,6 +22,7 @@ package org.olat.core.commons.services.webdav; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -33,6 +34,7 @@ import junit.framework.Assert; import org.apache.http.Header; import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPut; @@ -42,8 +44,14 @@ import org.apache.http.util.EntityUtils; import org.apache.poi.util.IOUtils; import org.junit.Test; import org.olat.basesecurity.BaseSecurity; +import org.olat.core.commons.modules.bc.FolderConfig; +import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; +import org.olat.core.util.FileUtils; +import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSItem; +import org.olat.core.util.vfs.VFSLeaf; import org.olat.course.CourseFactory; import org.olat.repository.RepositoryEntry; import org.olat.restapi.CoursePublishTest; @@ -131,6 +139,110 @@ public class WebDAVCommandsTest extends WebDAVTestCase { IOUtils.closeQuietly(conn); } + @Test + public void testMkcol_public() + throws IOException, URISyntaxException { + //create a user + Identity user = JunitTestHelper.createAndPersistIdentityAsAuthor("webdav-2a-" + UUID.randomUUID().toString()); + + //create a file + String publicPath = FolderConfig.getUserHomes() + "/" + user.getName() + "/public"; + VFSContainer vfsPublic = new OlatRootFolderImpl(publicPath, null); + Assert.assertTrue(vfsPublic.exists()); + + + WebDAVConnection conn = new WebDAVConnection(); + conn.setCredentials(user.getName(), "A6B7C8"); + + //author check course folder + URI publicUri = conn.getBaseURI().path("webdav").path("home").path("public").build(); + String publicXml = conn.propfind(publicUri, 2); + Assert.assertTrue(publicXml.indexOf("<D:href>/webdav/home/public/</D:href>") > 0); + + //make a folder + URI newUri = UriBuilder.fromUri(publicUri).path("newFolder").build(); + int returnMkcol = conn.mkcol(newUri); + Assert.assertEquals(201, returnMkcol); + + //check if folder exists + VFSItem newItem = vfsPublic.resolve("newFolder"); + Assert.assertNotNull(newItem); + Assert.assertTrue(newItem instanceof VFSContainer); + Assert.assertTrue(newItem.exists()); + + IOUtils.closeQuietly(conn); + } + + @Test + public void testMove_public() + throws IOException, URISyntaxException { + //create a user + Identity user = JunitTestHelper.createAndPersistIdentityAsAuthor("webdav-2b-" + UUID.randomUUID().toString()); + + //create a file + String publicPath = FolderConfig.getUserHomes() + "/" + user.getName() + "/public"; + VFSContainer vfsPublic = new OlatRootFolderImpl(publicPath, null); + createFile(vfsPublic, "test.txt"); + VFSContainer subPublic = vfsPublic.createChildContainer("moveto"); + + WebDAVConnection conn = new WebDAVConnection(); + conn.setCredentials(user.getName(), "A6B7C8"); + + //author check course folder + URI publicUri = conn.getBaseURI().path("webdav").path("home").path("public").build(); + URI fileUri = UriBuilder.fromUri(publicUri).path("test.txt").build(); + String destination = UriBuilder.fromUri(publicUri).path("moveto").path("test.txt").build().toString(); + int returnMove = conn.move(fileUri, destination); + Assert.assertEquals(201, returnMove); + + //check move + VFSItem movedItem = subPublic.resolve("test.txt"); + Assert.assertNotNull(movedItem); + Assert.assertTrue(movedItem instanceof VFSLeaf); + Assert.assertTrue(movedItem.exists()); + + VFSItem sourceItem = vfsPublic.resolve("test.txt"); + Assert.assertNull(sourceItem); + + IOUtils.closeQuietly(conn); + } + + @Test + public void testCopy_public() + throws IOException, URISyntaxException { + //create a user + Identity user = JunitTestHelper.createAndPersistIdentityAsAuthor("webdav-2b-" + UUID.randomUUID().toString()); + + //create a file + String publicPath = FolderConfig.getUserHomes() + "/" + user.getName() + "/public"; + VFSContainer vfsPublic = new OlatRootFolderImpl(publicPath, null); + createFile(vfsPublic, "test.txt"); + VFSContainer subPublic = vfsPublic.createChildContainer("copyto"); + + WebDAVConnection conn = new WebDAVConnection(); + conn.setCredentials(user.getName(), "A6B7C8"); + + //author check course folder + URI publicUri = conn.getBaseURI().path("webdav").path("home").path("public").build(); + URI fileUri = UriBuilder.fromUri(publicUri).path("test.txt").build(); + String destination = UriBuilder.fromUri(publicUri).path("copyto").path("copy.txt").build().toString(); + int returnMove = conn.copy(fileUri, destination); + Assert.assertEquals(201, returnMove); + + //check move + VFSItem movedItem = subPublic.resolve("copy.txt"); + Assert.assertNotNull(movedItem); + Assert.assertTrue(movedItem instanceof VFSLeaf); + Assert.assertTrue(movedItem.exists()); + + VFSItem sourceItem = vfsPublic.resolve("test.txt"); + Assert.assertNotNull(sourceItem); + Assert.assertTrue(sourceItem instanceof VFSLeaf); + Assert.assertTrue(sourceItem.exists()); + + IOUtils.closeQuietly(conn); + } + @Test public void testPut_course() throws IOException, URISyntaxException { @@ -166,7 +278,9 @@ public class WebDAVCommandsTest extends WebDAVTestCase { } /** - * PROPPATCH is essential for Windows + * PROPPATCH is essential for Windows, the content of the response + * is not important but it must not return an error. + * * @throws IOException * @throws URISyntaxException */ @@ -192,6 +306,7 @@ public class WebDAVCommandsTest extends WebDAVTestCase { put.setEntity(entity); HttpResponse putResponse = conn.execute(put); Assert.assertEquals(201, putResponse.getStatusLine().getStatusCode()); + EntityUtils.consume(putResponse.getEntity()); //PROPPATCH URI patchUri = UriBuilder.fromUri(privateUri).path("test.txt").build(); @@ -222,12 +337,19 @@ public class WebDAVCommandsTest extends WebDAVTestCase { IOUtils.closeQuietly(conn); } + /** + * In the this test, an author and its assistant try to concurrently + * lock a file. + * + * @throws IOException + * @throws URISyntaxException + */ @Test public void testLock() throws IOException, URISyntaxException { //create a user - Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("webdav-3-" + UUID.randomUUID().toString()); - Identity assistant = JunitTestHelper.createAndPersistIdentityAsAuthor("webdav-4-" + UUID.randomUUID().toString()); + Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("webdav-4-" + UUID.randomUUID().toString()); + Identity assistant = JunitTestHelper.createAndPersistIdentityAsAuthor("webdav-5-" + UUID.randomUUID().toString()); deployTestCourse(author, assistant); WebDAVConnection authorConn = new WebDAVConnection(); @@ -245,14 +367,89 @@ public class WebDAVCommandsTest extends WebDAVTestCase { String assistantPublicXml = assistantConn.propfind(courseUri, 2); Assert.assertTrue(assistantPublicXml.indexOf("<D:href>/webdav/coursefolders/Kurs/_courseelementdata/</D:href>") > 0); - //author lock the course folder + //PUT a file to lock + URI putUri = UriBuilder.fromUri(courseUri).path("Kurs").path("test.txt").build(); + HttpPut put = authorConn.createPut(putUri); + InputStream dataStream = WebDAVCommandsTest.class.getResourceAsStream("text.txt"); + InputStreamEntity entity = new InputStreamEntity(dataStream, -1); + put.setEntity(entity); + HttpResponse putResponse = authorConn.execute(put); + Assert.assertEquals(201, putResponse.getStatusLine().getStatusCode()); + EntityUtils.consume(putResponse.getEntity()); + + //author lock the file in the course folder + String authorLockToken = UUID.randomUUID().toString().replace("-", "").toLowerCase(); + String authorResponseLockToken = authorConn.lock(putUri, authorLockToken); + Assert.assertNotNull(authorResponseLockToken); + //coauthor try to lock the same file + String coauthorLockToken = UUID.randomUUID().toString().replace("-", "").toLowerCase(); + int coauthorLock = assistantConn.lockTry(putUri, coauthorLockToken); + Assert.assertEquals(423, coauthorLock);// it's lock + //author unlock the file + int unlockCode = authorConn.unlock(putUri, authorResponseLockToken); + Assert.assertEquals(204, unlockCode); + + //coauthor try a second time to lock the file + String coauthorLockToken_2 = UUID.randomUUID().toString().replace("-", "").toLowerCase(); + int coauthorLock_2 = assistantConn.lockTry(putUri, coauthorLockToken_2); + Assert.assertEquals(200, coauthorLock_2);// it's lock IOUtils.closeQuietly(authorConn); IOUtils.closeQuietly(assistantConn); } + @Test + public void testDelete() + throws IOException, URISyntaxException { + //create a user + Identity user = JunitTestHelper.createAndPersistIdentityAsUser("webdav-6-" + UUID.randomUUID().toString()); + + //create a file + String publicPath = FolderConfig.getUserHomes() + "/" + user.getName() + "/public"; + VFSContainer vfsPublic = new OlatRootFolderImpl(publicPath, null); + createFile(vfsPublic, "testDelete.txt"); + + //check + VFSItem item = vfsPublic.resolve("testDelete.txt"); + Assert.assertTrue(item instanceof VFSLeaf); + Assert.assertTrue(item.exists()); + Assert.assertTrue(((VFSLeaf)item).getSize() > 0); + + //delete the file + WebDAVConnection conn = new WebDAVConnection(); + conn.setCredentials(user.getName(), "A6B7C8"); + + //check public folder + URI checkUri = conn.getBaseURI().path("webdav").path("home").path("public").path("testDelete.txt").build(); + String publicXml = conn.propfind(checkUri, 1); + Assert.assertTrue(publicXml.indexOf("<D:multistatus") > 0);//Windows need the D namespace + Assert.assertTrue(publicXml.indexOf("<D:href>/webdav/home/public/testDelete.txt</D:href>") > 0);//check the root + + //delete the file + HttpDelete delete = conn.createDelete(checkUri); + HttpResponse deleteResponse = conn.execute(delete); + Assert.assertEquals(204, deleteResponse.getStatusLine().getStatusCode()); + EntityUtils.consume(deleteResponse.getEntity()); + + //check if really deleted + VFSItem reloadTestLeaf = vfsPublic.resolve("testDelete.txt"); + Assert.assertNull(reloadTestLeaf); + + IOUtils.closeQuietly(conn); + } + + private void createFile(VFSContainer container, String filename) throws IOException { + VFSLeaf testLeaf = container.createChildLeaf(filename); + InputStream in = WebDAVCommandsTest.class.getResourceAsStream("text.txt"); + OutputStream out = testLeaf.getOutputStream(false); + FileUtils.copy(in, out); + out.flush(); + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(out); + } + private void deployTestCourse(Identity author, Identity coAuthor) throws URISyntaxException { URL courseWithForumsUrl = CoursePublishTest.class.getResource("myCourseWS.zip"); Assert.assertNotNull(courseWithForumsUrl); diff --git a/src/test/java/org/olat/core/commons/services/webdav/WebDAVConnection.java b/src/test/java/org/olat/core/commons/services/webdav/WebDAVConnection.java index 5375091de13fe05451ad0852cd64c92bb834c802..848554fc066ad539167accd4c9456caaf1322bb9 100644 --- a/src/test/java/org/olat/core/commons/services/webdav/WebDAVConnection.java +++ b/src/test/java/org/olat/core/commons/services/webdav/WebDAVConnection.java @@ -21,6 +21,7 @@ package org.olat.core.commons.services.webdav; import java.io.Closeable; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; @@ -29,15 +30,18 @@ import javax.ws.rs.core.UriBuilder; import junit.framework.Assert; import org.apache.commons.io.IOUtils; +import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CookieStore; import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; @@ -97,6 +101,75 @@ public class WebDAVConnection implements Closeable { return EntityUtils.toString(response.getEntity()); } + public int mkcol(URI uri) throws IOException, URISyntaxException { + HttpMkcol mkcol = new HttpMkcol(uri); + HttpResponse response = execute(mkcol); + int returnCode = response.getStatusLine().getStatusCode(); + EntityUtils.consume(response.getEntity()); + return returnCode; + } + + public int move(URI uri, String destination) throws IOException, URISyntaxException { + HttpMove move = new HttpMove(uri); + move.setHeader("Destination", destination); + HttpResponse response = execute(move); + int returnCode = response.getStatusLine().getStatusCode(); + EntityUtils.consume(response.getEntity()); + return returnCode; + } + + public int copy(URI uri, String destination) throws IOException, URISyntaxException { + HttpCopy copy = new HttpCopy(uri); + copy.setHeader("Destination", destination); + HttpResponse response = execute(copy); + int returnCode = response.getStatusLine().getStatusCode(); + EntityUtils.consume(response.getEntity()); + return returnCode; + } + + public String lock(URI uri, String lockToken) throws IOException, URISyntaxException { + HttpLock lock = new HttpLock(uri); + decorateLockRequest(lock, lockToken); + HttpResponse response = execute(lock); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + Header responseToken = response.getFirstHeader("Lock-Token"); + Assert.assertNotNull(responseToken); + EntityUtils.consume(response.getEntity()); + return responseToken.getValue(); + } + + public int lockTry(URI uri, String lockToken) throws IOException, URISyntaxException { + HttpLock lock = new HttpLock(uri); + decorateLockRequest(lock, lockToken); + HttpResponse response = execute(lock); + int returnCode = response.getStatusLine().getStatusCode(); + EntityUtils.consume(response.getEntity()); + return returnCode; + } + + private void decorateLockRequest(HttpLock lock, String lockToken) throws UnsupportedEncodingException { + lock.addHeader("Lock-Token", lockToken); + StringBuilder sb = new StringBuilder(); + sb.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>") + .append("<D:lockinfo xmlns:D='DAV:'>") + .append(" <D:lockscope><D:exclusive/></D:lockscope>") + .append(" <D:locktype><D:write/></D:locktype>") + .append(" <D:owner>") + .append(" <D:href>").append(lock.getURI().toString()).append("</D:href>") + .append(" </D:owner>") + .append(" </D:lockinfo>"); + lock.setEntity(new StringEntity(sb.toString())); + } + + public int unlock(URI uri, String lockToken) throws IOException, URISyntaxException { + HttpUnlock unlock = new HttpUnlock(uri); + unlock.addHeader("Lock-Token", lockToken); + HttpResponse response = execute(unlock); + int returnCode = response.getStatusLine().getStatusCode(); + EntityUtils.consume(response.getEntity()); + return returnCode; + } + public HttpOptions createOptions(URI uri) throws IOException, URISyntaxException { HttpOptions options = new HttpOptions(uri); return options; @@ -108,6 +181,11 @@ public class WebDAVConnection implements Closeable { return put; } + public HttpDelete createDelete(URI uri) { + HttpDelete delete = new HttpDelete(uri); + return delete; + } + public HttpPropPatch createPropPatch(URI uri) { HttpPropPatch proppatch = new HttpPropPatch(uri); proppatch.addHeader("Accept", "*/*"); diff --git a/src/test/java/org/olat/core/commons/services/webdav/WebDAVTestCase.java b/src/test/java/org/olat/core/commons/services/webdav/WebDAVTestCase.java index a92b8025362d0a22cb85af79ef7788de3be1eb99..7b77ec4d3eba15e543fcff0085413f2776be5dd4 100644 --- a/src/test/java/org/olat/core/commons/services/webdav/WebDAVTestCase.java +++ b/src/test/java/org/olat/core/commons/services/webdav/WebDAVTestCase.java @@ -26,9 +26,14 @@ package org.olat.core.commons.services.webdav; -import java.io.IOException; +import static io.undertow.servlet.Servlets.defaultContainer; +import static io.undertow.servlet.Servlets.deployment; +import static io.undertow.servlet.Servlets.servlet; +import io.undertow.Undertow; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.DeploymentManager; -import javax.servlet.Servlet; +import javax.servlet.ServletException; import org.junit.BeforeClass; import org.olat.core.logging.OLog; @@ -36,9 +41,6 @@ import org.olat.core.logging.Tracing; import org.olat.core.servlets.OpenOLATServlet; import org.olat.test.OlatTestCase; -import com.sun.grizzly.http.embed.GrizzlyWebServer; -import com.sun.grizzly.http.servlet.ServletAdapter; - /** * * Description:<br> @@ -55,33 +57,33 @@ public abstract class WebDAVTestCase extends OlatTestCase { public final static String HOST = "localhost"; public final static String PROTOCOL = "http"; - private static GrizzlyWebServer webServer; + private static Undertow webServer; @BeforeClass public static void setUp() throws Exception { + + try { if(webServer == null) { - webServer = new GrizzlyWebServer(PORT); - webServer.useAsynchronousWrite(false); - ServletAdapter sa = new ServletAdapter(); - Servlet servletInstance = null; - try { - servletInstance = new OpenOLATServlet(); - } catch (Exception ex) { - log.error("Cannot instantiate the Grizzly Servlet Container", ex); - } - sa.setServletInstance(servletInstance); - sa.addInitParameter("debug", "0"); - sa.addInitParameter("input", "32768"); - sa.addInitParameter("output", "32768"); - sa.addInitParameter("listings", "true"); - sa.addInitParameter("readonly", "false"); - webServer.addGrizzlyAdapter(sa, new String[]{""}); + DeploymentInfo servletBuilder = deployment() + .setClassLoader(WebDAVTestCase.class.getClassLoader()) + .setContextPath("/") + .setDeploymentName("test.war") + .addServlets( + servlet("MessageServlet", OpenOLATServlet.class) + .addInitParam("message", "Hello World") + .addMapping("/*")); + + DeploymentManager manager = defaultContainer().addDeployment(servletBuilder); + manager.deploy(); - log.info("Starting the Grizzly Web Container for WebDAV..."); - webServer.start(); + webServer = Undertow.builder() + .addListener(PORT, HOST) + .setHandler(manager.start()) + .build(); + webServer.start(); } - } catch (IOException ex) { + } catch (ServletException ex) { log.error("Cannot start the Grizzly Web Container for WebDAV"); } } diff --git a/src/test/java/org/olat/restapi/RestConnection.java b/src/test/java/org/olat/restapi/RestConnection.java index 06d90edb5fa8c7c1849aa84e9e3e4934f2911c3b..2e15fb5bce5d7174285838c58887557ca98f92e5 100644 --- a/src/test/java/org/olat/restapi/RestConnection.java +++ b/src/test/java/org/olat/restapi/RestConnection.java @@ -70,7 +70,7 @@ import org.olat.restapi.security.RestSecurityHelper; /** * * Description:<br> - * Manage a connection to the grizzly server used by the unit test + * Manage a connection to the server used by the unit test * with some helpers methods. * * <P> diff --git a/src/test/java/org/olat/test/OlatJerseyTestCase.java b/src/test/java/org/olat/test/OlatJerseyTestCase.java index 9bda28718b01c7219c226be56a075de0fbc2d6df..582f71a2d24a3270ef8e69a128d0f4fb5f99ad00 100644 --- a/src/test/java/org/olat/test/OlatJerseyTestCase.java +++ b/src/test/java/org/olat/test/OlatJerseyTestCase.java @@ -26,13 +26,20 @@ package org.olat.test; -import java.io.IOException; +import static io.undertow.servlet.Servlets.defaultContainer; +import static io.undertow.servlet.Servlets.deployment; +import static io.undertow.servlet.Servlets.filter; +import static io.undertow.servlet.Servlets.servlet; +import io.undertow.Undertow; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.DeploymentManager; + import java.io.InputStream; import java.net.URI; import java.util.List; -import javax.servlet.Servlet; -import javax.servlet.http.HttpServlet; +import javax.servlet.DispatcherType; +import javax.servlet.ServletException; import javax.ws.rs.core.UriBuilder; import org.codehaus.jackson.JsonFactory; @@ -49,13 +56,10 @@ import org.olat.restapi.support.vo.FileVO; import org.olat.restapi.support.vo.LinkVO; import org.springframework.beans.factory.annotation.Autowired; -import com.sun.grizzly.http.embed.GrizzlyWebServer; -import com.sun.grizzly.http.servlet.ServletAdapter; - /** * * Description:<br> - * Abstract class which start and stop a grizzly server for every test + * Abstract class which start and stop an undertow server * * <P> * Initial Date: 14 apr. 2010 <br> @@ -75,7 +79,7 @@ public abstract class OlatJerseyTestCase extends OlatTestCase { public final static String PROTOCOL = "http"; private static boolean webServerStarted = false; - private static GrizzlyWebServer webServer; + private static Undertow webServer; @Autowired private RestModule restModule; @@ -85,28 +89,38 @@ public abstract class OlatJerseyTestCase extends OlatTestCase { */ public OlatJerseyTestCase() { super(); - instantiateGrizzlyWebServer(); + instantiateServer(); } /** - * Instantiates the Grizzly Web Server + * Instantiates the server */ - private void instantiateGrizzlyWebServer() { + private void instantiateServer() { if(webServer == null) { - webServer = new GrizzlyWebServer(PORT); - webServer.useAsynchronousWrite(false); - ServletAdapter sa = new ServletAdapter(); - Servlet servletInstance = null; try { - servletInstance = (HttpServlet)Class.forName("com.sun.jersey.spi.container.servlet.ServletContainer").newInstance(); - } catch (Exception ex) { - log.error("Cannot instantiate the Grizzly Servlet Container", ex); + DeploymentInfo servletBuilder = deployment() + .setClassLoader(OlatJerseyTestCase.class.getClassLoader()) + .setContextPath("/" + CONTEXT_PATH) + .setDeploymentName("rest.war") + .addServlets( + servlet("REST Servlet", com.sun.jersey.spi.container.servlet.ServletContainer.class) + .addInitParam("javax.ws.rs.Application", OlatRestApplication.class.getName()) + .addMapping("/*")) + .addFilters(filter("REST security filter", RestApiLoginFilter.class)) + .addFilterUrlMapping("REST security filter", "/*", DispatcherType.REQUEST); + + DeploymentManager manager = defaultContainer().addDeployment(servletBuilder); + manager.deploy(); + + webServer = Undertow.builder() + .addListener(PORT, HOST) + .setHandler(manager.start()) + .build(); + webServer.start(); + webServerStarted = true; + } catch (ServletException e) { + log.error("", e); } - sa.setServletInstance(servletInstance); - sa.addFilter(new RestApiLoginFilter(), "jerseyfilter", null); - sa.addInitParameter("javax.ws.rs.Application", OlatRestApplication.class.getName()); - sa.setContextPath("/" + CONTEXT_PATH); - webServer.addGrizzlyAdapter(sa, new String[]{""}); } } @@ -121,17 +135,13 @@ public abstract class OlatJerseyTestCase extends OlatTestCase { @Before public void setUp() throws Exception { //always enabled the REST API for testing - restModule.setEnabled(true); - - try { - if(!webServerStarted) { - log.info("Starting the Grizzly Web Container..."); - webServer.start(); - webServerStarted=true; - } - } catch (IOException ex) { - log.error("Cannot start the Grizzly Web Container"); - } + restModule.setEnabled(true); + + if(!webServerStarted) { + log.info("Starting the Grizzly Web Container..."); + webServer.start(); + webServerStarted=true; + } } protected List<ErrorVO> parseErrorArray(InputStream body) { @@ -139,7 +149,7 @@ public abstract class OlatJerseyTestCase extends OlatTestCase { ObjectMapper mapper = new ObjectMapper(jsonFactory); return mapper.readValue(body, new TypeReference<List<ErrorVO>>(){/* */}); } catch (Exception e) { - e.printStackTrace(); + log.error("", e); return null; } } @@ -149,7 +159,7 @@ public abstract class OlatJerseyTestCase extends OlatTestCase { ObjectMapper mapper = new ObjectMapper(jsonFactory); return mapper.readValue(body, new TypeReference<List<LinkVO>>(){/* */}); } catch (Exception e) { - e.printStackTrace(); + log.error("", e); return null; } } @@ -159,7 +169,7 @@ public abstract class OlatJerseyTestCase extends OlatTestCase { ObjectMapper mapper = new ObjectMapper(jsonFactory); return mapper.readValue(body, new TypeReference<List<FileVO>>(){/* */}); } catch (Exception e) { - e.printStackTrace(); + log.error("", e); return null; } }