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    /*
021     * Copyright (C) 2012 eXo Platform SAS.
022     *
023     * This is free software; you can redistribute it and/or modify it
024     * under the terms of the GNU Lesser General Public License as
025     * published by the Free Software Foundation; either version 2.1 of
026     * the License, or (at your option) any later version.
027     *
028     * This software is distributed in the hope that it will be useful,
029     * but WITHOUT ANY WARRANTY; without even the implied warranty of
030     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
031     * Lesser General Public License for more details.
032     *
033     * You should have received a copy of the GNU Lesser General Public
034     * License along with this software; if not, write to the Free
035     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
036     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
037     */
038    
039    /*
040     * Copyright (C) 2012 eXo Platform SAS.
041     *
042     * This is free software; you can redistribute it and/or modify it
043     * under the terms of the GNU Lesser General Public License as
044     * published by the Free Software Foundation; either version 2.1 of
045     * the License, or (at your option) any later version.
046     *
047     * This software is distributed in the hope that it will be useful,
048     * but WITHOUT ANY WARRANTY; without even the implied warranty of
049     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
050     * Lesser General Public License for more details.
051     *
052     * You should have received a copy of the GNU Lesser General Public
053     * License along with this software; if not, write to the Free
054     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
055     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
056     */
057    
058    /*
059     * Copyright (C) 2012 eXo Platform SAS.
060     *
061     * This is free software; you can redistribute it and/or modify it
062     * under the terms of the GNU Lesser General Public License as
063     * published by the Free Software Foundation; either version 2.1 of
064     * the License, or (at your option) any later version.
065     *
066     * This software is distributed in the hope that it will be useful,
067     * but WITHOUT ANY WARRANTY; without even the implied warranty of
068     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
069     * Lesser General Public License for more details.
070     *
071     * You should have received a copy of the GNU Lesser General Public
072     * License along with this software; if not, write to the Free
073     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
074     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
075     */
076    
077    package org.crsh.cli.impl.descriptor;
078    
079    import org.crsh.cli.SyntaxException;
080    import org.crsh.cli.descriptor.CommandDescriptor;
081    import org.crsh.cli.descriptor.Description;
082    import org.crsh.cli.descriptor.OptionDescriptor;
083    import org.crsh.cli.descriptor.ParameterDescriptor;
084    import org.crsh.cli.impl.ParameterType;
085    import org.crsh.cli.impl.invocation.CommandInvoker;
086    import org.crsh.cli.impl.invocation.InvocationException;
087    import org.crsh.cli.impl.invocation.InvocationMatch;
088    import org.crsh.cli.impl.invocation.ParameterMatch;
089    import org.crsh.cli.impl.invocation.Resolver;
090    import org.crsh.cli.type.ValueTypeFactory;
091    
092    import java.io.IOException;
093    import java.lang.reflect.Type;
094    import java.util.Arrays;
095    import java.util.LinkedHashMap;
096    import java.util.Map;
097    
098    /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
099    public class HelpDescriptor<T> extends CommandDescriptorImpl<T> {
100    
101      public static <T> HelpDescriptor<T> create(CommandDescriptorImpl<T> descriptor) {
102        return new HelpDescriptor<T>(descriptor);
103      }
104    
105      /** . */
106      static final OptionDescriptor HELP_OPTION = new OptionDescriptor(
107          null,
108          ParameterType.create(ValueTypeFactory.DEFAULT, Boolean.class),
109          Arrays.asList("h", "help"),
110          new Description("this help", "Display this help message"),
111          false,
112          false,
113          false,
114          null,
115          null
116      );
117    
118      /** . */
119      private final HelpDescriptor<T> owner;
120    
121      /** . */
122      private final CommandDescriptorImpl<T> delegate;
123    
124      /** . */
125      private final LinkedHashMap<String, HelpDescriptor<T>> subordinates;
126    
127      public HelpDescriptor(CommandDescriptorImpl<T> delegate) throws IntrospectionException {
128        this(null, delegate);
129      }
130    
131      private HelpDescriptor(HelpDescriptor<T> owner, CommandDescriptorImpl<T> delegate) throws IntrospectionException {
132        super(delegate.getName(), delegate.getDescription());
133    
134        //
135        for (ParameterDescriptor parameter : delegate.getParameters()) {
136          addParameter(parameter);
137        }
138    
139        // Override the help parameter only for the root level
140        // otherwise it may be repeated several times
141        if (owner == null) {
142          addParameter(HELP_OPTION);
143        }
144    
145        // Wrap subordinates
146        LinkedHashMap<String, HelpDescriptor<T>> subordinates = new LinkedHashMap<String, HelpDescriptor<T>>();
147        for (CommandDescriptorImpl<T> subordinate : delegate.getSubordinates().values()) {
148          subordinates.put(subordinate.getName(), new HelpDescriptor<T>(this, subordinate));
149        }
150    
151        //
152        this.owner = owner;
153        this.delegate = delegate;
154        this.subordinates = subordinates;
155      }
156    
157      public CommandDescriptor<T> getDelegate() {
158        return delegate;
159      }
160    
161      @Override
162      public CommandInvoker<T> getInvoker(final InvocationMatch<T> match) {
163        final CommandInvoker<T> invoker = delegate.getInvoker(match);
164        return new CommandInvoker<T>() {
165          @Override
166          public Class<?> getReturnType() {
167            return invoker != null ? invoker.getReturnType() : Void.class;
168          }
169    
170          @Override
171          public Type getGenericReturnType() {
172            return invoker != null ? invoker.getGenericReturnType() : Void.class;
173          }
174    
175          @Override
176          public Class<?>[] getParameterTypes() {
177            return invoker != null ? invoker.getParameterTypes() : new Class[0];
178          }
179    
180          @Override
181          public Type[] getGenericParameterTypes() {
182            return invoker != null ? invoker.getGenericParameterTypes() : new Type[0];
183          }
184    
185          @Override
186          public Object invoke(Resolver resolver, T command) throws InvocationException, SyntaxException {
187    
188            // Get the option from the top match
189            ParameterMatch<OptionDescriptor> help = null;
190            for (InvocationMatch<T> current = match;current != null && help == null;current = current.owner()) {
191              help = current.getParameter(HELP_OPTION);
192            }
193    
194            //
195            if (help == null && invoker != null) {
196              return invoker.invoke(resolver, command);
197            } else {
198              return new Help<T>(delegate);
199            }
200          }
201        };
202      }
203    
204      @Override
205      public Class<T> getType() {
206        return delegate.getType();
207      }
208    
209      @Override
210      public CommandDescriptor<T> getOwner() {
211        return owner;
212      }
213    
214      @Override
215      public Map<String, ? extends HelpDescriptor<T>> getSubordinates() {
216        return subordinates;
217      }
218    
219      @Override
220      public HelpDescriptor<T> getSubordinate(String name) {
221        return subordinates.get(name);
222      }
223    }