001    package org.crsh.cmdline.completers;
002    
003    import org.crsh.cmdline.ParameterDescriptor;
004    import org.crsh.cmdline.spi.Completer;
005    import org.crsh.cmdline.spi.ValueCompletion;
006    
007    import java.util.Collection;
008    
009    /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
010    public abstract class AbstractPathCompleter<P> implements Completer {
011    
012      protected abstract String getCurrentPath() throws Exception;
013    
014      protected abstract P getPath(String path) throws Exception;
015    
016      protected abstract boolean exists(P path) throws Exception;
017    
018      protected abstract boolean isDirectory(P path) throws Exception;
019    
020      protected abstract boolean isFile(P path) throws Exception;
021    
022      protected abstract Collection<P> getChilren(P path) throws Exception;
023    
024      protected abstract String getName(P path) throws Exception;
025    
026      public final ValueCompletion complete(ParameterDescriptor<?> parameter, String prefix) throws Exception {
027    
028        // Handle empty dir
029        if (!prefix.startsWith("/")) {
030          String currentPath = getCurrentPath();
031          if (!currentPath.endsWith("/")) {
032            currentPath += "/";
033          }
034          if (prefix.length() > 0) {
035            prefix = currentPath + prefix;
036          } else {
037            prefix = currentPath;
038          }
039        }
040    
041        //
042        P f = getPath(prefix);
043    
044        //
045        if (exists(f)) {
046          if (isDirectory(f)) {
047            if (prefix.endsWith("/")) {
048              Collection<P> children = getChilren(f);
049              if (children != null) {
050                if (children.size() > 0) {
051                  return listDir(f, "");
052                } else {
053                  return ValueCompletion.create();
054                }
055              } else {
056                return ValueCompletion.create();
057              }
058            } else {
059              Collection<P> children = getChilren(f);
060              if (children == null) {
061                return ValueCompletion.create();
062              } else {
063                return ValueCompletion.create("/", false);
064              }
065            }
066          } else if (isFile(f)) {
067            return ValueCompletion.create("", true);
068          }
069          return ValueCompletion.create();
070        } else {
071          int pos = prefix.lastIndexOf('/');
072          if (pos != -1) {
073            String filter;
074            if (pos == 0) {
075              f = getPath("/");
076              filter = prefix.substring(1);
077            } else {
078              f = getPath(prefix.substring(0, pos));
079              filter = prefix.substring(pos + 1);
080            }
081            if (exists(f)) {
082              if (isDirectory(f)) {
083                return listDir(f, filter);
084              } else {
085                return ValueCompletion.create();
086              }
087            } else {
088              return ValueCompletion.create();
089            }
090          } else {
091            return ValueCompletion.create();
092          }
093        }
094      }
095    
096      private ValueCompletion listDir(P dir, final String filter) throws Exception {
097        Collection<P> children = getChilren(dir);
098        if (children != null) {
099          ValueCompletion map = new ValueCompletion(filter);
100          for (P child : children) {
101            String name = getName(child);
102            if (name.startsWith(filter)) {
103              String suffix = name.substring(filter.length());
104              if (isDirectory(child)) {
105                Collection<P> grandChildren = getChilren(child);
106                if (grandChildren != null) {
107                  map.put(suffix + "/", false);
108                } else {
109                  // Skip it
110                }
111              } else {
112                map.put(suffix, true);
113              }
114            }
115          }
116          return map;
117        } else {
118          return ValueCompletion.create();
119        }
120      }
121    }