/*
* Jopr 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, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also as published by the Free
* Software Foundation.
*
* 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 and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser 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.plugins.jbossas;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.mc4j.ems.connection.EmsConnection;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.inventory.ApplicationServerComponent;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.plugins.jbossas.util.DeploymentUtility;
import org.rhq.plugins.jmx.JMXComponent;
import org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent;
/**
* Discovery component used to discover both enterprise and web applications.
*
* @author Jason Dobies
*/
public class ApplicationDiscoveryComponent extends MBeanResourceDiscoveryComponent<JMXComponent<?>> {
// ResourceDiscoveryComponent Implementation --------------------------------------------
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext<JMXComponent<?>> context) {
// Parent will discover deployed applications through JMX
Set<DiscoveredResourceDetails> jmxResources = super.discoverResources(context);
// JMX resources don't set the filename property, so munge them before going on
JMXComponent parentComponent = context.getParentResourceComponent();
ApplicationServerComponent applicationServerComponent = (ApplicationServerComponent) parentComponent;
EmsConnection emsConnection = parentComponent.getEmsConnection();
String deployDirectoryPath = generateDeployDirectory(applicationServerComponent.getConfigurationPath()
.getPath());
List<String> earNames = new ArrayList<String>();
for (DiscoveredResourceDetails jmxResource : jmxResources) {
earNames.add(jmxResource.getResourceName());
}
Map<String, String> pathMap = DeploymentUtility.getEarDeploymentPath(emsConnection, earNames);
for (DiscoveredResourceDetails jmxResource : jmxResources) {
Configuration pluginConfiguration = jmxResource.getPluginConfiguration();
String path;
if (pathMap.containsKey(jmxResource.getResourceName()))
path = pathMap.get(jmxResource.getResourceName());
else
path = deployDirectoryPath + jmxResource.getResourceName(); // Fallback, just in case
pluginConfiguration.put(new PropertySimple("filename", path));
}
// Find all deployed but unstarted applications
Set<DiscoveredResourceDetails> fileSystemResources = discoverFileSystem(context);
// Merge. The addAll operation will only add items that are not already present, so resources discovered
// by JMX will be used instead of those found by the file system scan.
jmxResources.addAll(fileSystemResources);
return jmxResources;
}
// Private --------------------------------------------
/**
* Discovers applications that are deployed but did not start and are thus not discoverable through JMX.
*
* @param context discovery context, will be used to determine what type of application (EAR, WAR) is being found
*
* @return set of all applications discovered on the file system; this should include at least some of the
* applications discovered through JMX as well
*/
private Set<DiscoveredResourceDetails> discoverFileSystem(ResourceDiscoveryContext<JMXComponent<?>> context) {
Configuration defaultConfiguration = context.getDefaultPluginConfiguration();
// Find the location of the deploy directory
JMXComponent parentComponent = context.getParentResourceComponent();
ApplicationServerComponent applicationServerComponent = (ApplicationServerComponent) parentComponent;
String deployDirectoryPath = generateDeployDirectory(applicationServerComponent.getConfigurationPath()
.getPath());
File deployDirectory = new File(deployDirectoryPath);
// Set up filter for application type
String extension = defaultConfiguration.getSimple("extension").getStringValue();
FilenameFilter filter = new ApplicationFileFilter(extension);
File[] files = deployDirectory.listFiles(filter);
// For each file found, create a resource details instance for it
ResourceType resourceType = context.getResourceType();
Set<DiscoveredResourceDetails> resources = new HashSet<DiscoveredResourceDetails>(files.length);
for (File file : files) {
String resourceKey = determineResourceKey(defaultConfiguration, file.getName());
String objectName = resourceKey;
String resourceName = file.getName();
String description = defaultConfiguration.getSimple("descriptionTemplate").getStringValue();
DiscoveredResourceDetails resource = new DiscoveredResourceDetails(resourceType, resourceKey, resourceName,
"", description, null, null);
Configuration resourcePluginConfiguration = resource.getPluginConfiguration();
resourcePluginConfiguration.put(new PropertySimple("name", resourceName));
resourcePluginConfiguration.put(new PropertySimple("objectName", objectName));
resourcePluginConfiguration.put(new PropertySimple("filename", deployDirectoryPath + resourceName));
resources.add(resource);
}
return resources;
}
// Private --------------------------------------------
/**
* Generates the string representing the deployment directory for this AS instance. This may have to change in the
* future to take into account WARs nested inside of EARs.
*
* @param profilePath path to the AS profile directory (i.e. /opt/jboss/server/default)
*
* @return path to the deployment directory
*/
private String generateDeployDirectory(String profilePath) {
return profilePath + File.separator + "deploy" + File.separator;
}
/**
* Creates the appropriate resource key. The resource key is generated by substituting the file name into the plugin
* descriptor provided JMX object name template. This will only be run for applications that are not currently
* deployed and accessible through JMX. This method mimics the resource key created by the super class handling of
* JMX discovered applications.
*
* @param defaultConfiguration default plugin configuration for the application's resource type
* @param fileName file name of the application found (e.g. rhq.ear)
*
* @return resource key to use for the indicated application file
*/
private String determineResourceKey(Configuration defaultConfiguration, String fileName) {
String template = defaultConfiguration.getSimple("objectName").getStringValue();
String resourceKey = template.replaceAll("%name%", fileName);
return resourceKey;
}
// Inner Classes --------------------------------------------
/**
* Filter used to find applications.
*/
private static class ApplicationFileFilter implements FilenameFilter {
// Attributes --------------------------------------------
private String applicationExtension;
// Constructors --------------------------------------------
private ApplicationFileFilter(String applicationExtension) {
this.applicationExtension = applicationExtension;
}
// FilenameFilter Implementation --------------------------------------------
public boolean accept(File dir, String name) {
// TODO: If on Windows, this check should be case-insensitive.
boolean result = name.endsWith(applicationExtension);
return result;
}
}
}