modules/core/dbutils/src/main/java/org/rhq/core/db/ant/Base64.java | 319 ------- modules/core/dbutils/src/main/java/org/rhq/core/db/ant/MD5Task.java | 2 modules/core/util/src/main/java/org/rhq/core/util/Base64.java | 319 +++++++ modules/core/util/src/main/java/org/rhq/core/util/ByteUtil.java | 59 + modules/enterprise/remoting/cli/src/main/samples/add-as7-standalone-server-to-cluster.js | 455 ++++++++++ modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java | 2 modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java | 222 +++- 7 files changed, 1012 insertions(+), 366 deletions(-)
New commits: commit 70ea9ac32b250b0aa96db1215efe5f4720483745 Author: Lukas Krejci lkrejci@redhat.com Date: Fri Apr 27 22:20:40 2012 +0200
[BZ 801638] - adding a sample CLI script that can make an AS7 standalone server join a cluster (and copy over the deployments to it).
diff --git a/modules/enterprise/remoting/cli/src/main/samples/add-as7-standalone-server-to-cluster.js b/modules/enterprise/remoting/cli/src/main/samples/add-as7-standalone-server-to-cluster.js new file mode 100644 index 0000000..c629fe6 --- /dev/null +++ b/modules/enterprise/remoting/cli/src/main/samples/add-as7-standalone-server-to-cluster.js @@ -0,0 +1,455 @@ +/** + * This script can be used to add a standalone vJBoss AS7 server into a cluster. + * + * All the functions with names starting with an underscore are considered + * private. + * + * @author: Lukas Krejci + */ + +/** + * This function adds an AS7 server to a cluster with another AS7 instance, using + * the provided node name as its identifier. + * <p> + * This method only makes the new member use the same configuration as the existing + * member and synchronizes its jgroups, messaging and modcluster socket bindings + * with the cluster. Optionally it also copies over all the deployments to the + * new member. + * <p> + * The configurations are therefore assumed to be otherwise compatible - i.e. + * the infinispan cache containers should be configured correctly (or left at + * default values, which are configured correctly), etc. + * + * @param newAs7Resource the resource proxy of the AS7 instance to add + * @param newNodeName the node name, i.e. unique identification, of the new member + * in the cluster + * @param existingClusterMemberResource an AS7 instance that belongs to a cluster + * the new member should join into. + * @param copyDeployments whether or not to copy the deployments from the existing + * member to the new member + */ +function addToCluster(newAs7Resource, newNodeName, existingClusterMemberResource, copyDeployments) { + println("Reading config of the existing cluster member"); + var clusterConfig = _getClusterSignificantConfig(existingClusterMemberResource); + + println("Reading config of the new member"); + var memberConfig = _getClusterSignificantConfig(newAs7Resource); + + var memberResourceConfiguration = newAs7Resource.resourceConfiguration; + + if (memberConfig['config'] != clusterConfig['config']) { + println("The configurations of the servers differ.\n" + + "The new cluster member's configuration will be changed to match the configuration of the existing member."); + + //switch to the same configuration + var pluginConfig = newAs7Resource.pluginConfiguration; + pluginConfig.getSimple('config').setValue(clusterConfig['config']); + newAs7Resource.updatePluginConfiguration(pluginConfig); + + //we need to restart straight away so that we see the changes to the + //rest of the configuration caused by the change of current config. + println("Restarting the new cluster member to switch it to the new configuration."); + newAs7Resource.restart(); + + //refresh the resource + newAs7Resource = ProxyFactory.getResource(newAs7Resource.id); + + //refresh the cluster specific config after the restart with the new + //config + memberConfig = _getClusterSignificantConfig(newAs7Resource); + memberResourceConfiguration = newAs7Resource.resourceConfiguration; + } + + //now check what's the node name we see + if (memberConfig['node-name'] != newNodeName) { + println("Updating the node name of the new cluster member from '" + memberConfig['node-name'] + "' to '" + newNodeName + "'"); + _updateNodeName(memberResourceConfiguration, newNodeName); + newAs7Resource.updateResourceConfiguration(memberResourceConfiguration); + } + + //now apply the socket binding changes for jgroups and other cluster + //significant subsystems + //first find the socket binding group config in the new member + for(i in newAs7Resource.children) { + var child = newAs7Resource.children[i]; + if (child.resourceType.name == 'SocketBindingGroup' && + child.resourceType.plugin == 'jboss-as-7') { + + println("Updating socket bindings of jgroups, messaging and modcluster subsystems"); + + var portOffset = javascriptString(child.resourceConfiguration.getSimpleValue('port-offset', '0')); + var clusterMemberPortOffset = clusterConfig['port-offset']; + + var newConfig = child.resourceConfiguration.deepCopy(false); + + _updateSocketBindings(newConfig, portOffset, clusterMemberPortOffset, clusterConfig['jgroups']); + _updateSocketBindings(newConfig, portOffset, clusterMemberPortOffset, clusterConfig['messaging']); + _updateSocketBindings(newConfig, portOffset, clusterMemberPortOffset, clusterConfig['modcluster']); + + child.updateResourceConfiguration(newConfig); + } + } + + println("Restarting the new member for the new socket bindings to take effect."); + newAs7Resource.restart(); + + if (copyDeployments) { + println("Copying the deployments to the new cluster member..."); + copyDeployments(existingClusterMemberResource, newAs7Resource); + + println("Restarting the new cluster member."); + newAs7Resource.restart(); + } +} + +/** + * Copies all deployments from the source to the target. Both resources must + * be standalone AS7 servers. + * + * @param sourceAS7 the resource id or object of the source AS7 standalone instance + * @param targetAS7 the resource id or object of the target AS7 standalone instance + */ +function copyDeployments(sourceAS7, targetAS7) { + if (typeof sourceAS7 == 'object') { + sourceAS7 = sourceAS7.id; + } + + if (typeof targetAS7 == 'object') { + targetAS7 = targetAS7.id; + } + + var deploymentResourceType = ResourceTypeManager.getResourceTypeByNameAndPlugin('Deployment', 'jboss-as-7'); + + var deploymentsCrit = new ResourceCriteria; + deploymentsCrit.addFilterParentResourceId(sourceAS7); + deploymentsCrit.addFilterResourceTypeId(deploymentResourceType.id); + + var unlimitedPageControl = PageControl.unlimitedInstance; + + var sourceDeployments = ResourceManager.findResourcesByCriteria(deploymentsCrit); + var iterator = sourceDeployments.iterator(); + while (iterator.hasNext()) { + var deploymentResource = iterator.next(); + //get a resource proxy for easy access to configurations, etc. + deploymentResource = ProxyFactory.getResource(deploymentResource.id); + + println("Copying deployment " + deploymentResource.name); + + var installedPackage = ContentManager.getBackingPackageForResource(deploymentResource.id); + var content = ContentManager.getPackageBytes(deploymentResource.id, installedPackage.id); + + var runtimeName = deploymentResource.resourceConfiguration.getSimpleValue('runtime-name', deploymentResource.name); + + var deploymentConfiguration = new Configuration; + deploymentConfiguration.put(new PropertySimple('runtimeName', runtimeName)); + + //so now we have both metadata and the data of the deployment, let's + //push a copy of it to the target server + var history = ResourceFactoryManager.createPackageBackedResource(targetAS7, + deploymentResourceType.id, deploymentResource.name, + deploymentResource.pluginConfiguration, + installedPackage.packageVersion.generalPackage.name, + installedPackage.packageVersion.version, + installedPackage.packageVersion.architecture.id, + deploymentConfiguration, content, null); + + while (history.status.name() == 'IN_PROGRESS') { + java.lang.Thread.sleep(1000); + //the API for checking the create histories is kinda weird.. + var histories = ResourceFactoryManager.findCreateChildResourceHistory(targetAS7, null, null, unlimitedPageControl); + var hit = histories.iterator(); + var found = false; + while(hit.hasNext()) { + var h = hit.next(); + + if (h.id == history.id) { + history = h; + found = true; + break; + } + } + + if (!found) { + throw "The history object for the deployment seems to have disappeared, this is very strange."; + } + } + + println("Deployment finished with status: " + history.status.toString() + + (history.status.name() == 'SUCCESS' ? "." : (", error message: " + history.errorMessage + "."))); + } +} + +/** + * The config properties of AS7 can have a form of ${propertyName:defaultvalue}. + * Because we can't figure out the value of the property if it is defined, + * (or get at its default value), we return the following hash from this function + * { + * property : propertyName, + * value : defaultvalue + * } + * + * At least one of the keys in the above hash will have a value. + */ +function _parseValueFromExpr(expr) { + var strExpr = expr + ''; + if (strExpr.indexOf('${') == 0) { + var colonIdx = strExpr.indexOf(':'); + if (colonIdx == -1) { + return { 'property' : expr }; + } else { + var property = strExpr.substring(2, colonIdx); + var value = strExpr.substring(colonIdx + 1, strExpr.length - 1); + + return { 'property' : property, 'value' : value }; + } + } else { + return { 'value' : expr }; + } +} + +/** + * This converts the result of _parseValueFromExpr() function back into the + * ${property:defaultvalue} format. + */ +function _composeValueExpr(parsedValue) { + if (parsedValue.property == undefined) { + return parsedValue.value; + } else { + return '${' + parsedValue.property + ':' + parsedValue.value + '}'; + } +} + +function _updateNodeName(serverResourceConfiguration, newNodeName) { + //define it as a system prop + var systemProps = serverResourceConfiguration.getList('*2'); + if (systemProps == null) { + systemProps = new PropertyList('*2'); + serverResourceConfiguration.put(systemProps); + } + + var it = systemProps.list.iterator(); + var updated = false; + while (it.hasNext()) { + var systemProp = it.next(); + var systemPropName = systemProp.getSimpleValue('name', null); + if (systemPropName == 'jboss.node.name') { + var systemPropValue = systemProp.getSimple('value'); + if (systemPropValue == null) { + systemPropValue = new PropertySimple('value', newNodeName); + systemProp.put(systemPropValue); + } else { + systemPropValue.setValue(newNodeName); + } + + updated = true; + break; + } + } + + if (!updated) { + var systemProp = new PropertyMap('*:name'); + systemProp.put(new PropertySimple('name', 'jboss.node.name')); + systemProp.put(new PropertySimple('value', newNodeName)); + systemProps.add(systemProp); + } +} + +function _updateSocketBindings(socketBindingsConfig, portOffset, clusterMemberPortOffset, socketBindingConfig) { + portOffset = _parseValueFromExpr(portOffset); + clusterMemberPortOffset = _parseValueFromExpr(clusterMemberPortOffset); + + var portOffsetValue = portOffset.value != undefined ? portOffset.value : 0; + var clusterMemberPortOffsetValue = clusterMemberPortOffset.value != undefined ? + clusterMemberPortOffset.value : 0; + + var portOffsetDiff = clusterMemberPortOffsetValue - portOffsetValue; + + var ports = socketBindingsConfig.get('*'); + var portIterator = ports.list.iterator(); + + var appliedProperties = []; + + while (portIterator.hasNext()) { + var port = portIterator.next(); + + var name = port.getSimpleValue('name', null); + + if (socketBindingConfig[name] != undefined) { + //k, this is a significant config, port it over + + //compute the value of the ports + if (socketBindingConfig[name]['fixed-port'] == 'true') { + port.put(new PropertySimple('port:expr', socketBindingConfig[name]['port:expr'])); + port.put(new PropertySimple('multicast-port:expr', socketBindingConfig[name]['multicast-port:expr'])); + port.put(new PropertySimple('multicast-address', socketBindingConfig[name]['multicast-address'])); + port.put(new PropertySimple('fixed-port', 'true')); + } else { + var portExprToUse = _parseValueFromExpr(socketBindingConfig[name]['port:expr']); + if (portExprToUse.value != undefined) { + portExprToUse.value = portOffsetDiff + parseInt(portExprToUse.value) + ''; + } + + var multicastPortExprToUse = _parseValueFromExpr(socketBindingConfig[name]['multicast-port:expr']); + if (multicastPortExprToUse.value != undefined) { + multicastPortExprToUse.value = portOffsetDiff + parseInt(multicastPortExprToUse.value) + ''; + } + + port.put(new PropertySimple('port:expr', _composeValueExpr(portExprToUse))); + port.put(new PropertySimple('multicast-port:expr', _composeValueExpr(multicastPortExprToUse))); + port.put(new PropertySimple('multicast-address', socketBindingConfig[name]['multicast-address'])); + port.put(new PropertySimple('fixed-port', 'false')); + } + appliedProperties.push(name); + } + } + + //I need contains() and Rhino's Array object apparently doesn't have indexOf() + //which I could otherwise use. + appliedProperties = java.util.Arrays.asList(appliedProperties); + + //now add to the list the props that were not there + for(name in socketBindingConfig) { + if (appliedProperties.contains(name)) { + continue; + } + + var port = new PropertyMap; + ports.add(port); + + port.put(new PropertySimple('name', name)); + port.put(new PropertySimple('multicast-address', socketBindingConfig[name]['multicast-address'])); + port.put(new PropertySimple('fixed-port', socketBindingConfig[name]['fixed-port'])); + + var portExprToUse = _parseValueFromExpr(socketBindingConfig[name]['port:expr']); + if (portExprToUse.value != undefined && !socketBindingConfig[name]['fixed-port']) { + portExprToUse.value = portOffsetDiff + parseInt(portExprToUse.value) + ''; + } + + var multicastPortExprToUse = _parseValueFromExpr(socketBindingConfig[name]['multicast-port:expr']); + if (multicastPortExprToUse.value != undefined && !socketBindingConfig[name]['fixed-port']) { + multicastPortExprToUse.value = portOffsetDiff + parseInt(multicastPortExprToUse.value) + ''; + } + + port.put(new PropertySimple('port:expr'), _composeValueExpr(portExprToUse)); + port.put(new PropertySimple('multicast-port:expr', _composeValueExpr(multicastPortExprToUse))); + } +} + + +/** + * Returns a javascript hash of configuration properties significant for the + * cluster configuration. + * + * This method is quite simplistic - it merely reads out the important socket + * bindings and Infinispan configuration properties. + * + * It doesn't try to be smart about specifying which concrete caches and cache + * containers are used for individual subsystems like EJB3, JPA or web apps. + * + * @param resource the resource proxy of the AS7 + */ +function _getClusterSignificantConfig(as7Resource) { + var ret = {}; + + ret['config'] = javascriptString(as7Resource.pluginConfiguration.getSimpleValue('config', null)); + + ret['node-name'] = javascriptString(as7Resource.resourceConfiguration.getSimpleValue('node-name', null)); + + //the standalone server has a single socket binding group + for(var i in as7Resource.children) { + var child = as7Resource.children[i]; + if (child.resourceType.plugin != 'jboss-as-7') { + continue; + } + if (child.resourceType.name == 'SocketBindingGroup') { + ret['port-offset'] = javascriptString(child.resourceConfiguration.getSimpleValue('port-offset', '0')); + var ports = child.resourceConfiguration.get('*'); + var portIterator = ports.list.iterator(); + + var jgroups = {}; + var messaging = {}; + var modcluster = {}; + + ret['jgroups'] = jgroups; + ret['messaging'] = messaging; + ret['modcluster'] = modcluster; + + while (portIterator.hasNext()) { + var port = portIterator.next(); + var name = javascriptString(port.getSimpleValue('name', null)); + + if (name.indexOf('jgroups') == 0) { + jgroups[name] = _getSocketBinding(port); + } else if (name.indexOf('messaging') == 0) { + messaging[name] = _getSocketBinding(port); + } else if (name.indexOf('modcluster') == 0) { + modcluster[name] = _getSocketBinding(port); + } + } + } else if (child.resourceType.name == 'Infinispan') { + var ispn = {}; + ret['infinispan'] = ispn; + + //This has disappeared + //ispn['default-cache-container'] = javascriptString(child.defaultCacheContainer.value); + var cacheContainers = {}; + ispn['cache-containers'] = cacheContainers; + + for(cc in child.children) { + var cacheContainer = child.children[cc]; + + var caches = {}; + + cacheContainers[cacheContainer.name] = { + 'default-cache' : javascriptString(cacheContainer.resourceConfiguration.getSimpleValue('default-cache', null)), + 'aliases' : _asArray(cacheContainer.resourceConfiguration.get('aliases')), + 'caches' : caches + }; + + for (c in cacheContainer.children) { + var cache = cacheContainer.children[c]; + + caches[cache.name] = { + '_flavor' : javascriptString(cache.resourceConfiguration.getSimpleValue('_flavor', null)), + 'batching' : javascriptString(cache.resourceConfiguration.getSimpleValue('batching', null)), + 'indexing' : javascriptString(cache.resourceConfiguration.getSimpleValue('indexing', null)), + 'mode' : javascriptString(cache.resourceConfiguration.getSimpleValue('mode', null)) + }; + } + } + } + } + + return ret; +} + +function _getSocketBinding(port) { + return { + 'port:expr' : javascriptString(port.getSimpleValue('port:expr', '0')), + 'multicast-port:expr' : javascriptString(port.getSimpleValue('multicast-port:expr', null)), + 'multicast-address' : javascriptString(port.getSimpleValue('multicast-address', null)), + 'fixed-port' : javascriptString(port.getSimpleValue('fixed-port', null)) + }; +} + +function javascriptString(string) { + return string == null || string == undefined ? string : string + ''; +} + +function _asArray(propertyList) { + var ret = []; + if (propertyList == undefined || propertyList == null) { + return ret; + } + + var it = propertyList.list.iterator(); + while (it.hasNext()) { + var prop = it.next(); + + if (prop instanceof PropertySimple) { + ret.push(javascriptString(prop.stringValue)); + } + } + + return ret; +}
commit d3927476f7f8f4f6172a1d92ee636ee853f931f7 Author: Lukas Krejci lkrejci@redhat.com Date: Fri Apr 27 22:16:26 2012 +0200
[BZ 816593][BZ 816587] - Deployments now correctly advertise their content packages (we only support archived deployments for now). Also added support for retrieving the package bits.
diff --git a/modules/core/dbutils/src/main/java/org/rhq/core/db/ant/Base64.java b/modules/core/dbutils/src/main/java/org/rhq/core/db/ant/Base64.java deleted file mode 100644 index e01f0fb..0000000 --- a/modules/core/dbutils/src/main/java/org/rhq/core/db/ant/Base64.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2005-2008 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed 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 org.rhq.core.db.ant; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; - -/** - * Class to Base64 encode strings. - */ -public class Base64 { - private static final char[] S_BASE64CHAR = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', - 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', - '6', '7', '8', '9', '+', '/' }; - private static final char S_BASE64PAD = '='; - private static final byte[] S_DECODETABLE = new byte[128]; - - static { - for (int i = 0; i < S_DECODETABLE.length; i++) { - S_DECODETABLE[i] = Byte.MAX_VALUE; // 127 - } - - for (int i = 0; i < S_BASE64CHAR.length; i++) // 0 to 63 - { - S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i; - } - } - - private static int decode0(char[] ibuf, byte[] obuf, int wp) { - int outlen = 3; - if (ibuf[3] == S_BASE64PAD) { - outlen = 2; - } - - if (ibuf[2] == S_BASE64PAD) { - outlen = 1; - } - - int b0 = S_DECODETABLE[ibuf[0]]; - int b1 = S_DECODETABLE[ibuf[1]]; - int b2 = S_DECODETABLE[ibuf[2]]; - int b3 = S_DECODETABLE[ibuf[3]]; - switch (outlen) { - case 1: { - obuf[wp] = (byte) (((b0 << 2) & 0xfc) | ((b1 >> 4) & 0x3)); - return 1; - } - - case 2: { - obuf[wp++] = (byte) (((b0 << 2) & 0xfc) | ((b1 >> 4) & 0x3)); - obuf[wp] = (byte) (((b1 << 4) & 0xf0) | ((b2 >> 2) & 0xf)); - return 2; - } - - case 3: { - obuf[wp++] = (byte) (((b0 << 2) & 0xfc) | ((b1 >> 4) & 0x3)); - obuf[wp++] = (byte) (((b1 << 4) & 0xf0) | ((b2 >> 2) & 0xf)); - obuf[wp] = (byte) (((b2 << 6) & 0xc0) | (b3 & 0x3f)); - return 3; - } - - default: { - throw new RuntimeException("Internal Errror"); - } - } - } - - /** - */ - public static byte[] decode(char[] data, int off, int len) { - char[] ibuf = new char[4]; - int ibufcount = 0; - byte[] obuf = new byte[(len / 4 * 3) + 3]; - int obufcount = 0; - for (int i = off; i < (off + len); i++) { - char ch = data[i]; - if ((ch == S_BASE64PAD) || ((ch < S_DECODETABLE.length) && (S_DECODETABLE[ch] != Byte.MAX_VALUE))) { - ibuf[ibufcount++] = ch; - if (ibufcount == ibuf.length) { - ibufcount = 0; - obufcount += decode0(ibuf, obuf, obufcount); - } - } - } - - if (obufcount == obuf.length) { - return obuf; - } - - byte[] ret = new byte[obufcount]; - System.arraycopy(obuf, 0, ret, 0, obufcount); - return ret; - } - - /** - */ - public static byte[] decode(String data) { - char[] ibuf = new char[4]; - int ibufcount = 0; - byte[] obuf = new byte[(data.length() / 4 * 3) + 3]; - int obufcount = 0; - for (int i = 0; i < data.length(); i++) { - char ch = data.charAt(i); - if ((ch == S_BASE64PAD) || ((ch < S_DECODETABLE.length) && (S_DECODETABLE[ch] != Byte.MAX_VALUE))) { - ibuf[ibufcount++] = ch; - if (ibufcount == ibuf.length) { - ibufcount = 0; - obufcount += decode0(ibuf, obuf, obufcount); - } - } - } - - if (obufcount == obuf.length) { - return obuf; - } - - byte[] ret = new byte[obufcount]; - System.arraycopy(obuf, 0, ret, 0, obufcount); - return ret; - } - - /** - */ - public static void decode(char[] data, int off, int len, OutputStream ostream) throws IOException { - char[] ibuf = new char[4]; - int ibufcount = 0; - byte[] obuf = new byte[3]; - for (int i = off; i < (off + len); i++) { - char ch = data[i]; - if ((ch == S_BASE64PAD) || ((ch < S_DECODETABLE.length) && (S_DECODETABLE[ch] != Byte.MAX_VALUE))) { - ibuf[ibufcount++] = ch; - if (ibufcount == ibuf.length) { - ibufcount = 0; - int obufcount = decode0(ibuf, obuf, 0); - ostream.write(obuf, 0, obufcount); - } - } - } - } - - /** - */ - public static void decode(String data, OutputStream ostream) throws IOException { - char[] ibuf = new char[4]; - int ibufcount = 0; - byte[] obuf = new byte[3]; - for (int i = 0; i < data.length(); i++) { - char ch = data.charAt(i); - if ((ch == S_BASE64PAD) || ((ch < S_DECODETABLE.length) && (S_DECODETABLE[ch] != Byte.MAX_VALUE))) { - ibuf[ibufcount++] = ch; - if (ibufcount == ibuf.length) { - ibufcount = 0; - int obufcount = decode0(ibuf, obuf, 0); - ostream.write(obuf, 0, obufcount); - } - } - } - } - - /** - * Returns base64 representation of specified byte array. - */ - public static String encode(byte[] data) { - return encode(data, 0, data.length); - } - - /** - * Returns base64 representation of specified byte array. - */ - public static String encode(byte[] data, int off, int len) { - if (len <= 0) { - return ""; - } - - char[] out = new char[(len / 3 * 4) + 4]; - int rindex = off; - int windex = 0; - int rest = len - off; - while (rest >= 3) { - int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff); - out[windex++] = S_BASE64CHAR[i >> 18]; - out[windex++] = S_BASE64CHAR[(i >> 12) & 0x3f]; - out[windex++] = S_BASE64CHAR[(i >> 6) & 0x3f]; - out[windex++] = S_BASE64CHAR[i & 0x3f]; - rindex += 3; - rest -= 3; - } - - if (rest == 1) { - int i = data[rindex] & 0xff; - out[windex++] = S_BASE64CHAR[i >> 2]; - out[windex++] = S_BASE64CHAR[(i << 4) & 0x3f]; - out[windex++] = S_BASE64PAD; - out[windex++] = S_BASE64PAD; - } else if (rest == 2) { - int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff); - out[windex++] = S_BASE64CHAR[i >> 10]; - out[windex++] = S_BASE64CHAR[(i >> 4) & 0x3f]; - out[windex++] = S_BASE64CHAR[(i << 2) & 0x3f]; - out[windex++] = S_BASE64PAD; - } - - return new String(out, 0, windex); - } - - /** - * Outputs base64 representation of the specified byte array to a byte stream. - */ - public static void encode(byte[] data, int off, int len, OutputStream ostream) throws IOException { - if (len <= 0) { - return; - } - - byte[] out = new byte[4]; - int rindex = off; - int rest = len - off; - while (rest >= 3) { - int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff); - out[0] = (byte) S_BASE64CHAR[i >> 18]; - out[1] = (byte) S_BASE64CHAR[(i >> 12) & 0x3f]; - out[2] = (byte) S_BASE64CHAR[(i >> 6) & 0x3f]; - out[3] = (byte) S_BASE64CHAR[i & 0x3f]; - ostream.write(out, 0, 4); - rindex += 3; - rest -= 3; - } - - if (rest == 1) { - int i = data[rindex] & 0xff; - out[0] = (byte) S_BASE64CHAR[i >> 2]; - out[1] = (byte) S_BASE64CHAR[(i << 4) & 0x3f]; - out[2] = (byte) S_BASE64PAD; - out[3] = (byte) S_BASE64PAD; - ostream.write(out, 0, 4); - } else if (rest == 2) { - int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff); - out[0] = (byte) S_BASE64CHAR[i >> 10]; - out[1] = (byte) S_BASE64CHAR[(i >> 4) & 0x3f]; - out[2] = (byte) S_BASE64CHAR[(i << 2) & 0x3f]; - out[3] = (byte) S_BASE64PAD; - ostream.write(out, 0, 4); - } - } - - /** - * Outputs base64 representation of the specified byte array to a character stream. - */ - public static void encode(byte[] data, int off, int len, Writer writer) throws IOException { - if (len <= 0) { - return; - } - - char[] out = new char[4]; - int rindex = off; - int rest = len - off; - int output = 0; - while (rest >= 3) { - int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff); - out[0] = S_BASE64CHAR[i >> 18]; - out[1] = S_BASE64CHAR[(i >> 12) & 0x3f]; - out[2] = S_BASE64CHAR[(i >> 6) & 0x3f]; - out[3] = S_BASE64CHAR[i & 0x3f]; - writer.write(out, 0, 4); - rindex += 3; - rest -= 3; - output += 4; - if ((output % 76) == 0) { - writer.write("\n"); - } - } - - if (rest == 1) { - int i = data[rindex] & 0xff; - out[0] = S_BASE64CHAR[i >> 2]; - out[1] = S_BASE64CHAR[(i << 4) & 0x3f]; - out[2] = S_BASE64PAD; - out[3] = S_BASE64PAD; - writer.write(out, 0, 4); - } else if (rest == 2) { - int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff); - out[0] = S_BASE64CHAR[i >> 10]; - out[1] = S_BASE64CHAR[(i >> 4) & 0x3f]; - out[2] = S_BASE64CHAR[(i << 2) & 0x3f]; - out[3] = S_BASE64PAD; - writer.write(out, 0, 4); - } - } -} \ No newline at end of file diff --git a/modules/core/dbutils/src/main/java/org/rhq/core/db/ant/MD5Task.java b/modules/core/dbutils/src/main/java/org/rhq/core/db/ant/MD5Task.java index 824b777..2de2c86 100644 --- a/modules/core/dbutils/src/main/java/org/rhq/core/db/ant/MD5Task.java +++ b/modules/core/dbutils/src/main/java/org/rhq/core/db/ant/MD5Task.java @@ -24,6 +24,8 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task;
+import org.rhq.core.util.Base64; + /** * Encrypts a string. You can optionally have it base64 encode the MD5 string (which is the default). Set the "base64" * attribute to "false" if you do not want the string base64 encoded. diff --git a/modules/core/util/src/main/java/org/rhq/core/util/Base64.java b/modules/core/util/src/main/java/org/rhq/core/util/Base64.java new file mode 100644 index 0000000..34a3035 --- /dev/null +++ b/modules/core/util/src/main/java/org/rhq/core/util/Base64.java @@ -0,0 +1,319 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed 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 org.rhq.core.util; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +/** + * Class to Base64 encode strings. + */ +public class Base64 { + private static final char[] S_BASE64CHAR = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '+', '/' }; + private static final char S_BASE64PAD = '='; + private static final byte[] S_DECODETABLE = new byte[128]; + + static { + for (int i = 0; i < S_DECODETABLE.length; i++) { + S_DECODETABLE[i] = Byte.MAX_VALUE; // 127 + } + + for (int i = 0; i < S_BASE64CHAR.length; i++) // 0 to 63 + { + S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i; + } + } + + private static int decode0(char[] ibuf, byte[] obuf, int wp) { + int outlen = 3; + if (ibuf[3] == S_BASE64PAD) { + outlen = 2; + } + + if (ibuf[2] == S_BASE64PAD) { + outlen = 1; + } + + int b0 = S_DECODETABLE[ibuf[0]]; + int b1 = S_DECODETABLE[ibuf[1]]; + int b2 = S_DECODETABLE[ibuf[2]]; + int b3 = S_DECODETABLE[ibuf[3]]; + switch (outlen) { + case 1: { + obuf[wp] = (byte) (((b0 << 2) & 0xfc) | ((b1 >> 4) & 0x3)); + return 1; + } + + case 2: { + obuf[wp++] = (byte) (((b0 << 2) & 0xfc) | ((b1 >> 4) & 0x3)); + obuf[wp] = (byte) (((b1 << 4) & 0xf0) | ((b2 >> 2) & 0xf)); + return 2; + } + + case 3: { + obuf[wp++] = (byte) (((b0 << 2) & 0xfc) | ((b1 >> 4) & 0x3)); + obuf[wp++] = (byte) (((b1 << 4) & 0xf0) | ((b2 >> 2) & 0xf)); + obuf[wp] = (byte) (((b2 << 6) & 0xc0) | (b3 & 0x3f)); + return 3; + } + + default: { + throw new RuntimeException("Internal Errror"); + } + } + } + + /** + */ + public static byte[] decode(char[] data, int off, int len) { + char[] ibuf = new char[4]; + int ibufcount = 0; + byte[] obuf = new byte[(len / 4 * 3) + 3]; + int obufcount = 0; + for (int i = off; i < (off + len); i++) { + char ch = data[i]; + if ((ch == S_BASE64PAD) || ((ch < S_DECODETABLE.length) && (S_DECODETABLE[ch] != Byte.MAX_VALUE))) { + ibuf[ibufcount++] = ch; + if (ibufcount == ibuf.length) { + ibufcount = 0; + obufcount += decode0(ibuf, obuf, obufcount); + } + } + } + + if (obufcount == obuf.length) { + return obuf; + } + + byte[] ret = new byte[obufcount]; + System.arraycopy(obuf, 0, ret, 0, obufcount); + return ret; + } + + /** + */ + public static byte[] decode(String data) { + char[] ibuf = new char[4]; + int ibufcount = 0; + byte[] obuf = new byte[(data.length() / 4 * 3) + 3]; + int obufcount = 0; + for (int i = 0; i < data.length(); i++) { + char ch = data.charAt(i); + if ((ch == S_BASE64PAD) || ((ch < S_DECODETABLE.length) && (S_DECODETABLE[ch] != Byte.MAX_VALUE))) { + ibuf[ibufcount++] = ch; + if (ibufcount == ibuf.length) { + ibufcount = 0; + obufcount += decode0(ibuf, obuf, obufcount); + } + } + } + + if (obufcount == obuf.length) { + return obuf; + } + + byte[] ret = new byte[obufcount]; + System.arraycopy(obuf, 0, ret, 0, obufcount); + return ret; + } + + /** + */ + public static void decode(char[] data, int off, int len, OutputStream ostream) throws IOException { + char[] ibuf = new char[4]; + int ibufcount = 0; + byte[] obuf = new byte[3]; + for (int i = off; i < (off + len); i++) { + char ch = data[i]; + if ((ch == S_BASE64PAD) || ((ch < S_DECODETABLE.length) && (S_DECODETABLE[ch] != Byte.MAX_VALUE))) { + ibuf[ibufcount++] = ch; + if (ibufcount == ibuf.length) { + ibufcount = 0; + int obufcount = decode0(ibuf, obuf, 0); + ostream.write(obuf, 0, obufcount); + } + } + } + } + + /** + */ + public static void decode(String data, OutputStream ostream) throws IOException { + char[] ibuf = new char[4]; + int ibufcount = 0; + byte[] obuf = new byte[3]; + for (int i = 0; i < data.length(); i++) { + char ch = data.charAt(i); + if ((ch == S_BASE64PAD) || ((ch < S_DECODETABLE.length) && (S_DECODETABLE[ch] != Byte.MAX_VALUE))) { + ibuf[ibufcount++] = ch; + if (ibufcount == ibuf.length) { + ibufcount = 0; + int obufcount = decode0(ibuf, obuf, 0); + ostream.write(obuf, 0, obufcount); + } + } + } + } + + /** + * Returns base64 representation of specified byte array. + */ + public static String encode(byte[] data) { + return encode(data, 0, data.length); + } + + /** + * Returns base64 representation of specified byte array. + */ + public static String encode(byte[] data, int off, int len) { + if (len <= 0) { + return ""; + } + + char[] out = new char[(len / 3 * 4) + 4]; + int rindex = off; + int windex = 0; + int rest = len - off; + while (rest >= 3) { + int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff); + out[windex++] = S_BASE64CHAR[i >> 18]; + out[windex++] = S_BASE64CHAR[(i >> 12) & 0x3f]; + out[windex++] = S_BASE64CHAR[(i >> 6) & 0x3f]; + out[windex++] = S_BASE64CHAR[i & 0x3f]; + rindex += 3; + rest -= 3; + } + + if (rest == 1) { + int i = data[rindex] & 0xff; + out[windex++] = S_BASE64CHAR[i >> 2]; + out[windex++] = S_BASE64CHAR[(i << 4) & 0x3f]; + out[windex++] = S_BASE64PAD; + out[windex++] = S_BASE64PAD; + } else if (rest == 2) { + int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff); + out[windex++] = S_BASE64CHAR[i >> 10]; + out[windex++] = S_BASE64CHAR[(i >> 4) & 0x3f]; + out[windex++] = S_BASE64CHAR[(i << 2) & 0x3f]; + out[windex++] = S_BASE64PAD; + } + + return new String(out, 0, windex); + } + + /** + * Outputs base64 representation of the specified byte array to a byte stream. + */ + public static void encode(byte[] data, int off, int len, OutputStream ostream) throws IOException { + if (len <= 0) { + return; + } + + byte[] out = new byte[4]; + int rindex = off; + int rest = len - off; + while (rest >= 3) { + int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff); + out[0] = (byte) S_BASE64CHAR[i >> 18]; + out[1] = (byte) S_BASE64CHAR[(i >> 12) & 0x3f]; + out[2] = (byte) S_BASE64CHAR[(i >> 6) & 0x3f]; + out[3] = (byte) S_BASE64CHAR[i & 0x3f]; + ostream.write(out, 0, 4); + rindex += 3; + rest -= 3; + } + + if (rest == 1) { + int i = data[rindex] & 0xff; + out[0] = (byte) S_BASE64CHAR[i >> 2]; + out[1] = (byte) S_BASE64CHAR[(i << 4) & 0x3f]; + out[2] = (byte) S_BASE64PAD; + out[3] = (byte) S_BASE64PAD; + ostream.write(out, 0, 4); + } else if (rest == 2) { + int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff); + out[0] = (byte) S_BASE64CHAR[i >> 10]; + out[1] = (byte) S_BASE64CHAR[(i >> 4) & 0x3f]; + out[2] = (byte) S_BASE64CHAR[(i << 2) & 0x3f]; + out[3] = (byte) S_BASE64PAD; + ostream.write(out, 0, 4); + } + } + + /** + * Outputs base64 representation of the specified byte array to a character stream. + */ + public static void encode(byte[] data, int off, int len, Writer writer) throws IOException { + if (len <= 0) { + return; + } + + char[] out = new char[4]; + int rindex = off; + int rest = len - off; + int output = 0; + while (rest >= 3) { + int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff); + out[0] = S_BASE64CHAR[i >> 18]; + out[1] = S_BASE64CHAR[(i >> 12) & 0x3f]; + out[2] = S_BASE64CHAR[(i >> 6) & 0x3f]; + out[3] = S_BASE64CHAR[i & 0x3f]; + writer.write(out, 0, 4); + rindex += 3; + rest -= 3; + output += 4; + if ((output % 76) == 0) { + writer.write("\n"); + } + } + + if (rest == 1) { + int i = data[rindex] & 0xff; + out[0] = S_BASE64CHAR[i >> 2]; + out[1] = S_BASE64CHAR[(i << 4) & 0x3f]; + out[2] = S_BASE64PAD; + out[3] = S_BASE64PAD; + writer.write(out, 0, 4); + } else if (rest == 2) { + int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff); + out[0] = S_BASE64CHAR[i >> 10]; + out[1] = S_BASE64CHAR[(i >> 4) & 0x3f]; + out[2] = S_BASE64CHAR[(i << 2) & 0x3f]; + out[3] = S_BASE64PAD; + writer.write(out, 0, 4); + } + } +} \ No newline at end of file diff --git a/modules/core/util/src/main/java/org/rhq/core/util/ByteUtil.java b/modules/core/util/src/main/java/org/rhq/core/util/ByteUtil.java new file mode 100644 index 0000000..3600d7e --- /dev/null +++ b/modules/core/util/src/main/java/org/rhq/core/util/ByteUtil.java @@ -0,0 +1,59 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2012 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.core.util; + +/** + * Utilities for working with bytes and byte arrays. + * + * @author Lukas Krejci + */ +public class ByteUtil { + + private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); + + private ByteUtil() { + + } + + /** + * Converts the byte array into a string of hexadecimal numbers. + * Each byte in the array is represented by exactly two characters + * in the resulting string, which form a hexadecimal number with the + * value that represents the bits in the byte. + * + * @param bytes + * @return a string of hexadecimal numbers representing the bytes + */ + public static String toHexString(byte[] bytes) { + char[] str = new char[bytes.length * 2]; + + for (int i = 0; i < bytes.length; ++i) { + byte b = bytes[i]; + + int lower = b & 0x0f; + int upper = (b & 0xf0) >>> 4; + + str[2 * i] = HEX_DIGITS[upper]; + str[2 * i + 1] = HEX_DIGITS[lower]; + } + + return new String(str); + } +} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java index 09c25cd..851937b 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java @@ -43,12 +43,12 @@ import org.rhq.core.clientapi.server.core.ConnectAgentRequest; import org.rhq.core.clientapi.server.core.ConnectAgentResults; import org.rhq.core.clientapi.server.core.CoreServerService; import org.rhq.core.clientapi.server.core.PingRequest; -import org.rhq.core.db.ant.Base64; import org.rhq.core.domain.cloud.PartitionEventType; import org.rhq.core.domain.cloud.Server; import org.rhq.core.domain.cloud.composite.FailoverListComposite; import org.rhq.core.domain.plugin.Plugin; import org.rhq.core.domain.resource.Agent; +import org.rhq.core.util.Base64; import org.rhq.core.util.exception.WrappedRemotingException; import org.rhq.enterprise.communications.command.client.RemoteInputStream; import org.rhq.enterprise.server.alert.engine.AlertConditionCacheManagerLocal; diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java index f8d48ec..9771cee 100644 --- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java +++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java @@ -1,9 +1,13 @@ package org.rhq.modules.plugins.jbossas7;
+import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -25,9 +29,17 @@ import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.pluginapi.content.ContentFacet; import org.rhq.core.pluginapi.content.ContentServices; +import org.rhq.core.pluginapi.content.FileContentDelegate; import org.rhq.core.pluginapi.inventory.CreateResourceReport; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceComponent; +import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.operation.OperationFacet; import org.rhq.core.pluginapi.operation.OperationResult; +import org.rhq.core.util.Base64; +import org.rhq.core.util.ByteUtil; +import org.rhq.core.util.file.ContentFileInfo; +import org.rhq.core.util.file.JarContentFileInfo; import org.rhq.modules.plugins.jbossas7.json.Address; import org.rhq.modules.plugins.jbossas7.json.ComplexResult; import org.rhq.modules.plugins.jbossas7.json.Operation; @@ -40,10 +52,17 @@ import org.rhq.modules.plugins.jbossas7.json.Result; * Deal with deployments * @author Heiko W. Rupp */ -public class DeploymentComponent extends BaseComponent implements OperationFacet, ContentFacet { +public class DeploymentComponent extends BaseComponent<ResourceComponent<?>> implements OperationFacet, ContentFacet {
private boolean verbose = ASConnection.verbose; - + private File deploymentFile; + + @Override + public void start(ResourceContext<ResourceComponent<?>> context) throws InvalidPluginConfigurationException, Exception { + super.start(context); + deploymentFile = determineDeploymentFile(); + } + @Override public AvailabilityType getAvailability() { Operation op = new ReadAttribute(getAddress(),"enabled"); @@ -170,59 +189,170 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
@Override public RemovePackagesResponse removePackages(Set<ResourcePackageDetails> packages) { - return null; // TODO: Customise this generated block + RemovePackagesResponse response = new RemovePackagesResponse(ContentResponseResult.NOT_PERFORMED); + response.setOverallRequestErrorMessage("Removal of packages backing the deployments is not supported."); + return response; }
@Override public Set<ResourcePackageDetails> discoverDeployedPackages(PackageType type) { + if (deploymentFile == null) { + return Collections.emptySet(); + } + + String name = getDeploymentName(); + String sha256 = getSHA256(deploymentFile); + String version = getVersion(sha256); + + PackageDetailsKey key = new PackageDetailsKey(name, version, type.getName(), "noarch"); + ResourcePackageDetails details = new ResourcePackageDetails(key); + + details.setDisplayVersion(getDisplayVersion(deploymentFile)); + details.setFileCreatedDate(null); //TODO figure this out from Sigar somehow? + details.setFileName(name); + details.setFileSize(deploymentFile.length()); + details.setInstallationTimestamp(deploymentFile.lastModified()); + details.setLocation(deploymentFile.getAbsolutePath()); + details.setSHA256(sha256); + + return Collections.singleton(details); + }
- Set<ResourcePackageDetails> details = new HashSet<ResourcePackageDetails>(); - - // PackageType = "Deployment" - Address address1 = getAddress().getParent(); - Operation op = new ReadChildrenResources(address1,"deployment"); - ComplexResult cres = getASConnection().executeComplex(op); - - if (cres==null) - return details; - - if (!cres.isSuccess()) - return details; - - Map<String,Object> deployments = cres.getResult(); - for (String key : deployments.keySet()) { - Map<String,Object> deployment = (Map<String, Object>) deployments.get(key); - log.info("Discover package [" + key + "] for type [" + type + "]"); - - List<Map> contentList = (List<Map>) deployment.get("content"); - if (contentList!=null) { - - Map<String,Map> hashMap = contentList.get(0); - Map<String,String> bvMap = hashMap.get("hash"); - String content; - if (bvMap!=null) { - content = bvMap.get("BYTES_VALUE"); - } - else { - content = hashMap.get("relative-to") + File.separator + hashMap.get("path"); - } - PackageDetailsKey pdKey = new PackageDetailsKey(key, - content, // no way to obtain the user defined version from the server - type.getName(), - "noarch" - ); - ResourcePackageDetails detail = new ResourcePackageDetails(pdKey); - detail.setSHA256(content); - - details.add(detail); + @Override + public InputStream retrievePackageBits(ResourcePackageDetails packageDetails) { + try { + return deploymentFile == null ? new ByteArrayInputStream(new byte[0]) : new FileInputStream(deploymentFile); + } catch (FileNotFoundException e) { + throw new IllegalStateException("Deployment file seems to have disappeared"); + } + } + + private File determineDeploymentFile() { + Operation op = new ReadAttribute(getAddress(), "content"); + Result result = getASConnection().execute(op); + + @SuppressWarnings("unchecked") + List<Map<String, Object>> content = (List<Map<String, Object>>) result.getResult(); + if (content.isEmpty()) { + log.warn("Could not determine the location of the deployment - the content descriptor wasn't found for deployment" + getAddress() + "."); + return null; + } + + Boolean archive = (Boolean) content.get(0).get("archive"); + if (archive != null && !archive) { + log.debug("Exploded deployments not supported for retrieving the content."); + return null; + } + + File deploymentFile = null; + if (content.get(0).containsKey("path")) { + String path = (String) content.get(0).get("path"); + String relativeTo = (String) content.get(0).get("relative-to"); + deploymentFile = getDeploymentFileFromPath(relativeTo, path); + } else if (content.get(0).containsKey("hash")) { + @SuppressWarnings("unchecked") + String base64Hash = ((Map<String, String>)content.get(0).get("hash")).get("BYTES_VALUE"); + byte[] hash = Base64.decode(base64Hash); + Address contentPathAddress = new Address("core-service", "server-environment"); + op = new ReadAttribute(contentPathAddress, "content-dir"); + result = getASConnection().execute(op); + + String contentPath = (String) result.getResult(); + deploymentFile = getDeploymentFileFromHash(hash, contentPath); + } else { + log.warn("Failed to determine the deployment file of " + getAddress() + " deployment. Neither path nor hash attributes were available."); + } + + return deploymentFile; + } + + private File getDeploymentFileFromPath(String relativeTo, String path) { + if (relativeTo == null || relativeTo.trim().isEmpty()) { + return new File(path); + } else { + //Transform the property name into the name used in the server environment + if (relativeTo.startsWith("jboss.server")) { + relativeTo = relativeTo.substring("jboss.server.".length()); + relativeTo = relativeTo.replace('.', '-'); + + //now look for the transformed relativeTo in the server environment + Operation op = new ReadAttribute(new Address("core-service", "server-environment"), relativeTo); + Result res = getASConnection().execute(op); + + relativeTo = (String) res.getResult(); + + return new File(relativeTo, path); + } else { + log.warn("Unsupported property used as a base for deployment path specification: " + relativeTo); + return null; + } + } + } + + private File getDeploymentFileFromHash(byte[] hash, String contentPath) { + String hashStr = ByteUtil.toHexString(hash); + + String head = hashStr.substring(0, 2); + String tail = hashStr.substring(2); + + File hashPath = new File(new File(head, tail), "content"); + + return new File(contentPath, hashPath.getPath()); + } + + /** + * Retrieve SHA256 for a deployed app. + * + * Shamelessly copied from the AS5 plugin. + * + * @param file application file + * @return SHA256 of the content + */ + private String getSHA256(File file) { + String sha256 = null; + + try { + FileContentDelegate fileContentDelegate = new FileContentDelegate(); + sha256 = fileContentDelegate.retrieveDeploymentSHA(file, context.getResourceDataDirectory()); + } catch (Exception iex) { + if (log.isDebugEnabled()) { + log.debug("Problem calculating digest of package [" + file.getPath() + "]." + iex.getMessage()); } }
- return details; + return sha256; }
- @Override - public InputStream retrievePackageBits(ResourcePackageDetails packageDetails) { - return null; // TODO: Customise this generated block + /** + * Shamelessly copied from the AS5 plugin. + * + * @param sha256 + * @return + */ + private static String getVersion(String sha256) { + return "[sha256=" + sha256 + "]"; + } + + /** + * Retrieve the display version for the component. The display version should be stored + * in the manifest of the application (implementation and/or specification version). + * It will attempt to retrieve the version for both archived or exploded deployments. + * + * Shamelessly copied from the AS5 plugin + * + * @param file component file + * @return + */ + private String getDisplayVersion(File file) { + //JarContentFileInfo extracts the version from archived and exploded deployments + ContentFileInfo contentFileInfo = new JarContentFileInfo(file); + return contentFileInfo.getVersion(null); + } + + private String getDeploymentName() { + Operation op = new ReadAttribute(getAddress(), "name"); + Result res = getASConnection().execute(op); + + return (String) res.getResult(); } }
rhq-commits@lists.fedorahosted.org