/*
* RHQ Management Platform
* Copyright (C) 2005-2013 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.core.pluginapi.inventory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.configuration.definition.ConfigurationTemplate;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.system.ProcessInfo;
/**
* This contains all the details for a resource that was discovered by a {@link ResourceDiscoveryComponent}.
*
* <p>Note that any newly discovered resource must have a unique resource key as compared to other sibling resources.
* That is to say, a parent resource's children must have unique resource keys (the children cannot share keys). A
* corollary to this is that if a discovery component "re-discovers" a resource, the discovery component must ensure
* that it assigns the same key to that re-discovered resource (i.e. resource keys must be consistent and stable across
* multiple discoveries of that same resource). As an example, if you discover a resource "foo" and assign it a resource
* key of "fooKey"; then the next time that "foo" resource is discovered again, the discovery component must ensure that
* it discovers it with the resource key "fooKey" again.</p>
*
* @author John Mazzitelli
*/
public class DiscoveredResourceDetails {
private static final int RESOURCE_KEY_MAX_LENGTH = 500;
private static final int RESOURCE_NAME_MAX_LENGTH = 500;
private static final int RESOURCE_VERSION_MAX_LENGTH = 100;
private static final int RESOURCE_DESCRIPTION_MAX_LENGTH = 1000;
private final Log log = LogFactory.getLog(this.getClass());
private ResourceType resourceType;
private String resourceKey;
private String resourceName;
private String resourceVersion;
private String resourceDescription;
private Configuration pluginConfiguration;
private ProcessInfo processInfo;
/**
* This creates a new instance that provides details for a newly discovered resource.
*
* <p>The Resource type, key, and name must not be <code>null</code>. Additionally the key and name must not be "",
* and the key must not be longer than 500 characters. If any of these requirements are not met, an exception will
* be thrown.</p>
*
* @param resourceType the type of resource that was discovered (must not be <code>null</code>)
* @param resourceKey the discovered resource's key where the key must be unique among the resource's
* sibling resources; that is, a parent's direct child resources must all have unique
* resource keys, but those keys need not be unique across the entire inventory of all
* resources (must not be <code>null</code>)
* @param resourceName the name of the discovered resource, used mainly for UI display purposes (must not be
* <code>null</code>)
* @param resourceVersion the discovered resource's version string (which may have any form or syntax
* appropriate for the resource and may be <code>null</code>)
* @param resourceDescription a simple description of the discovered resource, which may or may not be an
* internationalized string (may be <code>null</code>)
* @param pluginConfiguration the discovered resource's plugin configuration that will be used by the plugin to
* connect to it (may be <code>null</code>, which means the new resource will just use
* the default plugin configuration as defined by its resource type)
* @param processInfo information on the process in which the newly discovered resource is running (this
* may be <code>null</code> if unknown or not applicable)
*
* @throws IllegalArgumentException if the resource type, key, or name is <code>null</code>; the key or name is "";
* or the key is longer than 500 characters
*/
public DiscoveredResourceDetails(ResourceType resourceType, String resourceKey, String resourceName,
String resourceVersion, String resourceDescription, Configuration pluginConfiguration, ProcessInfo processInfo) {
if (resourceType == null) {
throw new IllegalArgumentException("resourceType==null");
}
this.resourceType = resourceType;
this.processInfo = processInfo;
setResourceKey(resourceKey);
setResourceName(resourceName);
setResourceVersion(resourceVersion);
setResourceDescription(resourceDescription);
setPluginConfiguration(pluginConfiguration);
return;
}
/**
* The type of resource that was discovered.
*
* @return new resource's type (will not be <code>null</code>)
*/
public ResourceType getResourceType() {
return resourceType;
}
/**
* The discovered resource's key where the key must be unique among the resource's sibling resources; that is, a
* parent's direct child resources must all have unique resource keys, but those keys need not be unique across the
* entire inventory of all resources.
*
* @return resource's unique key (will not be <code>null</code>)
*/
public String getResourceKey() {
return resourceKey;
}
/**
* Sets the discovered resource's unique key. The key must be unique among the resource's sibling resources; that
* is, a parent's direct child resources must all have unique resource keys, but those keys need not be unique
* across the entire inventory of all resources.
*
* @param resourceKey the discovered resource's key (must not be <code>null</code> or "")
*
* @throws IllegalArgumentException if <code>resourceKey</code> is <code>null</code>, "", or more than 500
* characters long
*/
public void setResourceKey(String resourceKey) {
if (resourceKey == null) {
throw new IllegalArgumentException("resourceKey==null");
}
if (resourceKey.length() == 0) {
throw new IllegalArgumentException("resourceKey==\"\"");
}
if (resourceKey.length() > RESOURCE_KEY_MAX_LENGTH) {
throw new IllegalArgumentException("Plugin error: Resource key [" + resourceKey + "] specified by ["
+ this.resourceType + "] discovery component is longer than the maximum length ("
+ RESOURCE_KEY_MAX_LENGTH + ").");
}
this.resourceKey = resourceKey;
}
/**
* The name of the discovered resource, which is used mainly for UI display purposes. This has no uniqueness
* requirements (that is, resources can have the same names; this is true even for sibling resources).
*
* @return resource's name (will not be <code>null</code>)
*/
public String getResourceName() {
return resourceName;
}
/**
* Sets the name of the discovered resource, which is used mainly for UI display purposes. The name can be anything
* (other than <code>null</code> or ""); it has no uniqueness requirements (that is, even sibling resources can have
* the same name). If the name is longer than 500 characters, it will automatically be truncated to 500 characters.
*
* @param resourceName the discovered resource's name (must not be <code>null</code> or "")
*
* @throws IllegalArgumentException if <code>resourceName</code> is <code>null</code> or ""
*/
public void setResourceName(String resourceName) {
if (resourceName == null) {
throw new IllegalArgumentException("resourceName==null");
}
if (resourceName.length() == 0) {
throw new IllegalArgumentException("resourceName==\"\"");
}
if (resourceName.length() > RESOURCE_NAME_MAX_LENGTH) {
log.warn("Plugin error: Resource name [" + resourceName + "] specified by [" + this.resourceType
+ "] discovery component is longer than the maximum length (" + RESOURCE_NAME_MAX_LENGTH
+ " - truncating it to " + RESOURCE_NAME_MAX_LENGTH + " characters...");
this.resourceName = resourceName.substring(0, RESOURCE_NAME_MAX_LENGTH);
} else {
this.resourceName = resourceName;
}
}
/**
* The discovered resource's version string (which may have any form or syntax that is appropriate for the resource
* and may be <code>null</code>)
*
* @return resource version string
*/
public String getResourceVersion() {
return resourceVersion;
}
/**
* Sets the discovered resource's version string (which may have any form or syntax that is appropriate for the
* resource and may be <code>null</code> which correlates to an empty version string). If the version is longer than
* 100 characters, it will automatically be truncated to 100 characters.
*
* @param resourceVersion the discovered resource's version string; may be <code>null</code>, if the Resource
* does not have a version or if its version could not be determined
*/
public void setResourceVersion(String resourceVersion) {
if (resourceVersion != null && (resourceVersion.length() == 0)) {
this.resourceVersion = null;
} else {
if (resourceVersion != null && (resourceVersion.length() > RESOURCE_VERSION_MAX_LENGTH)) {
log.warn("Plugin error: Resource version [" + resourceVersion + "] specified by [" + this.resourceType
+ "] discovery component is longer than the maximum length (" + RESOURCE_VERSION_MAX_LENGTH
+ ") - truncating it to " + RESOURCE_VERSION_MAX_LENGTH + " characters...");
this.resourceVersion = resourceVersion.substring(0, RESOURCE_VERSION_MAX_LENGTH);
} else {
this.resourceVersion = resourceVersion;
}
}
}
/**
* Gets the simple description of the resource, which may or may not be an internationalized string
*
* @return discovered resource's simple description string (may be <code>null</code>)
*/
public String getResourceDescription() {
return resourceDescription;
}
/**
* Sets a simple description of the resource, which may or may not be an internationalized string. If the
* description is longer than 1000 characters, it will automatically be truncated to 1000 characters.
*
* @param resourceDescription the discovered resource's description; may be <code>null</code>
*/
public void setResourceDescription(String resourceDescription) {
if ((resourceDescription != null) && (resourceDescription.length() == 0)) {
this.resourceDescription = null;
} else {
if ((resourceDescription != null) && (resourceDescription.length() > RESOURCE_DESCRIPTION_MAX_LENGTH)) {
log.warn("Plugin error: Resource description [" + resourceDescription + "] specified by [" + this.resourceType
+ "] discovery component is longer than the maximum length (" + RESOURCE_DESCRIPTION_MAX_LENGTH
+ " - truncating it to " + RESOURCE_DESCRIPTION_MAX_LENGTH + " characters...");
this.resourceDescription = resourceDescription.substring(0, RESOURCE_DESCRIPTION_MAX_LENGTH);
} else {
this.resourceDescription = resourceDescription;
}
}
}
/**
* Returns the discovered resource's plugin configuration. If this was never
* {@link #setPluginConfiguration(Configuration) set} before, a copy of the default plugin configuration, as defined
* in the {@link #getResourceType() resource type}'s default template, is returned.
*
* @return copy of the resource's default plugin configuration
*/
public Configuration getPluginConfiguration() {
if (pluginConfiguration == null) {
pluginConfiguration = createDefaultPluginConfiguration();
}
return pluginConfiguration;
}
/**
* Returns the information on the operating system process in which the resource is running.
*
* @return resource's process information or <code>null</code> if not known or not applicable (e.g. a platform
* resource)
*/
public ProcessInfo getProcessInfo() {
return processInfo;
}
public void setProcessInfo(ProcessInfo processInfo) {
this.processInfo = processInfo;
}
/**
* Defines the discovered resource's plugin configuration. You normally call {@link #getPluginConfiguration()} first
* to get a copy of the resource's default plugin configuration, and then modify that default configuration with
* custom values.
*
* <p>If you never need to customize or change a discovered resource's plugin configuration, you will not have to
* call this method. The plugin container will simply use the default plugin configuration from the resource's
* {@link #getResourceType() type}.</p>
*
* @param pluginConfiguration the discovered resource's new plugin configuration
*
* @see #setPluginConfiguration(Configuration)
*/
public void setPluginConfiguration(Configuration pluginConfiguration) {
this.pluginConfiguration = pluginConfiguration;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("key=");
buf.append(getResourceKey());
buf.append(",name=");
buf.append(getResourceName());
buf.append(",type=");
buf.append(getResourceType().getName());
buf.append(",version=");
buf.append(getResourceVersion());
buf.append(",description=");
buf.append(getResourceDescription());
return buf.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if ((o == null) || (getClass() != o.getClass())) {
return false;
}
DiscoveredResourceDetails that = (DiscoveredResourceDetails) o;
if (!resourceKey.equals(that.resourceKey)) {
return false;
}
if (!resourceType.equals(that.resourceType)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result;
result = resourceType.hashCode();
result = (31 * result) + resourceKey.hashCode();
return result;
}
/**
* Returns a copy of the {@link #getResourceType() resource type}'s default plugin configuration.
*
* @return copy of the resource's default plugin configuration
*/
private Configuration createDefaultPluginConfiguration() {
ConfigurationDefinition definition = resourceType.getPluginConfigurationDefinition();
if (definition != null) {
ConfigurationTemplate template = definition.getDefaultTemplate();
if (template != null) {
return template.getConfiguration().deepCopy();
}
}
// There is no default plugin config template defined - return an empty one.
return new Configuration();
}
}