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.example;
18  
19  import java.io.BufferedReader;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStreamReader;
23  import java.net.URL;
24  import java.nio.charset.Charset;
25  import java.text.DateFormat;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Collection;
29  import java.util.Date;
30  import java.util.List;
31  import java.util.StringTokenizer;
32  
33  import org.apache.commons.lang3.ArrayUtils;
34  import org.apache.commons.vfs2.Capability;
35  import org.apache.commons.vfs2.FileContent;
36  import org.apache.commons.vfs2.FileObject;
37  import org.apache.commons.vfs2.FileSystemException;
38  import org.apache.commons.vfs2.FileSystemManager;
39  import org.apache.commons.vfs2.FileType;
40  import org.apache.commons.vfs2.Selectors;
41  import org.apache.commons.vfs2.VFS;
42  import org.apache.commons.vfs2.impl.StandardFileSystemManager;
43  import org.apache.commons.vfs2.operations.FileOperationProvider;
44  import org.apache.commons.vfs2.util.FileObjectUtils;
45  
46  /**
47   * A simple command-line shell for performing file operations.
48   * <p>
49   * See <a href="https://wiki.apache.org/commons/VfsExampleShell">Commons VFS Shell Examples</a> in Apache Commons Wiki.
50   */
51  public final class Shell {
52  
53      private final FileSystemManager mgr;
54      private FileObject cwd;
55      private final BufferedReader reader;
56  
57      private Shell() throws IOException {
58          final String providers = System.getProperty("providers");
59          final URL providersUrl = (providers != null) ? Shell.class.getResource("/" + providers) : null;
60  
61          if (providersUrl != null) {
62              mgr = new StandardFileSystemManager();
63              System.out.println("Custom providers configuration used: " + providersUrl);
64              ((StandardFileSystemManager) mgr).setConfiguration(providersUrl);
65              ((StandardFileSystemManager) mgr).init();
66          } else {
67              mgr = VFS.getManager();
68          }
69  
70          cwd = mgr.toFileObject(new File(System.getProperty("user.dir")));
71          reader = new BufferedReader(new InputStreamReader(System.in, Charset.defaultCharset()));
72      }
73  
74      public static void main(final String[] args) {
75          try {
76              new Shell().go();
77          } catch (final Exception e) {
78              e.printStackTrace();
79              System.exit(1);
80          }
81          System.exit(0);
82      }
83  
84      private void go() throws Exception {
85          System.out.println("VFS Shell " + getVersion(Shell.class));
86          while (true) {
87              final String[] commands = nextCommand();
88              if (commands == null) {
89                  return;
90              }
91              if (commands.length == 0) {
92                  continue;
93              }
94              final String cmdName = commands[0];
95              if (cmdName.equalsIgnoreCase("exit") || cmdName.equalsIgnoreCase("quit")) {
96                  return;
97              }
98              try {
99                  handleCommand(commands);
100             } catch (final Exception e) {
101                 System.err.println("Command failed:");
102                 e.printStackTrace(System.err);
103             }
104         }
105     }
106 
107     /**
108      * Handles a command.
109      */
110     private void handleCommand(final String[] cmd) throws Exception {
111         final String cmdName = cmd[0];
112         if (cmdName.equalsIgnoreCase("cat")) {
113             cat(cmd);
114         } else if (cmdName.equalsIgnoreCase("cd")) {
115             cd(cmd);
116         } else if (cmdName.equalsIgnoreCase("cp")) {
117             cp(cmd);
118         } else if (cmdName.equalsIgnoreCase("help") || cmdName.equals("?")) {
119             help();
120         } else if (cmdName.equalsIgnoreCase("ls")) {
121             ls(cmd);
122         } else if (cmdName.equalsIgnoreCase("pwd")) {
123             pwd();
124         } else if (cmdName.equalsIgnoreCase("pwfs")) {
125             pwfs();
126         } else if (cmdName.equalsIgnoreCase("rm")) {
127             rm(cmd);
128         } else if (cmdName.equalsIgnoreCase("touch")) {
129             touch(cmd);
130         } else if (cmdName.equalsIgnoreCase("info")) {
131             info(cmd);
132         } else {
133             System.err.println("Unknown command \"" + cmdName + "\" (Try 'help').");
134         }
135     }
136 
137     private void info(final String[] cmd) throws Exception {
138         if (cmd.length > 1) {
139             info(cmd[1]);
140         } else {
141             System.out.println(
142                     "Default manager: \"" + mgr.getClass().getName() + "\" " + "version " + getVersion(mgr.getClass()));
143             final String[] schemes = mgr.getSchemes();
144             final List<String> virtual = new ArrayList<>();
145             final List<String> physical = new ArrayList<>();
146             for (final String scheme : schemes) {
147                 final Collection<Capability> caps = mgr.getProviderCapabilities(scheme);
148                 if (caps != null) {
149                     if (caps.contains(Capability.VIRTUAL) || caps.contains(Capability.COMPRESS)
150                             || caps.contains(Capability.DISPATCHER)) {
151                         virtual.add(scheme);
152                     } else {
153                         physical.add(scheme);
154                     }
155                 }
156             }
157             if (!physical.isEmpty()) {
158                 System.out.println("  Provider Schemes: " + physical);
159             }
160             if (!virtual.isEmpty()) {
161                 System.out.println("   Virtual Schemes: " + virtual);
162             }
163         }
164     }
165 
166     private void info(final String scheme) throws Exception {
167         System.out.println("Provider Info for scheme \"" + scheme + "\":");
168         final Collection<Capability> caps;
169         caps = mgr.getProviderCapabilities(scheme);
170         if (caps != null && !caps.isEmpty()) {
171             System.out.println("  capabilities: " + caps);
172         }
173         final FileOperationProvider[] ops = mgr.getOperationProviders(scheme);
174         if (ops != null && ops.length > 0) {
175             System.out.println("  operations: " + Arrays.toString(ops));
176         }
177     }
178 
179     /**
180      * Does a 'help' command.
181      */
182     private void help() {
183         System.out.println("Commands:");
184         System.out.println("cat <file>         Displays the contents of a file.");
185         System.out.println("cd [folder]        Changes current folder.");
186         System.out.println("cp <src> <dest>    Copies a file or folder.");
187         System.out.println("help               Shows this message.");
188         System.out.println("info [scheme]      Displays information about providers.");
189         System.out.println("ls [-R] [path]     Lists contents of a file or folder.");
190         System.out.println("pwd                Displays current folder.");
191         System.out.println("pwfs               Displays current file system.");
192         System.out.println("rm <path>          Deletes a file or folder.");
193         System.out.println("touch <path>       Sets the last-modified time of a file.");
194         System.out.println("exit, quit         Exits this program.");
195     }
196 
197     /**
198      * Does an 'rm' command.
199      */
200     private void rm(final String[] cmd) throws Exception {
201         if (cmd.length < 2) {
202             throw new Exception("USAGE: rm <path>");
203         }
204 
205         final FileObject file = mgr.resolveFile(cwd, cmd[1]);
206         file.delete(Selectors.SELECT_SELF);
207     }
208 
209     /**
210      * Does a 'cp' command.
211      */
212     private void cp(final String[] cmd) throws Exception {
213         if (cmd.length < 3) {
214             throw new Exception("USAGE: cp <src> <dest>");
215         }
216 
217         final FileObject src = mgr.resolveFile(cwd, cmd[1]);
218         FileObject dest = mgr.resolveFile(cwd, cmd[2]);
219         if (dest.exists() && dest.getType() == FileType.FOLDER) {
220             dest = dest.resolveFile(src.getName().getBaseName());
221         }
222 
223         dest.copyFrom(src, Selectors.SELECT_ALL);
224     }
225 
226     /**
227      * Does a 'cat' command.
228      */
229     private void cat(final String[] cmd) throws Exception {
230         if (cmd.length < 2) {
231             throw new Exception("USAGE: cat <path>");
232         }
233 
234         // Locate the file
235         final FileObject file = mgr.resolveFile(cwd, cmd[1]);
236 
237         // Dump the contents to System.out
238         FileObjectUtils.writeContent(file, System.out);
239         System.out.println();
240     }
241 
242     /**
243      * Does a 'pwd' command.
244      */
245     private void pwd() {
246         System.out.println("Current folder is " + cwd.getName());
247     }
248 
249     /**
250      * Does a 'pwfs' command.
251      */
252     private void pwfs() {
253         System.out.println("FileSystem of current folder is " + cwd.getFileSystem() + " (root: "
254                 + cwd.getFileSystem().getRootURI() + ")");
255     }
256 
257     /**
258      * Does a 'cd' command. If the taget directory does not exist, a message is printed to {@code System.err}.
259      */
260     private void cd(final String[] cmd) throws Exception {
261         final String path;
262         if (cmd.length > 1) {
263             path = cmd[1];
264         } else {
265             path = System.getProperty("user.home");
266         }
267 
268         // Locate and validate the folder
269         final FileObject tmp = mgr.resolveFile(cwd, path);
270         if (tmp.exists()) {
271             cwd = tmp;
272         } else {
273             System.out.println("Folder does not exist: " + tmp.getName());
274         }
275         System.out.println("Current folder is " + cwd.getName());
276     }
277 
278     /**
279      * Does an 'ls' command.
280      */
281     private void ls(final String[] cmd) throws FileSystemException {
282         int pos = 1;
283         final boolean recursive;
284         if (cmd.length > pos && cmd[pos].equals("-R")) {
285             recursive = true;
286             pos++;
287         } else {
288             recursive = false;
289         }
290 
291         final FileObject file;
292         if (cmd.length > pos) {
293             file = mgr.resolveFile(cwd, cmd[pos]);
294         } else {
295             file = cwd;
296         }
297 
298         if (file.getType() == FileType.FOLDER) {
299             // List the contents
300             System.out.println("Contents of " + file.getName());
301             listChildren(file, recursive, "");
302         } else {
303             // Stat the file
304             System.out.println(file.getName());
305             final FileContent content = file.getContent();
306             System.out.println("Size: " + content.getSize() + " bytes.");
307             final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
308             final String lastMod = dateFormat.format(new Date(content.getLastModifiedTime()));
309             System.out.println("Last modified: " + lastMod);
310         }
311     }
312 
313     /**
314      * Does a 'touch' command.
315      */
316     private void touch(final String[] cmd) throws Exception {
317         if (cmd.length < 2) {
318             throw new Exception("USAGE: touch <path>");
319         }
320         final FileObject file = mgr.resolveFile(cwd, cmd[1]);
321         if (!file.exists()) {
322             file.createFile();
323         }
324         file.getContent().setLastModifiedTime(System.currentTimeMillis());
325     }
326 
327     /**
328      * Lists the children of a folder.
329      */
330     private void listChildren(final FileObject dir, final boolean recursive, final String prefix)
331             throws FileSystemException {
332         final FileObject[] children = dir.getChildren();
333         for (final FileObject child : children) {
334             System.out.print(prefix);
335             System.out.print(child.getName().getBaseName());
336             if (child.getType() == FileType.FOLDER) {
337                 System.out.println("/");
338                 if (recursive) {
339                     listChildren(child, true, prefix + "    ");
340                 }
341             } else {
342                 System.out.println();
343             }
344         }
345     }
346 
347     /**
348      * Returns the next command, split into tokens.
349      */
350     private String[] nextCommand() throws IOException {
351         System.out.print("> ");
352         final String line = reader.readLine();
353         if (line == null) {
354             return null;
355         }
356         final ArrayList<String> cmd = new ArrayList<>();
357         final StringTokenizer tokens = new StringTokenizer(line);
358         while (tokens.hasMoreTokens()) {
359             cmd.add(tokens.nextToken());
360         }
361         return cmd.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
362     }
363 
364     private static String getVersion(final Class<?> cls) {
365         try {
366             return cls.getPackage().getImplementationVersion();
367         } catch (final Exception ignored) {
368             return "N/A";
369         }
370     }
371 }