- Timestamp:
- 08/28/12 12:00:07 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/java-utils/src/main/java/de/ugoe/cs/util/console/CommandExecuter.java
r639 r661 1 1 2 package de.ugoe.cs.util.console; 2 3 4 import java.io.File; 5 import java.io.FileInputStream; 6 import java.io.FilenameFilter; 7 import java.io.IOException; 8 import java.net.URL; 3 9 import java.security.InvalidParameterException; 4 10 import java.util.ArrayList; 11 import java.util.Arrays; 12 import java.util.Enumeration; 5 13 import java.util.List; 14 import java.util.jar.JarEntry; 15 import java.util.jar.JarInputStream; 6 16 import java.util.logging.Level; 7 17 8 18 /** 9 19 * <p> 10 * Executes commands. The commands have to implement the {@link Command} 11 * interface and be in packages registered using addCommandPackage(). 12 * Additionally, default commands are implemented in the 13 * de.ugoe.cs.util.console.defaultcommands package. 20 * Executes commands. The commands have to implement the {@link Command} interface and be in 21 * packages registered using addCommandPackage(). Additionally, default commands are implemented in 22 * the de.ugoe.cs.util.console.defaultcommands package. 14 23 * </p> 15 24 * <p> … … 22 31 public class CommandExecuter { 23 32 24 /** 25 * <p> 26 * Handle of the CommandExecuter instance. 27 * </p> 28 */ 29 private final static CommandExecuter theInstance = new CommandExecuter(); 30 31 /** 32 * <p> 33 * Prefix of all command classes. 34 * </p> 35 */ 36 private static final String cmdPrefix = "CMD"; 37 38 /** 39 * <p> 40 * Name of the package for default commands. 41 * </p> 42 */ 43 private static final String defaultPackage = "de.ugoe.cs.util.console.defaultcommands"; 44 45 /** 46 * <p> 47 * List of packages in which commands may be defined. The exec methods trys 48 * to load command from these packages in the order they have been added. 49 * </p> 50 * <p> 51 * The de.ugoe.cs.util.console.defaultcommands package has always lowest 52 * priority, unless it is specifically added. 53 * </p> 54 */ 55 private List<String> commandPackageList; 56 57 /** 58 * <p> 59 * Returns the instance of CommandExecuter. If no instances exists yet, a 60 * new one is created. 61 * </p> 62 * 63 * @return the instance of CommandExecuter 64 */ 65 public static synchronized CommandExecuter getInstance() { 66 return theInstance; 67 } 68 69 /** 70 * <p> 71 * Creates a new CommandExecuter. Private to prevent multiple instances 72 * (Singleton). 73 * </p> 74 */ 75 private CommandExecuter() { 76 commandPackageList = new ArrayList<String>(); 77 } 78 79 /** 80 * <p> 81 * Adds a package that will be used by {@link #exec(String)} to load command 82 * from. 83 * </p> 84 * 85 * @param pkg 86 * package where commands are located 87 * @throws InvalidParameterException 88 * thrown if the package name is null or empty string 89 */ 90 public void addCommandPackage(String pkg) { 91 if ("".equals(pkg) || pkg == null) { 92 throw new InvalidParameterException( 93 "package name must not be null or empty string"); 94 } 95 commandPackageList.add(pkg); 96 } 97 98 /** 99 * <p> 100 * Executes the command defined by string. A command has the following form 101 * (mix of EBNF and natural language): 102 * </p> 103 * <code> 104 * <command> := <commandname><whitespace>{<parameter>}<br> 105 * <commandname> := String without whitespaces. Has to be a valid Java class name<br> 106 * <parameter> := <string>|<stringarray><br> 107 * <string> := <stringwithoutwhitespaces>|<stringwithwhitespaces> 108 * <stringwithoutwhitespaces> := a string without whitespaces<br> 109 * <stringwithoutwhitespaces> := a string, that can have whitespaces, but must be in double quotes<br> 110 * <stringarray> := "["<string>{<whitespace><string>"]" 111 * </code> 112 * 113 * @param command 114 * the command as a string 115 */ 116 public void exec(String command) { 117 Console.commandNotification(command); 118 Command cmd = null; 119 CommandParser parser = new CommandParser(); 120 parser.parse(command); 121 for (int i = 0; cmd == null && i < commandPackageList.size(); i++) { 122 cmd = loadCMD(commandPackageList.get(i) + "." + cmdPrefix 123 + parser.getCommandName()); 124 } 125 if (cmd == null) { // check if command is available as default command 126 cmd = loadCMD(defaultPackage + "." + cmdPrefix 127 + parser.getCommandName()); 128 } 129 if (cmd == null) { 130 Console.println("Unknown command"); 131 } else { 132 try { 133 cmd.run(parser.getParameters()); 134 } catch (InvalidParameterException e) { 135 cmd.help(); 136 } 137 } 138 } 139 140 /** 141 * <p> 142 * Helper method that loads a class and tries to cast it to {@link Command}. 143 * </p> 144 * 145 * @param className 146 * qualified name of the class (including package name) 147 * @return if class is available and implement {@link Command} and instance 148 * of the class, null otherwise 149 */ 150 private Command loadCMD(String className) { 151 Command cmd = null; 152 try { 153 Class<?> cmdClass = Class.forName(className); 154 cmd = (Command) cmdClass.newInstance(); 155 } catch (NoClassDefFoundError e) { 156 String[] splitResult = e.getMessage().split("CMD"); 157 String correctName = splitResult[splitResult.length - 1].replace( 158 ")", ""); 159 Console.println("Did you mean " + correctName + "?"); 160 } catch (ClassNotFoundException e) { 161 } catch (IllegalAccessException e) { 162 } catch (InstantiationException e) { 163 } catch (ClassCastException e) { 164 Console.traceln(Level.WARNING, className + "found, but does not implement Command"); 165 } 166 return cmd; 167 } 33 /** 34 * <p> 35 * Handle of the CommandExecuter instance. 36 * </p> 37 */ 38 private final static CommandExecuter theInstance = new CommandExecuter(); 39 40 /** 41 * <p> 42 * Prefix of all command classes. 43 * </p> 44 */ 45 private static final String cmdPrefix = "CMD"; 46 47 /** 48 * <p> 49 * Name of the package for default commands. 50 * </p> 51 */ 52 private static final String defaultPackage = "de.ugoe.cs.util.console.defaultcommands"; 53 54 /** 55 * <p> 56 * List of packages in which commands may be defined. The exec methods trys to load command from 57 * these packages in the order they have been added. 58 * </p> 59 * <p> 60 * The de.ugoe.cs.util.console.defaultcommands package has always lowest priority, unless it is 61 * specifically added. 62 * </p> 63 */ 64 private List<String> commandPackageList; 65 66 /** 67 * <p> 68 * Returns the instance of CommandExecuter. If no instances exists yet, a new one is created. 69 * </p> 70 * 71 * @return the instance of CommandExecuter 72 */ 73 public static synchronized CommandExecuter getInstance() { 74 return theInstance; 75 } 76 77 /** 78 * <p> 79 * Creates a new CommandExecuter. Private to prevent multiple instances (Singleton). 80 * </p> 81 */ 82 private CommandExecuter() { 83 commandPackageList = new ArrayList<String>(); 84 } 85 86 /** 87 * <p> 88 * Adds a package that will be used by {@link #exec(String)} to load command from. 89 * </p> 90 * 91 * @param pkg 92 * package where commands are located 93 * @throws InvalidParameterException 94 * thrown if the package name is null or empty string 95 */ 96 public void addCommandPackage(String pkg) { 97 if ("".equals(pkg) || pkg == null) { 98 throw new InvalidParameterException("package name must not be null or empty string"); 99 } 100 commandPackageList.add(pkg); 101 } 102 103 /** 104 * <p> 105 * Executes the command defined by string. A command has the following form (mix of EBNF and 106 * natural language): 107 * </p> 108 * <code> 109 * <command> := <commandname><whitespace>{<parameter>}<br> 110 * <commandname> := String without whitespaces. Has to be a valid Java class name<br> 111 * <parameter> := <string>|<stringarray><br> 112 * <string> := <stringwithoutwhitespaces>|<stringwithwhitespaces> 113 * <stringwithoutwhitespaces> := a string without whitespaces<br> 114 * <stringwithoutwhitespaces> := a string, that can have whitespaces, but must be in double quotes<br> 115 * <stringarray> := "["<string>{<whitespace><string>"]" 116 * </code> 117 * 118 * @param command 119 * the command as a string 120 */ 121 public void exec(String command) { 122 Console.commandNotification(command); 123 Command cmd = null; 124 CommandParser parser = new CommandParser(); 125 parser.parse(command); 126 for (int i = 0; cmd == null && i < commandPackageList.size(); i++) { 127 cmd = loadCMD(commandPackageList.get(i) + "." + cmdPrefix + parser.getCommandName()); 128 } 129 if (cmd == null) { // check if command is available as default command 130 cmd = loadCMD(defaultPackage + "." + cmdPrefix + parser.getCommandName()); 131 } 132 if (cmd == null) { 133 Console.println("Unknown command"); 134 } 135 else { 136 try { 137 cmd.run(parser.getParameters()); 138 } 139 catch (InvalidParameterException e) { 140 cmd.help(); 141 } 142 } 143 } 144 145 /** 146 * <p> 147 * Helper method that loads a class and tries to cast it to {@link Command}. 148 * </p> 149 * 150 * @param className 151 * qualified name of the class (including package name) 152 * @return if class is available and implement {@link Command} and instance of the class, null 153 * otherwise 154 */ 155 private Command loadCMD(String className) { 156 Command cmd = null; 157 try { 158 Class<?> cmdClass = Class.forName(className); 159 cmd = (Command) cmdClass.newInstance(); 160 } 161 catch (NoClassDefFoundError e) { 162 String[] splitResult = e.getMessage().split("CMD"); 163 String correctName = splitResult[splitResult.length - 1].replace(")", ""); 164 Console.println("Did you mean " + correctName + "?"); 165 } 166 catch (ClassNotFoundException e) {} 167 catch (IllegalAccessException e) {} 168 catch (InstantiationException e) {} 169 catch (ClassCastException e) { 170 Console.traceln(Level.WARNING, className + "found, but does not implement Command"); 171 } 172 return cmd; 173 } 174 175 /** 176 * <p> 177 * reads all available commands from the registered command packages and returns a list of 178 * their names 179 * </p> 180 * 181 * @return an array containing the names of the available commands. 182 */ 183 public String[] getAvailableCommands() { 184 List<String> commands = new ArrayList<String>(); 185 List<String> packages = new ArrayList<String>(); 186 packages.addAll(commandPackageList); 187 packages.add(defaultPackage); 188 189 FilenameFilter filter = new FilenameFilter() { 190 @Override 191 public boolean accept(File dir, String name) { 192 return (name != null) && (name.startsWith(cmdPrefix)) && (name.endsWith(".class")); 193 } 194 }; 195 196 List<String> classNames = new ArrayList<String>(); 197 for (String packageName : packages) { 198 String path = packageName.replace('.', '/'); 199 try { 200 Enumeration<URL> resources = ClassLoader.getSystemResources(path); 201 202 while (resources.hasMoreElements()) { 203 URL resource = resources.nextElement(); 204 File packageDir = new File(resource.getFile()); 205 206 if (packageDir.isDirectory()) { 207 for (File classFile : packageDir.listFiles(filter)) { 208 String className = classFile.getName().substring 209 (0, classFile.getName().lastIndexOf('.')); 210 classNames.add(packageName + "." + className); 211 } 212 } 213 else { 214 resource.getFile().startsWith("file:"); 215 int index = resource.getFile().lastIndexOf('!'); 216 if ((index > 0) && (resource.getFile().startsWith("file:")) && 217 (resource.getFile().endsWith("!/" + path))) 218 { 219 String jarFile = resource.getFile().substring("file:".length(), index); 220 221 // we have to read the package content from a jar file 222 JarInputStream jarInputStream = null; 223 try { 224 jarInputStream = new JarInputStream(new FileInputStream(jarFile)); 225 } 226 catch (Exception e) { 227 e.printStackTrace(); 228 Console.traceln 229 (Level.WARNING, "could not read contents of jar " + jarFile); 230 } 231 232 JarEntry entry = null; 233 do { 234 entry = jarInputStream.getNextJarEntry(); 235 if ((entry != null) && (!entry.isDirectory()) && 236 (entry.getName().startsWith(path))) 237 { 238 String className = entry.getName().substring 239 (path.length(), entry.getName().lastIndexOf('.')); 240 classNames.add(packageName + "." + className); 241 } 242 } 243 while (entry != null); 244 } 245 } 246 } 247 } 248 catch (IOException e) { 249 Console.traceln(Level.WARNING, "could not read commands of package " + packageName); 250 } 251 } 252 253 for (String className : classNames) { 254 String commandStr = 255 className.substring(className.lastIndexOf('.') + cmdPrefix.length() + 1); 256 257 // commands may be found twice as a package may be available twice on the 258 // class path. Therefore check, if the command was already dumped before 259 // dumping it. 260 if (!commands.contains(commandStr)) { 261 // class may still be inner classes. Therefore load the command, to 262 // see if it is really available and a command. 263 if (loadCMD(className) != null) { 264 commands.add(commandStr); 265 } 266 } 267 } 268 269 String[] commandArray = commands.toArray(new String[commands.size()]); 270 Arrays.sort(commandArray); 271 return commandArray; 272 } 168 273 }
Note: See TracChangeset
for help on using the changeset viewer.