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 }