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.cli.impl.lang; 021 022 import org.crsh.cli.descriptor.ArgumentDescriptor; 023 import org.crsh.cli.descriptor.CommandDescriptor; 024 import org.crsh.cli.descriptor.Description; 025 import org.crsh.cli.impl.descriptor.CommandDescriptorImpl; 026 import org.crsh.cli.impl.descriptor.IntrospectionException; 027 import org.crsh.cli.descriptor.OptionDescriptor; 028 import org.crsh.cli.descriptor.ParameterDescriptor; 029 import org.crsh.cli.SyntaxException; 030 import org.crsh.cli.impl.invocation.CommandInvoker; 031 import org.crsh.cli.impl.invocation.InvocationException; 032 import org.crsh.cli.impl.invocation.InvocationMatch; 033 import org.crsh.cli.impl.invocation.ParameterMatch; 034 import org.crsh.cli.impl.invocation.Resolver; 035 036 import java.lang.reflect.InvocationTargetException; 037 import java.lang.reflect.Method; 038 import java.lang.reflect.Type; 039 import java.util.Collections; 040 import java.util.Map; 041 042 class MethodDescriptor<T> extends CommandDescriptorImpl<T> { 043 044 /** . */ 045 private final ClassDescriptor<T> owner; 046 047 /** . */ 048 private final Method method; 049 050 /** . */ 051 private final int size; 052 053 public MethodDescriptor( 054 ClassDescriptor<T> owner, 055 Method method, 056 String name, 057 Description info) throws IntrospectionException { 058 super(name, info); 059 060 // 061 this.owner = owner; 062 this.method = method; 063 this.size = method.getParameterTypes().length; 064 } 065 066 /** 067 * Returns the parameter descriptor for the specified method parameter index. 068 * 069 * @param index the parameter index 070 * @return the parameter descriptor or null if none can be bound 071 * @throws IndexOutOfBoundsException if the index is not valid 072 */ 073 ParameterDescriptor getParameter(int index) throws IndexOutOfBoundsException { 074 if (index < 0 || index >= size) { 075 throw new IndexOutOfBoundsException("Bad index value " + index); 076 } 077 for (ParameterDescriptor argument : getParameters()) { 078 if (((MethodArgumentBinding)argument.getBinding()).getIndex() == index) { 079 return argument; 080 } 081 } 082 return null; 083 } 084 085 @Override 086 protected void addParameter(ParameterDescriptor parameter) throws IntrospectionException, NullPointerException, IllegalArgumentException { 087 super.addParameter(parameter); 088 } 089 090 @Override 091 public CommandDescriptor<T> getOwner() { 092 return owner; 093 } 094 095 @Override 096 public Map<String, ? extends CommandDescriptorImpl<T>> getSubordinates() { 097 return Collections.emptyMap(); 098 } 099 100 @Override 101 public CommandDescriptorImpl<T> getSubordinate(String name) { 102 return null; 103 } 104 105 public Method getMethod() { 106 return method; 107 } 108 109 @Override 110 public Class<T> getType() { 111 return owner.getType(); 112 } 113 114 public CommandInvoker<T> getInvoker(final InvocationMatch<T> _match) { 115 return new CommandInvoker<T>() { 116 @Override 117 public Class<?> getReturnType() { 118 return getMethod().getReturnType(); 119 } 120 121 @Override 122 public Type getGenericReturnType() { 123 return getMethod().getGenericReturnType(); 124 } 125 126 @Override 127 public Class<?>[] getParameterTypes() { 128 return getMethod().getParameterTypes(); 129 } 130 131 @Override 132 public Type[] getGenericParameterTypes() { 133 return getMethod().getGenericParameterTypes(); 134 } 135 136 @Override 137 public Object invoke(Resolver resolver, T command) throws InvocationException, SyntaxException { 138 139 // 140 owner.configure(_match.owner(), command); 141 142 // Prepare invocation 143 Method m = getMethod(); 144 Class<?>[] parameterTypes = m.getParameterTypes(); 145 Object[] mArgs = new Object[parameterTypes.length]; 146 for (int i = 0;i < mArgs.length;i++) { 147 ParameterDescriptor parameter = getParameter(i); 148 149 // 150 Class<?> parameterType = parameterTypes[i]; 151 152 Object v; 153 if (parameter == null) { 154 // Attempt to obtain from resolver 155 v = resolver.resolve(parameterType); 156 } else { 157 ParameterMatch match = _match.getParameter(parameter); 158 if (match != null) { 159 v = match.computeValue(); 160 } else { 161 v = null; 162 } 163 } 164 165 // 166 if (v == null) { 167 if (parameterType.isPrimitive() || parameter.isRequired()) { 168 if (parameter instanceof ArgumentDescriptor) { 169 ArgumentDescriptor argument = (ArgumentDescriptor)parameter; 170 throw new SyntaxException("Missing argument " + argument.getName()); 171 } else { 172 OptionDescriptor option = (OptionDescriptor)parameter; 173 throw new SyntaxException("Missing option " + option.getNames()); 174 } 175 } 176 } 177 178 // 179 mArgs[i] = v; 180 } 181 182 // Perform method invocation 183 try { 184 return m.invoke(command, mArgs); 185 } 186 catch (InvocationTargetException e) { 187 Throwable t = e.getTargetException(); 188 if (t instanceof Error) { 189 throw (Error)t; 190 } else { 191 throw new InvocationException(t); 192 } 193 } 194 catch (IllegalAccessException t) { 195 throw new InvocationException(t); 196 } 197 } 198 }; 199 } 200 }