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
077package org.crsh.cli.impl.descriptor;
078
079import org.crsh.cli.SyntaxException;
080import org.crsh.cli.descriptor.CommandDescriptor;
081import org.crsh.cli.descriptor.Description;
082import org.crsh.cli.descriptor.OptionDescriptor;
083import org.crsh.cli.descriptor.ParameterDescriptor;
084import org.crsh.cli.impl.ParameterType;
085import org.crsh.cli.impl.invocation.CommandInvoker;
086import org.crsh.cli.impl.invocation.InvocationException;
087import org.crsh.cli.impl.invocation.InvocationMatch;
088import org.crsh.cli.impl.invocation.ParameterMatch;
089import org.crsh.cli.impl.invocation.Resolver;
090import org.crsh.cli.type.ValueTypeFactory;
091
092import java.lang.reflect.Type;
093import java.util.Arrays;
094import java.util.LinkedHashMap;
095import java.util.Map;
096
097/** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
098public class HelpDescriptor<T> extends CommandDescriptorImpl<T> {
099
100  public static <T> HelpDescriptor<T> create(CommandDescriptorImpl<T> descriptor) {
101    return new HelpDescriptor<T>(descriptor);
102  }
103
104  /** . */
105  static final OptionDescriptor HELP_OPTION = new OptionDescriptor(
106      null,
107      ParameterType.create(ValueTypeFactory.DEFAULT, Boolean.class),
108      Arrays.asList("h", "help"),
109      new Description("this help", "Display this help message"),
110      false,
111      false,
112      false,
113      null,
114      null
115  );
116
117  /** . */
118  private final HelpDescriptor<T> owner;
119
120  /** . */
121  private final CommandDescriptorImpl<T> delegate;
122
123  /** . */
124  private final LinkedHashMap<String, HelpDescriptor<T>> subordinates;
125
126  public HelpDescriptor(CommandDescriptorImpl<T> delegate) throws IntrospectionException {
127    this(null, delegate);
128  }
129
130  private HelpDescriptor(HelpDescriptor<T> owner, CommandDescriptorImpl<T> delegate) throws IntrospectionException {
131    super(delegate.getName(), delegate.getDescription());
132
133    //
134    for (ParameterDescriptor parameter : delegate.getParameters()) {
135      addParameter(parameter);
136    }
137
138    // Override the help parameter only for the root level
139    // otherwise it may be repeated several times
140    if (owner == null) {
141      addParameter(HELP_OPTION);
142    }
143
144    // Wrap subordinates
145    LinkedHashMap<String, HelpDescriptor<T>> subordinates = new LinkedHashMap<String, HelpDescriptor<T>>();
146    for (CommandDescriptorImpl<T> subordinate : delegate.getSubordinates().values()) {
147      subordinates.put(subordinate.getName(), new HelpDescriptor<T>(this, subordinate));
148    }
149
150    //
151    this.owner = owner;
152    this.delegate = delegate;
153    this.subordinates = subordinates;
154  }
155
156  public CommandDescriptor<T> getDelegate() {
157    return delegate;
158  }
159
160  @Override
161  public CommandInvoker<T, ?> getInvoker(final InvocationMatch<T> match) {
162
163    //
164    final CommandInvoker<T, ?> invoker = delegate.getInvoker(match);
165
166    // Get the option from the top match
167    ParameterMatch<OptionDescriptor> helpDesc = null;
168    for (InvocationMatch<T> current = match;current != null && helpDesc == null;current = current.owner()) {
169      helpDesc = current.getParameter(HELP_OPTION);
170    }
171
172    //
173    final boolean help = helpDesc != null || invoker == null;
174
175    //
176    if (help) {
177      return new CommandInvoker<T, Help>() {
178        @Override
179        public InvocationMatch<T> getMatch() {
180          return match;
181        }
182        @Override
183        public Class<Help> getReturnType() {
184          return Help.class;
185        }
186        @Override
187        public Type getGenericReturnType() {
188          return Help.class;
189        }
190        @Override
191        public Class<?>[] getParameterTypes() {
192          return new Class[0];
193        }
194        @Override
195        public Type[] getGenericParameterTypes() {
196          return new Type[0];
197        }
198        @Override
199        public Help invoke(Resolver resolver, T command) throws InvocationException, SyntaxException {
200          return new Help<T>(delegate);
201        }
202      };
203    } else {
204      return invoker;
205    }
206  }
207
208  @Override
209  public Class<T> getType() {
210    return delegate.getType();
211  }
212
213  @Override
214  public CommandDescriptor<T> getOwner() {
215    return owner;
216  }
217
218  @Override
219  public Map<String, ? extends HelpDescriptor<T>> getSubordinates() {
220    return subordinates;
221  }
222
223  @Override
224  public HelpDescriptor<T> getSubordinate(String name) {
225    return subordinates.get(name);
226  }
227}