001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.vfs2.example;
018
019import java.io.BufferedReader;
020import java.io.File;
021import java.io.IOException;
022import java.io.InputStreamReader;
023import java.nio.charset.Charset;
024import java.text.DateFormat;
025import java.util.ArrayList;
026import java.util.Collection;
027import java.util.Date;
028import java.util.List;
029import java.util.StringTokenizer;
030
031import org.apache.commons.vfs2.Capability;
032import org.apache.commons.vfs2.FileContent;
033import org.apache.commons.vfs2.FileObject;
034import org.apache.commons.vfs2.FileSystemException;
035import org.apache.commons.vfs2.FileSystemManager;
036import org.apache.commons.vfs2.FileType;
037import org.apache.commons.vfs2.FileUtil;
038import org.apache.commons.vfs2.Selectors;
039import org.apache.commons.vfs2.VFS;
040import org.apache.commons.vfs2.operations.FileOperationProvider;
041
042/**
043 * A simple command-line shell for performing file operations.
044 * <p>
045 * See
046 * <a href="https://wiki.apache.org/commons/VfsExampleShell">Commons VFS Shell Examples</a>
047 * in Apache Commons Wiki.
048 */
049public final class Shell
050{
051    private final FileSystemManager mgr;
052    private FileObject cwd;
053    private final BufferedReader reader;
054
055    private Shell() throws IOException
056    {
057        mgr = VFS.getManager();
058        cwd = mgr.toFileObject(new File(System.getProperty("user.dir")));
059        reader = new BufferedReader(new InputStreamReader(System.in, Charset.defaultCharset()));
060    }
061
062    public static void main(final String[] args)
063    {
064        try
065        {
066            new Shell().go();
067        }
068        catch (final Exception e)
069        {
070            e.printStackTrace();
071            System.exit(1);
072        }
073        System.exit(0);
074    }
075
076    private void go() throws Exception
077    {
078        System.out.println("VFS Shell " + getVersion(Shell.class));
079        while (true)
080        {
081            final String[] cmd = nextCommand();
082            if (cmd == null)
083            {
084                return;
085            }
086            if (cmd.length == 0)
087            {
088                continue;
089            }
090            final String cmdName = cmd[0];
091            if (cmdName.equalsIgnoreCase("exit") || cmdName.equalsIgnoreCase("quit"))
092            {
093                return;
094            }
095            try
096            {
097                handleCommand(cmd);
098            }
099            catch (final Exception e)
100            {
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    {
112        final String cmdName = cmd[0];
113        if (cmdName.equalsIgnoreCase("cat"))
114        {
115            cat(cmd);
116        }
117        else if (cmdName.equalsIgnoreCase("cd"))
118        {
119            cd(cmd);
120        }
121        else if (cmdName.equalsIgnoreCase("cp"))
122        {
123            cp(cmd);
124        }
125        else if (cmdName.equalsIgnoreCase("help") || cmdName.equals("?"))
126        {
127            help();
128        }
129        else if (cmdName.equalsIgnoreCase("ls"))
130        {
131            ls(cmd);
132        }
133        else if (cmdName.equalsIgnoreCase("pwd"))
134        {
135            pwd();
136        }
137        else if (cmdName.equalsIgnoreCase("rm"))
138        {
139            rm(cmd);
140        }
141        else if (cmdName.equalsIgnoreCase("touch"))
142        {
143            touch(cmd);
144        }
145        else if (cmdName.equalsIgnoreCase("info"))
146        {
147            info(cmd);
148        }
149        else
150        {
151            System.err.println("Unknown command \"" + cmdName + "\" (Try 'help').");
152        }
153    }
154
155    private void info(String[] cmd) throws Exception
156    {
157        if (cmd.length > 1)
158        {
159            info(cmd[1]);
160        }
161        else
162        {
163            System.out.println("Default manager: \"" + mgr.getClass().getName() + "\" " +
164                                   "version " + getVersion(mgr.getClass()));
165            String[] schemes = mgr.getSchemes();
166            List<String> virtual = new ArrayList<String>();
167            List<String> physical = new ArrayList<String>();
168            for (int i = 0; i < schemes.length; i++)
169            {
170                Collection<Capability> caps = mgr.getProviderCapabilities(schemes[i]);
171                if (caps != null)
172                {
173                    if (caps.contains(Capability.VIRTUAL)  ||
174                            caps.contains(Capability.COMPRESS) ||
175                            caps.contains(Capability.DISPATCHER))
176                    {
177                        virtual.add(schemes[i]);
178                    }
179                    else
180                    {
181                        physical.add(schemes[i]);
182                    }
183                }
184            }
185            if (!physical.isEmpty())
186            {
187                System.out.println("  Provider Schemes: " + physical);
188            }
189            if (!virtual.isEmpty())
190            {
191                System.out.println("   Virtual Schemes: " + virtual);
192            }
193         }
194    }
195
196    private void info(String scheme) throws Exception
197    {
198         System.out.println("Provider Info for scheme \"" + scheme + "\":");
199         Collection<Capability> caps;
200         caps = mgr.getProviderCapabilities(scheme);
201         if (caps != null && !caps.isEmpty())
202         {
203             System.out.println("  capabilities: " + caps);
204         }
205         FileOperationProvider[] ops = mgr.getOperationProviders(scheme);
206         if (ops != null && ops.length > 0)
207         {
208             System.out.println("  operations: " + ops);
209         }
210    }
211
212    /**
213     * Does a 'help' command.
214     */
215    private void help()
216    {
217        System.out.println("Commands:");
218        System.out.println("cat <file>         Displays the contents of a file.");
219        System.out.println("cd [folder]        Changes current folder.");
220        System.out.println("cp <src> <dest>    Copies a file or folder.");
221        System.out.println("help               Shows this message.");
222        System.out.println("info [scheme]      Displays information about providers.");
223        System.out.println("ls [-R] [path]     Lists contents of a file or folder.");
224        System.out.println("pwd                Displays current folder.");
225        System.out.println("rm <path>          Deletes a file or folder.");
226        System.out.println("touch <path>       Sets the last-modified time of a file.");
227        System.out.println("exit, quit         Exits this program.");
228    }
229
230    /**
231     * Does an 'rm' command.
232     */
233    private void rm(final String[] cmd) throws Exception
234    {
235        if (cmd.length < 2)
236        {
237            throw new Exception("USAGE: rm <path>");
238        }
239
240        final FileObject file = mgr.resolveFile(cwd, cmd[1]);
241        file.delete(Selectors.SELECT_SELF);
242    }
243
244    /**
245     * Does a 'cp' command.
246     */
247    private void cp(final String[] cmd) throws Exception
248    {
249        if (cmd.length < 3)
250        {
251            throw new Exception("USAGE: cp <src> <dest>");
252        }
253
254        final FileObject src = mgr.resolveFile(cwd, cmd[1]);
255        FileObject dest = mgr.resolveFile(cwd, cmd[2]);
256        if (dest.exists() && dest.getType() == FileType.FOLDER)
257        {
258            dest = dest.resolveFile(src.getName().getBaseName());
259        }
260
261        dest.copyFrom(src, Selectors.SELECT_ALL);
262    }
263
264    /**
265     * Does a 'cat' command.
266     */
267    private void cat(final String[] cmd) throws Exception
268    {
269        if (cmd.length < 2)
270        {
271            throw new Exception("USAGE: cat <path>");
272        }
273
274        // Locate the file
275        final FileObject file = mgr.resolveFile(cwd, cmd[1]);
276
277        // Dump the contents to System.out
278        FileUtil.writeContent(file, System.out);
279        System.out.println();
280    }
281
282    /**
283     * Does a 'pwd' command.
284     */
285    private void pwd()
286    {
287        System.out.println("Current folder is " + cwd.getName());
288    }
289
290    /**
291     * Does a 'cd' command.
292     * If the taget directory does not exist, a message is printed to <code>System.err</code>.
293     */
294    private void cd(final String[] cmd) throws Exception
295    {
296        final String path;
297        if (cmd.length > 1)
298        {
299            path = cmd[1];
300        }
301        else
302        {
303            path = System.getProperty("user.home");
304        }
305
306        // Locate and validate the folder
307        final FileObject tmp = mgr.resolveFile(cwd, path);
308        if (tmp.exists())
309        {
310            cwd = tmp;
311        }
312        else
313        {
314            System.out.println("Folder does not exist: " + tmp.getName());
315        }
316        System.out.println("Current folder is " + cwd.getName());
317    }
318
319    /**
320     * Does an 'ls' command.
321     */
322    private void ls(final String[] cmd) throws FileSystemException
323    {
324        int pos = 1;
325        final boolean recursive;
326        if (cmd.length > pos && cmd[pos].equals("-R"))
327        {
328            recursive = true;
329            pos++;
330        }
331        else
332        {
333            recursive = false;
334        }
335
336        final FileObject file;
337        if (cmd.length > pos)
338        {
339            file = mgr.resolveFile(cwd, cmd[pos]);
340        }
341        else
342        {
343            file = cwd;
344        }
345
346        if (file.getType() == FileType.FOLDER)
347        {
348            // List the contents
349            System.out.println("Contents of " + file.getName());
350            listChildren(file, recursive, "");
351        }
352        else
353        {
354            // Stat the file
355            System.out.println(file.getName());
356            final FileContent content = file.getContent();
357            System.out.println("Size: " + content.getSize() + " bytes.");
358            final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
359            final String lastMod = dateFormat.format(new Date(content.getLastModifiedTime()));
360            System.out.println("Last modified: " + lastMod);
361        }
362    }
363
364    /**
365     * Does a 'touch' command.
366     */
367    private void touch(final String[] cmd) throws Exception
368    {
369        if (cmd.length < 2)
370        {
371            throw new Exception("USAGE: touch <path>");
372        }
373        final FileObject file = mgr.resolveFile(cwd, cmd[1]);
374        if (!file.exists())
375        {
376            file.createFile();
377        }
378        file.getContent().setLastModifiedTime(System.currentTimeMillis());
379    }
380
381    /**
382     * Lists the children of a folder.
383     */
384    private void listChildren(final FileObject dir,
385                              final boolean recursive,
386                              final String prefix)
387        throws FileSystemException
388    {
389        final FileObject[] children = dir.getChildren();
390        for (final FileObject child : children)
391        {
392            System.out.print(prefix);
393            System.out.print(child.getName().getBaseName());
394            if (child.getType() == FileType.FOLDER)
395            {
396                System.out.println("/");
397                if (recursive)
398                {
399                    listChildren(child, recursive, prefix + "    ");
400                }
401            }
402            else
403            {
404                System.out.println();
405            }
406        }
407    }
408
409    /**
410     * Returns the next command, split into tokens.
411     */
412    private String[] nextCommand() throws IOException
413    {
414        System.out.print("> ");
415        final String line = reader.readLine();
416        if (line == null)
417        {
418            return null;
419        }
420        final ArrayList<String> cmd = new ArrayList<String>();
421        final StringTokenizer tokens = new StringTokenizer(line);
422        while (tokens.hasMoreTokens())
423        {
424            cmd.add(tokens.nextToken());
425        }
426        return cmd.toArray(new String[cmd.size()]);
427    }
428
429    private static String getVersion(Class<?> cls)
430    {
431        try
432        {
433            return cls.getPackage().getImplementationVersion();
434        }
435        catch (Exception ignored)
436        {
437            return "N/A";
438        }
439    }
440}