--- old/application/org.openjdk.jmc.rjmx/src/main/java/org/openjdk/jmc/rjmx/services/internal/MBeanOperationsWrapper.java 2019-02-13 10:07:38.000000000 +0100 +++ /dev/null 2019-02-13 10:07:38.000000000 +0100 @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The contents of this file are subject to the terms of either the Universal Permissive License - * v 1.0 as shown at http://oss.oracle.com/licenses/upl - * - * or the following license: - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions - * and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided with - * the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY - * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.openjdk.jmc.rjmx.services.internal; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - -import javax.management.MBeanFeatureInfo; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanParameterInfo; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; - -import org.openjdk.jmc.common.util.TypeHandling; -import org.openjdk.jmc.rjmx.services.IOperation; -import org.openjdk.jmc.rjmx.services.IOperation.OperationImpact; -import org.openjdk.jmc.rjmx.services.IllegalOperandException; -import org.openjdk.jmc.rjmx.util.internal.SimpleAttributeInfo; - -public final class MBeanOperationsWrapper extends ArrayList { - - private static final int MAX_DESCRIPTORS = 8; - private static final int MAX_LINE_LENGTH = 100; - private static final String ELLIPSIS_STRING = "..."; //$NON-NLS-1$ - private static final long serialVersionUID = -8499920218074514535L; - private static final String IMPACT = ".vmImpact"; //$NON-NLS-1$ - private final ObjectName bean; - private final transient MBeanServerConnection connection; - - public MBeanOperationsWrapper(ObjectName bean, MBeanOperationInfo[] operations, MBeanServerConnection connection) { - super(operations.length); - this.connection = connection; - this.bean = bean; - for (MBeanOperationInfo info : operations) { - add(new MBeanOperation(info)); - } - } - - private static String convertDescription(MBeanFeatureInfo info) { - // FIXME: Building tool tips and descriptors should be unified into a toolkit - StringBuilder sb = new StringBuilder(); - if (info.getDescriptor() != null && info.getDescriptor().getFields() != null) { - String[] fields = info.getDescriptor().getFields(); - if (fields.length > 0) { - // TODO: This is a workaround to get the descriptors to UI-layer. Should be handled using some adaptive mechanism. - sb.append(Messages.MBeanOperationsWrapper_DESCRIPTOR).append(":\n "); //$NON-NLS-1$ - for (int i = 0; i < Math.min(fields.length, MAX_DESCRIPTORS); i++) { - String str = fields[i]; - int cur = 0; - int newLine = 0; - while (cur < str.length() && newLine != -1) { - newLine = str.indexOf('\n', cur); - if (newLine == -1) { - sb.append(shorten(str.substring(cur))).append("\n "); //$NON-NLS-1$ - } else { - sb.append(shorten(str.substring(cur, newLine))).append("\n "); //$NON-NLS-1$ - cur = newLine + 1; - } - } - } - } - } - return shorten(info.getDescription()) + "\n " + sb.toString().trim(); //$NON-NLS-1$ - } - - private static String shorten(String s) { - if (s == null) { - return ""; //$NON-NLS-1$ - } else if (s.length() > MAX_LINE_LENGTH) { - return (s.subSequence(0, MAX_LINE_LENGTH - ELLIPSIS_STRING.length()) + ELLIPSIS_STRING); - } else { - return s; - } - } - - private static List convertArguments(MBeanOperationInfo info) { - MBeanParameterInfo[] sign = info.getSignature(); - List signature = new ArrayList<>(sign.length); - for (MBeanParameterInfo paramInfo : sign) { - // Use name primarily. Use description as name only if name is null or empty. - String name = asNonNullNorEmptyString(paramInfo.getName(), - asNonNullNorEmptyString(paramInfo.getDescription(), "")); //$NON-NLS-1$ - signature.add(new SimpleAttributeInfo(name, paramInfo.getType(), convertDescription(paramInfo))); - } - return signature; - } - - /** - * @return {@code string} if it is not {@code null} and it is not an empty or blank string, - * otherwise {@code defaultString} - */ - private static String asNonNullNorEmptyString(String string, String defaultString) { - return (string != null && string.trim().length() > 0) ? string : defaultString; - } - - private static OperationImpact convertImpact(MBeanOperationInfo info) { - for (String name : info.getDescriptor().getFieldNames()) { - if (name.endsWith(IMPACT)) { - Object impactField = info.getDescriptor().getFieldValue(name); - if (impactField != null) { - String impact = impactField.toString(); - if (impact.startsWith("Low")) { //$NON-NLS-1$ - return OperationImpact.IMPACT_LOW; - } - if (impact.startsWith("Medium")) { //$NON-NLS-1$ - return OperationImpact.IMPACT_MEDIUM; - } - if (impact.startsWith("High")) { //$NON-NLS-1$ - return OperationImpact.IMPACT_HIGH; - } - } - } - } - return OperationImpact.IMPACT_UNKNOWN; - } - - private class MBeanOperation extends AbstractOperation { - - public MBeanOperation(MBeanOperationInfo info) { - super(info.getName(), convertDescription(info), info.getReturnType(), convertArguments(info), - convertImpact(info)); - } - - @Override - public Callable getInvocator(final Object ... argVals) throws IllegalOperandException { - List params = getSignature(); - final StringBuilder argString = new StringBuilder("("); //$NON-NLS-1$ - if (argVals.length < params.size()) { - // Argument list is shorter than the signature - throw new IllegalOperandException(params.subList(argVals.length, params.size())); - } - final String[] sig = new String[params.size()]; - for (int i = 0; i < params.size(); i++) { - sig[i] = params.get(i).getType(); - if (argVals[i] != null) { - argString.append(' ').append(describeValue(argVals[i])).append(','); - } else if (TypeHandling.isPrimitive(sig[i])) { - // Argument value of primitive type is null - IllegalOperandException ex = new IllegalOperandException(params.get(i)); - while (++i < params.size()) { - // Check for other attributes with the same error - if (argVals[i] == null && TypeHandling.isPrimitive(params.get(i).getType())) { - ex.addInvalidValue(params.get(i)); - } - } - throw ex; - } - } - if (argString.charAt(argString.length() - 1) == ',') { - argString.deleteCharAt(argString.length() - 1); - } - argString.append(" )"); //$NON-NLS-1$ - - return new Callable() { - - @Override - public Object call() throws Exception { - return connection.invoke(bean, getName(), argVals, sig); - } - - @Override - public String toString() { - return getName() + argString.toString().replace("\n", "\\n").replace("\r", "\\r"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - } - }; - } - } - - private static String describeValue(Object o) { - if (o.getClass().isArray()) { - return o.getClass().getComponentType().getName() + "[" + Array.getLength(o) + "]"; //$NON-NLS-1$ //$NON-NLS-2$ - } else if (o instanceof String) { - return "\"" + o + "\""; //$NON-NLS-1$ //$NON-NLS-2$ - } else { - return o.toString(); - } - } - - private void writeObject(ObjectOutputStream out) throws IOException { - throw new NotSerializableException("MBeanOperationsWrappers should not be serialized!"); //$NON-NLS-1$ - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - throw new NotSerializableException("MBeanOperationsWrappers should not be serialized!"); //$NON-NLS-1$ - } -}