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.net.URL; 024import java.nio.charset.Charset; 025import java.text.DateFormat; 026import java.util.ArrayList; 027import java.util.Arrays; 028import java.util.Collection; 029import java.util.Date; 030import java.util.List; 031import java.util.StringTokenizer; 032 033import org.apache.commons.lang3.ArrayUtils; 034import org.apache.commons.lang3.SystemProperties; 035import org.apache.commons.vfs2.Capability; 036import org.apache.commons.vfs2.FileContent; 037import org.apache.commons.vfs2.FileObject; 038import org.apache.commons.vfs2.FileSystemException; 039import org.apache.commons.vfs2.FileSystemManager; 040import org.apache.commons.vfs2.FileType; 041import org.apache.commons.vfs2.Selectors; 042import org.apache.commons.vfs2.VFS; 043import org.apache.commons.vfs2.impl.StandardFileSystemManager; 044import org.apache.commons.vfs2.operations.FileOperationProvider; 045import org.apache.commons.vfs2.util.FileObjectUtils; 046 047/** 048 * A simple command-line shell for performing file operations. 049 * <p> 050 * See <a href="https://wiki.apache.org/commons/VfsExampleShell">Commons VFS Shell Examples</a> in Apache Commons Wiki. 051 */ 052public final class Shell { 053 054 private static String getVersion(final Class<?> cls) { 055 try { 056 return cls.getPackage().getImplementationVersion(); 057 } catch (final Exception ignored) { 058 return "N/A"; 059 } 060 } 061 /** 062 * Invokes this example from the command line. 063 * 064 * @param args Arguments TODO 065 */ 066 public static void main(final String[] args) { 067 try { 068 new Shell().go(); 069 } catch (final Exception e) { 070 e.printStackTrace(); 071 System.exit(1); 072 } 073 System.exit(0); 074 } 075 private final FileSystemManager mgr; 076 077 private FileObject cwd; 078 079 private final BufferedReader reader; 080 081 private Shell() throws IOException { 082 final String providers = System.getProperty("providers"); 083 final URL providersUrl = providers != null ? Shell.class.getResource("/" + providers) : null; 084 085 if (providersUrl != null) { 086 mgr = new StandardFileSystemManager(); 087 System.out.println("Custom providers configuration used: " + providersUrl); 088 ((StandardFileSystemManager) mgr).setConfiguration(providersUrl); 089 ((StandardFileSystemManager) mgr).init(); 090 } else { 091 mgr = VFS.getManager(); 092 } 093 094 cwd = mgr.toFileObject(new File(System.getProperty("user.dir"))); 095 reader = new BufferedReader(new InputStreamReader(System.in, Charset.defaultCharset())); 096 } 097 098 /** 099 * Does a 'cat' command. 100 */ 101 private void cat(final String[] cmd) throws Exception { 102 if (cmd.length < 2) { 103 throw new Exception("USAGE: cat <path>"); 104 } 105 106 // Locate the file 107 final FileObject file = mgr.resolveFile(cwd, cmd[1]); 108 109 // Dump the contents to System.out 110 FileObjectUtils.writeContent(file, System.out); 111 System.out.println(); 112 } 113 114 /** 115 * Does a 'cd' command. If the taget directory does not exist, a message is printed to {@code System.err}. 116 */ 117 private void cd(final String[] cmd) throws Exception { 118 final String path; 119 if (cmd.length > 1) { 120 path = cmd[1]; 121 } else { 122 path = SystemProperties.getUserHome(); 123 } 124 125 // Locate and validate the folder 126 final FileObject tmp = mgr.resolveFile(cwd, path); 127 if (tmp.exists()) { 128 cwd = tmp; 129 } else { 130 System.out.println("Folder does not exist: " + tmp.getName()); 131 } 132 System.out.println("Current folder is " + cwd.getName()); 133 } 134 135 /** 136 * Does a 'cp' command. 137 */ 138 private void cp(final String[] cmd) throws Exception { 139 if (cmd.length < 3) { 140 throw new Exception("USAGE: cp <src> <dest>"); 141 } 142 143 final FileObject src = mgr.resolveFile(cwd, cmd[1]); 144 FileObject dest = mgr.resolveFile(cwd, cmd[2]); 145 if (dest.exists() && dest.getType() == FileType.FOLDER) { 146 dest = dest.resolveFile(src.getName().getBaseName()); 147 } 148 149 dest.copyFrom(src, Selectors.SELECT_ALL); 150 } 151 152 private void go() throws Exception { 153 System.out.println("VFS Shell " + getVersion(Shell.class)); 154 while (true) { 155 final String[] commands = nextCommand(); 156 if (commands == null) { 157 return; 158 } 159 if (commands.length == 0) { 160 continue; 161 } 162 final String cmdName = commands[0]; 163 if (cmdName.equalsIgnoreCase("exit") || cmdName.equalsIgnoreCase("quit")) { 164 return; 165 } 166 try { 167 handleCommand(commands); 168 } catch (final Exception e) { 169 System.err.println("Command failed:"); 170 e.printStackTrace(System.err); 171 } 172 } 173 } 174 175 /** 176 * Handles a command. 177 */ 178 private void handleCommand(final String[] cmd) throws Exception { 179 final String cmdName = cmd[0]; 180 if (cmdName.equalsIgnoreCase("cat")) { 181 cat(cmd); 182 } else if (cmdName.equalsIgnoreCase("cd")) { 183 cd(cmd); 184 } else if (cmdName.equalsIgnoreCase("cp")) { 185 cp(cmd); 186 } else if (cmdName.equalsIgnoreCase("help") || cmdName.equals("?")) { 187 help(); 188 } else if (cmdName.equalsIgnoreCase("ls")) { 189 ls(cmd); 190 } else if (cmdName.equalsIgnoreCase("pwd")) { 191 pwd(); 192 } else if (cmdName.equalsIgnoreCase("pwfs")) { 193 pwfs(); 194 } else if (cmdName.equalsIgnoreCase("rm")) { 195 rm(cmd); 196 } else if (cmdName.equalsIgnoreCase("touch")) { 197 touch(cmd); 198 } else if (cmdName.equalsIgnoreCase("info")) { 199 info(cmd); 200 } else { 201 System.err.println("Unknown command \"" + cmdName + "\" (Try 'help')."); 202 } 203 } 204 205 /** 206 * Does a 'help' command. 207 */ 208 private void help() { 209 System.out.println("Commands:"); 210 System.out.println("cat <file> Displays the contents of a file."); 211 System.out.println("cd [folder] Changes current folder."); 212 System.out.println("cp <src> <dest> Copies a file or folder."); 213 System.out.println("help Shows this message."); 214 System.out.println("info [scheme] Displays information about providers."); 215 System.out.println("ls [-R] [path] Lists contents of a file or folder."); 216 System.out.println("pwd Displays current folder."); 217 System.out.println("pwfs Displays current file system."); 218 System.out.println("rm <path> Deletes a file or folder."); 219 System.out.println("touch <path> Sets the last-modified time of a file."); 220 System.out.println("exit, quit Exits this program."); 221 } 222 223 private void info(final String scheme) throws Exception { 224 System.out.println("Provider Info for scheme \"" + scheme + "\":"); 225 final Collection<Capability> caps; 226 caps = mgr.getProviderCapabilities(scheme); 227 if (caps != null && !caps.isEmpty()) { 228 System.out.println(" capabilities: " + caps); 229 } 230 final FileOperationProvider[] ops = mgr.getOperationProviders(scheme); 231 if (ops != null && ops.length > 0) { 232 System.out.println(" operations: " + Arrays.toString(ops)); 233 } 234 } 235 236 private void info(final String[] cmd) throws Exception { 237 if (cmd.length > 1) { 238 info(cmd[1]); 239 } else { 240 System.out.println("Default manager: \"" + mgr.getClass().getName() + "\" " + "version " + getVersion(mgr.getClass())); 241 final String[] schemes = mgr.getSchemes(); 242 final List<String> virtual = new ArrayList<>(); 243 final List<String> physical = new ArrayList<>(); 244 for (final String scheme : schemes) { 245 final Collection<Capability> caps = mgr.getProviderCapabilities(scheme); 246 if (caps != null) { 247 if (caps.contains(Capability.VIRTUAL) || caps.contains(Capability.COMPRESS) || caps.contains(Capability.DISPATCHER)) { 248 virtual.add(scheme); 249 } else { 250 physical.add(scheme); 251 } 252 } 253 } 254 if (!physical.isEmpty()) { 255 System.out.println(" Provider Schemes: " + physical); 256 } 257 if (!virtual.isEmpty()) { 258 System.out.println(" Virtual Schemes: " + virtual); 259 } 260 } 261 } 262 263 /** 264 * Lists the children of a folder. 265 */ 266 private void listChildren(final FileObject dir, final boolean recursive, final String prefix) throws FileSystemException { 267 final FileObject[] children = dir.getChildren(); 268 for (final FileObject child : children) { 269 System.out.print(prefix); 270 System.out.print(child.getName().getBaseName()); 271 if (child.getType() == FileType.FOLDER) { 272 System.out.println("/"); 273 if (recursive) { 274 listChildren(child, true, prefix + " "); 275 } 276 } else { 277 System.out.println(); 278 } 279 } 280 } 281 282 /** 283 * Does an 'ls' command. 284 */ 285 private void ls(final String[] cmd) throws FileSystemException { 286 int pos = 1; 287 final boolean recursive; 288 if (cmd.length > pos && cmd[pos].equals("-R")) { 289 recursive = true; 290 pos++; 291 } else { 292 recursive = false; 293 } 294 295 final FileObject file; 296 if (cmd.length > pos) { 297 file = mgr.resolveFile(cwd, cmd[pos]); 298 } else { 299 file = cwd; 300 } 301 302 if (file.getType() == FileType.FOLDER) { 303 // List the contents 304 System.out.println("Contents of " + file.getName()); 305 listChildren(file, recursive, ""); 306 } else { 307 // Stat the file 308 System.out.println(file.getName()); 309 final FileContent content = file.getContent(); 310 System.out.println("Size: " + content.getSize() + " bytes."); 311 final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); 312 final String lastMod = dateFormat.format(new Date(content.getLastModifiedTime())); 313 System.out.println("Last modified: " + lastMod); 314 } 315 } 316 317 /** 318 * Returns the next command, split into tokens. 319 */ 320 private String[] nextCommand() throws IOException { 321 System.out.print("> "); 322 final String line = reader.readLine(); 323 if (line == null) { 324 return null; 325 } 326 final ArrayList<String> cmd = new ArrayList<>(); 327 final StringTokenizer tokens = new StringTokenizer(line); 328 while (tokens.hasMoreTokens()) { 329 cmd.add(tokens.nextToken()); 330 } 331 return cmd.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 332 } 333 334 /** 335 * Does a 'pwd' command. 336 */ 337 private void pwd() { 338 System.out.println("Current folder is " + cwd.getName()); 339 } 340 341 /** 342 * Does a 'pwfs' command. 343 */ 344 private void pwfs() { 345 System.out.println("FileSystem of current folder is " + cwd.getFileSystem() + " (root: " + cwd.getFileSystem().getRootURI() + ")"); 346 } 347 348 /** 349 * Does an 'rm' command. 350 */ 351 private void rm(final String[] cmd) throws Exception { 352 if (cmd.length < 2) { 353 throw new Exception("USAGE: rm <path>"); 354 } 355 356 final FileObject file = mgr.resolveFile(cwd, cmd[1]); 357 file.delete(Selectors.SELECT_SELF); 358 } 359 360 /** 361 * Does a 'touch' command. 362 */ 363 private void touch(final String[] cmd) throws Exception { 364 if (cmd.length < 2) { 365 throw new Exception("USAGE: touch <path>"); 366 } 367 final FileObject file = mgr.resolveFile(cwd, cmd[1]); 368 if (!file.exists()) { 369 file.createFile(); 370 } 371 file.getContent().setLastModifiedTime(System.currentTimeMillis()); 372 } 373}