Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 596229 Details for
Bug 796983
Database plugin: Improve discovery and use of column formatted metrics
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Heiko's diff
BZ_796983_-__Improve_database_plugin.patch (text/plain), 53.34 KB, created by
Heiko W. Rupp
on 2012-07-04 14:01:02 UTC
(
hide
)
Description:
Heiko's diff
Filename:
MIME Type:
Creator:
Heiko W. Rupp
Created:
2012-07-04 14:01:02 UTC
Size:
53.34 KB
patch
obsolete
>Index: modules/plugins/database/src/test/java/org/rhq/plugins/database/ComponentTest.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/test/java/org/rhq/plugins/database/ComponentTest.java (revision ) >+++ modules/plugins/database/src/test/java/org/rhq/plugins/database/ComponentTest.java (revision ) >@@ -0,0 +1,545 @@ >+package org.rhq.plugins.database; >+ >+import static org.testng.AssertJUnit.assertEquals; >+import static org.testng.AssertJUnit.assertNotNull; >+import static org.testng.AssertJUnit.assertTrue; >+import static org.testng.AssertJUnit.fail; >+ >+import java.io.File; >+import java.io.InputStream; >+import java.net.URL; >+import java.util.ArrayList; >+import java.util.Arrays; >+import java.util.Collections; >+import java.util.Comparator; >+import java.util.Enumeration; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.LinkedHashMap; >+import java.util.List; >+import java.util.Map; >+import java.util.Set; >+import java.util.concurrent.Executor; >+import java.util.concurrent.Executors; >+ >+import javax.xml.bind.JAXBElement; >+ >+import org.apache.commons.logging.Log; >+import org.apache.commons.logging.LogFactory; >+import org.rhq.core.clientapi.agent.metadata.PluginMetadataManager; >+import org.rhq.core.clientapi.descriptor.AgentPluginDescriptorUtil; >+import org.rhq.core.clientapi.descriptor.configuration.ConfigurationProperty; >+import org.rhq.core.clientapi.descriptor.plugin.MetricDescriptor; >+import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor; >+import org.rhq.core.clientapi.descriptor.plugin.ResourceDescriptor; >+import org.rhq.core.clientapi.descriptor.plugin.ServerDescriptor; >+import org.rhq.core.clientapi.descriptor.plugin.ServiceDescriptor; >+import org.rhq.core.domain.configuration.Configuration; >+import org.rhq.core.domain.configuration.PropertySimple; >+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.MeasurementDefinition; >+import org.rhq.core.domain.measurement.MeasurementReport; >+import org.rhq.core.domain.measurement.MeasurementSchedule; >+import org.rhq.core.domain.measurement.MeasurementScheduleRequest; >+import org.rhq.core.domain.resource.ProcessScan; >+import org.rhq.core.domain.resource.Resource; >+import org.rhq.core.domain.resource.ResourceType; >+import org.rhq.core.pc.PluginContainer; >+import org.rhq.core.pc.PluginContainerConfiguration; >+import org.rhq.core.pc.availability.AvailabilityContextImpl; >+import org.rhq.core.pc.content.ContentContextImpl; >+import org.rhq.core.pc.event.EventContextImpl; >+import org.rhq.core.pc.event.EventManager; >+import org.rhq.core.pc.inventory.ResourceContainer; >+import org.rhq.core.pc.operation.OperationContextImpl; >+import org.rhq.core.pluginapi.availability.AvailabilityContext; >+import org.rhq.core.pluginapi.configuration.ConfigurationFacet; >+import org.rhq.core.pluginapi.content.ContentContext; >+import org.rhq.core.pluginapi.event.EventContext; >+import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; >+import org.rhq.core.pluginapi.inventory.PluginContainerDeployment; >+import org.rhq.core.pluginapi.inventory.ProcessScanResult; >+import org.rhq.core.pluginapi.inventory.ResourceComponent; >+import org.rhq.core.pluginapi.inventory.ResourceContext; >+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; >+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; >+import org.rhq.core.pluginapi.measurement.MeasurementFacet; >+import org.rhq.core.pluginapi.operation.OperationContext; >+import org.rhq.core.system.ProcessInfo; >+import org.rhq.core.system.SystemInfo; >+import org.rhq.core.system.SystemInfoFactory; >+import org.rhq.core.system.pquery.ProcessInfoQuery; >+import org.testng.annotations.AfterSuite; >+import org.testng.annotations.AfterTest; >+import org.testng.annotations.BeforeClass; >+import org.testng.annotations.BeforeSuite; >+ >+/** >+ * Base class for RHQ Component Testing. >+ * Initializes a plugin configuration. >+ * >+ * Methods to override: >+ * >+ * {@link #setConfiguration(Configuration, ResourceType)} >+ */ >+public abstract class ComponentTest { >+ >+ /** >+ * Logging component. >+ */ >+ protected final Log log = LogFactory.getLog(getClass()); >+ >+ private static File temp = new File(System.getProperty("java.io.tmpdir")); >+ >+ /** >+ * Associates a resource component with a resource. >+ */ >+ protected Map<ResourceComponent, Resource> components = new LinkedHashMap<ResourceComponent, Resource>(); >+ >+ /** >+ * Associates a name of a resource with a resource descriptor. >+ */ >+ protected Map<String, ResourceDescriptor> descriptors = new LinkedHashMap<String, ResourceDescriptor>(); >+ >+ /** >+ * Associates a name of a resource with a type. >+ * This is useful for manually adding resources. >+ * >+ * @see #manuallyAdd(ResourceType, Configuration) >+ */ >+ protected Map<String, ResourceType> resourceTypes = new LinkedHashMap<String, ResourceType>(); >+ >+ /** >+ * Event manager; used to obtain events. >+ */ >+ private EventManager eventManager; >+ >+ private PluginContainer pluginContainer = PluginContainer.getInstance(); >+ >+ private SystemInfo systemInfo = SystemInfoFactory.createSystemInfo(); >+ >+ /** >+ * Scan all processes before starting; false will disable this feature. >+ * Disabling is suggested for running tests against a remote instance. >+ */ >+ private boolean processScan = true; >+ >+ // TODO >+ >+ private final PluginMetadataManager pmm = new PluginMetadataManager(); >+ private final File temporaryDirectory = temp; >+ private final File dataDirectory = temp; >+ private final String pluginContainerName = "rhq"; >+ private final OperationContext operationContext = new OperationContextImpl(0); >+ private final ContentContext contentContext = new ContentContextImpl(0); >+ private final Executor availCollectorThreadPool = Executors.newCachedThreadPool(); >+ private PluginContainerDeployment pluginContainerDeployment = null; >+ private Resource platform; >+ private ResourceContainer platformContainer; >+ private List<ProcessInfo> processInfo = Collections.emptyList(); >+ private PluginDescriptor pluginDescriptor; >+ private AvailabilityContext availabilityContext; >+ >+ >+ /** >+ * Constructs a new component test. >+ */ >+ protected ComponentTest() { >+ } >+ >+ /** >+ * Initializes the plugin container. >+ * This is run before {@link #before()}. >+ */ >+ @BeforeSuite >+ protected void beforeSuite() { >+ // Speed up propagation of events by adjusting delay/period to 1 second >+ PluginContainerConfiguration pcc = new PluginContainerConfiguration(); >+ pcc.setEventSenderInitialDelay(1); >+ pcc.setEventSenderPeriod(1); >+ pluginContainer.setConfiguration(pcc); >+ pluginContainer.initialize(); >+ eventManager = pluginContainer.getEventManager(); >+ platform = pluginContainer.getInventoryManager().getPlatform(); >+ platformContainer = pluginContainer.getInventoryManager().getResourceContainer(platform); >+ if (platformContainer == null) { >+ platformContainer = new ResourceContainer(platform, getClass().getClassLoader()); >+ } >+ } >+ >+ /** >+ * Initializes all plugins defined in the system; using auto-discovery where possible. >+ * This is run once per test class. >+ */ >+ @BeforeClass >+ protected void before() throws Exception { >+ if (processScan) { >+ processInfo = getProcessInfos(); >+ if (processInfo == null) >+ processInfo = Collections.emptyList(); >+ log.debug("Process Info " + processInfo); >+ for (ProcessInfo i : processInfo) { >+ log.debug(i.getBaseName() + " " + Arrays.toString(i.getCommandLine())); >+ } >+ } >+ Enumeration<URL> e = getClass().getClassLoader().getResources("META-INF/rhq-plugin.xml"); >+ List<URL> l = Collections.list(e); >+ Collections.sort(l, new Comparator<URL>() { >+ @Override >+ public int compare(URL u1, URL u2) { >+ return u2.toString().compareTo(u1.toString()); >+ } >+ }); >+ for (URL url : l) { >+ log.debug("parse " + url); >+ InputStream is = url.openStream(); >+ PluginDescriptor pd = AgentPluginDescriptorUtil.parsePluginDescriptor(is); >+ processPluginDescriptor(pd); >+ log.debug("pmm names " + pmm.getPluginNames()); >+ buildDesc(pd.getServers()); >+ buildDesc(pd.getServices()); >+ is.close(); >+ } >+ } >+ >+ @AfterSuite >+ protected void afterSuite() { >+ pluginContainer.shutdown(); >+ } >+ >+ /** >+ * Process a plugin descriptor. >+ */ >+ private void processPluginDescriptor(PluginDescriptor pd) throws Exception { >+ this.pluginDescriptor = pd; >+ Set<ResourceType> types = pmm.loadPlugin(pd); >+ mapResourceTypeNames(types); >+ log.info("Resource types: " + resourceTypes); >+ resources(types, platform, platformContainer.getResourceComponent(), platformContainer.getResourceContext()); >+ log.info("ResourceComponent map: " + components); >+ } >+ >+ private void mapResourceTypeNames(Set<ResourceType> types) { >+ for (ResourceType type : types) { >+ this.resourceTypes.put(type.getName(), type); >+ mapResourceTypeNames(type.getChildResourceTypes()); >+ } >+ } >+ >+ /** >+ * Manually create a component by name. >+ */ >+ public ResourceComponent manuallyAdd(String name) throws Exception { >+ ResourceType resourceType = resourceTypes.get(name); >+ if (resourceType == null) >+ throw new IllegalStateException("no type " + name); >+ Configuration configuration = resourceType.getPluginConfigurationDefinition().getDefaultTemplate().createConfiguration(); >+ setConfiguration(configuration, resourceType); >+ return manuallyAdd(resourceType, configuration); >+ } >+ >+ /** >+ * Manually create a component by resource type. >+ */ >+ public ResourceComponent manuallyAdd(ResourceType type, Configuration configuration) throws Exception { >+ return manuallyAdd(type, configuration, platformContainer.getResourceComponent()); >+ } >+ >+ /** >+ * Manually create a component by resource type, configuration, parent. >+ */ >+ public ResourceComponent manuallyAdd(ResourceType type, Configuration configuration, ResourceComponent parent) throws Exception { >+ DiscoveredResourceDetails drd = new DiscoveredResourceDetails(type, >+ "key", "name", "ver", "desc", configuration, (ProcessInfo) null); >+ ResourceDiscoveryComponent c = null; >+ return createChild(drd, platform, configuration, parent, c); >+ } >+ >+ private ResourceComponent createChild(DiscoveredResourceDetails drd, >+ Resource resource, >+ Configuration configuration, >+ ResourceComponent parentComponent, >+ ResourceDiscoveryComponent rdc) throws Exception >+ { >+ ResourceType type = pmm.getType(drd.getResourceType()); >+ >+ Resource cresource = new Resource(); >+ cresource.setResourceType(type); >+ cresource.setPluginConfiguration(configuration); >+ cresource.setResourceKey(drd.getResourceKey()); >+ cresource.setParentResource(resource); >+ cresource.setName(drd.getResourceName()); >+ cresource.setVersion(drd.getResourceVersion()); >+ >+ String rclassname = pmm.getComponentClass(type); >+ ResourceComponent component = (ResourceComponent) Class.forName(rclassname).newInstance(); >+ >+ availabilityContext = new AvailabilityContextImpl(cresource,availCollectorThreadPool); >+ EventContext eventContext = new EventContextImpl(resource); >+ ResourceContext context = new ResourceContext(cresource, parentComponent, >+ null, rdc, systemInfo, temporaryDirectory, dataDirectory, >+ pluginContainerName, eventContext, operationContext, contentContext, >+ availabilityContext, pluginContainerDeployment); >+ >+ component.start(context); >+ components.put(component, cresource); >+ resources(type.getChildResourceTypes(), cresource, component, context); >+ return component; >+ } >+ >+ private void resources(Set<ResourceType> types, Resource parent, ResourceComponent component, ResourceContext context) throws Exception { >+ for (ResourceType type : types) { >+ String s = pmm.getDiscoveryClass(type); >+ if (s == null) { >+ throw new NullPointerException("no discovery " + type); >+ } >+ ResourceDiscoveryComponent rdc = (ResourceDiscoveryComponent) Class.forName(s).newInstance(); >+ log.debug("rdc=" + rdc); >+ ResourceDiscoveryContext resourceDiscoveryContext = new ResourceDiscoveryContext(type, component, >+ context, systemInfo, >+ performProcessScans(type), new ArrayList<Configuration>(), >+ pluginContainerName, pluginContainerDeployment); >+ Set<DiscoveredResourceDetails> drds = rdc.discoverResources(resourceDiscoveryContext); >+ for (DiscoveredResourceDetails drd : drds) { >+ log.debug("discovered " + drd); >+ ResourceType resourceType = drd.getResourceType(); >+ setConfiguration(drd.getPluginConfiguration(), resourceType); >+ createChild(drd, parent, drd.getPluginConfiguration(), component, rdc); >+ } >+ if (drds.isEmpty()) { >+ log.warn("not discovered " + type); >+ context.getPluginConfiguration(); >+ } >+ } >+ >+ } >+ >+ /** >+ * Called before the configuration is processed; override to set specific plugin parameters. >+ */ >+ protected void setConfiguration(Configuration configuration, ResourceType resourceType) { >+ } >+ >+ /** >+ * Stops all components, stops the plugin container. >+ */ >+ @AfterTest >+ protected void after() throws Exception { >+ for (ResourceComponent c : components.keySet()) >+ c.stop(); >+// PluginContainer.getInstance().shutdown(); >+ } >+ >+ /** >+ * Returns a measurement report. >+ */ >+ public MeasurementReport getMeasurementReport(ResourceComponent component) throws Exception { >+ Resource resource = this.components.get(component); >+ ResourceType type = resource.getResourceType(); >+ MeasurementReport report = new MeasurementReport(); >+ Set<MeasurementScheduleRequest> s = new HashSet<MeasurementScheduleRequest>(); >+ for (MeasurementDefinition md : type.getMetricDefinitions()) >+ s.add(new MeasurementScheduleRequest(new MeasurementSchedule(md, resource))); >+ ((MeasurementFacet)component).getValues(report, s); >+ return report; >+ } >+ >+ /** >+ * Returns the first resource component by resource name, then looks by matching resource type name, >+ * then asserts failure if not found. >+ */ >+ public ResourceComponent getComponent(String name) { >+ for (Map.Entry<ResourceComponent, Resource> c : components.entrySet()) >+ if (c.getValue().getName().equals(name)) >+ return c.getKey(); >+ for (Map.Entry<ResourceComponent, Resource> c : components.entrySet()) >+ if (c.getValue().getResourceType().getName().equals(name)) >+ return c.getKey(); >+ fail("component not found " + name + " in " + components.entrySet()); >+ return null; >+ } >+ >+ /** >+ * Returns a resource matching this component. >+ */ >+ public Resource getResource(ResourceComponent rc) { >+ Resource r = components.get(rc); >+ if (r == null) >+ throw new IllegalStateException(); >+ return r; >+ } >+ >+ /** >+ * Returns a resource matching this name. >+ */ >+ public Resource getResource(String name) { >+ return getResource(getComponent(name)); >+ } >+ >+ /** >+ * Builds a new configuration for a resource type. >+ */ >+ public Configuration getConfiguration(ResourceType resourceType) { >+ Configuration configuration = resourceType.getPluginConfigurationDefinition().getDefaultTemplate().createConfiguration(); >+ setConfiguration(configuration, resourceType); >+ return configuration; >+ } >+ >+ // ASSERT METHOD >+ >+ /** >+ * From a measurement report, returns a measurement value, or asserts failure if no such value exists. >+ */ >+ public static Double getValue(MeasurementReport report, String name) { >+ for (MeasurementDataNumeric m: report.getNumericData()) { >+ if (m.getName().equals(name)) { >+ return m.getValue(); >+ } >+ } >+ fail("report does not incude " + name + " report " + report.getNumericData()); >+ return null; >+ } >+ >+ /** >+ * Asserts the resource component is available. >+ */ >+ public static void assertUp(ResourceComponent component) { >+ assertEquals("up " + component, AvailabilityType.UP, component.getAvailability()); >+ } >+ >+ /** >+ * Asserts the resource component is unavailable. >+ */ >+ public static void assertDown(ResourceComponent component) { >+ assertEquals("down " + component, AvailabilityType.DOWN, component.getAvailability()); >+ } >+ >+ /** >+ * Sets a configuration option. >+ */ >+ public static void set(Configuration config, String name, String value) { >+ PropertySimple s = config.getSimple(name); >+ if (s == null) { >+ s = new PropertySimple(name, value); >+ config.put(s); >+ } else { >+ s.setStringValue(value); >+ } >+ } >+ >+ private List<ProcessScanResult> performProcessScans(ResourceType serverType) { >+ List<ProcessScanResult> scanResults = new ArrayList<ProcessScanResult>(); >+ Set<ProcessScan> processScans = serverType.getProcessScans(); >+ log.debug("Executing process scans for server type " + serverType + "..."); >+ ProcessInfoQuery piq = new ProcessInfoQuery(processInfo); >+ for (ProcessScan processScan : processScans) { >+ List<ProcessInfo> queryResults = piq.query(processScan.getQuery()); >+ for (ProcessInfo autoDiscoveredProcess : queryResults) { >+ scanResults.add(new ProcessScanResult(processScan, autoDiscoveredProcess)); >+ log.info("Process scan auto-detected new server resource: scan=[" + processScan >+ + "], discovered-process=[" + autoDiscoveredProcess + "]"); >+ } >+ } >+ return scanResults; >+ } >+ >+ /** >+ * AutoDiscoveryExecutor method. >+ */ >+ private List<ProcessInfo> getProcessInfos() { >+ SystemInfo systemInfo = SystemInfoFactory.createSystemInfo(); >+ log.debug("Retrieving process table..."); >+ long startTime = System.currentTimeMillis(); >+ List<ProcessInfo> processInfos = null; >+ try { >+ processInfos = systemInfo.getAllProcesses(); >+ } catch (UnsupportedOperationException uoe) { >+ log.debug("Cannot perform process scan - not supported on this platform. (" + systemInfo.getClass() + ")"); >+ } >+ long elapsedTime = System.currentTimeMillis() - startTime; >+ log.debug("Retrieval of process table took " + elapsedTime + " ms."); >+ return processInfos; >+ } >+ >+ /** >+ * Returns the plugin descriptor. >+ */ >+ public PluginDescriptor getPluginDescriptor() { >+ return pluginDescriptor; >+ } >+ >+ /** >+ * Returns the plugin descriptor. >+ */ >+ public ResourceDescriptor getResourceDescriptor(String name) { >+ ResourceDescriptor rd = descriptors.get(name); >+ if (rd == null) >+ throw new IllegalStateException("no descriptor " + name + " in " + descriptors.keySet()); >+ return rd; >+ } >+ >+ private void buildDesc(List<? extends ResourceDescriptor> l) { >+ for (ResourceDescriptor rd : l) { >+ descriptors.put(rd.getName(), rd); >+ if (rd instanceof ServerDescriptor) { >+ buildDesc(((ServerDescriptor)rd).getServers()); >+ buildDesc(((ServerDescriptor)rd).getServices()); >+ } >+ if (rd instanceof ServiceDescriptor) { >+ buildDesc(((ServiceDescriptor)rd).getServices()); >+ buildDesc(((ServiceDescriptor)rd).getServices()); >+ } >+ } >+ } >+ >+ /** >+ * Asserts that all measurements in the report are present >+ * according to the resource descriptor. >+ * >+ * @see #getResourceDescriptor(String) for obtaining this. >+ * @param report >+ */ >+ public static void assertAll(MeasurementReport report, ResourceDescriptor l) { >+ HashMap<String, MetricDescriptor> map = new HashMap<String, MetricDescriptor>(); >+ for (MetricDescriptor md : l.getMetric()) { >+ map.put(md.getProperty(), md); >+ } >+ for (MeasurementDataNumeric n : report.getNumericData()) { >+ map.remove(n.getName()); >+ } >+ for (MeasurementDataTrait n : report.getTraitData()) { >+ map.remove(n.getName()); >+ } >+ assertTrue("Measurements not found " + map.keySet(), map.isEmpty()); >+ } >+ >+ /** >+ * Returns the event manager. >+ */ >+ public EventManager getEventManager() { >+ return eventManager; >+ } >+ >+ /** >+ * Set to false to avoid scanning local machine processes to speed up testing. >+ */ >+ public void setProcessScan(boolean processScan) { >+ this.processScan = processScan; >+ } >+ >+ public void assertAll(ConfigurationFacet cf, ResourceDescriptor rd) throws Exception { >+ Configuration config = cf.loadResourceConfiguration(); >+ List<JAXBElement<? extends ConfigurationProperty>> templates = rd.getResourceConfiguration().getConfigurationProperty(); >+ for (JAXBElement<? extends ConfigurationProperty> template : templates) { >+ String name = template.getValue().getName(); >+ // Property property = config.get(name); >+ assertNotNull("config contains " + name, config.get(name)); >+ Object value = config.getSimpleValue(name, null); >+ assertNotNull("value for " + name, value); >+ log.debug("config found " + name + " value " + value ); >+ } >+ } >+ >+} >Index: modules/plugins/database/pom.xml >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- modules/plugins/database/pom.xml (revision b70072126da6810a1fc96d6e33cbd100c438e369) >+++ modules/plugins/database/pom.xml (revision ) >@@ -16,7 +16,12 @@ > <description>An abstract plugin for managing databases via JDBC</description> > > <dependencies> >- >+ <dependency> >+ <groupId>com.h2database</groupId> >+ <artifactId>h2</artifactId> >+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. --> >+ <scope>test</scope> >+ </dependency> > </dependencies> > > <profiles> >\ No newline at end of file >Index: modules/plugins/database/src/main/resources/META-INF/rhq-plugin.xml >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- modules/plugins/database/src/main/resources/META-INF/rhq-plugin.xml (revision b70072126da6810a1fc96d6e33cbd100c438e369) >+++ modules/plugins/database/src/main/resources/META-INF/rhq-plugin.xml (revision ) >@@ -7,4 +7,61 @@ > pluginLifecycleListener="DatabasePluginLifecycleListener" > xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > xmlns="urn:xmlns:rhq-plugin"> >+ >+<!-- Example use: Create a plugin to query from an Oracle database. >+ >+ <depends plugin="Oracle" useClasses="true"/> >+ >+ <server name="Generic Query" class="org.rhq.plugins.database.CustomTableComponent" >+ discovery="org.rhq.plugins.database.CustomTableDiscoveryComponent" >+ description="Query the database for various results" >+ supportsManualAdd="true" singleton="false" >+ createDeletePolicy="both"> >+ <runs-inside> >+ ... note: this works for any database component that implements 'org.rhq.plugins.database.DatabaseComponent' >+ <parent-resource-type name="Oracle Server" plugin="Oracle"/> >+ </runs-inside> >+ <plugin-configuration> >+ <c:simple-property name="table" type="string" default="sometable"/> >+ ... table is optional; if table is not defined discovery will be skipped >+ <c:simple-property name="metricQuery" type="string" default="select a, b from sometable"/> >+ <c:simple-property name="column" type="boolean" default="true"/> >+ ... use column default='false' for data appearing like: >+ col1 col2 >+ ~~~~~~~~ >+ a 123 >+ b 323 >+ >+ and query 'select col1, col2 from sometable' >+ </plugin-configuration> >+ ... columns from Oracle appear uppercase ... >+ <metric property="A" displayName="A results" displayType="summary" >+ description="Number appearing in A column" >+ units="none" dataType="measurement"/> >+ <metric property="B" displayName="B results" displayType="summary" >+ description="Number appearing in B column" >+ units="none" dataType="measurement"/> >+ </server> >+ >+ ... select rows from a database and create sub-components based on that key >+ >+ <service name="Oracle User" >+ discovery="org.rhq.plugins.database.CustomTableRowDiscoveryComponent" >+ class="org.rhq.plugins.oracle.OracleUserComponent"> >+ >+ <plugin-configuration> >+ <c:simple-property name="table" default="DBA_USERS"/> >+ <c:simple-property name="metricQuery" default="SELECT {key} FROM DBA_USERS"/> >+ <c:simple-property name="keyColumn" default="username"/> >+ <c:simple-property name="name" default="{key}"/> >+ <c:simple-property name="description" default="Oracle User"/> >+ </plugin-configuration> >+ >+ <metric property="connections" displayName="Total Connections" displayType="summary"/> >+ <metric property="active" displayName="Active Connections" displayType="summary"/> >+ >+ </service> >+ >+--> >+ >-</plugin> >\ No newline at end of file >+</plugin> >Index: modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableDiscoveryComponent.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableDiscoveryComponent.java (revision b70072126da6810a1fc96d6e33cbd100c438e369) >+++ modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableDiscoveryComponent.java (revision ) >@@ -24,7 +24,10 @@ > import java.util.Collections; > import java.util.Set; > >+import org.apache.commons.logging.Log; >+import org.apache.commons.logging.LogFactory; > import org.rhq.core.domain.configuration.Configuration; >+import org.rhq.core.domain.resource.ResourceType; > import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; > import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; > import org.rhq.core.pluginapi.inventory.ManualAddFacet; >@@ -33,45 +36,61 @@ > import org.rhq.core.util.jdbc.JDBCUtil; > > /** >- * Discovery for a generic component that can read data out of a table for monitoring purposes. Neccessary configuration >- * properties table - the name of the table to search for during inventory metricQuery - the query run to load metric >- * data name - the name of the resource description - the description of the resource >+ * Discovery for a generic component that can read data out of a table for >+ * monitoring purposes. Necessary configuration properties >+ * <li> table - the name of the table to search for during inventory. Note: If absent only >+ * supports manual adding. >+ * <li> metricQuery - the query run to load metric data >+ * <li> name - the name of the resource >+ * <li> description - the description of the resource > * > * @author Greg Hinkle > */ > public class CustomTableDiscoveryComponent implements ManualAddFacet<DatabaseComponent<?>>, > ResourceDiscoveryComponent<DatabaseComponent<?>> { >+ >+ protected Log log = LogFactory.getLog(getClass()); >+ > public Set<DiscoveredResourceDetails> discoverResources( > ResourceDiscoveryContext<DatabaseComponent<?>> resourceDiscoveryContext) > throws InvalidPluginConfigurationException, Exception { >+ >+ Configuration config = resourceDiscoveryContext.getDefaultPluginConfiguration(); >+ String table = config.getSimpleValue("table", ""); >+ ResourceType rt = resourceDiscoveryContext.getResourceType(); >+ String resourceName = config.getSimpleValue("name", rt.getName()); >+ String resourceDescription = config.getSimpleValue("description", rt.getDescription()); >+ >+ if (table.isEmpty()) { >+ log.debug("'table' value not set, cannot discover " + resourceName); >+ return Collections.emptySet(); >+ } >+ > Statement statement = null; > try { > Connection conn = resourceDiscoveryContext.getParentResourceComponent().getConnection(); >+ if (conn == null) >+ throw new InvalidPluginConfigurationException("cannot obtain connection from parent"); > >- Configuration config = resourceDiscoveryContext.getDefaultPluginConfiguration(); >- String table = config.getSimpleValue("table", null); >- String resourceName = config.getSimpleValue("name", table); >- String resourceDescription = config.getSimpleValue("description", null); >- > statement = conn.createStatement(); >- statement.executeQuery("SELECT COUNT(*) FROM " + table); >- >+ statement.setMaxRows(1); >+ statement.setFetchSize(1); >+ // This is more efficient than 'count(*)' >+ // unless the JDBC driver fails to support setMaxRows or doesn't stream results >+ statement.executeQuery("SELECT * FROM " + table).close(); > DiscoveredResourceDetails details = new DiscoveredResourceDetails( > resourceDiscoveryContext.getResourceType(), table + resourceName, resourceName, null, > resourceDescription, config, null); > >+ log.debug("discovered " + details); > return Collections.singleton(details); > } catch (SQLException e) { >+ log.debug("discovery failed " + e + " for " + table); > // table not found, don't inventory > } finally { > JDBCUtil.safeClose(statement); > } > >- if (!resourceDiscoveryContext.getPluginConfigurations().isEmpty()) { >- return Collections.singleton(discoverResource(resourceDiscoveryContext.getPluginConfigurations().get(0), >- resourceDiscoveryContext)); >- } >- > return Collections.emptySet(); > } > >@@ -79,14 +98,15 @@ > ResourceDiscoveryContext<DatabaseComponent<?>> discoveryContext) throws InvalidPluginConfigurationException { > > Configuration config = pluginConfiguration; >- > String table = config.getSimpleValue("table", null); > String resourceName = config.getSimpleValue("name", table); >- String resourceDescription = config.getSimpleValue("description", null); >+ String resourceDescription = config.getSimpleValue("description", >+ discoveryContext.getResourceType().getDescription()); >+ String resourceVersion = config.getSimpleValue("version", null); > > DiscoveredResourceDetails details = new DiscoveredResourceDetails(discoveryContext.getResourceType(), table >- + resourceName, resourceName, null, resourceDescription, config, null); >+ + resourceName, resourceName, resourceVersion, resourceDescription, config, null); > > return details; > } >-} >\ No newline at end of file >+} >Index: modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java (revision b70072126da6810a1fc96d6e33cbd100c438e369) >+++ modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java (revision ) >@@ -57,14 +57,20 @@ > } > > public String getTable() { >- return this.context.getPluginConfiguration().getSimpleValue("table", null); >+ return this.context.getPluginConfiguration().getSimpleValue("table", ""); > } > > public AvailabilityType getAvailability() { >+ if (getTable().isEmpty()) { >+ // not set >+ return AvailabilityType.UP; >+ } > Statement statement = null; > try { > statement = getConnection().createStatement(); >- statement.executeQuery("SELECT COUNT(*) FROM " + getTable()); >+ statement.setMaxRows(1); >+ statement.setFetchSize(1); >+ statement.executeQuery("SELECT * FROM " + getTable()).close(); > return AvailabilityType.UP; > } catch (SQLException e) { > return AvailabilityType.DOWN; >@@ -75,8 +81,8 @@ > > public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { > >- Configuration conf = this.context.getPluginConfiguration(); >- String query = conf.getSimpleValue("metricQuery", null); >+ Configuration config = this.context.getPluginConfiguration(); >+ String query = config.getSimpleValue("metricQuery", null); > > if (query == null) { > if (log.isTraceEnabled()) { >@@ -93,9 +99,18 @@ > return; > } > >- query = CustomTableRowDiscoveryComponent.formatMessage(query, conf.getSimpleValue("key", null)); >- >- Map<String, Double> values = DatabaseQueryUtility.getNumericQueryValueMap(this, query); >+ query = CustomTableRowDiscoveryComponent.formatMessage(query, config.getSimpleValue("key", null)); >+ String column = config.getSimpleValue("column", ""); >+ Map<String, Double> values; >+ if (Boolean.parseBoolean(column)) { >+ // data in column format >+ values = DatabaseQueryUtility.getNumericQueryValues(this, query); >+ } else { >+ // data in row format >+ values = DatabaseQueryUtility.getNumericQueryValueMap(this, query); >+ } >+ if (log.isDebugEnabled()) >+ log.debug("returned values " + values); > > // this is a for loop because the name of each column can be the name of the metric > for (MeasurementScheduleRequest request : metrics) { >@@ -126,4 +141,4 @@ > public void removeConnection() { > this.context.getParentResourceComponent().removeConnection(); > } >-} >\ No newline at end of file >+} >Index: modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java (revision b70072126da6810a1fc96d6e33cbd100c438e369) >+++ modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java (revision ) >@@ -38,9 +38,12 @@ > import org.rhq.core.util.jdbc.JDBCUtil; > > /** >- * Discovery for a generic component that can read data out of a table for monitoring purposes. Neccessary configuration >- * properties table - the name of the table to search for during inventory metricQuery - the query run to load metric >- * data name - the name of the resource description - the description of the resource >+ * Discovery for a generic component that can read data out of a table for >+ * monitoring purposes. Necessary configuration properties: >+ * <li> table - the name of the table to search for during inventory >+ * <li> keyColumn - the key of the table used to load metric data >+ * <li> name - the name of the resource >+ * <li> description - the description of the resource > * > * @author Greg Hinkle > */ >@@ -112,4 +115,4 @@ > message = message.replaceAll("\\{key\\}", key); > return message; > } >-} >\ No newline at end of file >+} >Index: modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseQueryUtility.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseQueryUtility.java (revision b70072126da6810a1fc96d6e33cbd100c438e369) >+++ modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseQueryUtility.java (revision ) >@@ -24,8 +24,10 @@ > import java.sql.ResultSetMetaData; > import java.sql.SQLException; > import java.sql.Statement; >+import java.util.ArrayList; > import java.util.Collections; > import java.util.HashMap; >+import java.util.List; > import java.util.Map; > > import org.apache.commons.logging.Log; >@@ -34,11 +36,25 @@ > import org.rhq.core.util.exception.ThrowableUtil; > > /** >+ * Various database (JDBC) query functions. >+ * > * @author Greg Hinkle > */ > public class DatabaseQueryUtility { >+ > private static final Log LOG = LogFactory.getLog(DatabaseQueryUtility.class); > >+ private DatabaseQueryUtility() {} >+ >+ /** >+ * Executes a database update. >+ * >+ * @param databaseComponent >+ * @param query >+ * @param parameters >+ * @return >+ * @throws SQLException >+ */ > public static int executeUpdate(DatabaseComponent databaseComponent, String query, Object... parameters) > throws SQLException { > PreparedStatement statement = null; >@@ -55,6 +71,10 @@ > } > } > >+ /** >+ * Returns the result of a query as a single Double value. >+ * Returns {@link Double#NaN} if the query fails. >+ */ > public static Double getSingleNumericQueryValue(DatabaseComponent databaseComponent, String query, > Object... parameters) { > PreparedStatement statement = null; >@@ -77,13 +97,15 @@ > } > > /** >- * Used to read a single row of columns into a map >+ * Executes a query, returning the results as a map where the keys >+ * are the column names and values are the value of that column. >+ * Note depending on the database, the column names may be uppercase (Oracle) or lowercase. > * > * @param databaseComponent >- * @param query >- * @param parameters >+ * @param query SQL query string >+ * @param parameters optional bind parameters > * >- * @return >+ * @return a map of query results > */ > public static Map<String, Double> getNumericQueryValues(DatabaseComponent databaseComponent, String query, > Object... parameters) { >@@ -122,9 +144,49 @@ > } > > /** >- * Used to access a set of rows as key, value pairs where the key is the first column and is a string and the second >- * is a value and is numeric >+ * Returns a list of values, one per row, containing a map of column names to values of that row. >+ * Note depending on the database, the column names may be uppercase (Oracle) or lowercase. >+ * @param databaseComponent database to query >+ * @param query SQL query >+ * @param parameters parameters to bind to the query > * >+ * @throws SQLException if query fails >+ */ >+ public static List<Map<String, Object>> getGridValues(DatabaseComponent databaseComponent, String query, >+ Object... parameters) throws SQLException { >+ PreparedStatement statement = null; >+ ResultSet resultSet = null; >+ List<Map<String, Object>> l = new ArrayList<Map<String, Object>>(); >+ try { >+ statement = databaseComponent.getConnection().prepareStatement(query); >+ bindParameters(statement, parameters); >+ >+ resultSet = statement.executeQuery(); >+ >+ while (resultSet.next()) { >+ Map<String, Object> row = new HashMap<String, Object>(); >+ l.add(row); >+ >+ ResultSetMetaData md = resultSet.getMetaData(); >+ String[] names = getColumns(md); >+ >+ for (String name : names) { >+ Object o = resultSet.getObject(name); >+ row.put(name, o); >+ } >+ } >+ >+ } finally { >+ close(statement, resultSet); >+ } >+ return l; >+ >+ } >+ >+ /** >+ * Returns a mapping of rows as key-value pairs where the key is the >+ * first column (a string) and the second column is a value numeric. >+ * > * @param databaseComponent the component to execute on > * @param query the sql query to run > * @param parameters any parameters to bind first >@@ -166,6 +228,9 @@ > return Collections.emptyMap(); > } > >+ /** >+ * Binds arguments to a prepared statement. >+ */ > private static void bindParameters(PreparedStatement statement, Object... parameters) throws SQLException { > int i = 1; > for (Object p : parameters) { >@@ -179,6 +244,9 @@ > } > } > >+ /** >+ * Returns an array of strings as upper-case column names. >+ */ > public static String[] getColumns(ResultSetMetaData rsmd) throws SQLException { > String[] names = new String[rsmd.getColumnCount()]; > for (int i = 0; i < rsmd.getColumnCount(); i++) { >@@ -188,11 +256,9 @@ > return names; > } > >- public static class StatementParameter { >- private String name; >- private String value; >- } >- >+ /** >+ * Closes statements and result sets. >+ */ > public static void close(Statement statement, ResultSet resultSet) { > if (resultSet != null) { > try { >@@ -208,4 +274,4 @@ > } > } > } >-} >\ No newline at end of file >+} >Index: modules/plugins/database/src/test/java/org/rhq/plugins/database/H2Database.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/test/java/org/rhq/plugins/database/H2Database.java (revision ) >+++ modules/plugins/database/src/test/java/org/rhq/plugins/database/H2Database.java (revision ) >@@ -0,0 +1,79 @@ >+package org.rhq.plugins.database; >+ >+import java.sql.Connection; >+import java.sql.DriverManager; >+import java.sql.SQLException; >+ >+import org.apache.commons.logging.Log; >+import org.apache.commons.logging.LogFactory; >+import org.rhq.core.domain.configuration.Configuration; >+import org.rhq.core.domain.measurement.AvailabilityType; >+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.util.jdbc.JDBCUtil; >+ >+/** >+ * Tests using the H2Database. >+ */ >+public class H2Database implements DatabaseComponent<ResourceComponent<?>> { >+ >+ private Log log = LogFactory.getLog(this.getClass()); >+ protected ResourceContext resourceContext; >+ private Connection connection; >+ private Configuration configuration; >+ >+ public void start(ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception { >+ this.resourceContext = resourceContext; >+ this.configuration = resourceContext.getPluginConfiguration(); >+ } >+ >+ public void stop() { >+ removeConnection(); >+ } >+ >+ public AvailabilityType getAvailability() { >+ Connection conn = getConnection(); >+ AvailabilityType result = AvailabilityType.DOWN; >+ if (conn != null) { >+ result = AvailabilityType.UP; >+ } >+ return result; >+ >+ } >+ >+ public Connection getConnection() { >+ try { >+ if (this.connection == null || connection.isClosed()) { >+ this.connection = buildConnection(); >+ } >+ } catch (SQLException e) { >+ log.info("Unable to create connection", e); >+ } >+ return this.connection; >+ } >+ >+ @Override >+ public void removeConnection() { >+ JDBCUtil.safeClose(connection); >+ this.connection = null; >+ } >+ >+ private Connection buildConnection() throws SQLException { >+ String driverClass = configuration.getSimpleValue("driverClass", "org.h2.Driver"); >+ try { >+ Class.forName(driverClass); >+ } catch (ClassNotFoundException e) { >+ throw new InvalidPluginConfigurationException("Specified JDBC driver class (" + driverClass >+ + ") not found."); >+ } >+ >+ String url = configuration.getSimpleValue("url", "jdbc:h2:test"); >+ String username = configuration.getSimpleValue("username", "sa"); >+ String password = configuration.getSimpleValue("password", ""); >+ log.debug("Attempting JDBC connection to [" + url + "]"); >+ return DriverManager.getConnection(url, username, password); >+ } >+ >+ >+} >Index: modules/plugins/database/src/test/java/org/rhq/plugins/database/PluginTest.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/test/java/org/rhq/plugins/database/PluginTest.java (revision ) >+++ modules/plugins/database/src/test/java/org/rhq/plugins/database/PluginTest.java (revision ) >@@ -0,0 +1,52 @@ >+/* >+ * 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.plugins.database; >+ >+import java.sql.Connection; >+import java.util.List; >+import java.util.Map; >+ >+import org.rhq.core.domain.configuration.Configuration; >+import org.rhq.core.domain.measurement.MeasurementReport; >+import org.rhq.core.domain.resource.ResourceType; >+import org.testng.annotations.Test; >+import org.testng.AssertJUnit; >+ >+@Test >+public class PluginTest extends ComponentTest { >+ >+ public void test() throws Exception { >+ H2Database db = (H2Database)manuallyAdd("H2 Database"); >+ assertUp(db); >+ Connection connection = db.getConnection(); >+ connection.prepareStatement("create table sometable(a int, b int)").execute(); >+ connection.prepareStatement("insert into sometable values(42, 54)").execute(); >+ ResourceType rt = resourceTypes.get("Generic Query"); >+ Configuration configuration = getConfiguration(rt); >+ CustomTableComponent ctc = (CustomTableComponent) manuallyAdd(rt, configuration, db); >+ MeasurementReport report = getMeasurementReport(ctc); >+ assertAll(report, getResourceDescriptor("Generic Query")); >+ List<Map<String, Object>> grid = DatabaseQueryUtility.getGridValues(db, "select a, b from sometable"); >+ assert grid.size() == 1; >+ Map<String, Object> map = grid.get(0); >+ AssertJUnit.assertEquals(42, map.get("A")); >+ } >+ >+} >Index: modules/plugins/database/src/test/resources/META-INF/rhq-plugin.xml >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- modules/plugins/database/src/test/resources/META-INF/rhq-plugin.xml (revision ) >+++ modules/plugins/database/src/test/resources/META-INF/rhq-plugin.xml (revision ) >@@ -0,0 +1,47 @@ >+<?xml version="1.0" encoding="UTF-8" ?> >+ >+<plugin name="H2" >+ displayName="H2 Database" >+ description="Plugin supporting H2 database" >+ package="org.rhq.plugins.database" >+ pluginLifecycleListener="DatabasePluginLifecycleListener" >+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >+ xmlns:c="urn:xmlns:rhq-configuration" >+ xmlns="urn:xmlns:rhq-plugin"> >+ >+ <depends plugin="Database" useClasses="true"/> >+ >+ <server name="H2 Database" class="org.rhq.plugins.database.H2Database" discovery="org.rhq.plugins.database.H2DatabaseDiscovery"> >+ <plugin-configuration> >+ <c:simple-property name="url" type="string" default="jdbc:h2:mem:"/> >+ <c:simple-property name="username" type="string" default="sa"/> >+ <c:simple-property name="password" type="string" default=""/> >+ </plugin-configuration> >+ >+ </server> >+ >+ <service name="Generic Query" class="org.rhq.plugins.database.CustomTableComponent" >+ discovery="org.rhq.plugins.database.CustomTableDiscoveryComponent" >+ description="Query the database for various results" >+ supportsManualAdd="true" singleton="false" >+ createDeletePolicy="both"> >+ >+ <runs-inside> >+ <parent-resource-type name="H2 Database" plugin="H2"/> >+ </runs-inside> >+ >+ <plugin-configuration> >+ <c:simple-property name="metricQuery" type="string" default="select a, b from sometable"/> >+ <c:simple-property name="column" type="boolean" default="true"/> >+ </plugin-configuration> >+ <metric property="A" displayName="A results" displayType="summary" >+ description="Number appearing in A column" >+ units="none" dataType="measurement"/> >+ <metric property="B" displayName="B results" displayType="summary" >+ description="Number appearing in B column" >+ units="none" dataType="measurement"/> >+ </service> >+ >+ >+</plugin> >+ >Index: modules/plugins/database/src/test/java/org/rhq/plugins/database/H2DatabaseDiscovery.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/test/java/org/rhq/plugins/database/H2DatabaseDiscovery.java (revision ) >+++ modules/plugins/database/src/test/java/org/rhq/plugins/database/H2DatabaseDiscovery.java (revision ) >@@ -0,0 +1,46 @@ >+package org.rhq.plugins.database; >+ >+import java.util.Collections; >+import java.util.Set; >+ >+import org.jetbrains.annotations.Nullable; >+import org.rhq.core.domain.configuration.Configuration; >+import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; >+import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; >+import org.rhq.core.pluginapi.inventory.ManualAddFacet; >+import org.rhq.core.pluginapi.inventory.ResourceComponent; >+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; >+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; >+import org.rhq.core.system.ProcessInfo; >+ >+public class H2DatabaseDiscovery implements ResourceDiscoveryComponent<ResourceComponent<?>>, ManualAddFacet<ResourceComponent<?>> { >+ >+ @Override >+ public Set<DiscoveredResourceDetails> discoverResources( >+ ResourceDiscoveryContext<ResourceComponent<?>> context) { >+ return Collections.emptySet(); >+ } >+ >+ @Override >+ public DiscoveredResourceDetails discoverResource(Configuration pluginConfiguration, >+ ResourceDiscoveryContext<ResourceComponent<?>> context) >+ throws InvalidPluginConfigurationException { >+ >+ String version = ""; >+ DiscoveredResourceDetails details = createResourceDetails(context, pluginConfiguration, >+ version, null); >+ return details; >+ >+ } >+ >+ private static DiscoveredResourceDetails createResourceDetails(ResourceDiscoveryContext discoveryContext, >+ Configuration pluginConfig, String version, @Nullable >+ ProcessInfo processInfo) { >+ String key = pluginConfig.getSimpleValue("url", ""); >+ String name = key; >+ String description = "Database " + version + " (" + key + ")"; >+ return new DiscoveredResourceDetails(discoveryContext.getResourceType(), key, name, version, description, >+ pluginConfig, processInfo); >+ } >+ >+} >Index: modules/plugins/database/src/main/java/org/rhq/plugins/database/AbstractDatabaseComponent.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>ISO-8859-1 >=================================================================== >--- modules/plugins/database/src/main/java/org/rhq/plugins/database/AbstractDatabaseComponent.java (revision b70072126da6810a1fc96d6e33cbd100c438e369) >+++ modules/plugins/database/src/main/java/org/rhq/plugins/database/AbstractDatabaseComponent.java (revision ) >@@ -24,6 +24,7 @@ > import org.rhq.core.pluginapi.inventory.ResourceContext; > > /** >+ * Base class for database components. > * @author Greg Hinkle > */ > public abstract class AbstractDatabaseComponent<T extends DatabaseComponent<?>> implements DatabaseComponent { >@@ -45,5 +46,10 @@ > > public void removeConnection() { > this.resourceContext.getParentResourceComponent().removeConnection(); >+ } >+ >+ @Override >+ public String toString() { >+ return getClass().getName() + " key=" + resourceContext.getResourceKey(); > } > } >\ No newline at end of file
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 796983
:
570666
|
570667
| 596229