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.matcher; 021 022 import org.crsh.cmdline.ArgumentDescriptor; 023 import org.crsh.cmdline.OptionDescriptor; 024 import org.crsh.cmdline.binding.MethodArgumentBinding; 025 import org.crsh.cmdline.MethodDescriptor; 026 import org.crsh.cmdline.ParameterDescriptor; 027 028 import java.io.IOException; 029 import java.lang.reflect.InvocationTargetException; 030 import java.lang.reflect.Method; 031 import java.util.ArrayList; 032 import java.util.HashSet; 033 import java.util.List; 034 import java.util.Map; 035 import java.util.Set; 036 037 /** 038 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> 039 * @version $Revision$ 040 */ 041 public class MethodMatch<T> extends CommandMatch<T, MethodDescriptor<T>, MethodArgumentBinding> { 042 043 /** . */ 044 private final MethodDescriptor<T> descriptor; 045 046 /** . */ 047 private final ClassMatch<T> owner; 048 049 /** . */ 050 private final boolean implicit; 051 052 public MethodMatch( 053 ClassMatch<T> owner, 054 MethodDescriptor<T> descriptor, 055 boolean implicit, 056 List<OptionMatch<MethodArgumentBinding>> optionMatches, 057 List<ArgumentMatch<MethodArgumentBinding>> argumentMatches, 058 String rest) { 059 super(optionMatches, argumentMatches, rest); 060 061 // 062 this.owner = owner; 063 this.descriptor = descriptor; 064 this.implicit = implicit; 065 } 066 067 public boolean isImplicit() { 068 return implicit; 069 } 070 071 @Override 072 public MethodDescriptor<T> getDescriptor() { 073 return descriptor; 074 } 075 076 public ClassMatch<T> getOwner() { 077 return owner; 078 } 079 080 @Override 081 public void printMan(Appendable writer) throws IOException { 082 if (implicit) { 083 getOwner().printMan(writer); 084 } else { 085 descriptor.printMan(writer); 086 } 087 } 088 089 @Override 090 public void printUsage(Appendable writer) throws IOException { 091 if (implicit) { 092 getOwner().printUsage(writer); 093 } else { 094 descriptor.printUsage(writer); 095 } 096 } 097 098 @Override 099 public Set<ParameterDescriptor<?>> getParameters() { 100 Set<ParameterDescriptor<?>> unused = new HashSet<ParameterDescriptor<?>>(); 101 unused.addAll(descriptor.getArguments()); 102 unused.addAll(descriptor.getOptions()); 103 unused.addAll(owner.getDescriptor().getOptions()); 104 return unused; 105 } 106 107 @Override 108 public List<ParameterMatch<?, ?>> getParameterMatches() { 109 List<ParameterMatch<?, ?>> matches = new ArrayList<ParameterMatch<?, ?>>(); 110 matches.addAll(getOptionMatches()); 111 matches.addAll(getArgumentMatches()); 112 matches.addAll(owner.getOptionMatches()); 113 return matches; 114 } 115 116 @Override 117 protected Object doInvoke(InvocationContext context, T command, Map<ParameterDescriptor<?>, Object> values) throws CmdInvocationException, CmdSyntaxException { 118 119 // Prepare invocation 120 MethodDescriptor<T> descriptor = getDescriptor(); 121 Method m = descriptor.getMethod(); 122 Class<?>[] parameterTypes = m.getParameterTypes(); 123 Object[] mArgs = new Object[parameterTypes.length]; 124 for (int i = 0;i < mArgs.length;i++) { 125 ParameterDescriptor<MethodArgumentBinding> parameter = descriptor.getParameter(i); 126 127 // 128 Class<?> parameterType = parameterTypes[i]; 129 130 // 131 Object v; 132 if (parameter == null) { 133 // Attempt to obtain from invocation context 134 v = context.getAttribute(parameterType); 135 } else { 136 v = values.get(parameter); 137 } 138 139 // 140 if (v == null) { 141 if (parameterType.isPrimitive() || parameter.isRequired()) { 142 if (parameter instanceof ArgumentDescriptor) { 143 ArgumentDescriptor<?> argument = (ArgumentDescriptor<?>)parameter; 144 throw new CmdSyntaxException("Missing argument " + argument.getName()); 145 } else { 146 OptionDescriptor<?> option = (OptionDescriptor<?>)parameter; 147 throw new CmdSyntaxException("Missing option " + option.getNames()); 148 } 149 } 150 } 151 152 // 153 mArgs[i] = v; 154 } 155 156 // First configure command 157 owner.doInvoke(context, command, values); 158 159 // Perform method invocation 160 try { 161 return m.invoke(command, mArgs); 162 } 163 catch (InvocationTargetException e) { 164 Throwable t = e.getTargetException(); 165 if (t instanceof Error) { 166 throw (Error)t; 167 } else { 168 throw new CmdInvocationException(t); 169 } 170 } 171 catch (IllegalAccessException t) { 172 throw new CmdInvocationException(t); 173 } 174 } 175 }