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