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 }