Index: trunk/java-utils/src/main/java/de/ugoe/cs/util/console/CommandExecuter.java
===================================================================
--- trunk/java-utils/src/main/java/de/ugoe/cs/util/console/CommandExecuter.java	(revision 1018)
+++ trunk/java-utils/src/main/java/de/ugoe/cs/util/console/CommandExecuter.java	(revision 1238)
@@ -78,4 +78,12 @@
      */
     private List<String> commandPackageList;
+    
+    /**
+     * <p>
+     * the list of available commands (lazy instantiation in the method
+     * {@link #getAvailableCommands()})
+     * <p>
+     */
+    private Command[] availableCommands;
 
     /**
@@ -218,98 +226,104 @@
      */
     public Command[] getAvailableCommands() {
-        List<Command> commands = new ArrayList<Command>();
-        List<String> packages = new ArrayList<String>();
-        packages.addAll(commandPackageList);
-        packages.add(defaultPackage);
-
-        FilenameFilter filter = new FilenameFilter() {
-            @Override
-            public boolean accept(File dir, String name) {
-                return (name != null) && (name.startsWith(cmdPrefix)) && (name.endsWith(".class"));
-            }
-        };
-
-        SortedSet<String> classNames = new TreeSet<String>(new Comparator<String>() {
-            @Override
-            public int compare(String arg1, String arg2) {
-                String str1 = arg1.substring(arg1.lastIndexOf('.') + cmdPrefix.length() + 1);
-                String str2 = arg2.substring(arg2.lastIndexOf('.') + cmdPrefix.length() + 1);
-                return str1.compareTo(str2);
-            }
-
-        });
-
-        for (String packageName : packages) {
-            String path = packageName.replace('.', '/');
-            try {
-                Enumeration<URL> resources = ClassLoader.getSystemResources(path);
-
-                while (resources.hasMoreElements()) {
-                    URL resource = resources.nextElement();
-                    File packageDir = new File(resource.getFile());
-
-                    if (packageDir.isDirectory()) {
-                        for (File classFile : packageDir.listFiles(filter)) {
-                            String className =
-                                classFile.getName().substring(0,
-                                                              classFile.getName().lastIndexOf('.'));
-                            classNames.add(packageName + "." + className);
+        if (availableCommands == null) {
+            List<Command> commands = new ArrayList<Command>();
+            List<String> packages = new ArrayList<String>();
+            packages.addAll(commandPackageList);
+            packages.add(defaultPackage);
+
+            FilenameFilter filter = new FilenameFilter() {
+                @Override
+                public boolean accept(File dir, String name) {
+                    return
+                        (name != null) && (name.startsWith(cmdPrefix)) && (name.endsWith(".class"));
+                }
+            };
+
+            SortedSet<String> classNames = new TreeSet<String>(new Comparator<String>() {
+                @Override
+                public int compare(String arg1, String arg2) {
+                    String str1 = arg1.substring(arg1.lastIndexOf('.') + cmdPrefix.length() + 1);
+                    String str2 = arg2.substring(arg2.lastIndexOf('.') + cmdPrefix.length() + 1);
+                    return str1.compareTo(str2);
+                }
+
+            });
+
+            for (String packageName : packages) {
+                String path = packageName.replace('.', '/');
+                try {
+                    Enumeration<URL> resources = ClassLoader.getSystemResources(path);
+
+                    while (resources.hasMoreElements()) {
+                        URL resource = resources.nextElement();
+                        File packageDir = new File(resource.getFile());
+
+                        if (packageDir.isDirectory()) {
+                            for (File classFile : packageDir.listFiles(filter)) {
+                                String className = classFile.getName().substring
+                                    (0, classFile.getName().lastIndexOf('.'));
+                                classNames.add(packageName + "." + className);
+                            }
+                        }
+                        else {
+                            int index = resource.getFile().lastIndexOf('!');
+                            if ((index > 0) && (resource.getFile().startsWith("file:")) &&
+                                (resource.getFile().endsWith("!/" + path)))
+                            {
+                                String jarFile =
+                                    resource.getFile().substring("file:".length(), index);
+
+                                // we have to read the package content from a jar file
+                                JarInputStream jarInputStream = null;
+                                try {
+                                    jarInputStream =
+                                        new JarInputStream(new FileInputStream(jarFile));
+                                    JarEntry entry = null;
+                                    do {
+                                        entry = jarInputStream.getNextJarEntry();
+                                        if ((entry != null) && (!entry.isDirectory()) &&
+                                                (entry.getName().startsWith(path)))
+                                        {
+                                            String className = entry.getName().substring
+                                                (path.length() + 1, entry.getName().lastIndexOf('.'));
+                                            classNames.add(packageName + "." + className);
+                                        }
+                                    }
+                                    while (entry != null);
+                                }
+                                catch (Exception e) {
+                                    e.printStackTrace();
+                                    Console.traceln(Level.WARNING, "could not read contents of " +
+                                                    "jar " + jarFile);
+                                }
+                                finally {
+                                    if (jarInputStream != null) {
+                                        jarInputStream.close();
+                                    }
+                                }
+
+                            }
                         }
                     }
-                    else {
-                        int index = resource.getFile().lastIndexOf('!');
-                        if ((index > 0) && (resource.getFile().startsWith("file:")) &&
-                            (resource.getFile().endsWith("!/" + path)))
-                        {
-                            String jarFile = resource.getFile().substring("file:".length(), index);
-
-                            // we have to read the package content from a jar file
-                            JarInputStream jarInputStream = null;
-                            try {
-                                jarInputStream = new JarInputStream(new FileInputStream(jarFile));
-                                JarEntry entry = null;
-                                do {
-                                    entry = jarInputStream.getNextJarEntry();
-                                    if ((entry != null) && (!entry.isDirectory()) &&
-                                            (entry.getName().startsWith(path)))
-                                    {
-                                        String className = entry.getName().substring
-                                            (path.length() + 1, entry.getName().lastIndexOf('.'));
-                                        classNames.add(packageName + "." + className);
-                                    }
-                                }
-                                while (entry != null);
-                            }
-                            catch (Exception e) {
-                                e.printStackTrace();
-                                Console.traceln(Level.WARNING, "could not read contents of jar " +
-                                    jarFile);
-                            }
-                            finally {
-                                if (jarInputStream != null) {
-                                    jarInputStream.close();
-                                }
-                            }
-
-                        }
-                    }
-                }
-            }
-            catch (IOException e) {
-                Console.traceln(Level.WARNING, "could not read commands of package " + packageName);
-            }
-        }
-
-        for (String className : classNames) {
-            // class may still be inner classes. Therefore load the command, to
-            // see if it is really available and a command.
-            Command cmd = loadCMD(className);
-            if (cmd != null) {
-                commands.add(cmd);
-            }
-        }
-
-        Command[] commandArray = commands.toArray(new Command[commands.size()]);
-        return commandArray;
+                }
+                catch (IOException e) {
+                    Console.traceln
+                        (Level.WARNING, "could not read commands of package " + packageName);
+                }
+            }
+
+            for (String className : classNames) {
+                // class may still be inner classes. Therefore load the command, to
+                // see if it is really available and a command.
+                Command cmd = loadCMD(className);
+                if (cmd != null) {
+                    commands.add(cmd);
+                }
+            }
+
+            availableCommands = commands.toArray(new Command[commands.size()]);
+        }
+        
+        return availableCommands;
     }
     
@@ -326,3 +340,58 @@
         return commandPackageListCopy;
     }
+
+    /**
+     * <p>
+     * this method method performs an auto completion of the provided String as far as possible
+     * regarding the available commands. It auto completes to the full command name, if only
+     * one command matches the given prefix. It auto completes to the common denominator, if
+     * several commands match the prefix
+     * </p>
+     *
+     * @param commandPrefix the prefix to be auto completed
+     * 
+     * @return as described
+     */
+    public String autoCompleteCommand(String commandPrefix) {
+        Command[] commands = getAvailableCommands();
+        
+        List<Command> matchingCommands = new ArrayList<Command>();
+        for (Command command : commands) {
+            String commandName = command.getClass().getSimpleName().substring(3);
+            if (commandName.startsWith(commandPrefix)) {
+                matchingCommands.add(command);
+            }
+        }
+        
+        StringBuffer completedPrefix = new StringBuffer(commandPrefix);
+        
+        boolean foundCompletion = false;
+        
+        while (!foundCompletion) {
+            char nextCompletionChar = 0;
+            for (Command command : matchingCommands) {
+                String commandName = command.getClass().getSimpleName().substring(3);
+                if (commandName.length() > completedPrefix.length()) {
+                    if (nextCompletionChar == 0) {
+                        nextCompletionChar = commandName.charAt(completedPrefix.length());
+                    }
+                    else if (nextCompletionChar != commandName.charAt(completedPrefix.length())) {
+                        foundCompletion = true;
+                    }
+                }
+                else {
+                    foundCompletion = true;
+                }
+            }
+            
+            if (!foundCompletion && (nextCompletionChar != 0)) {
+                completedPrefix.append(nextCompletionChar);
+            }
+            else {
+                foundCompletion = true;
+            }
+        }
+        
+        return completedPrefix.toString();
+    }
 }
