001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.cmdline;
021    
022    import org.crsh.cmdline.binding.ClassFieldBinding;
023    import static org.crsh.cmdline.Util.indent;
024    
025    import org.crsh.cmdline.matcher.Matcher;
026    import org.crsh.cmdline.matcher.impl.MatcherImpl;
027    import org.slf4j.Logger;
028    import org.slf4j.LoggerFactory;
029    
030    import java.io.IOException;
031    import java.util.Formatter;
032    import java.util.HashSet;
033    import java.util.Map;
034    import java.util.Set;
035    
036    public class ClassDescriptor<T> extends CommandDescriptor<T, ClassFieldBinding> {
037    
038      /** . */
039      private static final Logger log = LoggerFactory.getLogger(ClassDescriptor.class);
040    
041      /** . */
042      private final Class<T> type;
043    
044      /** . */
045      private final Map<String, MethodDescriptor<T>> methods;
046    
047      ClassDescriptor(Class<T> type, Map<String, MethodDescriptor<T>> methods, Description info) throws IntrospectionException {
048        super(type.getSimpleName().toLowerCase(), info);
049    
050        //
051        this.methods = methods;
052        this.type = type;
053      }
054    
055      public Matcher<T> matcher() {
056        return new MatcherImpl<T>(this);
057      }
058    
059      public Matcher<T> matcher(String mainName) {
060        return new MatcherImpl<T>(mainName, this);
061      }
062    
063      @Override
064      void addParameter(ParameterDescriptor<ClassFieldBinding> parameter) throws IntrospectionException {
065    
066        // Check we can add the option
067        if (parameter instanceof OptionDescriptor<?>) {
068          OptionDescriptor<ClassFieldBinding> option = (OptionDescriptor<ClassFieldBinding>)parameter;
069          Set<String> blah = new HashSet<String>();
070          for (String optionName : option.getNames()) {
071            blah.add((optionName.length() == 1 ? "-" : "--") + optionName);
072          }
073          for (MethodDescriptor<T> method : methods.values()) {
074            Set<String> diff = new HashSet<String>(method.getOptionNames());
075            diff.retainAll(blah);
076            if (diff.size() > 0) {
077              throw new IntrospectionException("Cannot add method " + method.getName() + " because it has common "
078              + " options with its class: " + diff);
079            }
080          }
081        }
082    
083        //
084        super.addParameter(parameter);
085      }
086    
087      @Override
088      public Class<T> getType() {
089        return type;
090      }
091    
092      @Override
093      public Map<String, ? extends CommandDescriptor<T, ?>> getSubordinates() {
094        return methods;
095      }
096    
097      @Override
098      public OptionDescriptor<?> findOption(String name) {
099        return getOption(name);
100      }
101    
102      @Override
103      public void printUsage(Appendable writer) throws IOException {
104        if (methods.size() == 1) {
105          methods.values().iterator().next().printUsage(writer);
106        } else {
107          writer.append("usage: ").append(getName());
108          for (OptionDescriptor<?> option : getOptions()) {
109            option.printUsage(writer);
110          }
111          writer.append(" COMMAND [ARGS]\n\n");
112          writer.append("The most commonly used ").append(getName()).append(" commands are:\n");
113          String format = "   %1$-16s %2$s\n";
114          for (MethodDescriptor<T> method : getMethods()) {
115            Formatter formatter = new Formatter(writer);
116            formatter.format(format, method.getName(), method.getUsage());
117          }
118        }
119      }
120    
121      public void printMan(Appendable writer) throws IOException {
122        if (methods.size() == 1) {
123          methods.values().iterator().next().printMan(writer);
124        } else {
125    
126          // Name
127          writer.append("NAME\n");
128          writer.append(Util.MAN_TAB).append(getName());
129          if (getUsage().length() > 0) {
130            writer.append(" - ").append(getUsage());
131          }
132          writer.append("\n\n");
133    
134          // Synopsis
135          writer.append("SYNOPSIS\n");
136          writer.append(Util.MAN_TAB).append(getName());
137          for (OptionDescriptor<?> option : getOptions()) {
138            writer.append(" ");
139            option.printUsage(writer);
140          }
141          writer.append(" COMMAND [ARGS]\n\n");
142    
143          //
144          String man = getDescription().getMan();
145          if (man.length() > 0) {
146            writer.append("DESCRIPTION\n");
147            indent(Util.MAN_TAB, man, writer);
148            writer.append("\n\n");
149          }
150    
151          // Common options
152          if (getOptions().size() > 0) {
153            writer.append("PARAMETERS\n");
154            for (OptionDescriptor<?> option : getOptions()) {
155              writer.append(Util.MAN_TAB);
156              option.printUsage(writer);
157              String optionText = option.getDescription().getBestEffortMan();
158              if (optionText.length() > 0) {
159                writer.append("\n");
160                indent(Util.MAN_TAB_EXTRA, optionText, writer);
161              }
162              writer.append("\n\n");
163            }
164          }
165    
166          //
167          writer.append("COMMANDS\n");
168          for (MethodDescriptor<T> method : getMethods()) {
169            writer.append(Util.MAN_TAB).append(method.getName());
170            String methodText = method.getDescription().getBestEffortMan();
171            if (methodText.length() > 0) {
172              writer.append("\n");
173              indent(Util.MAN_TAB_EXTRA, methodText, writer);
174            }
175            writer.append("\n\n");
176          }
177        }
178      }
179    
180      public Iterable<MethodDescriptor<T>> getMethods() {
181        return methods.values();
182      }
183    
184      public MethodDescriptor<T> getMethod(String name) {
185        return methods.get(name);
186      }
187    }