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.CommandDescriptor;
023    import org.crsh.cli.descriptor.Description;
024    import org.crsh.cli.impl.descriptor.IntrospectionException;
025    import org.crsh.cli.descriptor.OptionDescriptor;
026    import org.crsh.cli.descriptor.ParameterDescriptor;
027    import org.crsh.cli.impl.SyntaxException;
028    import org.crsh.cli.impl.invocation.InvocationException;
029    import org.crsh.cli.impl.invocation.InvocationMatch;
030    
031    import java.lang.reflect.Type;
032    import java.util.HashSet;
033    import java.util.Map;
034    import java.util.Set;
035    
036    class ClassDescriptor<T> extends ObjectCommandDescriptor<T> {
037    
038      /** . */
039      private final Class<T> type;
040    
041      /** . */
042      private final Map<String, MethodDescriptor<T>> methods;
043    
044      ClassDescriptor(Class<T> type, String name, Map<String, MethodDescriptor<T>> methods, Description info) throws IntrospectionException {
045        super(name, info);
046    
047        //
048        this.methods = methods;
049        this.type = type;
050      }
051    
052      @Override
053      protected void addParameter(ParameterDescriptor parameter) throws IntrospectionException {
054    
055        // Check we can add the option
056        if (parameter instanceof OptionDescriptor) {
057          OptionDescriptor option = (OptionDescriptor)parameter;
058          Set<String> blah = new HashSet<String>();
059          for (String optionName : option.getNames()) {
060            blah.add((optionName.length() == 1 ? "-" : "--") + optionName);
061          }
062          for (MethodDescriptor<T> method : methods.values()) {
063            Set<String> diff = new HashSet<String>(method.getOptionNames());
064            diff.retainAll(blah);
065            if (diff.size() > 0) {
066              throw new IntrospectionException("Cannot add method " + method.getName() + " because it has common "
067              + " options with its class: " + diff);
068            }
069          }
070        }
071    
072        //
073        super.addParameter(parameter);
074      }
075    
076      @Override
077      public ObjectCommandInvoker<T, ?> getInvoker(final InvocationMatch<Instance<T>> match) {
078    
079        if (Runnable.class.isAssignableFrom(type)) {
080          return new ObjectCommandInvoker<T, Void>(match) {
081            @Override
082            public Class<Void> getReturnType() {
083              return Void.class;
084            }
085            @Override
086            public Type getGenericReturnType() {
087              return Void.class;
088            }
089            @Override
090            public Class<?>[] getParameterTypes() {
091              return new Class<?>[0];
092            }
093            @Override
094            public Type[] getGenericParameterTypes() {
095              return new Type[0];
096            }
097            public Void invoke(Instance<T> commandInstance) throws InvocationException, SyntaxException {
098              T command;
099              try {
100                command = commandInstance.get();
101              }
102              catch (Exception e) {
103                throw new InvocationException(e);
104              }
105              MethodDescriptor.bind(match, getParameters(), command, Util.EMPTY_ARGS);
106              Runnable runnable = Runnable.class.cast(command);
107              try {
108                runnable.run();
109              }
110              catch (Exception e) {
111                throw new InvocationException(e);
112              }
113              return null;
114            }
115          };
116        } else {
117          return null;
118        }
119      }
120    
121      @Override
122      public CommandDescriptor<Instance<T>> getOwner() {
123        return null;
124      }
125    
126      @Override
127      public Map<String, ? extends MethodDescriptor<T>> getSubordinates() {
128        return methods;
129      }
130    
131    }