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

org.glassfish.admin.amx.util.jmx.MBeanInterfaceGenerator Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
//Portions Copyright [2018-2019] [Payara Foundationa and/or affiliates]

package org.glassfish.admin.amx.util.jmx;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.Descriptor;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import org.glassfish.admin.amx.util.ClassUtil;
import org.glassfish.admin.amx.util.jmx.stringifier.MBeanNotificationInfoStringifier;
import org.glassfish.admin.amx.util.stringifier.SmartStringifier;

/**
Generate an MBean ".java" file.
 */
public class MBeanInterfaceGenerator
{
    boolean mEmitComments;

    Map mCounts;

    public MBeanInterfaceGenerator() {
        mCounts = null;
        mEmitComments = true;
    }

    private static final String INDENT = "    ";

    private static final String NEWLINE = "\n";

    private static final String PARAM_DELIM = ", ";

    public static final String FINAL_PREFIX = "final ";

    public static final int IMPORT_THRESHOLD = 1;

    private static final String BRACKETS = "[]";

    static String stripBrackets(String name)
    {
        String result = name;

        while (result.endsWith(BRACKETS))
        {
            result = result.substring(0, result.length() - BRACKETS.length());
        }

        return (result);
    }

    private static void countType(Map counts, String typeIn) {
        final String type = stripBrackets(ClassUtil.getFriendlyClassname(typeIn));

        Integer count = counts.get(type);
        if (count == null) {
            count = 1;
        } else {
            count++;
        }

        counts.put(type, count);
    }

    /**
    Count how many times an Attribute type is used.
     */
    public static void countTypes(Map counts, MBeanAttributeInfo[] infos)
    {
        for (int i = 0; i < infos.length; ++i)
        {
            countType(counts, infos[i].getType());
        }
    }

    /**
    Count how many times the return type and parameter types are used.
     */
    private static void countTypes(Map counts, MBeanOperationInfo[] infos)
    {
        for (int i = 0; i < infos.length; ++i)
        {
            countType(counts, infos[i].getReturnType());

            final MBeanParameterInfo[] params = infos[i].getSignature();
            for (int p = 0; p < params.length; ++p)
            {
                countType(counts, params[p].getType());
            }
        }
    }

    String getCodeClassname(final String classnameIn) {
        final String name = ClassUtil.getFriendlyClassname(classnameIn);

        String base = name;
        String extra = "";

        final int idx = name.indexOf('[');
        if (idx > 0) {
            base = name.substring(0, idx);
            extra = name.substring(idx);
        }

        if (typeMayBeAbbreviated(base)) {
            base = ClassUtil.stripPackagePrefix(base);
        }

        return base + extra;
    }

    private Map countAllTypes(MBeanInfo info)
    {
        final Map counts = new HashMap();
        final MBeanAttributeInfo[] attrInfos = info.getAttributes();
        final MBeanOperationInfo[] operationInfos = info.getOperations();
        if (attrInfos != null)
        {
            countTypes(counts, attrInfos);
        }
        if (operationInfos != null)
        {
            countTypes(counts, operationInfos);
        }

        return (counts);
    }

    private String getImportBlock(Map counts)
    {
        final StringBuilder buf = new StringBuilder();

        for (final Map.Entry me : counts.entrySet())
        {
            final String key = me.getKey();
            final Integer count = me.getValue();

            // if used twice or more, generate an import statement
            if (count >= IMPORT_THRESHOLD && !isUnqualifiedType(key))
            {
                buf.append("import ").append(key).append(";" + NEWLINE);
            }
        }

        return (buf.toString());
    }

    protected boolean isUnqualifiedType(String type)
    {
        return (type.indexOf('.') < 0);
    }

    /**
    type must be the "friendly" name.
     */
    protected boolean typeMayBeAbbreviated(String type)
    {
        final Integer count = mCounts.get(type);
        if (count == null)
        {
            return (false);
        }

        return (count >= IMPORT_THRESHOLD);
    }

    public String generate(final MBeanInfo info, boolean emitComments)
    {
        mEmitComments = emitComments;

        final StringBuilder buf = new StringBuilder();

        if (mEmitComments)
        {
            buf.append(getHeaderComment(info)).append(NEWLINE + NEWLINE);
        }

        buf.append("package ").append(getPackageName(info)).append(";" + NEWLINE);

        mCounts = countAllTypes(info);
        buf.append(NEWLINE).append(getImportBlock(mCounts)).append(NEWLINE);

        if (mEmitComments)
        {
            buf.append(getInterfaceComment(info)).append(NEWLINE);
        }
        String interfaceName = getClassname(info);
        buf.append("public interface ").append(interfaceName).append(" \n{\n");

        final MBeanAttributeInfo[] attrInfos = info.getAttributes();
        final MBeanOperationInfo[] operationInfos = info.getOperations();
        if (attrInfos != null) {
            Arrays.sort(attrInfos, MBeanAttributeInfoComparator.INSTANCE);

            final List readOnlyAttrInfos = new ArrayList();
            final List writebleAttrInfos = new ArrayList();
            for (final MBeanAttributeInfo ai : attrInfos) {
                if (ai.isWritable()) {
                    writebleAttrInfos.add(ai);
                } else {
                    readOnlyAttrInfos.add(ai);
                }
            }

            buf.append(generateAttributes(readOnlyAttrInfos));
            buf.append(generateAttributes(writebleAttrInfos));
        }
        if (operationInfos != null && operationInfos.length != 0) {
                Arrays.sort(operationInfos, MBeanOperationInfoComparator.INSTANCE);

                buf.append(NEWLINE + "// -------------------- Operations --------------------" + NEWLINE);
                buf.append(generateOperations(operationInfos));
        }


        buf.append("\n}");

        return (buf.toString());
    }

    protected String indent(String contents, String prefix)
    {
        final StringBuilder buf = new StringBuilder();
        if (contents.length() != 0)
        {
            final String[] lines = contents.split(NEWLINE);

            for (int i = 0; i < lines.length; ++i)
            {
                buf.append(prefix).append(lines[i]).append(NEWLINE);
            }

            if (buf.length() != 0)
            {
                buf.setLength(buf.length() - 1);
            }
        }

        return (buf.toString());
    }

    protected String indent(String contents)
    {
        return (indent(contents, INDENT));
    }

    protected String makeJavadocComment(String contents)
    {
        if (contents == null || contents.length() == 0)
        {
            return "";
        }
        return ("/**" + NEWLINE + indent(contents) + NEWLINE + "*/");
    }

    private String padRight(final String s, final int fieldWidth)
    {
        final StringBuilder buf = new StringBuilder();
        buf.append(s);
        buf.append(" ");
        for( int i = 0; i < fieldWidth - s.length(); ++i )
        {
            buf.append(" ");
        }

        return buf.toString();
    }

    protected String formMethod(String returnType, String name, String[] params, String[] names)
    {
        final String begin = "public " + padRight( getCodeClassname(returnType), 16) + " " + name + "(";
        String paramsString = "";
        if (params != null && params.length != 0)
        {
            final StringBuilder buf = new StringBuilder();

            buf.append(" ");
            for (int i = 0; i < params.length; ++i) {
                buf.append(getCodeClassname(params[i]));
                buf.append(" ").append(names[i]);
                buf.append(PARAM_DELIM);
            }

            buf.setLength(buf.length() - PARAM_DELIM.length());	// strip last ","
            buf.append(" ");
            paramsString = buf.toString();
        }


        return (begin + paramsString + ");");
    }

    /**
    Return a comment regarding the Attribute name if it was mapped to a different
    Java name.
     */
    protected String getAttributeNameComment(String attributeName, String javaName)
    {
        String comment = "";

        if (!attributeName.equals(javaName))
        {
            comment = attributeName + " => " + javaName;
        }
        return comment;
    }

    protected String attributeNameToJavaName(final String attrName)
    {
        return attrName;
    }

    protected String generateAttributes( final List infos)
    {
        final StringBuilder buf = new StringBuilder();

        final String[] typeTemp = new String[1];
        final String[] nameTemp = new String[1];

        final MBeanAttributeInfo[] infosArray = new MBeanAttributeInfo[infos.size()];
        infos.toArray( infosArray );

        for ( final MBeanAttributeInfo info: infos )
        {
            final String attributeName = info.getName();
            final String type = info.getType();
            String comment = "";

            final String javaName = attributeNameToJavaName(attributeName);

            if ( info.isReadable() && info.isWritable() )
            {
                buf.append( NEWLINE  ); // extra blank line before read/write attribute
            }

            if (info.isReadable())
            {
                if (mEmitComments)
                {
                    comment = getGetterComment(info, javaName);
                    if (comment.length() != 0)
                    {
                        buf.append(indent(comment)).append(NEWLINE);
                    }
                }
                buf.append(indent(formMethod(type, "get" + javaName, null, null)));
				buf.append( NEWLINE );
            }

            if (info.isWritable())
            {
                if (mEmitComments)
                {
                    comment = getSetterComment(info, javaName);
                    if (comment.length() != 0)
                    {
                        buf.append(indent(comment)).append(NEWLINE);
                    }
                }

                typeTemp[0] = type;
                nameTemp[0] = "value";

                buf.append(indent(formMethod("void", "set" + javaName, typeTemp, nameTemp)));
                buf.append( NEWLINE  );
            }
        }

        return (buf.toString());
    }

    protected String generateOperations(MBeanOperationInfo[] infos)
    {
        final StringBuilder buf = new StringBuilder();

        for (int i = 0; i < infos.length; ++i)
        {
            final MBeanOperationInfo info = infos[i];
            final String name = info.getName();
            final String returnType = info.getReturnType();
            final MBeanParameterInfo[] paramInfos = info.getSignature();

            final String[] paramTypes = new String[paramInfos.length];
            for (int p = 0; p < paramInfos.length; ++p)
            {
                paramTypes[p] = paramInfos[p].getType();
            }

            final String[] paramNames = getParamNames(info);

            if (mEmitComments)
            {
                final String comment = getOperationComment(info, paramNames);
                if (comment.length() != 0)
                {
                    buf.append(NEWLINE).append(indent(comment)).append(NEWLINE);
                }
            }

            final String method = formMethod(returnType, name, paramTypes, paramNames);
            buf.append(indent(method)).append(NEWLINE);
        }

        return (buf.toString());
    }

    protected boolean isBoilerplateDescription(final String description)
    {
        if (description == null)
        {
            return true;
        }

        final String trimmed = description.trim();
        return trimmed.length() == 0 ||
                trimmed.contains("Attribute exposed for management") ||
                trimmed.contains("Operation exposed for management") ||
                trimmed.contains("No Description was available") ||
               trimmed.equals("n/a");
    }

    public String[] getParamNames(MBeanOperationInfo info)
    {
        final MBeanParameterInfo[] params = info.getSignature();

        final String[] names = new String[params.length];

        for (int i = 0; i < params.length; ++i)
        {
            names[i] = params[i].getName();
        }

        return (names);
    }

    public String getGetterComment(MBeanAttributeInfo info, String actualName)
    {
        String description = info.getDescription();
        if (isBoilerplateDescription(description))
        {
            description = "";
        }

        final String nameComment = getAttributeNameComment(info.getName(), actualName);

        String result = description;
        if ( description.length() != 0 )
        {
            result = result + NEWLINE;
        }
        result = result + toString(info.getDescriptor());

        if (nameComment.length() != 0)
        {
            result = result + nameComment;
        }

        result = makeJavadocComment(result);

        return (result);
    }

    public String getSetterComment(MBeanAttributeInfo info, String actualName)
    {
        return "";
    }

    private static String nvp(final String name, final Object value)
    {
        return name + " = " + SmartStringifier.DEFAULT.stringify(value);
    }

    public static String toString(final Descriptor d)
    {
        final String NL = NEWLINE;
        final StringBuilder buf = new StringBuilder();
        if (d != null && d.getFieldNames().length != 0) {
            for (final String fieldName : d.getFieldNames())
            {
                buf.append(nvp(fieldName, d.getFieldValue(fieldName))).append(NL);
            }
        }

        return buf.toString();
    }

    public String getOperationComment(MBeanOperationInfo info, final String[] paramNames)
    {
        final String description = info.getDescription();

        final StringBuilder buf = new StringBuilder();

        if (description != null && description.length() != 0 )
        {
            buf.append(description).append(NEWLINE);
        }

        final Descriptor desc = info.getDescriptor();
        buf.append(toString(desc));

        final MBeanParameterInfo[] signature = info.getSignature();
        for (int i = 0; i < paramNames.length; ++i)
        {
            final String paramDescription = signature[i].getDescription();

            buf.append("@param ").append(paramNames[i]).append(" ").append(paramDescription).append(NEWLINE);
        }

        final String returnType = getCodeClassname(info.getReturnType());
        if (!returnType.equals("void"))
        {
            buf.append("@return ").append(returnType).append(NEWLINE);
        }

        return (makeJavadocComment(buf.toString()));
    }

    public String getHeaderComment(final MBeanInfo info)
    {
        return makeJavadocComment("");
    }

    public String getInterfaceComment(final MBeanInfo info)
    {
        final StringBuilder buf = new StringBuilder();

        buf.append("Implementing class: ").append(info.getClassName()).append(NEWLINE);

        buf.append( NEWLINE + "Descriptor: " + NEWLINE);
        buf.append( toString(info.getDescriptor()) );

        final MBeanNotificationInfo[] notifs = info.getNotifications();
        if ( notifs != null && notifs.length != 0 )
        {
            buf.append( NEWLINE + "MBeanNotificationInfo: " + NEWLINE);
            for( final MBeanNotificationInfo notifInfo : notifs )
            {
                buf.append(MBeanNotificationInfoStringifier.toString(notifInfo)).append(NEWLINE);
            }
        }

        final String comment = buf.toString();

        return makeJavadocComment(comment);
    }

    public String getPackageName(final MBeanInfo info)
    {
        return ("mbeans.generated");
    }

    public String getClassname(final MBeanInfo info)
    {
        String name = info.getClassName();
        name = name.replace(".", "_");
        name = name.replace("$", "_");

        return name + "_Proxy";
    }

    public String getExceptions(final MBeanOperationInfo info)
    {
        return ("");
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy