| @@ -0,0 +1,6 @@ | ||
| package org.jpos.q2; | ||
|
|
||
| public interface CLICommand | ||
| { | ||
| public void exec(CLIContext cli, String[] strings) throws Exception; | ||
| } |
| @@ -0,0 +1,184 @@ | ||
| package org.jpos.q2; | ||
|
|
||
| import jline.ConsoleReader; | ||
| import org.jpos.iso.ISOUtil; | ||
| import org.jpos.q2.CLI.Command; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.PrintStream; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.StringTokenizer; | ||
| import java.util.WeakHashMap; | ||
|
|
||
| public class CLICommandInterface | ||
| { | ||
| CLIContext ctx; | ||
| List<String> prefixes = new ArrayList<String>(); | ||
| WeakHashMap<String, Object> commandCache = new WeakHashMap<String, Object>(100); | ||
|
|
||
| public List<String> getPrefixes() | ||
| { | ||
| return prefixes; | ||
| } | ||
|
|
||
| public CLICommandInterface(CLIContext ctx) | ||
| { | ||
| this.ctx = ctx; | ||
| } | ||
|
|
||
| public void addPrefix(String prefix) | ||
| { | ||
| prefixes.add(prefix); | ||
| } | ||
|
|
||
| public void execCommand(String line) throws IOException | ||
| { | ||
| for (String prefix : prefixes) | ||
| { | ||
| try | ||
| { | ||
| execCommand(prefix, line); | ||
| } | ||
| catch (ClassNotFoundException e) | ||
| { | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void execCommand(String prefix, String line) throws IOException, ClassNotFoundException | ||
| { | ||
| String args[] = parseCommand(line); | ||
| if (args.length == 0) | ||
| { | ||
| return; | ||
| } | ||
| String command = args[0].toUpperCase(); | ||
| String className = command; | ||
|
|
||
| if (command.indexOf(".") < 0) | ||
| { | ||
| className = prefix + command; | ||
| } | ||
|
|
||
| try | ||
| { | ||
| Object cmd = getCommand(className); | ||
| if (cmd != null) | ||
| { | ||
| try | ||
| { | ||
| long t1 = System.currentTimeMillis(); | ||
|
|
||
| args[0] = ISOUtil.unPadLeft(line, ' '); // full line | ||
| if (cmd instanceof Command) | ||
| { | ||
| ((Command) cmd).exec(new LegacyCommandAdapter(ctx), args); | ||
| } | ||
| else if (cmd instanceof CLICommand) | ||
| { | ||
| ((CLICommand) cmd).exec(ctx, args); | ||
| } | ||
| long elapsed = System.currentTimeMillis() - t1; | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| ctx.printThrowable(ex); | ||
| } | ||
| } | ||
| } | ||
| catch (ClassNotFoundException ex) | ||
| { | ||
| throw ex; | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| ctx.println("Invalid command '" + command + "'"); | ||
| ex.printStackTrace(); | ||
| } | ||
| } | ||
|
|
||
| private Object getCommand(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException | ||
| { | ||
| Object cmd = commandCache.get(className); | ||
| if (cmd == null) | ||
| { | ||
| Class<?> clazz = getClazz(className); | ||
| final Object o = clazz.newInstance(); | ||
| if (o instanceof Command || o instanceof CLICommand) | ||
| { | ||
| commandCache.put(className, o); | ||
| cmd = o; | ||
| } | ||
| } | ||
| return cmd; | ||
| } | ||
|
|
||
| private Class<?> getClazz(String className) throws ClassNotFoundException | ||
| { | ||
| return Thread.currentThread().getContextClassLoader().loadClass(className); | ||
| } | ||
|
|
||
| private String[] parseCommand(String line) throws IOException | ||
| { | ||
| if (line == null) | ||
| { | ||
| return new String[0]; | ||
| } | ||
|
|
||
| StringTokenizer st = new StringTokenizer(line); | ||
| String[] args = new String[st.countTokens()]; | ||
| for (int i = 0; st.hasMoreTokens(); i++) | ||
| { | ||
| args[i] = new String(st.nextToken()); | ||
| } | ||
| return args; | ||
| } | ||
|
|
||
| public static class LegacyCommandAdapter extends CLI | ||
| { | ||
| CLIContext ctx; | ||
|
|
||
| public LegacyCommandAdapter(CLIContext ctx) throws IOException | ||
| { | ||
| super(null, null, false); | ||
| this.ctx = ctx; | ||
| } | ||
|
|
||
| @Override | ||
| public void print(String s) | ||
| { | ||
| ctx.print(s); | ||
| } | ||
|
|
||
| @Override | ||
| public void println(String s) | ||
| { | ||
| ctx.println(s); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean confirm(String prompt) throws IOException | ||
| { | ||
| return ctx.confirm(prompt); | ||
| } | ||
|
|
||
| @Override | ||
| public Q2 getQ2() | ||
| { | ||
| return ctx.getQ2(); | ||
| } | ||
|
|
||
| @Override | ||
| public ConsoleReader getConsoleReader() | ||
| { | ||
| return ctx.getConsoleReader(); | ||
| } | ||
|
|
||
| @Override | ||
| public PrintStream getOutputStream() | ||
| { | ||
| return ctx.getOutputStream(); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,92 @@ | ||
| package org.jpos.q2; | ||
|
|
||
| import jline.ConsoleReader; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.PrintStream; | ||
|
|
||
| public class CLIContext | ||
| { | ||
| Q2 q2; | ||
| ConsoleReader consoleReader; | ||
| PrintStream outputStream; | ||
| boolean stopped = false; | ||
|
|
||
| public boolean isStopped() | ||
| { | ||
| return stopped; | ||
| } | ||
|
|
||
| public void setStopped(boolean stopped) | ||
| { | ||
| this.stopped = stopped; | ||
| } | ||
|
|
||
| public Q2 getQ2() | ||
| { | ||
| return q2; | ||
| } | ||
|
|
||
| public void setQ2(Q2 q2) | ||
| { | ||
| this.q2 = q2; | ||
| } | ||
|
|
||
| public ConsoleReader getConsoleReader() | ||
| { | ||
| return consoleReader; | ||
| } | ||
|
|
||
| public void setConsoleReader(ConsoleReader consoleReader) | ||
| { | ||
| this.consoleReader = consoleReader; | ||
| } | ||
|
|
||
| public PrintStream getOutputStream() | ||
| { | ||
| return outputStream; | ||
| } | ||
|
|
||
| public void setOutputStream(PrintStream outputStream) | ||
| { | ||
| this.outputStream = outputStream; | ||
| } | ||
|
|
||
| public void printThrowable(Throwable t) | ||
| { | ||
| t.printStackTrace(outputStream); | ||
| outputStream.flush(); | ||
| } | ||
|
|
||
| public void print(String s) | ||
| { | ||
| try | ||
| { | ||
| consoleReader.printString(s); | ||
| } | ||
| catch (IOException e) | ||
| { | ||
| e.printStackTrace(outputStream); | ||
| outputStream.flush(); | ||
| } | ||
| } | ||
|
|
||
| public void println(String s) | ||
| { | ||
| try | ||
| { | ||
| consoleReader.printString(s); | ||
| consoleReader.printNewline(); | ||
| } | ||
| catch (IOException e) | ||
| { | ||
| e.printStackTrace(outputStream); | ||
| outputStream.flush(); | ||
| } | ||
| } | ||
|
|
||
| public boolean confirm(String prompt) throws IOException | ||
| { | ||
| return "yes".equalsIgnoreCase(consoleReader.readLine(prompt)); | ||
| } | ||
| } |
| @@ -0,0 +1,152 @@ | ||
| package org.jpos.q2; | ||
|
|
||
| import jline.SimpleCompletor; | ||
|
|
||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.net.JarURLConnection; | ||
| import java.net.URI; | ||
| import java.net.URISyntaxException; | ||
| import java.net.URL; | ||
| import java.util.ArrayList; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
| import java.util.Enumeration; | ||
| import java.util.HashSet; | ||
| import java.util.Iterator; | ||
| import java.util.List; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| import java.util.jar.JarEntry; | ||
|
|
||
| public class CLIPrefixedClassNameCompletor extends SimpleCompletor | ||
| { | ||
| public CLIPrefixedClassNameCompletor(Collection<String> prefixes) | ||
| throws IOException | ||
| { | ||
| super(getClassNames(prefixes), new CmdFilter(prefixes)); | ||
| setDelimiter("."); | ||
| } | ||
|
|
||
| private static String[] getClassNames(Collection<String> prefixes) throws IOException | ||
| { | ||
| Set<String> classes = new HashSet<String>(); | ||
| for (String prefix : prefixes) | ||
| { | ||
| classes.addAll(getClassEntries(prefix)); | ||
| } | ||
|
|
||
| // now filter classes by changing "/" to "." and trimming the | ||
| // trailing ".class" | ||
| Set<String> classNames = new TreeSet<String>(); | ||
|
|
||
| for (Iterator i = classes.iterator(); i.hasNext(); ) | ||
| { | ||
| String name = (String) i.next(); | ||
| if (name.endsWith(".class")) | ||
| { | ||
| classNames.add(name.replace('/', '.'). | ||
| substring(0, name.length() - 6)); | ||
| } | ||
| } | ||
|
|
||
| return classNames.toArray(new String[classNames.size()]); | ||
| } | ||
|
|
||
| private static List<String> getClassEntries(String prefix) throws IOException | ||
| { | ||
| final String p = prefix.replaceAll("\\.", "\\/"); | ||
| List<String> result = new ArrayList<String>(); | ||
|
|
||
| Enumeration<URL> urls = CLIPrefixedClassNameCompletor.class.getClassLoader().getResources(p); | ||
| while (urls.hasMoreElements()) | ||
| { | ||
| URL url = urls.nextElement(); | ||
| if (url == null) { return Collections.emptyList(); } | ||
|
|
||
| try | ||
| { | ||
| final List<String> lst = url.getProtocol().equals("jar") ? | ||
| resolveModuleEntriesFromJar(url, p) : | ||
| resolveModuleEntriesFromFiles(url, p); | ||
| result.addAll(lst); | ||
| } | ||
| catch (URISyntaxException e) | ||
| { | ||
| throw new IOException("Bad URL", e); | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| private static List<String> resolveModuleEntriesFromFiles(URL url, String _prefix) throws IOException, URISyntaxException | ||
| { | ||
| final String prefix = _prefix.endsWith("/") ? _prefix : _prefix + "/"; | ||
|
|
||
| List<String> resourceList = new ArrayList<String>(); | ||
|
|
||
| final URI uri = url.toURI(); | ||
| File f = new File(uri); | ||
| addFiles(f, prefix, resourceList); | ||
|
|
||
| return resourceList; | ||
| } | ||
|
|
||
| private static void addFiles(File f, String prefix, List<String> resourceList) | ||
| { | ||
| File files[] = f.listFiles(); | ||
| if (files == null) { return; } | ||
|
|
||
| for (File file : files) | ||
| { | ||
| if (file.isDirectory()) | ||
| { | ||
| addFiles(file, prefix + file.getName() + "/", resourceList); | ||
| } | ||
| else | ||
| { | ||
| resourceList.add(prefix + file.getName()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private static List<String> resolveModuleEntriesFromJar(URL url, String _prefix) throws IOException | ||
| { | ||
| final String prefix = _prefix.endsWith("/") ? _prefix : _prefix + "/"; | ||
|
|
||
| List<String> resourceList = new ArrayList<String>(); | ||
|
|
||
| JarURLConnection conn = (JarURLConnection) url.openConnection(); | ||
| Enumeration entries = conn.getJarFile().entries(); | ||
| while (entries.hasMoreElements()) | ||
| { | ||
| JarEntry entry = (JarEntry) entries.nextElement(); | ||
| String name = entry.getName(); | ||
| if (name.startsWith(prefix) && !entry.isDirectory()) | ||
| { | ||
| resourceList.add(name); | ||
| } | ||
| } | ||
| return resourceList; | ||
| } | ||
|
|
||
| public static class CmdFilter implements SimpleCompletorFilter | ||
| { | ||
| Collection<String> prefixes; | ||
|
|
||
| public CmdFilter(Collection<String> prefixes) | ||
| { | ||
| this.prefixes = prefixes; | ||
| } | ||
|
|
||
| public String filter(String element) | ||
| { | ||
| for (String prefix : prefixes) | ||
| { | ||
| final String p = prefix; | ||
| if (element.startsWith(p)) { return element.substring(p.length()).toLowerCase(); } | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| } |