/* * Copyright 2013 The Generic MBean CLI Project * * The Generic MBean CLI Project 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 com.sohail.alam.generic.mbean.cli.jmx; import com.sohail.alam.generic.mbean.cli.logger.Logger; import javax.management.ObjectName; import java.util.ArrayList; import java.util.HashMap; import java.util.Set; /** * <p/> * The Implementation of {@link OperationHelper}. This is where most of the 'Magic' happens. * This class is solely responsible for anything and everything that has to do with MBean Operations * <p/> * * @author Sohail Alam * @version 1.0.0 Date: 19/5/13 * Time: 7:21 PM * @since 1.0.0 */ public class DefaultOperationHelper implements OperationHelper { /** * The JMX_INITIALIZER. */ private final JMXInitializer JMX_INITIALIZER; /** * The Storage. */ private DataStorage storage; /** * Instantiates a new Operation helper. */ private DefaultOperationHelper() { JMX_INITIALIZER = DefaultJMXInitializer.getInstance(); } /** * Gets instance. * * @return the instance */ public static OperationHelper getInstance() { return SingletonHolder.instance; } /** * Gets operation description. * * @param operationName the operation name * * @return the operation description */ @Override public StringBuffer getOperationInfo(String operationName) { StringBuffer buffer = new StringBuffer(); for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames()) { buffer.append(getOperationInfo(beanObjectName.getCanonicalName(), operationName)); } return buffer; } /** * Gets operation description. * * @param mbeanName the mbean name * @param name the name * * @return the operation description */ @Override public StringBuffer getOperationInfo(String mbeanName, String name) { StringBuffer buffer = new StringBuffer(); String userOperationName; boolean startsWithWildcard = false; boolean endsWithWildcard = false; if (name.contains("*")) { startsWithWildcard = name.startsWith("*"); endsWithWildcard = name.endsWith("*"); userOperationName = name.replaceAll("[*]", "").toLowerCase(); if (startsWithWildcard && endsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().contains(userOperationName)) { formatOperationInfo(buffer, beanObjectName, operationName); } } } } else if (startsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().endsWith(userOperationName)) { formatOperationInfo(buffer, beanObjectName, operationName); } } } } else if (endsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().startsWith(userOperationName)) { formatOperationInfo(buffer, beanObjectName, operationName); } } } } } else { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.equalsIgnoreCase(name.toLowerCase())) { formatOperationInfo(buffer, beanObjectName, operationName); } } } } if (buffer.length() == 0) { buffer.append("No such operation found, try using wildcard (*) search\n"); } return buffer; } /** * Format operation info. * * @param buffer the buffer * @param beanObjectName the bean object name * @param operationName the operation name */ private void formatOperationInfo(StringBuffer buffer, ObjectName beanObjectName, String operationName) { buffer .append("\n") .append("\n---------------------------------------------------------------------------------------\n") .append(" OPERATION INFORMATION ") .append("\n---------------------------------------------------------------------------------------\n") .append("MBean Name : ").append(beanObjectName.getCanonicalName()).append("\n") .append("Name : ").append(operationName).append("\n") .append("Description : ").append(storage.getBeanOperations().get(operationName).get(storage.DESCRIPTION_POSITION)).append("\n") .append("---------------------------------------------------------------------------------------\n"); } /** * Gets operation info. * * @param operationName the operation name * * @return the operation info */ @Override public StringBuffer getOperationHelp(String operationName) { StringBuffer buffer = new StringBuffer(); for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames()) { buffer.append(getOperationHelp(beanObjectName.getCanonicalName(), operationName)); } return buffer; } /** * Gets operation info. * * @param mbeanName the mbean name * @param name the name * * @return the operation info */ @Override public StringBuffer getOperationHelp(String mbeanName, String name) { StringBuffer buffer = new StringBuffer(); String userOperationName; boolean startsWithWildcard = false; boolean endsWithWildcard = false; if (name.contains("*")) { startsWithWildcard = name.startsWith("*"); endsWithWildcard = name.endsWith("*"); userOperationName = name.replaceAll("[*]", "").toLowerCase(); if (startsWithWildcard && endsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().contains(userOperationName)) { formatOperationHelp(buffer, beanObjectName, operationName); } } } } else if (startsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().endsWith(userOperationName)) { formatOperationHelp(buffer, beanObjectName, operationName); } } } } else if (endsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().startsWith(userOperationName)) { formatOperationHelp(buffer, beanObjectName, operationName); } } } } } else { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.equalsIgnoreCase(name.toLowerCase())) { formatOperationHelp(buffer, beanObjectName, operationName); } } } } if (buffer.length() == 0) { buffer.append("No such operation found, try using wildcard (*) search\n"); } return buffer; } /** * Format operation help. * * @param buffer the buffer * @param beanObjectName the bean object name * @param operationName the operation name */ private void formatOperationHelp(StringBuffer buffer, ObjectName beanObjectName, String operationName) { buffer .append("\n") .append("\n---------------------------------------------------------------------------------------\n") .append(" OPERATION INFORMATION ") .append("\n---------------------------------------------------------------------------------------\n") .append("MBean Name : ").append(beanObjectName.getCanonicalName()).append("\n") .append("Name : ").append(operationName).append("\n") .append("Return Type : ").append(storage.getBeanOperations().get(operationName).get(storage.RETURN_TYPE_POSITION)).append("\n") .append("Description : ").append(storage.getBeanOperations().get(operationName).get(storage.DESCRIPTION_POSITION)).append("\n"); ArrayList<HashMap<String, String>> tempList = (ArrayList<HashMap<String, String>>) storage.getBeanOperations().get(operationName).get(storage.PARAMETERS_POSITION); if (tempList != null && tempList.size() > 0) { int paramCount = 0; buffer.append("\nPARAMETERS INFO:\n"); buffer.append("...............\n"); for (HashMap map : tempList) { paramCount++; buffer.append("Parameter ").append(paramCount).append("\n"); buffer.append("Parameter Name : ").append(map.get(storage.NAME)).append("\n"); buffer.append("Parameter Type : ").append(map.get(storage.TYPE)).append("\n"); buffer.append("Parameter Description : ").append(map.get(storage.DESCRIPTION)).append("\n\n"); } } buffer.append("---------------------------------------------------------------------------------------\n"); } /** * Gets all operations. * * @return the all operations */ @Override public StringBuffer getAllOperations() { StringBuffer buffer = new StringBuffer(); for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames()) { buffer.append(getAllOperations(beanObjectName.getCanonicalName())); } return buffer; } /** * Gets all operations. * * @param mbeanName the mbean name * * @return the all operations */ @Override public StringBuffer getAllOperations(String mbeanName) { StringBuffer buffer = new StringBuffer(); for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); Set<String> allOperationNames = storage.getBeanOperations().keySet(); buffer.append("\n==============================================================================================================\n"); buffer.append("ALL OPERATIONS INFORMATION FOR MBEAN => ") .append(String.format("%-57s", beanObjectName.getCanonicalName())) .append("\n") .append("==============================================================================================================\n") .append(String.format("%-60s", "NAME")) .append(String.format("%-35s", "RETURN TYPE")) .append(String.format("%-15s", "PARAMETER COUNT")) .append("\n--------------------------------------------------------------------------------------------------------------\n"); for (String operationName : allOperationNames) { ArrayList<HashMap<String, String>> tempList = (ArrayList<HashMap<String, String>>) storage.getBeanOperations().get(operationName).get(storage.PARAMETERS_POSITION); int paramCount = 0; if (tempList != null && tempList.size() > 0) { for (HashMap map : tempList) { paramCount++; } } buffer.append(String.format("%-60s", operationName)) .append(String.format("%-35s", storage.getBeanOperations().get(operationName).get(storage.RETURN_TYPE_POSITION))) .append(String.format("%-15s", paramCount)) .append("\n"); } buffer.append("--------------------------------------------------------------------------------------------------------------\n"); } return buffer; } /** * TODO: Invoke operation. * * @param operationName the operation name * @param operationParameters the operation parameters * * @return the string buffer */ @Override public StringBuffer invokeOperation(String operationName, ArrayList<String> operationParameters) { StringBuffer buffer = new StringBuffer(); for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames()) { buffer.append(invokeOperation(beanObjectName.getCanonicalName(), operationName, operationParameters)); } return buffer; } /** * TODO: Invoke operation. * * @param mbeanName the mbean name * @param name the name * @param operationParameters the operation parameters * * @return the string buffer */ @Override public StringBuffer invokeOperation(String mbeanName, String name, ArrayList<String> operationParameters) { Logger.logTrace("Inside invokeOperation()", getClass(), false); StringBuffer buffer = new StringBuffer(); boolean found = false; String userOperationName; boolean startsWithWildcard = false; boolean endsWithWildcard = false; if (operationParameters == null) { operationParameters = new ArrayList<String>(0); } if (name.contains("*")) { startsWithWildcard = name.startsWith("*"); endsWithWildcard = name.endsWith("*"); userOperationName = name.replaceAll("[*]", "").toLowerCase(); if (startsWithWildcard && endsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().contains(userOperationName)) { found = true; buffer = tryToInvokeOperation(beanObjectName, operationName, operationParameters); } } } } else if (startsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().endsWith(userOperationName)) { found = true; buffer = tryToInvokeOperation(beanObjectName, operationName, operationParameters); } } } } else if (endsWithWildcard) { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.toLowerCase().startsWith(userOperationName)) { found = true; buffer = tryToInvokeOperation(beanObjectName, operationName, operationParameters); } } } } } else { for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames(mbeanName)) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.equalsIgnoreCase(name.toLowerCase())) { found = true; buffer = tryToInvokeOperation(beanObjectName, operationName, operationParameters); break; } } } } if (!found) { buffer.append("No such operation found, try using wildcard (*) search\n"); } return buffer; } /** * TODO: Try to invoke operation. * * @param mbeanObjectName the mbean object name * @param operationName the operation name * @param operationParameters the operation parameters * * @return the string buffer */ private StringBuffer tryToInvokeOperation(ObjectName mbeanObjectName, String operationName, ArrayList<String> operationParameters) { Logger.logTrace("Inside tryToInvokeOperation()", getClass(), false); StringBuffer buffer = new StringBuffer(); storage = DefaultDataStorage.getInstance(mbeanObjectName); ArrayList<HashMap<String, String>> tempList = (ArrayList<HashMap<String, String>>) storage.getBeanOperations().get(operationName).get(storage.PARAMETERS_POSITION); int size = 0; if (tempList != null) { size = tempList.size(); } if (operationParameters.size() >= size) { try { buffer.append("OPERATION NAME : ").append(operationName).append("\n"); buffer.append("OPERATION RETURN VALUE : ").append(String.valueOf( JMX_INITIALIZER.getMbsc().invoke( mbeanObjectName, operationName, // Operation Name getParamValues(mbeanObjectName, operationName, operationParameters), // Operation Parameter Values in correct order getParamTypes(mbeanObjectName, operationName)) // Operation Parameter type in correct order )); return buffer; } catch (Exception e) { Logger.logException(e, getClass()); } } else { buffer.insert(0, "Number of parameters does not match method signature: " + operationName + "\n"); } return buffer; } /** * TODO: Get param values. * * @param mbeanObjectName the mbean object name * @param name the name * @param operationParameters the operation parameters * * @return the object [ ] */ private Object[] getParamValues(ObjectName mbeanObjectName, String name, ArrayList<String> operationParameters) { Logger.logTrace("Inside getParamValues()", getClass(), false); Object[] paramValues = new Object[0]; storage = DefaultDataStorage.getInstance(mbeanObjectName); ArrayList<HashMap<String, String>> tempList = (ArrayList<HashMap<String, String>>) storage.getBeanOperations().get(name).get(storage.PARAMETERS_POSITION); int size = 0; if (tempList != null) { size = tempList.size(); } if (size > 0) { paramValues = new Object[size]; HashMap<String, String> paramMap; int parameterClassTypeSwitch; for (int i = 0; i < size; i++) { parameterClassTypeSwitch = 0; paramMap = tempList.get(i); if (JavaClassTypes.CLASS_TYPE_MAP.containsKey(paramMap.get(storage.TYPE))) { parameterClassTypeSwitch = JavaClassTypes.CLASS_TYPE_MAP.get(paramMap.get(storage.TYPE)); } else { parameterClassTypeSwitch = -1; } switch (parameterClassTypeSwitch) { case JavaClassTypes.INT_INT: case JavaClassTypes.INTEGER_WRAPPER_INT: paramValues[i] = Integer.parseInt(operationParameters.get(i)); break; case JavaClassTypes.FLOAT_INT: case JavaClassTypes.FLOAT_WRAPPER_INT: paramValues[i] = Float.parseFloat(operationParameters.get(i)); break; case JavaClassTypes.DOUBLE_INT: case JavaClassTypes.DOUBLE_WRAPPER_INT: paramValues[i] = Double.parseDouble(operationParameters.get(i)); break; case JavaClassTypes.BOOLEAN_INT: case JavaClassTypes.BOOLEAN_WRAPPER_INT: paramValues[i] = Boolean.parseBoolean(operationParameters.get(i)); break; case JavaClassTypes.STRING_INT: paramValues[i] = operationParameters.get(i); break; default: break; } } } return paramValues; } /** * TODO: Get param types. * * @param mbeanObjectName the mbean object name * @param name the name * * @return the string [ ] */ private String[] getParamTypes(ObjectName mbeanObjectName, String name) { Logger.logTrace("Inside getParamTypes()", getClass(), false); String[] paramTypes = new String[0]; storage = DefaultDataStorage.getInstance(mbeanObjectName); ArrayList<HashMap<String, String>> tempList = (ArrayList<HashMap<String, String>>) storage.getBeanOperations().get(name).get(DataStorage.PARAMETERS_POSITION); int size = 0; if (tempList != null) { size = tempList.size(); } if (size > 0) { paramTypes = new String[size]; int count = 0; // Organize the Parameter Types for (HashMap map : tempList) { paramTypes[count] = (String) map.get(DataStorage.TYPE); count++; } } return paramTypes; } /** * Check conflicts. * * @param name the name * * @return the string buffer */ @Override public StringBuffer checkConflicts(String name) { StringBuffer buffer = new StringBuffer(); for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames()) { buffer.append(checkConflicts(beanObjectName.getCanonicalName(), name)); } return buffer; } /** * Check conflicts. * * @param mbeanName the mbean name * @param name the attribute name * * @return the string buffer */ @Override public StringBuffer checkConflicts(String mbeanName, String name) { StringBuffer buffer = new StringBuffer(); int conflictCounter = 0; for (ObjectName beanObjectName : JMX_INITIALIZER.getMBeanObjectNames()) { storage = DefaultDataStorage.getInstance(beanObjectName); for (String operationName : storage.getBeanOperations().keySet()) { if (operationName.equalsIgnoreCase(name)) { conflictCounter = 1; buffer = new StringBuffer("\nMBean Name: "); buffer.append(beanObjectName.getCanonicalName()) .append("\nOperation Name: ").append(operationName); break; } if (operationName.toLowerCase().contains(name)) { conflictCounter++; buffer.append("\nMBean Name: ").append(beanObjectName.getCanonicalName()) .append("\nOperation Name: ").append(operationName).append("\n"); } } } buffer.append("\n................................................................................"); if (conflictCounter == 1) { // Get the Operation name only buffer = new StringBuffer( buffer.toString().split("\n")[2].replaceAll("Operation Name: ", "") ); } else { buffer.insert(0, "\nERROR:\nThere was a conflict resolving your command!\n"); } return buffer; } /** * The type Singleton holder. * <p/> * Initialization on Demand Holder (IODH) idiom which requires very little code and * has zero synchronization overhead. Zero, as in even faster than volatile. * IODH requires the same number of lines of code as plain old synchronization, and it's faster than DCL! * <p/> * {@code SOURCE: http://blog.crazybob.org/2007/01/lazy-loading-singletons.html} */ static class SingletonHolder { /** * The Instance. */ static OperationHelper instance = new DefaultOperationHelper(); } }