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