View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2.provider.webdav.test;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.nio.file.Files;
23  
24  import javax.jcr.Node;
25  import javax.jcr.NodeIterator;
26  import javax.jcr.Property;
27  import javax.jcr.PropertyIterator;
28  import javax.jcr.RepositoryException;
29  import javax.jcr.Session;
30  import javax.jcr.SimpleCredentials;
31  import javax.jcr.Value;
32  
33  import org.apache.commons.io.FileUtils;
34  import org.apache.commons.vfs2.AbstractProviderTestConfig;
35  import org.apache.commons.vfs2.FileObject;
36  import org.apache.commons.vfs2.FileSystemManager;
37  import org.apache.commons.vfs2.FileSystemOptions;
38  import org.apache.commons.vfs2.ProviderTestSuite;
39  import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
40  import org.apache.commons.vfs2.provider.temp.TemporaryFileProvider;
41  import org.apache.commons.vfs2.provider.webdav.WebdavFileProvider;
42  import org.apache.commons.vfs2.provider.webdav.WebdavFileSystemConfigBuilder;
43  import org.apache.commons.vfs2.util.FreeSocketPortUtil;
44  import org.apache.jackrabbit.core.TransientRepository;
45  import org.apache.log4j.Level;
46  import org.apache.log4j.Logger;
47  
48  import junit.framework.Test;
49  
50  /**
51   * Test cases for the WebDAV provider.
52   *
53   */
54  public class WebdavProviderTestCase extends AbstractProviderTestConfig {
55      private static final char[] PASSWORD = new char[0];
56  
57      private static final String USER_ID = "admin";
58  
59      private static int SocketPort;
60  
61      private static final String TEST_URI = "test.webdav.uri";
62  
63      private static JackrabbitMain JrMain;
64  
65      /**
66       * Use %40 for @ in URLs
67       */
68      private static String ConnectionUri;
69  
70      private static File RepoDirectory;
71  
72      private static final boolean DEBUG = Boolean.getBoolean("WebdavProviderTestCase.Debug");
73  
74      static File createTempDirectory() throws IOException {
75          // create base folder
76          final File base = new File("./target/test").getCanonicalFile();
77          base.mkdirs();
78  
79          final File tempFile = File.createTempFile("WebdavProviderTestCase_", ".tmp", base);
80  
81          if (!tempFile.delete()) {
82              throw new IOException("Could not delete temp file: " + tempFile.getAbsolutePath());
83          }
84  
85          if (!tempFile.mkdir()) {
86              throw new IOException("Could not create temp directory: " + tempFile.getAbsolutePath());
87          }
88  
89          if (DEBUG) {
90              System.out.println("Working in " + tempFile);
91          }
92  
93          return tempFile;
94      }
95  
96      private static void dump(final File repoDirectory) throws Exception {
97          final TransientRepository repository = getTransientRepository(repoDirectory);
98          try {
99              final Session session = getSession(repository);
100             message("Root node dump:");
101             dump(session.getRootNode());
102             session.logout();
103         } finally {
104             repository.shutdown();
105         }
106     }
107 
108     /** Recursively outputs the contents of the given node. */
109     private static void dump(final Node node) throws RepositoryException {
110         // First output the node path
111         message(node.getPath());
112         // Skip the virtual (and large!) jcr:system subtree
113         if (node.getName().equals("jcr:system")) {
114             return;
115         }
116 
117         if (node.getName().equals("jcr:content")) {
118             return;
119         }
120 
121         // Then output the properties
122         final PropertyIterator properties = node.getProperties();
123         while (properties.hasNext()) {
124             final Property property = properties.nextProperty();
125             if (property.getDefinition().isMultiple()) {
126                 // A multi-valued property, print all values
127                 final Value[] values = property.getValues();
128                 for (final Value value : values) {
129                     message(property.getPath() + " = " + value.getString());
130                 }
131             } else {
132                 // A single-valued property
133                 message(property.getPath() + " = " + property.getString());
134             }
135         }
136 
137         // Finally output all the child nodes recursively
138         final NodeIterator nodes = node.getNodes();
139         while (nodes.hasNext()) {
140             dump(nodes.nextNode());
141         }
142     }
143 
144     private static Session getSession(final TransientRepository repository) throws RepositoryException {
145         return repository.login(new SimpleCredentials(USER_ID, PASSWORD));
146     }
147 
148     private static String getSystemTestUriOverride() {
149         return System.getProperty(TEST_URI);
150     }
151 
152     private static TransientRepository getTransientRepository(final File repoDirectory) throws IOException {
153         // Jackrabbit 1.6:
154         // TransientRepository repository = new TransientRepository(repoDirectory);
155         // Jackrabbit 1.5.2:
156         return new TransientRepository(new File(repoDirectory, "repository.xml").toString(), repoDirectory.toString());
157     }
158 
159     private static void importFiles(final File repoDirectory, final File sourceDir) throws Exception {
160         final TransientRepository repository = getTransientRepository(repoDirectory);
161         try {
162             final Session session = getSession(repository);
163             importFiles(session.getRootNode(), sourceDir);
164             session.save();
165             session.logout();
166         } finally {
167             repository.shutdown();
168         }
169     }
170 
171     private static void importFiles(final Node parent, final File sourceDir) throws RepositoryException, IOException {
172         final File[] files = sourceDir.listFiles();
173         for (final File file : files) {
174             if (file.isFile()) {
175                 try (InputStream data = Files.newInputStream(file.toPath())) {
176                     message("Importing file " + file);
177                     JcrUtils.putFile(parent, file.getName(), "application/octet-stream", data);
178                 }
179             } else if (file.isDirectory()) {
180                 message("Importing folder " + file);
181                 final Node folder = JcrUtils.getOrAddFolder(parent, file.getName());
182                 importFiles(folder, file);
183             }
184         }
185     }
186 
187     private static void message(final IOException e) {
188         if (DEBUG) {
189             e.printStackTrace();
190         }
191     }
192 
193     private static void message(final String string) {
194         if (DEBUG) {
195             System.out.println(string);
196         }
197     }
198 
199     /**
200      * Creates and starts an embedded Apache WebDAV Server (Jackrabbit).
201      *
202      * @throws Exception
203      */
204     private static void setUpClass() throws Exception {
205         // Create temp dir for repo
206         RepoDirectory = createTempDirectory();
207         message("Created temp directory " + RepoDirectory);
208         // Populate repo
209         importFiles(RepoDirectory, new File(getTestDirectory()));
210         dump(RepoDirectory);
211         // Start server with temp repo
212         startJackrabbit(RepoDirectory);
213         message("Returned from org.apache.jackrabbit.standalone.Main " + SocketPort);
214     }
215 
216     /**
217      * Starts an embedded Apache Jackrabbit server.
218      *
219      * @param repoDirectory
220      * @throws Exception
221      */
222     private static void startJackrabbit(final File repoDirectory) throws Exception {
223         boolean quiet = false;
224         if (!DEBUG) {
225             Logger.getLogger("org.apache.jackrabbit").setLevel(Level.WARN);
226             Logger.getLogger("org.apache.commons.httpclient").setLevel(Level.ERROR);
227             Logger.getLogger("org.apache.commons.vfs2").setLevel(Level.WARN);
228             Logger.getLogger("org.mortbay").setLevel(Level.WARN);
229             quiet = true;
230         }
231         JrMain = new JackrabbitMain(new String[] { "--port", Integer.toString(SocketPort), "--repo",
232                 repoDirectory.toString(), quiet ? "--quiet" : "" });
233         JrMain.run();
234     }
235 
236     public static Test suite() throws Exception {
237         return new ProviderTestSuite(new WebdavProviderTestCase()) {
238             @Override
239             protected void setUp() throws Exception {
240                 if (getSystemTestUriOverride() == null) {
241                     setUpClass();
242                 }
243                 super.setUp();
244             }
245 
246             @Override
247             protected void tearDown() throws Exception {
248                 tearDownClass();
249                 super.tearDown();
250             }
251         };
252     }
253 
254     /**
255      * Tears down resources for this test case.
256      * <ol>
257      * <li>Shuts down the embedded Jackrabbit</li>
258      * <li>Extra clean up for org.apache.commons.httpclient.MultiThreadedHttpConnectionManager</li>
259      * <li>Remove temporary repository directory.</li>
260      * </ol>
261      * Stops the embedded Apache WebDAV Server.
262      *
263      * @throws Exception @throws
264      */
265     private static void tearDownClass() throws Exception {
266         // Main JR shutdown
267         JrMain.shutdown();
268 
269         if (DEBUG) {
270             message("Skipping cleanup of " + RepoDirectory);
271             return;
272         }
273 
274         // Remove repo dir
275         try {
276             message("Deleting temp directory " + RepoDirectory);
277             FileUtils.deleteDirectory(RepoDirectory);
278         } catch (final IOException e) {
279             message(e);
280             if (RepoDirectory.exists()) {
281                 message("Directory will be deleted on VM exit " + RepoDirectory);
282                 RepoDirectory.deleteOnExit();
283             }
284         }
285     }
286 
287     public WebdavProviderTestCase() throws IOException {
288         SocketPort = FreeSocketPortUtil.findFreeLocalPort();
289         message("FreeSocketPortUtil.findFreeLocalPort() = " + SocketPort);
290         // Use %40 for @ in a URL
291         // Any user id and password will do with the default Jackrabbit set up.
292         ConnectionUri = String.format("webdav://%s@localhost:%d/repository/default", USER_ID, SocketPort);
293     }
294 
295     /**
296      * Returns the base folder for tests.
297      */
298     @Override
299     public FileObject getBaseTestFolder(final FileSystemManager manager) throws Exception {
300         String uri = getSystemTestUriOverride();
301         if (uri == null) {
302             uri = ConnectionUri;
303         }
304         final WebdavFileSystemConfigBuilder builder = (WebdavFileSystemConfigBuilder) manager
305                 .getFileSystemConfigBuilder("webdav");
306         final FileSystemOptions opts = new FileSystemOptions();
307         builder.setRootURI(opts, uri);
308         return manager.resolveFile(uri, opts);
309     }
310 
311     @Override
312     public boolean isFileSystemRootAccessible() {
313         return false;
314     }
315 
316     /**
317      * Prepares the file system manager.
318      */
319     @Override
320     public void prepare(final DefaultFileSystemManager manager) throws Exception {
321         manager.addProvider("webdav", new WebdavFileProvider());
322         manager.addProvider("tmp", new TemporaryFileProvider());
323     }
324 
325 }