001 /*
002 * Copyright (C) 2010 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.MethodArgumentBinding;
023
024 import static org.crsh.cmdline.Util.indent;
025 import static org.crsh.cmdline.Util.tuples;
026
027 import org.slf4j.Logger;
028 import org.slf4j.LoggerFactory;
029
030 import java.io.IOException;
031 import java.lang.reflect.Method;
032 import java.util.ArrayList;
033 import java.util.Collections;
034 import java.util.Formatter;
035 import java.util.List;
036 import java.util.Map;
037 import java.util.Set;
038
039 /**
040 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
041 * @version $Revision$
042 */
043 public class MethodDescriptor<T> extends CommandDescriptor<T, MethodArgumentBinding> {
044
045 /** . */
046 private static final Set<String> MAIN_SINGLETON = Collections.singleton("main");
047
048 /** . */
049 private static final Logger log = LoggerFactory.getLogger(MethodDescriptor.class);
050
051 /** . */
052 private final ClassDescriptor<T> owner;
053
054 /** . */
055 private final Method method;
056
057 /** . */
058 private final int size;
059
060 MethodDescriptor(
061 ClassDescriptor<T> owner,
062 Method method,
063 String name,
064 Description info) throws IntrospectionException {
065 super(name, info);
066
067 //
068 this.owner = owner;
069 this.method = method;
070 this.size = method.getParameterTypes().length;
071 }
072
073 /**
074 * Returns the parameter descriptor for the specified method parameter index.
075 *
076 * @param index the parameter index
077 * @return the parameter descriptor or null if none can be bound
078 * @throws IndexOutOfBoundsException if the index is not valid
079 */
080 public ParameterDescriptor<MethodArgumentBinding> getParameter(int index) throws IndexOutOfBoundsException {
081 if (index < 0 || index >= size) {
082 throw new IndexOutOfBoundsException("Bad index value " + index);
083 }
084 for (ParameterDescriptor<MethodArgumentBinding> argument : getParameters()) {
085 if (argument.getBinding().getIndex() == index) {
086 return argument;
087 }
088 }
089 return null;
090 }
091
092 @Override
093 public Map<String, ? extends CommandDescriptor<T, ?>> getSubordinates() {
094 return Collections.emptyMap();
095 }
096
097 public Method getMethod() {
098 return method;
099 }
100
101 @Override
102 public Class<T> getType() {
103 return owner.getType();
104 }
105
106 @Override
107 public OptionDescriptor<?> findOption(String name) {
108 OptionDescriptor<?> option = getOption(name);
109 if (option == null) {
110 option = owner.findOption(name);
111 }
112 return option;
113 }
114
115 @Override
116 public void printUsage(Appendable writer) throws IOException {
117 int length = 0;
118 List<String> parameterUsages = new ArrayList<String>();
119 List<String> parameterBilto = new ArrayList<String>();
120 boolean printName = !owner.getSubordinates().keySet().equals(MAIN_SINGLETON);
121
122 //
123 writer.append("usage: ").append(owner.getName());
124
125 //
126 for (OptionDescriptor<?> option : owner.getOptions()) {
127 writer.append(" ");
128 StringBuilder sb = new StringBuilder();
129 option.printUsage(sb);
130 String usage = sb.toString();
131 writer.append(usage);
132
133 length = Math.max(length, usage.length());
134 parameterUsages.add(usage);
135 parameterBilto.add(option.getUsage());
136 }
137
138 //
139 writer.append(printName ? (" " + getName()) : "");
140
141 //
142 for (ParameterDescriptor<?> parameter : getParameters()) {
143 writer.append(" ");
144 StringBuilder sb = new StringBuilder();
145 parameter.printUsage(sb);
146 String usage = sb.toString();
147 writer.append(usage);
148
149 length = Math.max(length, usage.length());
150 parameterBilto.add(parameter.getUsage());
151 parameterUsages.add(usage);
152 }
153 writer.append("\n\n");
154
155 //
156 String format = " %1$-" + length + "s %2$s\n";
157 for (String[] tuple : tuples(String.class, parameterUsages, parameterBilto)) {
158 Formatter formatter = new Formatter(writer);
159 formatter.format(format, tuple[0], tuple[1]);
160 }
161
162 //
163 writer.append("\n\n");
164 }
165
166 public void printMan(Appendable writer) throws IOException {
167
168 //
169 boolean printName = !owner.getSubordinates().keySet().equals(MAIN_SINGLETON);
170
171 // Name
172 writer.append("NAME\n");
173 writer.append(Util.MAN_TAB).append(owner.getName());
174 if (printName) {
175 writer.append(" ").append(getName());
176 }
177 if (getUsage().length() > 0) {
178 writer.append(" - ").append(getUsage());
179 }
180 writer.append("\n\n");
181
182 // Synopsis
183 writer.append("SYNOPSIS\n");
184 writer.append(Util.MAN_TAB).append(owner.getName());
185 for (OptionDescriptor<?> option : owner.getOptions()) {
186 writer.append(" ");
187 option.printUsage(writer);
188 }
189 if (printName) {
190 writer.append(" ").append(getName());
191 }
192 for (OptionDescriptor<?> option : getOptions()) {
193 writer.append(" ");
194 option.printUsage(writer);
195 }
196 for (ArgumentDescriptor<?> argument : getArguments()) {
197 writer.append(" ");
198 argument.printUsage(writer);
199 }
200 writer.append("\n\n");
201
202 // Description
203 String man = getDescription().getMan();
204 if (man.length() > 0) {
205 writer.append("DESCRIPTION\n");
206 indent(Util.MAN_TAB, man, writer);
207 writer.append("\n\n");
208 }
209
210 // Parameters
211 List<OptionDescriptor<?>> options = new ArrayList<OptionDescriptor<?>>();
212 options.addAll(owner.getOptions());
213 options.addAll(getOptions());
214 if (options.size() > 0) {
215 writer.append("\nPARAMETERS\n");
216 for (ParameterDescriptor<?> parameter : Util.join(owner.getOptions(), getParameters())) {
217 writer.append(Util.MAN_TAB);
218 parameter.printUsage(writer);
219 String parameterText = parameter.getDescription().getBestEffortMan();
220 if (parameterText.length() > 0) {
221 writer.append("\n");
222 indent(Util.MAN_TAB_EXTRA, parameterText, writer);
223 }
224 writer.append("\n\n");
225 }
226 }
227 }
228 }