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