All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tomitribe.crest.help.CommandJavadoc Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.tomitribe.crest.help;

import org.tomitribe.util.IO;
import org.tomitribe.util.Join;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CommandJavadoc {
    private final String clazzName;
    private final String commandName;
    private final Properties properties = new Properties();

    public CommandJavadoc(final String clazzName, final String commandName) {
        this.clazzName = clazzName;
        this.commandName = commandName;
    }


    public void setJavadoc(final String javadoc) {
        this.getProperties().put("@javadoc", javadoc);
    }

    public String getJavadoc() {
        return this.getProperties().getProperty("@javadoc");
    }

    public void setArgNames(final List argNames) {
        this.getProperties().put("@arg.names", Join.join(", ", argNames));
    }

    public List getArgNames() {
        final String property = getProperties().getProperty("@arg.names");
        return Arrays.asList(property.split(", "));
    }

    public void setArgTypes(final List argTypes) {

        final List normalized = argTypes.stream()
                .map(s -> s.replaceAll("<[^<>]+>", ""))
                .collect(Collectors.toList());
        this.getProperties().put("@arg.types", Join.join(", ", normalized));
    }

    public boolean matches(final Class[] types) {
        final List list = Stream.of(types)
                .map(this::classSignature)
                .collect(Collectors.toList());
        final String expected = normalize(Join.join(", ", list));
        final String argtypes = normalize(getProperties().getProperty("@arg.types"));
        return expected.equals(argtypes);
    }

    /**
     * The javax.lang.model.element.Element.getSimpleName() method is used to
     * get the class name of each argument type.  This method will use a dot (.)
     * before inner class names.  The string it provides will
     * be in the format of {@code org.example.Outter.Inner}.  This is the way
     * these classes are referred to in source, so it is correct from that
     * perspective.
     *
     * However, java.lang.Class.getName() will use the dollar sign ($) before
     * inner class names.  The string it provides will
     * be in the format of {@code org.example.Outter$Inner}.  This is the way
     * these classes are referred to by classloaders, so it is correct from that
     * perspective.
     *
     * This method just says to heck with it and replaces all $ signs with dots.
     *
     * Though you can legally use a dollar sign in a class name, you will get a
     * duplicate class error by the compiler if you do so in a way that could
     * class with an inner class of the same name.  So this approach should be
     * fairly safe.
     */
    private String normalize(final String signature) {
        return signature.replace("$", ".");
    }

    public String classSignature(final Class aClass) {
        if (aClass.isArray()) {
            return String.format("%s[]", aClass.getComponentType().getName());
        } else {
            return aClass.getName();
        }
    }

    public String getClazzName() {
        return clazzName;
    }

    public String getCommandName() {
        return commandName;
    }

    public Properties getProperties() {
        return properties;
    }

    public String getName() {
        return String.format("%s/%s", clazzName, commandName);
    }

    public String getResourceFileName(final int i) {
        return getResourceFileName(clazzName, commandName, i);
    }

    public static String getResourceFileName(final String clazzName, final String commandName, final int i) {
        return String.format("META-INF/crest/%s/%s.%s.properties", clazzName, commandName, i);
    }

    public static List loadJavadoc(final Class clazz, final String commandName) {
        return loadJavadoc(clazz.getName().replace('$', '.'), commandName);
    }

    public static List loadJavadoc(final String clazzName, final String commandName) {
        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
        final List javadocs = new ArrayList<>();

        for (int i = 0; true; i++) {
            final String resourceFileName = getResourceFileName(clazzName, commandName, i);
            final URL resource = loader.getResource(resourceFileName);
            if (resource == null) break;

            final CommandJavadoc javadoc = new CommandJavadoc(clazzName, commandName);
            try (final InputStream in = IO.read(resource)) {
                javadoc.getProperties().load(in);
                javadocs.add(javadoc);
            } catch (IOException e) {
                throw new InvalidJavadocFileException(resourceFileName, e);
            }
        }

        return javadocs;
    }

    public static CommandJavadoc getCommandJavadocs(final Method method, final String name) {
        final List javadocs = loadJavadoc(method.getDeclaringClass(), name);

        return javadocs.stream()
                .filter(commandJavadoc -> commandJavadoc.matches(method.getParameterTypes()))
                .findFirst().orElse(null);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy