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