Search in sources :

Example 1 with MethodTarget

use of org.springframework.roo.shell.MethodTarget in project spring-roo by spring-projects.

the class HelpServiceImpl method locateTargets.

/**
 * Get the methods annotated with {@link CliCommand}
 * inside the {@link CommandMarker} classes, which value attribute matches
 * the given pattern.
 *
 * @param pattern
 * @param strictMatching
 * @param checkAvailabilityIndicators
 * @return the @{@link CliCommand} methods that matches the given pattern
 */
private Collection<MethodTarget> locateTargets(final String pattern, final boolean strictMatching, final boolean checkAvailabilityIndicators) {
    // Get all Services implement CommandMarker interface
    try {
        ServiceReference<?>[] references = this.context.getAllServiceReferences(CommandMarker.class.getName(), null);
        for (ServiceReference<?> ref : references) {
            CommandMarker command = (CommandMarker) this.context.getService(ref);
            if (!commands.contains(command)) {
                add(command);
            }
        }
    } catch (InvalidSyntaxException e) {
        LOGGER.warning("Cannot load CommandMarker on SimpleParser.");
    }
    Validate.notNull(pattern, "Buffer required");
    final Collection<MethodTarget> result = new HashSet<MethodTarget>();
    // is unlikely to be noticeable to a human being using the CLI)
    for (final CommandMarker command : commands) {
        for (final Method method : command.getClass().getMethods()) {
            final CliCommand cmd = method.getAnnotation(CliCommand.class);
            if (cmd != null) {
                // We have a @CliCommand.
                if (checkAvailabilityIndicators) {
                    // Decide if this @CliCommand is available at this
                    // moment
                    Boolean available = null;
                    for (final String value : cmd.value()) {
                        final MethodTarget mt = getAvailabilityIndicator(value);
                        if (mt != null) {
                            Validate.isTrue(available == null, "More than one availability indicator is defined for '" + method.toGenericString() + "'");
                            try {
                                available = (Boolean) mt.getMethod().invoke(mt.getTarget());
                            // We should "break" here, but we loop over
                            // all to ensure no conflicting availability
                            // indicators are defined
                            } catch (final Exception e) {
                                available = false;
                            }
                        }
                    }
                    // Skip this @CliCommand if it's not available
                    if (available != null && !available) {
                        continue;
                    }
                }
                for (final String value : cmd.value()) {
                    final String remainingBuffer = isMatch(pattern, value, strictMatching);
                    if (remainingBuffer != null) {
                        result.add(new MethodTarget(method, command, remainingBuffer, value));
                    }
                }
            }
        }
    }
    return result;
}
Also used : MethodTarget(org.springframework.roo.shell.MethodTarget) CommandMarker(org.springframework.roo.shell.CommandMarker) Method(java.lang.reflect.Method) InvalidSyntaxException(org.osgi.framework.InvalidSyntaxException) TemplateException(freemarker.template.TemplateException) IOException(java.io.IOException) ServiceReference(org.osgi.framework.ServiceReference) InvalidSyntaxException(org.osgi.framework.InvalidSyntaxException) CliCommand(org.springframework.roo.shell.CliCommand) HashSet(java.util.HashSet)

Example 2 with MethodTarget

use of org.springframework.roo.shell.MethodTarget in project spring-roo by spring-projects.

the class HelpServiceImpl method add.

public final void add(final CommandMarker command) {
    synchronized (mutex) {
        commands.add(command);
        for (final Method method : command.getClass().getMethods()) {
            final CliAvailabilityIndicator availability = method.getAnnotation(CliAvailabilityIndicator.class);
            if (availability != null) {
                Validate.isTrue(method.getParameterTypes().length == 0, "CliAvailabilityIndicator is only legal for 0 parameter methods ('%s')", method.toGenericString());
                Validate.isTrue(method.getReturnType().equals(Boolean.TYPE), "CliAvailabilityIndicator is only legal for primitive boolean return types (%s)", method.toGenericString());
                for (final String cmd : availability.value()) {
                    Validate.isTrue(!availabilityIndicators.containsKey(cmd), "Cannot specify an availability indicator for '%s' more than once", cmd);
                    availabilityIndicators.put(cmd, new MethodTarget(method, command));
                }
            }
        }
    }
}
Also used : CliAvailabilityIndicator(org.springframework.roo.shell.CliAvailabilityIndicator) MethodTarget(org.springframework.roo.shell.MethodTarget) Method(java.lang.reflect.Method)

Example 3 with MethodTarget

use of org.springframework.roo.shell.MethodTarget in project spring-roo by spring-projects.

the class HelpServiceImpl method obtainHelp.

/**
 * If the given pattern matches several commands, i.e. "web mvc"
 * or empty, this method writes to {@link #LOGGER} the list of
 * commands (command index) which names start with the given pattern.
 *
 * If the given pattern matches with only one command, this method
 * writes to {@link #LOGGER} the full info about that command.
 *
 * @param pattern
 */
public void obtainHelp(String pattern) {
    synchronized (mutex) {
        if (pattern == null) {
            pattern = "";
        }
        Template helpTemplate;
        // Create the data-model for Freemarker engine.
        Map<String, Object> fmContext = new HashMap<String, Object>();
        fmContext.put("LINE_SEPARATOR", IOUtils.LINE_SEPARATOR);
        fmContext.put("CMD_MAX_LENGTH", CMD_MAX_LENGTH);
        fmContext.put("OPT_MAX_LENGTH", OPT_MAX_LENGTH);
        // Get the methods annotated with @CliCommand that matches the pattern
        final Collection<MethodTarget> matchingTargets = locateTargets(pattern, false, false);
        try {
            // In that case the full command help will be rendered.
            if (matchingTargets.size() == 1) {
                helpTemplate = new Template("cmdTemplate", new StringReader(cmdTemplateStr), new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS));
                // Single command help
                final MethodTarget methodTarget = matchingTargets.iterator().next();
                // Argument conversion time
                final Annotation[][] parameterAnnotations = methodTarget.getMethod().getParameterAnnotations();
                // Offer specified help
                final CliCommand cmd = methodTarget.getMethod().getAnnotation(CliCommand.class);
                Validate.notNull(cmd, "CliCommand not found");
                // The command has options, those method arguments annotated with @CliOption
                if (parameterAnnotations.length > 0) {
                    // Synopsis
                    fmContext.put("synopsis", justify(cmd.value(), CMD_HELP_LEFT_PAD, LINE_MAX_LENGTH));
                    // Description
                    fmContext.put("description", justify(cmd.help(), CMD_HELP_LEFT_PAD, LINE_MAX_LENGTH));
                    // Options
                    Map<String, List<String>> options = new TreeMap<String, List<String>>();
                    fmContext.put("options", options);
                    // method arguments annotated with the @CliOption annotation
                    for (final Annotation[] annotations : parameterAnnotations) {
                        CliOption cliOption = null;
                        for (final Annotation a : annotations) {
                            if (a instanceof CliOption) {
                                cliOption = (CliOption) a;
                                for (final String option : cliOption.key()) {
                                    String dashOption = "--".concat(option);
                                    // Note justification should be done in the Freemarker template,
                                    // but it is easier to do it here and adjust both justifications
                                    // (cmd name and cmd help) depending on the cmd name length
                                    String optStr = StringUtils.repeat(" ", CMD_HELP_LEFT_PAD) + (dashOption.length() <= OPT_MAX_LENGTH ? StringUtils.rightPad(dashOption, OPT_MAX_LENGTH) : dashOption);
                                    // Add as left padding the cmd length to avoid overwrite the command on the left
                                    // +1 to add an empty char (space) between the command and the description
                                    options.put(optStr, justify(cliOption.help(), CMD_HELP_LEFT_PAD + OPT_MAX_LENGTH, LINE_MAX_LENGTH));
                                }
                            }
                        }
                    }
                } else // The command hasn't options, usually methods without arguments
                {
                    // Synopsis
                    fmContext.put("synopsis", justify(cmd.value(), CMD_HELP_LEFT_PAD, LINE_MAX_LENGTH));
                    // Description
                    fmContext.put("description", justify(cmd.help(), CMD_HELP_LEFT_PAD, LINE_MAX_LENGTH));
                }
            } else // There are several commands that matches the pattern. Example: "web mvc"
            // In that case only a list of command names and descriptions will be rendered.
            {
                helpTemplate = new Template("cmdIndexTemplate", new StringReader(cmdIndexTemplateStr), new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS));
                // Create the list of commands that start with the given token.
                // Note that empty token will cause all commands will be rendered.
                Map<String, List<String>> cmdList = new TreeMap<String, List<String>>();
                // method annotation @CliCommand
                for (final MethodTarget mt : matchingTargets) {
                    final CliCommand cmd = mt.getMethod().getAnnotation(CliCommand.class);
                    if (cmd != null) {
                        for (final String value : cmd.value()) {
                            // Note justification should be done in the Freemarker template,
                            // but it is easier to do it here and adjust both justifications
                            // (cmd name and cmd help) depending on the cmd name length
                            String cmdStr = StringUtils.repeat(" ", CMD_INDEX_LEFT_PAD) + (value.length() <= CMD_MAX_LENGTH ? StringUtils.rightPad(value, CMD_MAX_LENGTH) : value);
                            // Add as left padding the cmd length to avoid overwrite the command on the left
                            // +1 to add an empty char (space) between the command and the description
                            cmdList.put(cmdStr, justify(cmd.help(), CMD_INDEX_LEFT_PAD + CMD_MAX_LENGTH, LINE_MAX_LENGTH));
                        }
                    }
                }
                // Add the command list to the Freemarker context
                fmContext.put("commands", cmdList);
            }
            // Merge data-model with template
            Writer strWriter = new StringWriter();
            helpTemplate.process(fmContext, strWriter);
            LOGGER.info(strWriter.toString());
        } catch (TemplateException e) {
            LOGGER.log(Level.SEVERE, "Help engine internal error!", e);
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "Help engine internal error!", e);
        }
        LOGGER.warning("** Type 'hint' (without the quotes) and hit ENTER " + "for step-by-step guidance **" + LINE_SEPARATOR);
    }
}
Also used : MethodTarget(org.springframework.roo.shell.MethodTarget) Configuration(freemarker.template.Configuration) HashMap(java.util.HashMap) TemplateException(freemarker.template.TemplateException) IOException(java.io.IOException) TreeMap(java.util.TreeMap) Annotation(java.lang.annotation.Annotation) Template(freemarker.template.Template) CliOption(org.springframework.roo.shell.CliOption) StringWriter(java.io.StringWriter) StringReader(java.io.StringReader) CliCommand(org.springframework.roo.shell.CliCommand) List(java.util.List) ArrayList(java.util.ArrayList) Writer(java.io.Writer) StringWriter(java.io.StringWriter)

Aggregations

MethodTarget (org.springframework.roo.shell.MethodTarget)3 TemplateException (freemarker.template.TemplateException)2 IOException (java.io.IOException)2 Method (java.lang.reflect.Method)2 CliCommand (org.springframework.roo.shell.CliCommand)2 Configuration (freemarker.template.Configuration)1 Template (freemarker.template.Template)1 StringReader (java.io.StringReader)1 StringWriter (java.io.StringWriter)1 Writer (java.io.Writer)1 Annotation (java.lang.annotation.Annotation)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 List (java.util.List)1 TreeMap (java.util.TreeMap)1 InvalidSyntaxException (org.osgi.framework.InvalidSyntaxException)1 ServiceReference (org.osgi.framework.ServiceReference)1 CliAvailabilityIndicator (org.springframework.roo.shell.CliAvailabilityIndicator)1 CliOption (org.springframework.roo.shell.CliOption)1