/* * RHQ Management Platform * Copyright (C) 2005-2014 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.modules.plugins.jbossas7; import static org.rhq.modules.plugins.jbossas7.ASConnection.verbose; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.concurrent.TimeoutException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.jackson.JsonNode; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.Property; import org.rhq.core.domain.configuration.PropertyList; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinitionList; import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple; import org.rhq.core.domain.configuration.definition.PropertySimpleType; import org.rhq.core.domain.content.transfer.ResourcePackageDetails; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.DataType; import org.rhq.core.domain.measurement.MeasurementDataNumeric; import org.rhq.core.domain.measurement.MeasurementDataTrait; import org.rhq.core.domain.measurement.MeasurementReport; import org.rhq.core.domain.measurement.MeasurementScheduleRequest; import org.rhq.core.domain.operation.OperationDefinition; import org.rhq.core.domain.resource.CreateResourceStatus; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.pluginapi.configuration.ConfigurationFacet; import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; import org.rhq.core.pluginapi.content.ContentContext; import org.rhq.core.pluginapi.content.ContentServices; import org.rhq.core.pluginapi.inventory.CreateChildResourceFacet; import org.rhq.core.pluginapi.inventory.CreateResourceReport; import org.rhq.core.pluginapi.inventory.DeleteResourceFacet; import org.rhq.core.pluginapi.inventory.ResourceComponent; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.measurement.MeasurementFacet; import org.rhq.core.pluginapi.operation.OperationFacet; import org.rhq.core.pluginapi.operation.OperationResult; import org.rhq.core.pluginapi.util.StartScriptConfiguration; import org.rhq.modules.plugins.jbossas7.helper.Deployer; import org.rhq.modules.plugins.jbossas7.json.Address; import org.rhq.modules.plugins.jbossas7.json.Operation; import org.rhq.modules.plugins.jbossas7.json.ReadAttribute; import org.rhq.modules.plugins.jbossas7.json.ReadChildrenNames; import org.rhq.modules.plugins.jbossas7.json.ReadResource; import org.rhq.modules.plugins.jbossas7.json.Remove; import org.rhq.modules.plugins.jbossas7.json.ResolveExpression; import org.rhq.modules.plugins.jbossas7.json.Result; import org.rhq.modules.plugins.jbossas7.json.ResultFailedException; import org.rhq.modules.plugins.jbossas7.json.SecurityRealmNotReadyException; import org.rhq.modules.plugins.jbossas7.json.UnauthorizedException; /** * The base class for all AS7 resource components. * * @param <T> the type of the component's parent resource component */ public class BaseComponent<T extends ResourceComponent<?>> implements AS7Component<T>, MeasurementFacet, ConfigurationFacet, DeleteResourceFacet, CreateChildResourceFacet, OperationFacet { private static final Log LOG = LogFactory.getLog(BaseComponent.class); static final String INTERNAL = "_internal:"; static final int INTERNAL_SIZE = INTERNAL.length(); static final String EXPRESSION = "_expr:"; static final int EXPRESSION_SIZE = EXPRESSION.length(); static final String EXPRESSION_VALUE_KEY = "EXPRESSION_VALUE"; static final int AVAIL_OP_TIMEOUT_SECONDS = 60; public static final String MANAGED_SERVER = "Managed Server"; private static final String PROFILE_SUFFIX = " (Profile)"; /** * @deprecated as of 4.10. Use your own logger or {@link #getLog()} method. */ @Deprecated final Log log = LOG; ResourceContext<T> context; Configuration pluginConfiguration; String myServerName; String path; Address address; String key; boolean includeRuntime; private BaseServerComponent serverComponent; protected ASConnection testConnection; /** * Start the resource connection * @see org.rhq.core.pluginapi.inventory.ResourceComponent#start(org.rhq.core.pluginapi.inventory.ResourceContext) */ @Override public void start(ResourceContext<T> context) throws Exception { this.context = context; pluginConfiguration = context.getPluginConfiguration(); serverComponent = findServerComponent(); path = pluginConfiguration.getSimpleValue("path"); address = new Address(path); key = context.getResourceKey(); myServerName = context.getResourceKey().substring(context.getResourceKey().lastIndexOf("/") + 1); includeRuntime = Boolean.parseBoolean(pluginConfiguration.getSimpleValue("includeRuntime", null)); } @Override public void stop() { } /** * Return availability of this resource * @see org.rhq.core.pluginapi.inventory.ResourceComponent#getAvailability() */ @Override public AvailabilityType getAvailability() { ReadResource readResourceOperation = new ReadResource(address); /* * Make the operation return minimum information. We just want to make sure we can read the resource. There's no * need to read the children names, evaluate defaults, and retrieve runtime attributes. */ readResourceOperation.attributesOnly(true); readResourceOperation.includeDefaults(false); readResourceOperation.includeRuntime(false); Result res = getASConnection().execute(readResourceOperation, AVAIL_OP_TIMEOUT_SECONDS); if (res != null && res.isSuccess()) { return AvailabilityType.UP; } if (context.getResourceType().isSupportsMissingAvailabilityType()) { if (res != null && res.isRolledBack() && res.getFailureDescription().startsWith("JBAS014807")) { getLog().info("Reporting MISSING resource: " + getPath()); return AvailabilityType.MISSING; } } if (res != null && res.isTimedout()) { return AvailabilityType.UNKNOWN; } return AvailabilityType.DOWN; } protected String getResourceDescription() { return context.getResourceType() + " [" + context.getResourceKey() + "]"; } private BaseServerComponent findServerComponent() { BaseComponent<?> component = this; while ((component != null) && !(component instanceof BaseServerComponent)) { component = (BaseComponent<?>) component.context.getParentResourceComponent(); } return (BaseServerComponent) component; } public BaseServerComponent getServerComponent() { return serverComponent; } /** * Gather measurement data * @see org.rhq.core.pluginapi.measurement.MeasurementFacet#getValues(org.rhq.core.domain.measurement.MeasurementReport, java.util.Set) */ @Override public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { for (MeasurementScheduleRequest req : metrics) { getMetricValue(report, req, null); } } /** * gets metric value for given request * @param report * @param req * @param explicitExpressions set of metric names that could be represented by expression instead of value on AS7 (can be null) * @return ReadMetricResult value that if different from 'Success' determines why we failed to read metric */ protected ReadMetricResult getMetricValue(MeasurementReport report, MeasurementScheduleRequest req, Set<String> explicitExpressions) { if (req.getName().startsWith(INTERNAL)) processPluginStats(req, report); else { // Metrics from the application server String reqName = req.getName(); boolean resolveExpression = false; if (reqName.startsWith(EXPRESSION)) { resolveExpression = true; reqName = reqName.substring(EXPRESSION_SIZE); } else if (explicitExpressions != null && explicitExpressions.contains(reqName)) { resolveExpression = true; } ComplexRequest complexRequest = null; Operation op; if (reqName.contains(":")) { complexRequest = ComplexRequest.create(reqName); op = new ReadAttribute(address, complexRequest.getProp()); } else { op = new ReadAttribute(address, reqName); } Result res = getASConnection().execute(op); if (!res.isSuccess()) { if (LOG.isDebugEnabled()) { LOG.debug("Getting metric [" + req.getName() + "] at [ " + address + "] failed: " + res.getFailureDescription()); } return ReadMetricResult.RequestFailed; } Object val = res.getResult(); if (val == null) // One of the AS7 ways of telling "This is not implemented" See also AS7-1454 return ReadMetricResult.Null; if (req.getDataType() == DataType.MEASUREMENT) { if (val instanceof String && ((String) val).startsWith("JBAS018003")) // AS7 way of saying "no value available" return ReadMetricResult.Null; try { if (complexRequest != null) { @SuppressWarnings("unchecked") Map<String, Number> myValues = (Map<String, Number>) val; for (String key : myValues.keySet()) { String sub = complexRequest.getSub(); if (key.equals(sub)) { addMetric2Report(report, req, myValues.get(key), resolveExpression); } } } else { addMetric2Report(report, req, val, resolveExpression); } } catch (NumberFormatException e) { if (LOG.isDebugEnabled()) { LOG.debug("Non numeric input for [" + req.getName() + "] : [" + val + "]"); } return ReadMetricResult.ResolveFailed; } } else if (req.getDataType() == DataType.TRAIT) { if (resolveExpression && val instanceof Map && ((Map) val).containsKey(EXPRESSION_VALUE_KEY)) { String expression = (String) ((Map) val).get(EXPRESSION_VALUE_KEY); ResolveExpression resolveExpressionOperation = new ResolveExpression(expression); Result result = getASConnection().execute(resolveExpressionOperation); if (!result.isSuccess()) { if (LOG.isDebugEnabled()) { LOG.debug("Skipping trait [" + req.getName() + "] in measurement report. Could not resolve expression [" + expression + "], failureDescription:" + result.getFailureDescription()); return ReadMetricResult.ResolveFailed; } } val = result.getResult(); } MeasurementDataTrait data = new MeasurementDataTrait(req, getStringValue(val)); report.addData(data); } } return ReadMetricResult.Success; } private void addMetric2Report(MeasurementReport report, MeasurementScheduleRequest req, Object val, boolean resolveExpression) { if (resolveExpression && val instanceof Map && ((Map) val).containsKey(EXPRESSION_VALUE_KEY)) { String expression = (String) ((Map) val).get(EXPRESSION_VALUE_KEY); ResolveExpression resolveExpressionOperation = new ResolveExpression(expression); Result result = getASConnection().execute(resolveExpressionOperation); if (!result.isSuccess()) { if (LOG.isDebugEnabled()) { LOG.debug("Skipping metric [" + req.getName() + "] in measurement report. Could not resolve expression [" + expression + "], failureDescription:" + result.getFailureDescription()); return; } } val = result.getResult(); } Double d = Double.parseDouble(getStringValue(val)); MeasurementDataNumeric data = new MeasurementDataNumeric(req, d); report.addData(data); } protected String getStringValue(Object val) { String realVal; if (val instanceof String) realVal = (String) val; else realVal = String.valueOf(val); return realVal; } /** * Return internal statistics data * @param req Schedule for the requested data * @param report report to add th data to. */ private void processPluginStats(MeasurementScheduleRequest req, MeasurementReport report) { String name = req.getName(); if (!name.startsWith(INTERNAL)) return; name = name.substring(INTERNAL_SIZE); PluginStats stats = PluginStats.getInstance(); MeasurementDataNumeric data; Double val; if (name.equals("mgmtRequests")) { val = (double) stats.getRequestCount(); } else if (name.equals("requestTime")) { val = (double) stats.getRequestTime(); } else if (name.equals("maxTime")) { val = (double) stats.getMaxTime(); } else val = Double.NaN; data = new MeasurementDataNumeric(req, val); report.addData(data); } @Override public ASConnection getASConnection() { return (this.testConnection != null) ? this.testConnection : getServerComponent().getASConnection(); } @Override public String getPath() { return path; } @Override public Configuration loadResourceConfiguration() throws Exception { ConfigurationDefinition configDef = context.getResourceType().getResourceConfigurationDefinition(); ConfigurationLoadDelegate delegate = new ConfigurationLoadDelegate(configDef, getASConnection(), address, includeRuntime); Configuration configuration = delegate.loadResourceConfiguration(); // Read server state Operation op = new Operation("whoami", getAddress()); Result res = getASConnection().execute(op); //:whoami might fail host controller resources, in that case use :read-resource operation //which is slower due to larger content returned but more reliable since every resource has it. if (!res.isSuccess()) { op = new Operation("read-resource", getAddress()); res = getASConnection().execute(op); } includeOOBMessages(res, configuration); return configuration; } protected static void includeOOBMessages(Result res, Configuration configuration) { if (res.isReloadRequired()) { PropertySimple oobMessage = new PropertySimple("__OOB", "The server needs a reload for the latest changes to come effective."); configuration.put(oobMessage); } if (res.isRestartRequired()) { PropertySimple oobMessage = new PropertySimple("__OOB", "The server needs a restart for the latest changes to come effective."); configuration.put(oobMessage); } } @Override public void updateResourceConfiguration(ConfigurationUpdateReport report) { ConfigurationDefinition configDef = context.getResourceType().getResourceConfigurationDefinition(); ConfigurationWriteDelegate delegate = new ConfigurationWriteDelegate(configDef, getASConnection(), address); delegate.updateResourceConfiguration(report); } @Override public void deleteResource() throws Exception { if (LOG.isDebugEnabled()) { LOG.debug("Removing AS7 resource [" + path + "]..."); } if (context.getResourceType().getName().equals(MANAGED_SERVER)) { // We need to do two steps because of AS7-4032 Operation stop = new Operation("stop", getAddress()); Result res = getASConnection().execute(stop); if (!res.isSuccess()) { throw new IllegalStateException("Managed server [" + path + "] is still running and can't be stopped, so it cannot be removed."); } } Operation op = new Remove(address); Result res = getASConnection().execute(op, 120); if (!res.isSuccess()) { throw new IllegalArgumentException("Delete for [" + path + "] failed: " + res.getFailureDescription()); } } @Override public CreateResourceReport createResource(CreateResourceReport report) { if (report.getPackageDetails() != null) { // Content deployment return deployContent(report); } else { ASConnection connection = getASConnection(); ConfigurationDefinition configDef = report.getResourceType().getResourceConfigurationDefinition(); // Check for the Highlander principle boolean isSingleton = report.getResourceType().isSingleton(); if (isSingleton) { // check if there is already a child with th desired type is present Configuration pluginConfig = report.getPluginConfiguration(); PropertySimple pathProperty = pluginConfig.getSimple("path"); if (path == null || path.isEmpty()) { report.setErrorMessage("No path property found in plugin configuration"); report.setStatus(CreateResourceStatus.INVALID_CONFIGURATION); return report; } ReadChildrenNames op = new ReadChildrenNames(address, pathProperty.getStringValue()); Result res = connection.execute(op); if (res.isSuccess()) { @SuppressWarnings("unchecked") List<String> entries = (List<String>) res.getResult(); if (!entries.isEmpty()) { report.setErrorMessage("Resource is a singleton, but there are already children " + entries + " please remove them and retry"); report.setStatus(CreateResourceStatus.FAILURE); return report; } } } // Allow to modify the configuration coming in from the RHQ server see also BZ 825120 if (report.getResourceType().getName().equals("Network Interface")) { Configuration configuration = report.getResourceConfiguration(); NetworkInterfaceComponent.preProcessCreateChildConfiguration(configuration); } CreateResourceDelegate delegate = new CreateResourceDelegate(configDef, connection, address); return delegate.createResource(report); } } /** * Deploy content to the remote server - this is one half of #createResource * @param report Create resource report that tells us what to do * @return report that tells us what has been done. */ protected CreateResourceReport deployContent(CreateResourceReport report) { ContentContext cctx = context.getContentContext(); ResourcePackageDetails details = report.getPackageDetails(); ContentServices contentServices = cctx.getContentServices(); String resourceTypeName = report.getResourceType().getName(); ASUploadConnection uploadConnection = new ASUploadConnection(getServerComponent().getASConnection(), details .getKey().getName()); OutputStream out = uploadConnection.getOutputStream(); if (out == null) { report.setStatus(CreateResourceStatus.FAILURE); report.setErrorMessage("An error occured while the agent was preparing for content download"); return report; } long size; try { size = contentServices.downloadPackageBitsForChildResource(cctx, resourceTypeName, details.getKey(), out); } catch (Exception e) { uploadConnection.cancelUpload(); report.setStatus(CreateResourceStatus.FAILURE); LOG.debug("Failed to pull package from server", e); report.setErrorMessage("An error occured while the agent was uploading the content for [" + details.getKey() + "]"); return report; } if (0L == size) { uploadConnection.cancelUpload(); report.setStatus(CreateResourceStatus.FAILURE); report.setErrorMessage("An error occured (0 bytes) while the agent was uploading the content for [" + details.getKey() + "]"); return report; } JsonNode uploadResult = uploadConnection.finishUpload(); if (verbose) { LOG.info(uploadResult); } if (ASUploadConnection.isErrorReply(uploadResult)) { report.setStatus(CreateResourceStatus.FAILURE); report.setErrorMessage(ASUploadConnection.getFailureDescription(uploadResult)); return report; } // Key is available from UI and CLI String fileName = details.getKey().getName(); String runtimeName = report.getPackageDetails().getDeploymentTimeConfiguration().getSimpleValue("runtimeName"); if (runtimeName == null || runtimeName.isEmpty()) { runtimeName = fileName; } JsonNode resultNode = uploadResult.get("result"); String hash = resultNode.get("BYTES_VALUE").getTextValue(); return runDeploymentMagicOnServer(report, runtimeName, fileName, hash); } /** * Do the actual fumbling with the domain api to deploy the uploaded content * @param report CreateResourceReport to report the result * @param runtimeName File name to use as runtime name * @param deploymentName Name of the deployment * @param hash Hash of the content bytes * @return the passed report with success or failure settings */ public CreateResourceReport runDeploymentMagicOnServer(CreateResourceReport report, String runtimeName, String deploymentName, String hash) { LOG.info("Deploying [" + deploymentName + " (runtimeName=" + runtimeName + ")] ..."); Deployer deployer = new Deployer(deploymentName, runtimeName, hash, getASConnection()); Result result = deployer.deployToServer(context.getResourceType().getName().contains("Standalone")); String resourceKey = deployer.getNewResourceKey(); if ((!result.isSuccess())) { String failureDescription = result.getFailureDescription(); report.setErrorMessage(failureDescription); report.setStatus(CreateResourceStatus.FAILURE); LOG.warn("Deploy of [" + runtimeName + "] failed: " + failureDescription); } else { report.setStatus(CreateResourceStatus.SUCCESS); report.setResourceName(runtimeName); report.setResourceKey(resourceKey); report.getPackageDetails().setSHA256(hash); report.getPackageDetails().setInstallationTimestamp(System.currentTimeMillis()); LOG.info("Deploy of [" + runtimeName + "] succeeded - Resource key is [" + resourceKey + "]."); } return report; } @Override public OperationResult invokeOperation(String name, Configuration parameters) throws Exception { String what; String op; if (name.contains(":")) { int colonPos = name.indexOf(':'); what = name.substring(0, colonPos); op = name.substring(colonPos + 1); } else { what = ""; // dummy value op = name; } Operation operation; Address theAddress = new Address(); if (what.equals("server-group")) { String groupName = parameters.getSimpleValue("name", ""); String profile = parameters.getSimpleValue("profile", "default"); theAddress.add("server-group", groupName); operation = new Operation(op, theAddress); operation.addAdditionalProperty("profile", profile); } else if (what.equals("destination")) { theAddress.add(address); String newName = parameters.getSimpleValue("name", ""); String type = parameters.getSimpleValue("type", "jms-queue").toLowerCase(); theAddress.add(type, newName); PropertyList jndiNamesProp = parameters.getList("entries"); if (jndiNamesProp == null || jndiNamesProp.getList().isEmpty()) { OperationResult fail = new OperationResult(); fail.setErrorMessage("No jndi bindings given"); return fail; } List<String> jndiNames = new ArrayList<String>(); for (Property p : jndiNamesProp.getList()) { PropertySimple ps = (PropertySimple) p; jndiNames.add(ps.getStringValue()); } operation = new Operation(op, theAddress); operation.addAdditionalProperty("entries", jndiNames); if (type.equals("jms-queue")) { PropertySimple ps = (PropertySimple) parameters.get("durable"); if (ps != null) { boolean durable = Boolean.parseBoolean(ps.getStringValue()); operation.addAdditionalProperty("durable", durable); } String selector = parameters.getSimpleValue("selector", ""); if (!selector.isEmpty()) operation.addAdditionalProperty("selector", selector); } } else if (what.equals("domain")) { operation = new Operation(op, new Address()); } else if (what.equals("subsystem")) { operation = new Operation(op, new Address(this.path)); } else { // We have a generic operation so we pass it literally // with the parameters it has. operation = new Operation(op, new Address((path))); for (Property prop : parameters.getProperties()) { if (prop instanceof PropertySimple) { PropertySimple ps = (PropertySimple) prop; if (ps.getStringValue() != null) { Object val = getObjectForProperty(ps, op); operation.addAdditionalProperty(ps.getName(), val); } } else if (prop instanceof PropertyList) { PropertyList pl = (PropertyList) prop; List<Object> items = new ArrayList<Object>(pl.getList().size()); // Loop over the inner elements of the list for (Property p2 : pl.getList()) { if (p2 instanceof PropertySimple) { PropertySimple ps = (PropertySimple) p2; if (ps.getStringValue() != null) { Object val = getObjectForPropertyList(ps, pl, op); items.add(val); } } } operation.addAdditionalProperty(pl.getName(), items); } else { LOG.error("PropertyMap for " + prop.getName() + " not yet supported"); } } } OperationResult operationResult = new OperationResult(); Result result = getASConnection().execute(operation); if (result == null) { operationResult.setErrorMessage("Connection was null - is the server running?"); return operationResult; } if (!result.isSuccess()) { operationResult.setErrorMessage(result.getFailureDescription()); } else { String tmp; if (result.getResult() == null) tmp = "-none provided by the server-"; else tmp = result.getResult().toString(); operationResult.setSimpleResult(tmp); } return operationResult; } /** * Return a value object for the passed property. The type is determined by looking at the operation definition * @param prop Property to evaluate * @param operationName Name of the operation to look at * @return Value or null on failure */ Object getObjectForProperty(PropertySimple prop, String operationName) { ConfigurationDefinition parameterDefinitions = getParameterDefinitionsForOperation(operationName); if (parameterDefinitions == null) return null; PropertyDefinition pd = parameterDefinitions.get(prop.getName()); if (pd instanceof PropertyDefinitionSimple) { PropertyDefinitionSimple pds = (PropertyDefinitionSimple) pd; return getObjectForProperty(prop, pds); } else { LOG.warn("Property [" + prop.getName() + "] is not understood yet"); return null; } } /** * Return a value object for the passed property, which is part of a list. The type is determined by * looking at the operation definition and PropertyList#getMemberDefinition * @param prop Property to evaluate * @param propertyList Outer list * @param operationName Name of the operation * @return Value or null on failure */ Object getObjectForPropertyList(PropertySimple prop, PropertyList propertyList, String operationName) { ConfigurationDefinition parameterDefinitions = getParameterDefinitionsForOperation(operationName); if (parameterDefinitions == null) return null; PropertyDefinition def = parameterDefinitions.get(propertyList.getName()); if (def instanceof PropertyDefinitionList) { PropertyDefinitionList definitionList = (PropertyDefinitionList) def; PropertyDefinition tmp = definitionList.getMemberDefinition(); if (tmp instanceof PropertyDefinitionSimple) { return getObjectForProperty(prop, (PropertyDefinitionSimple) tmp); } } return null; } /** * Return the parameter definition for the operation with the name passed * @param operationName Name of the operation to look for * @return A configuration definition or null on failure */ ConfigurationDefinition getParameterDefinitionsForOperation(String operationName) { ResourceType type = context.getResourceType(); Set<OperationDefinition> operationDefinitions = type.getOperationDefinitions(); for (OperationDefinition definition : operationDefinitions) { if (definition.getName().equals(operationName)) { return definition.getParametersConfigurationDefinition(); } } return null; } /** * Return a value object for the passed property with the passed definition * @param prop Property to evaluate * @param propDef Definition to determine the type from * @return The value object */ Object getObjectForProperty(PropertySimple prop, PropertyDefinitionSimple propDef) { PropertySimpleType type = propDef.getType(); return getObjectForProperty(prop, type); } /** * Return the object representation of the passed PropertySimple for the passed type * @param prop Property to evaluate * @param type Type to convert into * @return Converted object -- if no valid type is found, a String-value is returned. */ private Object getObjectForProperty(PropertySimple prop, PropertySimpleType type) { switch (type) { case STRING: return prop.getStringValue(); case INTEGER: return prop.getIntegerValue(); case BOOLEAN: return prop.getBooleanValue(); case LONG: return prop.getLongValue(); case FLOAT: return prop.getFloatValue(); case DOUBLE: return prop.getDoubleValue(); default: return prop.getStringValue(); } } ///// These two are used to 'inject' the connection and the path from tests. public void setConnection(ASConnection connection) { this.testConnection = connection; } public void setPath(String path) { this.path = path; this.address = new Address(path); } public Address getAddress() { return address; } protected String readAttribute(String name) throws Exception { return readAttribute(getAddress(), name); } protected String readAttribute(String name, int timeoutSec) throws Exception { return readAttribute(getAddress(), name, timeoutSec); } protected String readAttribute(Address address, String name) throws Exception { return readAttribute(address, name, String.class); } protected String readAttribute(Address address, String name, int timeoutSec) throws Exception { return readAttribute(address, name, String.class, timeoutSec); } protected <R> R readAttribute(Address address, String name, Class<R> resultType) throws Exception { return readAttribute(address, name, resultType, 10); } protected <R> R readAttribute(Address address, String name, Class<R> resultType, int timeoutSec) throws Exception { Operation op = new ReadAttribute(address, name); Result res = getASConnection().execute(op, timeoutSec); if (!res.isSuccess()) { if (res.isTimedout()) { throw new TimeoutException("Read attribute operation timed out"); } if (res.isRolledBack() && res.getFailureDescription().startsWith("JBAS013456")) { throw new UnauthorizedException("Failed to read attribute [" + name + "] of address [" + getAddress().getPath() + "] - response: " + res); } if (res.isRolledBack() && !res.getFailureDescription().startsWith("JBAS015135")) { // this means we've connected, authenticated, but still failed throw new ResultFailedException("Failed to read attribute [" + name + "] of address [" + getAddress().getPath() + "] - response: " + res); } if (res.isRolledBack() && res.getFailureDescription().startsWith("JBAS015135")) { // this means we've connected, authenticated, but still failed throw new SecurityRealmNotReadyException("Failed to read attribute [" + name + "] of address [" + getAddress().getPath() + "] - response: " + res); } throw new Exception("Failed to read attribute [" + name + "] of address [" + getAddress().getPath() + "] - response: " + res); } return resultType.cast(res.getResult()); } protected Address getServerAddress() { throw new UnsupportedOperationException(); } protected String getSocketBindingGroup() { throw new UnsupportedOperationException(); } protected void collectMulticastAddressTrait(MeasurementReport report, MeasurementScheduleRequest request) { Address jgroupsUdpStackAddress = new Address(getServerAddress()); jgroupsUdpStackAddress.add("subsystem", "jgroups"); jgroupsUdpStackAddress.add("stack", "udp"); jgroupsUdpStackAddress.add("transport", "TRANSPORT"); String socketBinding; try { socketBinding = readAttribute(jgroupsUdpStackAddress, "socket-binding"); } catch (Exception e) { socketBinding = null; } if (socketBinding != null) { Address jgroupsSocketBindingAddress = new Address(getServerAddress()); String socketBindingGroup = getSocketBindingGroup(); jgroupsSocketBindingAddress.add("socket-binding-group", socketBindingGroup); jgroupsSocketBindingAddress.add("socket-binding", socketBinding); String multicastHost = null; Integer multicastPort; try { try { @SuppressWarnings("unchecked") Map<String, String> map = readAttribute(jgroupsSocketBindingAddress, "multicast-address", Map.class); String expressionValue = map.get("EXPRESSION_VALUE"); int beginIndex = expressionValue.indexOf("${jboss.default.multicast.address"); if (beginIndex >= 0) { int endIndex = expressionValue.indexOf('}', beginIndex); if (endIndex >= 0) { String expression = expressionValue.substring(beginIndex + 2, endIndex); StartScriptConfiguration startScriptConfig = getServerComponent() .getStartScriptConfiguration(); List<String> startScriptArgs = startScriptConfig.getStartScriptArgs(); for (String startScriptArg : startScriptArgs) { if (startScriptArg.startsWith("-Djboss.default.multicast.address=")) { multicastHost = startScriptArg.substring("-Djboss.default.multicast.address=" .length()); break; } } if (multicastHost == null) { int colonIndex = expression.indexOf(':'); String defaultValue = (colonIndex >= 0) ? expression.substring(colonIndex + 1) : null; if (defaultValue != null) { multicastHost = defaultValue; } else { LOG.error( "Failed to resolve expression value [" + expressionValue + "] of 'multicast-address' attribute."); } } } } } catch (ClassCastException cce) { multicastHost = readAttribute(jgroupsSocketBindingAddress, "multicast-address"); } multicastPort = readAttribute(jgroupsSocketBindingAddress, "multicast-port", Integer.class); } catch (Exception e) { throw new RuntimeException("Failed to lookup multicast address for socket binding [" + socketBinding + "]."); } if (multicastHost != null && multicastPort != null) { String multicastAddress = multicastHost + ":" + multicastPort; MeasurementDataTrait data = new MeasurementDataTrait(request, multicastAddress); report.addData(data); } } } static enum ReadMetricResult { Success, RequestFailed, Null, ResolveFailed } private static class ComplexRequest { private String prop; private String sub; private ComplexRequest(String prop, String sub) { this.prop = prop; this.sub = sub; } public String getProp() { return prop; } public String getSub() { return sub; } public static ComplexRequest create(String requestName) { StringTokenizer tokenizer = new StringTokenizer(requestName, ":"); return new ComplexRequest(tokenizer.nextToken(), tokenizer.nextToken()); } } /** * Get the logger for AS7 plugin resource components. * * @return */ public static Log getLog() { return LOG; } public static String resourceTypeNameByRemovingProfileSuffix(String resourceTypeName) { if (resourceTypeName.length() > PROFILE_SUFFIX.length() && resourceTypeName .substring(resourceTypeName.length() - PROFILE_SUFFIX.length(), resourceTypeName.length()) .equals(PROFILE_SUFFIX)) { resourceTypeName = resourceTypeName.substring(0, resourceTypeName.length() - PROFILE_SUFFIX.length()); } return resourceTypeName; } }