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 }