Package org.glassfish.admin.amx.core

Source Code of org.glassfish.admin.amx.core.Util

/*
* 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.
*/
package org.glassfish.admin.amx.core;

import java.util.regex.Pattern;

import org.glassfish.admin.amx.util.jmx.JMXUtil;
import org.glassfish.admin.amx.util.SetUtil;
import org.glassfish.admin.amx.util.ClassUtil;
import org.glassfish.admin.amx.core.AMXMBeanMetadata;

import static org.glassfish.external.amx.AMX.*;

import javax.management.Notification;
import javax.management.ObjectName;
import java.io.Serializable;
import java.util.*;
import javax.management.MBeanServer;
import org.glassfish.external.arc.Stability;
import org.glassfish.external.arc.Taxonomy;

/**
Utility routines pertinent to the MBean API.
*/
@Taxonomy(stability = Stability.UNCOMMITTED)
public final class Util {

    private static final String QUOTE_CHAR = "\"";

    private static void debug(final String s) {
        System.out.println(s);
    }

    public static String quoteIfNeeded(String name) {
        if(name.indexOf(":") > 1) {
           return ObjectName.quote(name);
        } else {
            return name;
        }
    }

    public  static String unquoteIfNeeded(String name) {
        if(name != null && (name.startsWith(QUOTE_CHAR) && name.endsWith(QUOTE_CHAR))) {
           return ObjectName.unquote(name);
        } else {
            return name;
        }
    }

    private Util() {
    }

    /**
    Create a new ObjectName, caller is guaranteeing that the name is
    well-formed (a RuntimeException will be thrown if not). This avoids
    having to catch all sorts of JMX exceptions.<br>
    <b>NOTE:</b> Do not call this method if there is not certainty of a well-formed name.

    @param name
     */
    public static ObjectName newObjectName(String name) {
        return (JMXUtil.newObjectName(name));
    }

    /**
    Build an ObjectName.  Calls newObjectName( domain + ":" + props )

    @param domain  the JMX domain
    @param props  properties of the ObjectName
     */
    public static ObjectName newObjectName(String domain, String props) {
        return (newObjectName(domain + ":" + props));
    }

    /**
    Build an ObjectName pattern.

    @param domain  the JMX domain
    @param props  properties of the ObjectName
     */
    public static ObjectName newObjectNamePattern(
            final String domain,
            final String props) {
        return (JMXUtil.newObjectNamePattern(domain, props));
    }

    /**
    Build an ObjectName pattern.

    @param objectName
     */
    public static ObjectName newObjectNamePattern(ObjectName objectName) {
        final String props = objectName.getKeyPropertyListString();

        return (newObjectNamePattern(objectName.getDomain(), props));
    }

    /**
    Make an ObjectName property of the form <i>name</i>=<i>value</i>.

    @param name
    @param value
     */
    public static String makeProp(
            final String name,
            final String value) {
        return (JMXUtil.makeProp(name, value));
    }

    /**
    Make an ObjectName property of the form type=<i>value</i>.

    @param value
     */
    public static String makeTypeProp(final String value) {
        return (makeProp(TYPE_KEY, value));
    }

    /**
    Make an ObjectName property of the form name=<i>value</i>.
     */
    public static String makeNameProp(final String name) {
        return (makeProp(NAME_KEY, "" + quoteIfNeeded(name)));
    }

    /**
    @param type
    @param name
     */
    public static String makeRequiredProps(
            final String type,
            final String name) {
        String props = Util.makeTypeProp(type);
        if (!(name == null || name.length() == 0 || name.equals(NO_NAME))) {
            final String nameProp = Util.makeNameProp(name);
            props = Util.concatenateProps(props, nameProp);
        }

        return (props);
    }

    /**
    Extract the type and name properties and return it as a single property
    <i>type</i>=<i>name</i>

    @param objectName
     */
    public static String getSelfProp(final ObjectName objectName) {
        final String type = objectName.getKeyProperty(TYPE_KEY);
        final String name = objectName.getKeyProperty(NAME_KEY);

        return (Util.makeProp(type, name));
    }

    /**
    Extract all properties other than type=<type>,name=<name>.

    @param objectName
     */
    public static String getAdditionalProps(final ObjectName objectName) {
        final java.util.Hashtable<String,String> allProps = objectName.getKeyPropertyList();
        allProps.remove(TYPE_KEY);
        allProps.remove(NAME_KEY);

        String props = "";
        for (final Map.Entry<String,String> e : allProps.entrySet()) {
            final String prop = makeProp(e.getKey(), e.getValue());
            props = concatenateProps(props, prop);
        }

        return props;
    }

    public static String concatenateProps(
            final String props1,
            final String props2) {
        return (JMXUtil.concatenateProps(props1, props2));
    }

    public static String concatenateProps(
            final String props1,
            final String props2,
            final String props3) {
        return (concatenateProps(concatenateProps(props1, props2), props3));
    }

    /**
    @return a List of ObjectNames from a Set of AMX.
     */
    public static List<ObjectName> toObjectNameList(final Collection<? extends AMXProxy> amxs) {
        final List<ObjectName> objectNames = new ArrayList<ObjectName>();
        for (final AMXProxy next : amxs) {
            objectNames.add(next.objectName());
        }
        return (Collections.checkedList(objectNames, ObjectName.class));
    }

    /**
    @return a Map of ObjectNames from a Map whose values are AMX.
     */
    public static Map<String, ObjectName> toObjectNameMap(final Map<String, ? extends AMXProxy> amxMap) {
        final Map<String, ObjectName> m = new HashMap<String, ObjectName>();

        for (final Map.Entry<String,? extends AMXProxy> e : amxMap.entrySet()) {
            final AMXProxy value = e.getValue();
            m.put(e.getKey(), value.objectName());
        }
        return (Collections.checkedMap(m, String.class, ObjectName.class));
    }

    /**
    @return an ObjectName[] from an AMX[]
     */
    public static ObjectName[] toObjectNamesArray(final AMXProxy[] amx) {
        final ObjectName[] objectNames = new ObjectName[amx.length];
        for (int i = 0; i < objectNames.length; ++i) {
            objectNames[i] = amx[i] == null ? null : amx[i].objectName();
        }

        return (objectNames);
    }

    public static ObjectName[] toObjectNamesArray(final Collection<? extends AMXProxy> amxs) {
        final ObjectName[] objectNames = new ObjectName[amxs.size()];
        int i = 0;
        for (final AMXProxy amx : amxs) {
            objectNames[i] = amx.objectName();
            ++i;
        }

        return (objectNames);
    }

    /**
    Create a Map keyed by the value of the NAME_KEY with
    value the AMX item.

    @param amxs Set of AMX
     */
    public static <T extends AMXProxy> Map<String, T> createNameMap(final Set<T> amxs) {
        final Map<String, T> m = new HashMap<String, T>();

        for (final T amx : amxs) {
            final String name = amx.getName();
            m.put(name, amx);
        }

        return (m);
    }

    /**
    Create a Map keyed by the value of the NAME_KEY with
    value the ObjectName. Note that if two or more ObjectNames
    share the same name, the resulting Map will contain only
    one of the original ObjectNames.

    @param objectNames Set of ObjectName
     */
    public static final Map<String, ObjectName> createObjectNameMap(final Set<ObjectName> objectNames) {
        final Map<String, ObjectName> m = new HashMap<String, ObjectName>();

        for (final ObjectName objectName : objectNames) {
            final String name = getNameProp(objectName);

            assert (!m.containsKey(name)) :
                    "createObjectNameMap: key already present: " + name + " in " + objectName;
            m.put(name, objectName);
        }

        assert (m.keySet().size() == objectNames.size());

        return (Collections.checkedMap(m, String.class, ObjectName.class));
    }

    public static <T extends AMXProxy> List<T> asProxyList(final Collection<? extends AMXProxy> c, final Class<T> intf) {
        final List<T> list = new ArrayList<T>();

        for (final AMXProxy amx : c) {
            list.add(amx.as(intf));
        }

        return list;
    }

    /**
    All Notifications emitted by AMX MBeans which are not
    standard types defined by JMX place a Map
    into the userData field of the Notification.  This call
    retrieves that Map, which may be null if no additional
    data is included.
     */
    public static Map<String, Serializable> getAMXNotificationData(final Notification notif) {
        return Collections.unmodifiableMap(
                JMXUtil.getUserDataMapString_Serializable(notif));
    }

    /**
    Use of generic type form taking Class<T> is preferred.
     */
    public static Serializable getAMXNotificationValue(final Notification notif, final String key) {
        final Map<String, Serializable> data =
                getAMXNotificationData(notif);

        if (data == null) {
            throw new IllegalArgumentException(notif.toString());
        }

        if (!data.containsKey(key)) {
            throw new IllegalArgumentException("Value not found for " + key
                    + " in " + notif);
        }

        return data.get(key);
    }

    /**
    Retrieve a particular value associated with the specified
    key from an AMX Notification.
    @see #getAMXNotificationData
     */
    public static <T extends Serializable> T getAMXNotificationValue(
            final Notification notif,
            final String key,
            final Class<T> theClass) {
        final Serializable value = getAMXNotificationValue(notif, key);

        return theClass.cast(value);
    }

    public static void sleep(final long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
        }
    }

    /**
    A safe way to cast to AMX.
     */
    public static AMXProxy asAMX(final Object o) {
        return AMXProxy.class.cast(o);
    }

    /**
    Filter the AMX dynamic proxies to those that implement the specified interface,
    and return a new Set with the matching items.  The 'desired' interface can be
    any AMX-defined class, including the mixin ones.

    @param candidates the Set to be filtered
    @param desired the interface to filter by
     */
    public static <T extends AMXProxy> Set<T> filterAMX(final Set<T> candidates, final Class<?> desired) {
        final Set<T> result = new HashSet<T>();
        for (final T amx : candidates) {
            if (desired.isAssignableFrom(amx.getClass())) {
                result.add(amx);
            }
        }
        return result;
    }

    public static Map<String, ObjectName> filterByType(final ObjectName[] objectNames, final String type) {
        Map<String, ObjectName> m = null;
        if (objectNames != null) {
            m = new HashMap<String, ObjectName>();
            for (final ObjectName o : objectNames) {
                if (type.equals(o.getKeyProperty(TYPE_KEY))) {
                    // use the name property, not the name from getNameProp()
                    m.put(o.getKeyProperty(NAME_KEY), o);
                }
            }
        }
        return m;
    }

    /**
    Filter the AMX dynamic proxies to those that implement the specified interface,
    and return a new Map with the matching items.  The 'desired' interface can be
    any AMX-defined class, including the mixin ones.

    @param candidates the Map to be filtered
    @param desired the interface to filter by
     */
    public static <T extends AMXProxy> Map<String, T> filterAMX(final Map<String, T> candidates, final Class<?> desired) {
        final Map<String, T> result = new HashMap<String, T>();
        for (final Map.Entry<String,T> e : candidates.entrySet()) {
            final T amx = e.getValue();
            if (desired.isAssignableFrom(amx.getClass())) {
                result.put(e.getKey(), amx);
            }
        }
        return result;
    }

    public static String getTypeProp(final ObjectName objectName) {
        return objectName.getKeyProperty(TYPE_KEY);
    }

    /**
    Get the value of the NAME_KEY property within the ObjectName, or null if
    not present.
    @return the name
     */
    public static String getNameProp(final ObjectName objectName) {
        return objectName.getKeyProperty(NAME_KEY);
    }

    public static String getParentPathProp(final ObjectName objectName) {
        return objectName.getKeyProperty(PARENT_PATH_KEY);
    }

    public static String getParentPathProp(final AMXProxy amx) {
        return getParentPathProp(amx.extra().objectName());
    }

    public static ObjectName getParent(final MBeanServer server, final ObjectName objectName) {
        return (ObjectName) JMXUtil.getAttribute(server, objectName, ATTR_PARENT);
    }

    /**
    Generate the default MBean type from a String, eg from a classname.
     */
    public static String typeFromName(final String s) {
        if (s.indexOf("-") >= 0) {
            return s;   // if it already has dashes, leave unchanged
        }

        String simpleName = s;
        final int idx = s.lastIndexOf(".");
        if (idx >= 0) {
            simpleName = s.substring(idx + 1);
        }
        return domConvertName(simpleName);
    }
    /** Proxy interfaces may contain a type field denoting the type to be used in the ObjectName;
     * this is an alternative to an annotation that may be desirable to avoid
     * a dependency on the amx-core module.  Some proxy interfaces also represent
     * MBeans whose type and other metadata is derived not from the proxy interface,
     * but from another authoritative source; this allows an explicit
     * linkage that allows the AMXProxyHandler to deduce the correct type, given
     * the interface (and avoids any further complexity, the KISS principle).
     * eg public static final String AMX_TYPE = "MyType";
     * <p>
     * A good example of this is the config MBeans which use lower case types with dashes. Other
     * types may use classnames, or other variants; the proxy code can't assume any particular
     * mapping from a proxy interface to the actual MBean type.
     */
    public static final String TYPE_FIELD = "AMX_TYPE";

    /**
    Deduce the type to be used in the path.  Presence of a TYPE_FIELD field always
    take precedence, then the AMXMBeanMetadata.
     */
    public static String deduceType(final Class<?> intf) {
        if (intf == null) {
            throw new IllegalArgumentException("null interface");
        }

        String type = null;

        AMXMBeanMetadata meta = null;
        final Object typeField = ClassUtil.getFieldValue(intf, TYPE_FIELD);
        if (typeField instanceof String) {
            type = (String) typeField;
        } else if ((meta = intf.getAnnotation(AMXMBeanMetadata.class)) != null) {
            final String typeValue = meta.type();

            if (typeValue.equals(AMXMBeanMetadata.NULL) || typeValue.length() == 0) {
                type = Util.typeFromName(intf.getName());
            } else {
                type = typeValue;
            }
        } else {
            // no annotation, use our default conversion
            type = Util.typeFromName(intf.getName());
        }
        return type;
    }

    public static ObjectName getAncestorByType(final MBeanServer mbeanServer, final ObjectName child, final String type) {
        ObjectName cur = child;

        while ((cur = (ObjectName) JMXUtil.getAttribute(mbeanServer, cur, ATTR_PARENT)) != null) {
            if (getTypeProp(cur).equals(type)) {
                break;
            }
        }
        return cur;
    }
    // BEGIN domConvertName
    /* Code below is taken from Dom.java to avoid a dependency */
    static final String[] PROPERTY_PREFIX = new String[]{"get", "set", "is", "has"};

    private static String domConvertName(final String nameIn) {
        String name = nameIn;
        for (final String p : PROPERTY_PREFIX) {
            if (name.startsWith(p)) {
                name = name.substring(p.length());
                break;
            }
        }
        // tokenize by finding 'x|X' and 'X|Xx' then insert '-'.
        final StringBuilder buf = new StringBuilder(name.length() + 5);
        for (final String t : TOKENIZER.split(name)) {
            if (buf.length() > 0) {
                buf.append('-');
            }
            buf.append(t.toLowerCase(Locale.ENGLISH));
        }
        return buf.toString();
    }
    /**
     * Used to tokenize the property name into XML name.
     */
    static final Pattern TOKENIZER;

    private static String split(String lookback, String lookahead) {
        return "((?<=" + lookback + ")(?=" + lookahead + "))";
    }

    private static String or(String... tokens) {
        final StringBuilder buf = new StringBuilder();
        for (String t : tokens) {
            if (buf.length() > 0) {
                buf.append('|');
            }
            buf.append(t);
        }
        return buf.toString();
    }

    static {
        String pattern = or(
                split("x", "X"), // AbcDef -> Abc|Def
                split("X", "Xx"), // USArmy -> US|Army
                //split("\\D","\\d"), // SSL2 -> SSL|2
                split("\\d", "\\D") // SSL2Connector -> SSL|2|Connector
                );
        pattern = pattern.replace("x", "\\p{Lower}").replace("X", "\\p{Upper}");
        TOKENIZER = Pattern.compile(pattern);
    }
    // END domConvertName
}
TOP

Related Classes of org.glassfish.admin.amx.core.Util

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.