package org.rhq.plugins.byteman;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.byteman.agent.submit.Submit;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.content.PackageDetailsKey;
import org.rhq.core.domain.content.PackageType;
import org.rhq.core.domain.content.transfer.ContentResponseResult;
import org.rhq.core.domain.content.transfer.DeployIndividualPackageResponse;
import org.rhq.core.domain.content.transfer.DeployPackageStep;
import org.rhq.core.domain.content.transfer.DeployPackagesResponse;
import org.rhq.core.domain.content.transfer.RemoveIndividualPackageResponse;
import org.rhq.core.domain.content.transfer.RemovePackagesResponse;
import org.rhq.core.domain.content.transfer.ResourcePackageDetails;
import org.rhq.core.domain.measurement.AvailabilityType;
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.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.ContentFacet;
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.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.util.MessageDigestGenerator;
import org.rhq.core.util.exception.ThrowableUtil;
/**
* Component that represents the remote Byteman agent listening for requests.
*
* A note about adding boot/system classpath jars and the content this component supports related to that feature.
* There are operations this component supports to add jars to the byteman classpath. Those operations tell the
* byteman agent to add jars, but those jars must already exist and be accessible for the byteman agent to do so.
* This component will not manage the jars added via the operations. If, however, a user pushes jar content
* from the RHQ server to this plugin via the content facet, those jars will be managed by this component as they
* are added to the byteman agent.
*
* @author John Mazzitelli
*/
public class BytemanAgentComponent implements ResourceComponent<BytemanAgentComponent>, MeasurementFacet,
OperationFacet, ContentFacet, CreateChildResourceFacet, ConfigurationFacet {
private static final String PKG_TYPE_NAME_BOOT_JAR = "bootJar";
private static final String PKG_TYPE_NAME_SYSTEM_JAR = "systemJar";
private final Log log = LogFactory.getLog(BytemanAgentComponent.class);
private ResourceContext<BytemanAgentComponent> resourceContext;
private Submit bytemanClient;
private File bootJarsDataDir; // where managed boot jars will be persisted
private File systemJarsDataDir; // where managed system jars will be persisted
private File scriptsDataDir; // where managed scripts will be persisted
private Map<String, String> allKnownScripts; // cached copy of currently known scripts
/**
* Start the management component. This will immediately attempt to add previously
* deployed classpath jars, if it is found that the remote Byteman agent no longer
* has those jars in its classpath.
*
* @see ResourceComponent#start(ResourceContext)
*/
public void start(ResourceContext<BytemanAgentComponent> context) {
this.resourceContext = context;
this.bootJarsDataDir = getResourceDataDirectory("boot");
this.systemJarsDataDir = getResourceDataDirectory("system");
this.scriptsDataDir = getResourceDataDirectory("script");
getBytemanClient(); // creates its client now
// now that we are starting to manage the byteman agent, make sure the managed classpath jars are added
try {
addDeployedClasspathJars();
} catch (Throwable t) {
log.warn("Failed to add managed classpath jars to the byteman agent - is it up?", t);
}
getAvailability(); // forces the scripts cache to load
return;
}
/**
* Called when the resource component will no longer manage the remote Byteman agent.
* This method will clean up the resource component.
*
* @see ResourceComponent#stop()
*/
public void stop() {
this.resourceContext = null;
this.bytemanClient = null;
this.allKnownScripts = null;
}
/**
* Determines if the Byteman agent is up by asking it for the current list of all scripts and their rules.
*
* @see AvailabilityFacet#getAvailability()
*/
public AvailabilityType getAvailability() {
try {
this.allKnownScripts = getBytemanClient().getAllRules();
return AvailabilityType.UP;
} catch (Exception e) {
this.allKnownScripts = null;
return AvailabilityType.DOWN;
}
}
/**
* The plugin container will call this method when metrics are to be collected.
*
* @see MeasurementFacet#getValues(MeasurementReport, Set)
*/
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> requests) {
Submit client = getBytemanClient();
// a cache so we don't ask the byteman agent more than once for this while we are in here
// we don't rely on this.allKnownScripts because we want the latest-n-greatest value for our metrics
Map<String, String> allScripts = null;
for (MeasurementScheduleRequest request : requests) {
String name = request.getName();
try {
if (name.equals("TRAIT-clientVersion")) {
String clientVersion = client.getClientVersion();
report.addData(new MeasurementDataTrait(request, clientVersion));
} else if (name.equals("totalNumberOfScripts")) {
int total = 0;
if (allScripts == null) {
allScripts = client.getAllRules();
}
if (allScripts != null) {
total += allScripts.size();
}
report.addData(new MeasurementDataNumeric(request, Double.valueOf(total)));
} else if (name.equals("totalNumberOfRules")) {
int total = 0;
if (allScripts == null) {
allScripts = client.getAllRules();
}
if (allScripts != null) {
for (String script : allScripts.values()) {
total += client.splitAllRulesFromScript(script).size();
}
}
report.addData(new MeasurementDataNumeric(request, Double.valueOf(total)));
} else if (name.equals("totalNumberOfBootJars")) {
int total = 0;
List<String> loadedJars = client.getLoadedBootClassloaderJars();
if (loadedJars != null) {
total = loadedJars.size();
}
report.addData(new MeasurementDataNumeric(request, Double.valueOf(total)));
} else if (name.equals("totalNumberOfSystemJars")) {
int total = 0;
List<String> loadedJars = client.getLoadedSystemClassloaderJars();
if (loadedJars != null) {
total = loadedJars.size();
}
report.addData(new MeasurementDataNumeric(request, Double.valueOf(total)));
} else {
throw new Exception("cannot collect unknown metric");
}
} catch (Exception e) {
log.error("Failed to obtain measurement [" + name + "]. Cause: " + e);
}
}
return;
}
public Configuration loadResourceConfiguration() throws Exception {
Properties props = getBytemanClient().listSystemProperties();
Configuration config = new Configuration();
PropertyList list = new PropertyList("bytemanSystemProperties");
for (Map.Entry<Object, Object> entry : props.entrySet()) {
String name = entry.getKey().toString();
if (name.startsWith("org.jboss.byteman.")) {
PropertyMap map = new PropertyMap("bytemanSystemProperty");
map.put(new PropertySimple("name", name));
map.put(new PropertySimple("value", entry.getValue().toString()));
list.add(map);
}
}
if (list.getList().size() > 0) {
config.put(list);
}
return config;
}
public void updateResourceConfiguration(ConfigurationUpdateReport report) {
try {
Properties propsToSet = new Properties();
Configuration config = report.getConfiguration();
PropertyList list = config.getList("bytemanSystemProperties");
List<Property> maps = list.getList();
for (Property map : maps) {
Map<String, Property> nameValue = ((PropertyMap) map).getMap();
String name = ((PropertySimple) nameValue.get("name")).getStringValue();
if (name.startsWith("org.jboss.byteman.")) {
String value = ((PropertySimple) nameValue.get("value")).getStringValue();
// byteman will not allow us to turn off strict mode
if (!name.equals("org.jboss.byteman.sysprops.strict") || value.equals("true")) {
propsToSet.put(name, value);
}
}
}
getBytemanClient().setSystemProperties(propsToSet);
log.info("Set byteman configuration: " + propsToSet);
report.setStatus(ConfigurationUpdateStatus.SUCCESS);
} catch (Exception e) {
report.setErrorMessageFromThrowable(e);
}
return;
}
/**
* The plugin container will call this method when it wants to invoke an operation on
* the Byteman agent.
*
* @see OperationFacet#invokeOperation(String, Configuration)
*/
public OperationResult invokeOperation(String name, Configuration configuration) {
OperationResult result = new OperationResult();
Submit client = getBytemanClient();
try {
if ("getRule".equals(name)) {
//
// getRule == retrieves the rule definition for a given rule
String ruleName = configuration.getSimpleValue("ruleName", null);
if (ruleName == null || ruleName.length() == 0) {
throw new Exception("Did not specify the name of the rule to get");
}
Map<String, String> allScripts = client.getAllRules();
for (String script : allScripts.values()) {
List<String> rules = client.splitAllRulesFromScript(script);
for (String rule : rules) {
if (ruleName.equals(client.determineRuleName(rule))) {
Configuration resultConfig = result.getComplexResults();
resultConfig.put(new PropertySimple("ruleDefinition", rule));
return result;
}
}
}
throw new Exception("No rule was found with the name [" + ruleName + "]");
} else if ("getClientVersion".equals(name)) {
//
// getClientVersion == return the version string of the client this plugin is using
String clientVersion = client.getClientVersion();
Configuration resultConfig = result.getComplexResults();
resultConfig.put(new PropertySimple("version", (clientVersion == null) ? "<unknown>" : clientVersion));
return result;
} else if ("addJarsToSystemClasspath".equals(name)) {
//
// addJarsToSystemClasspath == adds a jar to the remote byteman agent's system classpath
String jarPaths = configuration.getSimpleValue("jarPathnames", null);
if (jarPaths == null || jarPaths.length() == 0) {
throw new Exception("Did not specify any jars to add");
}
String[] jarPathsArr = jarPaths.split(",");
List<String> jarPathList = new ArrayList<String>();
for (String jarPathString : jarPathsArr) {
jarPathList.add(jarPathString);
}
String response = client.addJarsToSystemClassloader(jarPathList);
result.setSimpleResult(response);
return result;
} else if ("addJarsToBootClasspath".equals(name)) {
//
// addJarsToBootClasspath == adds a jar to the remote byteman agent's boot classpath
String jarPaths = configuration.getSimpleValue("jarPathnames", null);
if (jarPaths == null || jarPaths.length() == 0) {
throw new Exception("Did not specify any jars to add");
}
String[] jarPathsArr = jarPaths.split(",");
List<String> jarPathList = new ArrayList<String>();
for (String jarPathString : jarPathsArr) {
jarPathList.add(jarPathString);
}
String response = client.addJarsToBootClassloader(jarPathList);
result.setSimpleResult(response);
return result;
} else if ("getAddedClasspathJars".equals(name)) {
//
// getAddedClasspathJars == gets all jars that were added to the byteman agent's boot and system classpaths
Configuration resultConfig = result.getComplexResults();
List<String> jars;
jars = client.getLoadedBootClassloaderJars();
if (jars != null && !jars.isEmpty()) {
PropertyList list = new PropertyList("additionalBootClasspathJars");
for (String jar : jars) {
PropertyMap map = new PropertyMap("additionalBootClasspathJar");
map.put(new PropertySimple("jarPathname", jar));
list.add(map);
}
resultConfig.put(list);
}
jars = client.getLoadedSystemClassloaderJars();
if (jars != null && !jars.isEmpty()) {
PropertyList list = new PropertyList("additionalSystemClasspathJars");
for (String jar : jars) {
PropertyMap map = new PropertyMap("additionalSystemClasspathJar");
map.put(new PropertySimple("jarPathname", jar));
list.add(map);
}
resultConfig.put(list);
}
return result;
} else {
throw new UnsupportedOperationException(name);
}
} catch (Exception e) {
result.setErrorMessage(ThrowableUtil.getAllMessages(e));
return result;
}
}
/**
* Detects the different content for the Byteman agent. This will only discover
* content that was previously deployed by the RHQ content facet mechanism. In other words,
* content already deployed in the Byteman agent, or deployed by some other non-RHQ means,
* will not be detected.
*
* @see ContentFacet#discoverDeployedPackages(PackageType)
*/
public Set<ResourcePackageDetails> discoverDeployedPackages(PackageType type) {
Set<ResourcePackageDetails> details = new HashSet<ResourcePackageDetails>();
String typeName = type.getName();
try {
File[] discoveredFiles = null; // will only be non-null if 1 or more jars are discovered
File dataDir;
if (PKG_TYPE_NAME_BOOT_JAR.equals(typeName)) {
dataDir = this.bootJarsDataDir;
} else if (PKG_TYPE_NAME_SYSTEM_JAR.equals(typeName)) {
dataDir = this.systemJarsDataDir;
} else {
throw new UnsupportedOperationException("Can only deploy boot/system jars");
}
File[] files = dataDir.listFiles();
if (files != null && files.length > 0) {
discoveredFiles = files;
}
if (discoveredFiles != null) {
for (File file : discoveredFiles) {
String shortName = file.getName();
String sha256 = null;
try {
sha256 = new MessageDigestGenerator(MessageDigestGenerator.SHA_256).calcDigestString(file);
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("Failed to generate sha256 for [" + file + "]");
}
}
String version = getVersion(file, sha256);
PackageDetailsKey detailsKey = new PackageDetailsKey(shortName, version, typeName, "noarch");
ResourcePackageDetails detail = new ResourcePackageDetails(detailsKey);
detail.setDisplayName(shortName);
detail.setFileCreatedDate(file.lastModified());
detail.setFileName(shortName);
detail.setFileSize(file.length());
detail.setMD5(MessageDigestGenerator.getDigestString(file));
detail.setSHA256(sha256);
details.add(detail);
}
}
} catch (Exception e) {
log.error("Failed to perform discovery for packages of type [" + typeName + "]", e);
}
return details;
}
private String getVersion(File file, String sha256) {
// Version string in order of preference
// manifestVersion + sha256, sha256, manifestVersion, "0"
String version = "0";
String manifestVersion = null;
try {
manifestVersion = BytemanAgentDiscoveryComponent.getJarAttribute(file.getAbsolutePath(),
java.util.jar.Attributes.Name.IMPLEMENTATION_VERSION.toString(), null);
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("Failed to determine manifestVersion for [" + file + "]");
}
}
if ((null != manifestVersion) && (null != sha256)) {
// this protects against the occasional differing binaries with poor manifest maintenance
version = manifestVersion + " [sha256=" + sha256 + "]";
} else if (null != sha256) {
version = "[sha256=" + sha256 + "]";
} else if (null != manifestVersion) {
version = manifestVersion;
}
return version;
}
/**
* Deploys boot and system classpath jars to the Byteman agent.
*
* @see ContentFacet#deployPackages(Set, ContentServices)
*/
public DeployPackagesResponse deployPackages(Set<ResourcePackageDetails> packages, ContentServices contentServices) {
Submit client = getBytemanClient();
DeployPackagesResponse response = new DeployPackagesResponse();
DeployIndividualPackageResponse individualResponse;
for (ResourcePackageDetails detail : packages) {
PackageDetailsKey packageKey = detail.getKey();
String packageType = detail.getPackageTypeName();
individualResponse = new DeployIndividualPackageResponse(packageKey);
response.addPackageResponse(individualResponse);
try {
Boolean isBootJar = null; // null if not a classpath jar (this is for the future; today, it will always get set)
// if necessary, create the data directory where the file should be deployed
if (PKG_TYPE_NAME_BOOT_JAR.equals(packageType)) {
this.bootJarsDataDir.mkdirs();
isBootJar = Boolean.TRUE;
} else if (PKG_TYPE_NAME_SYSTEM_JAR.equals(packageType)) {
this.systemJarsDataDir.mkdirs();
isBootJar = Boolean.FALSE;
} else {
throw new UnsupportedOperationException("Cannot deploy package of type [" + packageType + "]");
}
// download the package to our data directory
File newFile = getPackageFile(detail);
FileOutputStream fos = new FileOutputStream(newFile);
try {
ContentContext contentContext = this.resourceContext.getContentContext();
contentServices.downloadPackageBits(contentContext, packageKey, fos, true);
} finally {
fos.close();
}
// tell the byteman agent to add it to the proper classloader
if (isBootJar != null) {
if (isBootJar.booleanValue()) {
client.addJarsToBootClassloader(Arrays.asList(newFile.getAbsolutePath()));
} else {
client.addJarsToSystemClassloader(Arrays.asList(newFile.getAbsolutePath()));
}
}
// everything is OK
individualResponse.setResult(ContentResponseResult.SUCCESS);
} catch (Exception e) {
individualResponse.setErrorMessage(ThrowableUtil.getStackAsString(e));
individualResponse.setResult(ContentResponseResult.FAILURE);
}
}
return response;
}
/**
* When a remote client wants to see the actual data content for an installed package, this method will be called.
* This method must return a stream of data containing the full content of the package.
*
* @see ContentFacet#retrievePackageBits(ResourcePackageDetails)
*/
public InputStream retrievePackageBits(ResourcePackageDetails packageDetails) {
try {
File file = getPackageFile(packageDetails);
return new FileInputStream(file);
} catch (Exception e) {
log.error("Cannot retrieve content for package [" + packageDetails + "]");
throw new RuntimeException(e);
}
}
/**
* Essentially a no-op - there are no installation steps associated with Byteman content.
*/
public List<DeployPackageStep> generateInstallationSteps(ResourcePackageDetails packageDetails) {
return new ArrayList<DeployPackageStep>(0);
}
/**
* Removes the packages, if they are managed by this component. Note that the Byteman agent does not
* support runtime removal of jars from its classpaths, so the Byteman agent will retain classpath
* jars in its memory until the VM is restarted, even if this component was asked to remove
* classpath jars.
*
* @see ContentFacet#removePackages(Set)
*/
public RemovePackagesResponse removePackages(Set<ResourcePackageDetails> packages) {
RemovePackagesResponse response = new RemovePackagesResponse();
RemoveIndividualPackageResponse individualResponse;
for (ResourcePackageDetails detail : packages) {
individualResponse = new RemoveIndividualPackageResponse(detail.getKey());
response.addPackageResponse(individualResponse);
try {
File packageFile = getPackageFile(detail);
if (packageFile.delete()) {
individualResponse.setResult(ContentResponseResult.SUCCESS);
} else {
individualResponse.setErrorMessage("Failed to delete [" + packageFile.getAbsolutePath() + "]");
individualResponse.setResult(ContentResponseResult.FAILURE);
}
} catch (Exception e) {
individualResponse.setErrorMessage(ThrowableUtil.getStackAsString(e));
individualResponse.setResult(ContentResponseResult.FAILURE);
}
}
return response;
}
/**
* Creates a new script by deploying the script file to the Byteman agent.
*
* @see CreateChildResourceFacet#createResource(CreateResourceReport)
*/
public CreateResourceReport createResource(CreateResourceReport report) {
try {
this.scriptsDataDir.mkdirs();
// determine where to store the script file when we download it;
// do not allow the file to be placed in a subdirectory under our data dir (i.e. take out file separators)
ResourcePackageDetails newDetails = report.getPackageDetails();
String newName = report.getUserSpecifiedResourceName();
if (newName == null) {
newName = newDetails.getName();
if (newName == null) {
throw new NullPointerException("was not given a name for the new script");
}
}
newName = newName.replace('/', '-').replace('\\', '-');
File newFile = new File(this.scriptsDataDir, newName);
String newFileAbsolutePath = newFile.getAbsolutePath();
// download the file from the server
ContentContext contentContext = this.resourceContext.getContentContext();
ContentServices contentServices = contentContext.getContentServices();
ResourceType newChildResourceType = report.getResourceType();
FileOutputStream fos = new FileOutputStream(newFile);
BufferedOutputStream outputStream = new BufferedOutputStream(fos);
try {
contentServices.downloadPackageBitsForChildResource(contentContext, newChildResourceType.getName(),
newDetails.getKey(), outputStream);
} finally {
outputStream.close();
}
// deploy the scripts rules in byteman agent
getBytemanClient().addRulesFromFiles(Arrays.asList(newFileAbsolutePath));
// we know where we put the file, fill in the details
newDetails.setDisplayName(newName);
newDetails.setFileName(newFileAbsolutePath);
newDetails.setFileSize(newFile.length());
newDetails.setInstallationTimestamp(newFile.lastModified());
newDetails.setMD5(MessageDigestGenerator.getDigestString(newFile));
// complete the report
report.setResourceKey(newFileAbsolutePath);
report.setResourceName(newName);
report.setStatus(CreateResourceStatus.SUCCESS);
} catch (Throwable t) {
log.error("Failed to create child resource [" + report + "]", t);
report.setException(t);
report.setStatus(CreateResourceStatus.FAILURE);
}
return report;
}
/**
* Returns a client that can be used to talk to the remote Byteman agent.
*
* @return client object
*/
public Submit getBytemanClient() {
if (this.bytemanClient == null) {
Configuration pc = this.resourceContext.getPluginConfiguration();
// get the address/port from the plugin config - defaults will be null to force NPEs which is OK, because nulls are error conditions
String address = pc.getSimpleValue(BytemanAgentDiscoveryComponent.PLUGIN_CONFIG_PROP_ADDRESS, null);
String port = pc.getSimpleValue(BytemanAgentDiscoveryComponent.PLUGIN_CONFIG_PROP_PORT, null);
this.bytemanClient = new Submit(address, Integer.valueOf(port).intValue());
}
return this.bytemanClient;
}
/**
* Returns a cached copy of all known scripts since the last availability check was made.
* Use this if you do not need the most up-to-date list, which helps avoid making unnecessary
* calls to the remote Byteman agent. If you need the most up-to-date data, call the agent
* using {@link #getBytemanClient() the client}.
*
* @return the last known set of scripts that were loaded in the remote Byteman agent. <code>null</code>
* if a problem occurred attempting to get the scripts
*/
public Map<String, String> getAllKnownScripts() {
// if we already have a non-null value, use it as-is; otherwise, try to get it now
if (this.allKnownScripts == null) {
try {
this.allKnownScripts = getBytemanClient().getAllRules();
} catch (Exception ignore) {
}
}
return this.allKnownScripts;
}
/**
* Given a package details, this will attempt to find that package's file.
* The details "file name" is examined first to figure out where the file is supposed to be.
* Only if that isn't set will the details general "name" be used as the file name.
* If the "file name" (or "name") is not absolute, it will be assumed to be in one
* of the subdirectories under this component's data directory, based on the package type name.
*
* @param packageDetails details describing the file
* @return the file that corresponds to the details object - this file may or may not exist;
* existence is not a requirement for this method to return a valid File object
*
* @throws Exception if the file could not be determined
*/
public File getPackageFile(ResourcePackageDetails packageDetails) throws Exception {
String path = packageDetails.getFileName();
if (path == null) {
path = packageDetails.getName(); // if no filename was given, assume the package name is the path
}
File file = new File(path);
if (!file.isAbsolute()) {
String typeName = packageDetails.getPackageTypeName();
if (PKG_TYPE_NAME_BOOT_JAR.equals(typeName)) {
file = new File(this.bootJarsDataDir, path);
} else if (PKG_TYPE_NAME_SYSTEM_JAR.equals(typeName)) {
file = new File(this.systemJarsDataDir, path);
} else if (BytemanScriptComponent.PKG_TYPE_NAME_SCRIPT.equals(typeName)) {
file = new File(this.scriptsDataDir, path);
} else {
throw new Exception("Invalid package type - cannot get package file");
}
}
return file;
}
/**
* @return directory where managed boot classpath jars are persisted
*/
public File getBootJarsDataDirectory() {
return this.bootJarsDataDir;
}
/**
* @return directory where managed system classpath jars are persisted
*/
public File getSystemJarsDataDirectory() {
return this.systemJarsDataDir;
}
/**
* @return directory where managed scripts are persisted. Scripts are files
* that contain rules.
*/
public File getScriptsDataDirectory() {
return this.scriptsDataDir;
}
/**
* Returns the component's data directory that is used to persist managed content.
* <code>suffix</code> is the last part of the file path, essentially providing a specific
* location for different kinds of content for the component.
*
* @param suffix identifies a specific location under a general data directory for this component.
* @return data directory that can be used to persist data for this component
*/
public File getResourceDataDirectory(String suffix) {
File pluginDataDir = this.resourceContext.getDataDirectory();
File resourceDataDir = new File(pluginDataDir, this.resourceContext.getResourceKey().replace(":", "-"));
if (suffix != null) {
resourceDataDir = new File(resourceDataDir, suffix);
}
return resourceDataDir;
}
/**
* Goes through all jars that were deployed via RHQ and ensures they are still deployed, adding
* them if need be.
*
* @throws Exception
*/
protected void addDeployedClasspathJars() throws Exception {
Submit client = getBytemanClient();
List<String> paths = new ArrayList<String>();
// do the boot jars first
File dataDir = this.bootJarsDataDir;
File[] files = dataDir.listFiles();
if (files != null && files.length > 0) {
List<String> loadedJars = client.getLoadedBootClassloaderJars();
for (File file : files) {
if (!loadedJars.contains(file.getAbsolutePath())) {
paths.add(file.getAbsolutePath());
}
}
client.addJarsToBootClassloader(paths);
}
// now do the system jars
paths.clear();
dataDir = this.systemJarsDataDir;
files = dataDir.listFiles();
if (files != null && files.length > 0) {
List<String> loadedJars = client.getLoadedSystemClassloaderJars();
for (File file : files) {
if (!loadedJars.contains(file.getAbsolutePath())) {
paths.add(file.getAbsolutePath());
}
}
client.addJarsToSystemClassloader(paths);
}
return;
}
}