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