Search in sources :

Example 1 with CommandMarker

use of org.springframework.roo.shell.CommandMarker 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 CommandMarker

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

the class HelpServiceImpl method helpReferenceGuide.

/**
 * {@inheritDoc}
 *
 * TODO: Refactor this method to use the Freemarker template engine. See {@link #obtainHelp(String)}.
 */
public void helpReferenceGuide() {
    synchronized (mutex) {
        // 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.");
        }
        final File f = new File(".");
        final File[] existing = f.listFiles(new FileFilter() {

            public boolean accept(final File pathname) {
                return pathname.getName().startsWith("appendix_");
            }
        });
        for (final File e : existing) {
            e.delete();
        }
        // Compute the sections we'll be outputting, and get them into a
        // nice order
        final SortedMap<String, Object> sections = new TreeMap<String, Object>(COMPARATOR);
        next_target: for (final Object target : commands) {
            final Method[] methods = target.getClass().getMethods();
            for (final Method m : methods) {
                final CliCommand cmd = m.getAnnotation(CliCommand.class);
                if (cmd != null) {
                    String sectionName = target.getClass().getSimpleName();
                    final Pattern p = Pattern.compile("[A-Z][^A-Z]*");
                    final Matcher matcher = p.matcher(sectionName);
                    final StringBuilder string = new StringBuilder();
                    while (matcher.find()) {
                        string.append(matcher.group()).append(" ");
                    }
                    sectionName = string.toString().trim();
                    if (sections.containsKey(sectionName)) {
                        throw new IllegalStateException("Section name '" + sectionName + "' not unique");
                    }
                    sections.put(sectionName, target);
                    continue next_target;
                }
            }
        }
        // Build each section of the appendix
        final DocumentBuilder builder = XmlUtils.getDocumentBuilder();
        final Document document = builder.newDocument();
        final List<Element> builtSections = new ArrayList<Element>();
        for (final Entry<String, Object> entry : sections.entrySet()) {
            final String section = entry.getKey();
            final Object target = entry.getValue();
            final SortedMap<String, Element> individualCommands = new TreeMap<String, Element>(COMPARATOR);
            final Method[] methods = target.getClass().getMethods();
            for (final Method m : methods) {
                final CliCommand cmd = m.getAnnotation(CliCommand.class);
                if (cmd != null) {
                    final StringBuilder cmdSyntax = new StringBuilder();
                    cmdSyntax.append(cmd.value()[0]);
                    // Build the syntax list
                    // Store the order options appear
                    final List<String> optionKeys = new ArrayList<String>();
                    // key: option key, value: help text
                    final Map<String, String> optionDetails = new HashMap<String, String>();
                    for (final Annotation[] ann : m.getParameterAnnotations()) {
                        for (final Annotation a : ann) {
                            if (a instanceof CliOption) {
                                final CliOption option = (CliOption) a;
                                // Figure out which key we want to use (use
                                // first non-empty string, or make it
                                // "(default)" if needed)
                                String key = option.key()[0];
                                if ("".equals(key)) {
                                    for (final String otherKey : option.key()) {
                                        if (!"".equals(otherKey)) {
                                            key = otherKey;
                                            break;
                                        }
                                    }
                                    if ("".equals(key)) {
                                        key = "[default]";
                                    }
                                }
                                final StringBuilder help = new StringBuilder();
                                if ("".equals(option.help())) {
                                    help.append("No help available");
                                } else {
                                    help.append(option.help());
                                }
                                if (option.specifiedDefaultValue().equals(option.unspecifiedDefaultValue())) {
                                    if (option.specifiedDefaultValue().equals(null)) {
                                        help.append("; no default value");
                                    } else {
                                        help.append("; default: '").append(option.specifiedDefaultValue()).append("'");
                                    }
                                } else {
                                    if (!"".equals(option.specifiedDefaultValue()) && !NULL.equals(option.specifiedDefaultValue())) {
                                        help.append("; default if option present: '").append(option.specifiedDefaultValue()).append("'");
                                    }
                                    if (!"".equals(option.unspecifiedDefaultValue()) && !NULL.equals(option.unspecifiedDefaultValue())) {
                                        help.append("; default if option not present: '").append(option.unspecifiedDefaultValue()).append("'");
                                    }
                                }
                                help.append(option.mandatory() ? " " : "");
                                // Store details for later
                                key = "--" + key;
                                optionKeys.add(key);
                                optionDetails.put(key, help.toString());
                                // Include it in the mandatory syntax
                                if (option.mandatory()) {
                                    cmdSyntax.append(" ").append(key);
                                }
                            }
                        }
                    }
                    // Make a variable list element
                    Element variableListElement = document.createElement("variablelist");
                    boolean anyVars = false;
                    for (final String optionKey : optionKeys) {
                        anyVars = true;
                        final String help = optionDetails.get(optionKey);
                        variableListElement.appendChild(new XmlElementBuilder("varlistentry", document).addChild(new XmlElementBuilder("term", document).setText(optionKey).build()).addChild(new XmlElementBuilder("listitem", document).addChild(new XmlElementBuilder("para", document).setText(help).build()).build()).build());
                    }
                    if (!anyVars) {
                        variableListElement = new XmlElementBuilder("para", document).setText("This command does not accept any options.").build();
                    }
                    // Now we've figured out the options, store this
                    // individual command
                    final CDATASection progList = document.createCDATASection(cmdSyntax.toString());
                    final String safeName = cmd.value()[0].replace("\\", "BCK").replace("/", "FWD").replace("*", "ASX");
                    final Element element = new XmlElementBuilder("section", document).addAttribute("xml:id", "command-index-" + safeName.toLowerCase().replace(' ', '-')).addChild(new XmlElementBuilder("title", document).setText(cmd.value()[0]).build()).addChild(new XmlElementBuilder("para", document).setText(cmd.help()).build()).addChild(new XmlElementBuilder("programlisting", document).addChild(progList).build()).addChild(variableListElement).build();
                    individualCommands.put(cmdSyntax.toString(), element);
                }
            }
            final Element topSection = document.createElement("section");
            topSection.setAttribute("xml:id", "command-index-" + section.toLowerCase().replace(' ', '-'));
            topSection.appendChild(new XmlElementBuilder("title", document).setText(section).build());
            topSection.appendChild(new XmlElementBuilder("para", document).setText(section + " are contained in " + target.getClass().getName() + ".").build());
            for (final Element value : individualCommands.values()) {
                topSection.appendChild(value);
            }
            builtSections.add(topSection);
        }
        final Element appendix = document.createElement("appendix");
        appendix.setAttribute("xmlns", "http://docbook.org/ns/docbook");
        appendix.setAttribute("version", "5.0");
        appendix.setAttribute("xml:id", "command-index");
        appendix.appendChild(new XmlElementBuilder("title", document).setText("Command Index").build());
        appendix.appendChild(new XmlElementBuilder("para", document).setText("This appendix was automatically built from Roo " + AbstractShell.versionInfo() + ".").build());
        appendix.appendChild(new XmlElementBuilder("para", document).setText("Commands are listed in alphabetic order, and are shown in monospaced font with any mandatory options you must specify when using the command. Most commands accept a large number of options, and all of the possible options for each command are presented in this appendix.").build());
        for (final Element section : builtSections) {
            appendix.appendChild(section);
        }
        document.appendChild(appendix);
        final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        final Transformer transformer = XmlUtils.createIndentingTransformer();
        // Causes an
        // "Error reported by XML parser: Multiple notations were used which had the name 'linespecific', but which were not determined to be duplicates."
        // when creating the DocBook
        // transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
        // "-//OASIS//DTD DocBook XML V4.5//EN");
        // transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
        // "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd");
        XmlUtils.writeXml(transformer, byteArrayOutputStream, document);
        try {
            final File output = new File(f, "appendix-command-index.xml");
            FileUtils.writeByteArrayToFile(output, byteArrayOutputStream.toByteArray());
        } catch (final IOException ioe) {
            throw new IllegalStateException(ioe);
        } finally {
            IOUtils.closeQuietly(byteArrayOutputStream);
        }
    }
}
Also used : CommandMarker(org.springframework.roo.shell.CommandMarker) Transformer(javax.xml.transform.Transformer) Matcher(java.util.regex.Matcher) HashMap(java.util.HashMap) Element(org.w3c.dom.Element) ArrayList(java.util.ArrayList) Document(org.w3c.dom.Document) CliOption(org.springframework.roo.shell.CliOption) CDATASection(org.w3c.dom.CDATASection) InvalidSyntaxException(org.osgi.framework.InvalidSyntaxException) FileFilter(java.io.FileFilter) Pattern(java.util.regex.Pattern) Method(java.lang.reflect.Method) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) TreeMap(java.util.TreeMap) XmlElementBuilder(org.springframework.roo.support.util.XmlElementBuilder) Annotation(java.lang.annotation.Annotation) ServiceReference(org.osgi.framework.ServiceReference) DocumentBuilder(javax.xml.parsers.DocumentBuilder) CliCommand(org.springframework.roo.shell.CliCommand) File(java.io.File)

Aggregations

IOException (java.io.IOException)2 Method (java.lang.reflect.Method)2 InvalidSyntaxException (org.osgi.framework.InvalidSyntaxException)2 ServiceReference (org.osgi.framework.ServiceReference)2 CliCommand (org.springframework.roo.shell.CliCommand)2 CommandMarker (org.springframework.roo.shell.CommandMarker)2 TemplateException (freemarker.template.TemplateException)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 File (java.io.File)1 FileFilter (java.io.FileFilter)1 Annotation (java.lang.annotation.Annotation)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 TreeMap (java.util.TreeMap)1 Matcher (java.util.regex.Matcher)1 Pattern (java.util.regex.Pattern)1 DocumentBuilder (javax.xml.parsers.DocumentBuilder)1 Transformer (javax.xml.transform.Transformer)1 CliOption (org.springframework.roo.shell.CliOption)1