package de.kroesch.clt;
import java.io.File;
import java.io.FilenameFilter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.imageio.spi.ServiceRegistry;
import de.kroesch.clt.internal.Crash;
import de.kroesch.clt.internal.Discover;
import de.kroesch.clt.internal.Error;
import de.kroesch.clt.internal.Get;
import de.kroesch.clt.internal.Help;
import de.kroesch.clt.internal.History;
import de.kroesch.clt.internal.Internal;
import de.kroesch.clt.internal.LoadProperties;
import de.kroesch.clt.internal.Match;
import de.kroesch.clt.internal.Print;
import de.kroesch.clt.internal.Repeat;
import de.kroesch.clt.internal.SaveProperties;
import de.kroesch.clt.internal.Set;
import de.kroesch.clt.internal.Shutdown;
import de.kroesch.clt.internal.Time;
import de.kroesch.clt.internal.Version;
import de.kroesch.clt.net.Curl;
import de.kroesch.clt.net.HttPing;
import de.kroesch.clt.scripting.Load;
import de.kroesch.clt.security.Login;
import de.kroesch.clt.storage.Ls;
/**
* Parses command line input.
*
* @author karsten
*
*/
public class Parser {
private Map<String, Class<? extends Command>> commandMap = new HashMap<String, Class<? extends Command>>();
private Environment environment;
private enum InternalCommands implements Runnable, Internal {
NOP {
public void run() {
// no operation
}
},
UNKNOWN {
public void run() {
environment.writer().printf("?Unknown command.\n");
}
};
public static Environment environment;
}
public Parser(Environment environment) {
changeEnvironment(environment);
commandMap.put("ls", Ls.class);
commandMap.put("dir", Ls.class);
commandMap.put("shutdown", Shutdown.class);
commandMap.put("hist", History.class);
commandMap.put("history", History.class);
commandMap.put("set", Set.class);
commandMap.put("get", Get.class);
commandMap.put("print", Print.class);
commandMap.put("match", Match.class);
commandMap.put("help", Help.class);
commandMap.put("echo", Print.class);
commandMap.put("load", Load.class);
commandMap.put("savep", SaveProperties.class);
commandMap.put("loadp", LoadProperties.class);
commandMap.put("discover", Discover.class);
commandMap.put("auth", Login.class);
commandMap.put("curl", Curl.class);
commandMap.put("ping", HttPing.class);
commandMap.put("version", Version.class);
commandMap.put("time", Time.class);
commandMap.put("repeat", Repeat.class);
// For testing purposes
commandMap.put("crash", Crash.class);
}
public Runnable parseCommand(String command) {
if (null == command || "".equals(command.trim())) return InternalCommands.NOP;
StringTokenizer tokenizer = new StringTokenizer(command, " ");
String commandName = tokenizer.nextToken();
if (commandMap.get(commandName.toLowerCase()) == null) return InternalCommands.UNKNOWN;
try {
Command cmd = (Command) commandMap.get(commandName).newInstance();
cmd.setEnvironment(environment);
if (cmd instanceof HasArguments) {
List<String> args = new ArrayList<String>();
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (token.startsWith("$")) {
token = eval(token);
}
if (token.startsWith("\"")) {
token = quoted(token, tokenizer);
}
args.add(token);
}
((HasArguments) cmd).setArguments(args);
}
return cmd;
} catch (InstantiationException e) {
return new Error(e.getMessage(), environment.writer());
} catch (IllegalAccessException e) {
return new Error(e.getMessage(), environment.writer());
}
}
/**
* Evaluate a variable.
*/
public String eval(String variable) {
if (null == environment.get(variable.substring(1))) return "null";
return environment.get(variable.substring(1));
}
/**
* Handles quoted tokens, possibly containing spaces.
*/
public String quoted(String token, StringTokenizer tokenizer) {
if (token.endsWith("\"")) return token.substring(1, token.length()-1);
StringBuffer spaced = new StringBuffer(token.substring(1));
while (tokenizer.hasMoreTokens()) {
String next = tokenizer.nextToken();
spaced.append(" ").append(next);
if (next.endsWith("\"")) break;
}
return spaced.toString().substring(0, spaced.length()-1);
}
public void changeEnvironment(Environment environment) {
this.environment = environment;
InternalCommands.environment = environment;
}
public List<String> availableCommands() {
List<String> commands = new ArrayList<String>(commandMap.keySet());
Collections.sort(commands);
return commands;
}
public Class<? extends Command> byName(String name) {
return commandMap.get(name);
}
public void discoverPlugins() {
File pluginDir = new File("plugins");
File[] jarFiles = pluginDir.listFiles(new JarFileFilter());
// Handle malformed or missing plugin directory
if (jarFiles == null) {
environment.writer().printf("?Plugin directory not found.\n");
return;
}
for (File jarFile : jarFiles) {
//environment.writer().printf("Searching for plugin in %s\n", jarFile);
// Try to load plugin classes
ClassLoader classLoader;
try {
classLoader = new URLClassLoader(new URL[]{jarFile.toURI().toURL()}, Parser.class.getClassLoader());
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
for (Iterator<Command> iter = ServiceRegistry.lookupProviders(Command.class, classLoader); iter.hasNext();) {
Command plugin = iter.next();
plugin.setEnvironment(environment);
environment.writer().printf("Found plugin information for %s\n", plugin.toString());
commandMap.put(plugin.toString(), plugin.getClass());
}
}
}
public static class JarFileFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
}
}