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    
028    import java.io.IOException;
029    import java.util.Formatter;
030    import java.util.HashSet;
031    import java.util.Map;
032    import java.util.Set;
033    import java.util.logging.Logger;
034    
035    public class ClassDescriptor<T> extends CommandDescriptor<T, ClassFieldBinding> {
036    
037      /** . */
038      private static final Logger log = Logger.getLogger(ClassDescriptor.class.getName());
039    
040      /** . */
041      private final Class<T> type;
042    
043      /** . */
044      private final Map<String, MethodDescriptor<T>> methods;
045    
046      ClassDescriptor(Class<T> type, Map<String, MethodDescriptor<T>> methods, Description info) throws IntrospectionException {
047        super(type.getSimpleName().toLowerCase(), info);
048    
049        //
050        this.methods = methods;
051        this.type = type;
052      }
053    
054      public Matcher<T> matcher() {
055        return new MatcherImpl<T>(this);
056      }
057    
058      public Matcher<T> matcher(String mainName) {
059        return new MatcherImpl<T>(mainName, this);
060      }
061    
062      @Override
063      void addParameter(ParameterDescriptor<ClassFieldBinding> parameter) throws IntrospectionException {
064    
065        // Check we can add the option
066        if (parameter instanceof OptionDescriptor<?>) {
067          OptionDescriptor<ClassFieldBinding> option = (OptionDescriptor<ClassFieldBinding>)parameter;
068          Set<String> blah = new HashSet<String>();
069          for (String optionName : option.getNames()) {
070            blah.add((optionName.length() == 1 ? "-" : "--") + optionName);
071          }
072          for (MethodDescriptor<T> method : methods.values()) {
073            Set<String> diff = new HashSet<String>(method.getOptionNames());
074            diff.retainAll(blah);
075            if (diff.size() > 0) {
076              throw new IntrospectionException("Cannot add method " + method.getName() + " because it has common "
077              + " options with its class: " + diff);
078            }
079          }
080        }
081    
082        //
083        super.addParameter(parameter);
084      }
085    
086      @Override
087      public Class<T> getType() {
088        return type;
089      }
090    
091      @Override
092      public Map<String, ? extends CommandDescriptor<T, ?>> getSubordinates() {
093        return methods;
094      }
095    
096      @Override
097      public OptionDescriptor<?> findOption(String name) {
098        return getOption(name);
099      }
100    
101      @Override
102      public void printUsage(Appendable writer) throws IOException {
103        if (methods.size() == 1) {
104          methods.values().iterator().next().printUsage(writer);
105        } else {
106          writer.append("usage: ").append(getName());
107          for (OptionDescriptor<?> option : getOptions()) {
108            option.printUsage(writer);
109          }
110          writer.append(" COMMAND [ARGS]\n\n");
111          writer.append("The most commonly used ").append(getName()).append(" commands are:\n");
112          String format = "   %1$-16s %2$s\n";
113          for (MethodDescriptor<T> method : getMethods()) {
114            Formatter formatter = new Formatter(writer);
115            formatter.format(format, method.getName(), method.getUsage());
116          }
117        }
118      }
119    
120      public void printMan(Appendable writer) throws IOException {
121        if (methods.size() == 1) {
122          methods.values().iterator().next().printMan(writer);
123        } else {
124    
125          // Name
126          writer.append("NAME\n");
127          writer.append(Util.MAN_TAB).append(getName());
128          if (getUsage().length() > 0) {
129            writer.append(" - ").append(getUsage());
130          }
131          writer.append("\n\n");
132    
133          // Synopsis
134          writer.append("SYNOPSIS\n");
135          writer.append(Util.MAN_TAB).append(getName());
136          for (OptionDescriptor<?> option : getOptions()) {
137            writer.append(" ");
138            option.printUsage(writer);
139          }
140          writer.append(" COMMAND [ARGS]\n\n");
141    
142          //
143          String man = getDescription().getMan();
144          if (man.length() > 0) {
145            writer.append("DESCRIPTION\n");
146            indent(Util.MAN_TAB, man, writer);
147            writer.append("\n\n");
148          }
149    
150          // Common options
151          if (getOptions().size() > 0) {
152            writer.append("PARAMETERS\n");
153            for (OptionDescriptor<?> option : getOptions()) {
154              writer.append(Util.MAN_TAB);
155              option.printUsage(writer);
156              String optionText = option.getDescription().getBestEffortMan();
157              if (optionText.length() > 0) {
158                writer.append("\n");
159                indent(Util.MAN_TAB_EXTRA, optionText, writer);
160              }
161              writer.append("\n\n");
162            }
163          }
164    
165          //
166          writer.append("COMMANDS\n");
167          for (MethodDescriptor<T> method : getMethods()) {
168            writer.append(Util.MAN_TAB).append(method.getName());
169            String methodText = method.getDescription().getBestEffortMan();
170            if (methodText.length() > 0) {
171              writer.append("\n");
172              indent(Util.MAN_TAB_EXTRA, methodText, writer);
173            }
174            writer.append("\n\n");
175          }
176        }
177      }
178    
179      public Iterable<MethodDescriptor<T>> getMethods() {
180        return methods.values();
181      }
182    
183      public MethodDescriptor<T> getMethod(String name) {
184        return methods.get(name);
185      }
186    }