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 }