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 }