Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Commit

Permalink
[BZ 1076126] - RFE: Canned dynaGroup expressions provided by plugin
Browse files Browse the repository at this point in the history
Added concept of 'additional descriptor' (optional zml file living in
plugin's META-INF folder side-by-side to plugin descriptor). This file is
parsed only by server when plugin is discovered. Within this xml file, we
currently store predefined expressions for read dynaGroup definitions. Such
expressions can install dynaGroup definitions automatically. This commit
contains also logic which takes care about dynaGroupDefs created using such
expressions. When plugin updates such expression, dynaGroup is updated (same
for delete). GroupDefinition table has now "weak" reference to expression
(Plugin:ExprId)

Predefined dynaGroup expressions hardcoded in SingleGroupDefinitionView.java
have been replaced by cannedExpressions provided by plugins. From user
perspective, almost nothing changed, except cannedExpressions contain more
than just expression string, so when user selects template/expression fields
like name,description,recursive,recalcInterval are pre-populated as well.

Added 3 expressions. First groups managed servers by server-group name
(deploys DG) 2nd groups managed servers by hostname (aka domain) (deploys
DG) 3rd groups enabled deployments per server-groups

For expressions with 'createByDefault=true': dynagroups being created are
attached to plugin (having non-null cannedExpression). Whenever this
dynagroup is changed (via API or UI) it get's detached from plugin (setting
cannedExpression to null). Also on plugin upgrade or first install, if we
find a detached dynagroup having same name as we are about to create, we
just log INFO message - this happens when DG got previously detached.
  • Loading branch information
Libor Zoubek committed Apr 22, 2014
1 parent 769bb64 commit 414a2a6
Show file tree
Hide file tree
Showing 24 changed files with 851 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public String getComponentClass(ResourceType resourceType) throws ResourceTypeNo
PluginMetadataParser parser = this.parsersByPlugin.get(resourceType.getPlugin());
return (parser != null) ? parser.getComponentClass(resourceType) : null;
}

/**
* Transforms the pluginDescriptor into domain object form and stores into this object's type system.
*
Expand Down Expand Up @@ -549,4 +549,5 @@ public void cleanupDescriptors() {
parser.cleanDescriptor();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -44,13 +45,16 @@
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.xml.sax.SAXException;

import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.metadata.PluginDependencyGraph;
import org.rhq.core.clientapi.agent.metadata.PluginDependencyGraph.PluginDependency;
import org.rhq.core.clientapi.descriptor.group.expressions.CannedGroupExpressions;
import org.rhq.core.clientapi.descriptor.plugin.ParentResourceType;
import org.rhq.core.clientapi.descriptor.plugin.PlatformDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor;
Expand All @@ -59,7 +63,6 @@
import org.rhq.core.clientapi.descriptor.plugin.ServiceDescriptor;
import org.rhq.core.domain.plugin.Plugin;
import org.rhq.core.util.exception.WrappedRemotingException;
import org.xml.sax.SAXException;

/**
* Utilities for agent plugin descriptors.
Expand All @@ -72,6 +75,8 @@ public abstract class AgentPluginDescriptorUtil {

private static final String PLUGIN_DESCRIPTOR_PATH = "META-INF/rhq-plugin.xml";
private static final String PLUGIN_SCHEMA_PATH = "rhq-plugin.xsd";
private static final String CANNED_GROUP_EXPRESSION_SCHEMA_PATH="rhq-canned-groups.xsd";
private static final String CANNED_GROUP_EXPRESSION_DESCRIPTOR_PATH="META-INF/rhq-group-expressions.xml";

/**
* Determines which of the two plugins is obsolete - in other words, this determines which
Expand Down Expand Up @@ -283,6 +288,58 @@ private static void addOptionalDependency(String pluginName,
return;
}

/**
* Retrieves file content as string from given jar
* @param pluginJarFileUrl URL to a plugin jar file
* @param additionPath addition file path within JAR (eg. META-INF/mydescriptor.xml)
* @return content of additionPath file as String, or null if file does not exist in JAR
* @throws PluginContainerException if we fail to read content
*/
public static CannedGroupExpressions loadCannedExpressionsFromUrl(URL pluginJarFileUrl) throws PluginContainerException {
final Log logger = LogFactory.getLog(AgentPluginDescriptorUtil.class);

if (pluginJarFileUrl == null) {
throw new PluginContainerException("A valid plugin JAR URL must be supplied.");
}
logger.debug("Loading plugin additions from plugin jar at [" + pluginJarFileUrl + "]...");
ValidationEventCollector validationEventCollector = new ValidationEventCollector();
testPluginJarIsReadable(pluginJarFileUrl);

JarInputStream jis = null;
JarEntry descriptorEntry = null;
try {
jis = new JarInputStream(pluginJarFileUrl.openStream());
JarEntry nextEntry = jis.getNextJarEntry();
while (nextEntry != null && descriptorEntry == null) {
if (CANNED_GROUP_EXPRESSION_DESCRIPTOR_PATH.equals(nextEntry.getName())) {
descriptorEntry = nextEntry;
} else {
jis.closeEntry();
nextEntry = jis.getNextJarEntry();
}
}

if (descriptorEntry == null) {
logger.debug("Plugin additions not found");
// plugin additions are optional thing
return null;
}
return parseCannedGroupExpressionsDescriptor(jis, validationEventCollector);
} catch (Exception e) {
throw new PluginContainerException("Could not parse the plugin additions ["
+ CANNED_GROUP_EXPRESSION_DESCRIPTOR_PATH + "] found in plugin jar at [" + pluginJarFileUrl + "].",
new WrappedRemotingException(e));
} finally {
if (jis != null) {
try {
jis.close();
} catch (Exception e) {
logger.warn("Cannot close jar stream [" + pluginJarFileUrl + "]. Cause: " + e);
}
}
}
}

/**
* Loads a plugin descriptor from the given plugin jar and returns it.
*
Expand Down Expand Up @@ -359,8 +416,32 @@ public static PluginDescriptor parsePluginDescriptor(InputStream is) throws Plug
public static PluginDescriptor parsePluginDescriptor(InputStream is,
ValidationEventCollector validationEventCollector) throws PluginContainerException {
JAXBContext jaxbContext;
return (PluginDescriptor) parsePluginDescriptor(is, validationEventCollector, PLUGIN_SCHEMA_PATH, DescriptorPackages.PC_PLUGIN);
}

/**
* Parses a descriptor from InputStream without a validator.
* @param is input to check
* @return parsed PluginDescriptor
* @throws PluginContainerException if validation fails
*/
public static CannedGroupExpressions parseCannedGroupExpressionsDescriptor(InputStream is,
ValidationEventCollector validationEventCollector) throws PluginContainerException {
JAXBContext jaxbContext;
return (CannedGroupExpressions) parsePluginDescriptor(is, validationEventCollector, CANNED_GROUP_EXPRESSION_SCHEMA_PATH, DescriptorPackages.CANNED_EXPRESSIONS);
}

/**
* Parses a descriptor from InputStream without a validator.
* @param is input to check
* @return parsed PluginDescriptor
* @throws PluginContainerException if validation fails
*/
private static Object parsePluginDescriptor(InputStream is,
ValidationEventCollector validationEventCollector, String xsd, String jaxbPackage) throws PluginContainerException {
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance(DescriptorPackages.PC_PLUGIN);
jaxbContext = JAXBContext.newInstance(jaxbPackage);
} catch (Exception e) {
throw new PluginContainerException("Failed to create JAXB Context.", new WrappedRemotingException(e));
}
Expand All @@ -369,14 +450,13 @@ public static PluginDescriptor parsePluginDescriptor(InputStream is,
try {
unmarshaller = jaxbContext.createUnmarshaller();
// Enable schema validation
URL pluginSchemaURL = AgentPluginDescriptorUtil.class.getClassLoader().getResource(PLUGIN_SCHEMA_PATH);
URL pluginSchemaURL = AgentPluginDescriptorUtil.class.getClassLoader().getResource(xsd);
Schema pluginSchema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
pluginSchemaURL);
unmarshaller.setSchema(pluginSchema);
unmarshaller.setEventHandler(validationEventCollector);

PluginDescriptor pluginDescriptor = (PluginDescriptor) unmarshaller.unmarshal(is);
return pluginDescriptor;
return unmarshaller.unmarshal(is);
} catch (JAXBException e) {
throw new PluginContainerException(e);
} catch (SAXException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@
public interface DescriptorPackages {
String CONFIGURATION = "org.rhq.core.clientapi.descriptor.configuration";
String PC_PLUGIN = "org.rhq.core.clientapi.descriptor.plugin";
String CANNED_EXPRESSIONS = "org.rhq.core.clientapi.descriptor.group.expressions";
}
90 changes: 90 additions & 0 deletions modules/core/client-api/src/main/resources/rhq-canned-groups.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

<!--
~ RHQ Management Platform
~ Copyright (C) 2005-2014 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.
-->

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:xmlns:rhq-canned-groups" xmlns:canned-groups="urn:xmlns:rhq-canned-groups"
xmlns:cg="urn:xmlns:rhq-canned-groups"
elementFormDefault="qualified" jaxb:version="2.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" blockDefault="">

<xs:annotation>
<xs:documentation>Schema for the definition of canned DynaGroup expressions
</xs:documentation>
<xs:appinfo>
<jaxb:schemaBindings>
<jaxb:package name="org.rhq.core.clientapi.descriptor.group.expressions" />
</jaxb:schemaBindings>
</xs:appinfo>
</xs:annotation>

<xs:simpleType name="idType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="80" />
</xs:restriction>
</xs:simpleType>

<xs:element name="expressions">
<xs:annotation>
<xs:documentation>
Top level element holding set of DynaGroup expressions
</xs:documentation>
<xs:appinfo>
<jaxb:class name="CannedGroupExpressions"/>
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="definition" minOccurs="1" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
DynaGroup expression definition
</xs:documentation>
<xs:appinfo>
<jaxb:property name="groupDefinitions" />
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="cg:idType" minOccurs="1" maxOccurs="1" />
<xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1" />
<xs:element name="createByDefault" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="recalcInMinutes" type="xs:positiveInteger" minOccurs="1" maxOccurs="1" />
<xs:element name="recursive" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="expression" type="xs:string" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

</xs:element>
</xs:sequence>

</xs:complexType>
<xs:unique name="unique-id">
<xs:selector xpath="GroupDefinition"/>
<xs:field xpath="@id"/>
</xs:unique>
</xs:element>
</xs:schema>
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,12 @@
<column name="CALC_INTERVAL" type="LONG"/>
<column name="RECURSIVE" type="BOOLEAN"/>
<column name="EXPRESSION" type="VARCHAR2" size="1000"/>
<column name="CANNED_EXPRESSION" type="VARCHAR2" size="100"/>

<index name="RHQ_GROUP_DEF_NAME" unique="true">
<field ref="NAME"/>
</index>
</table>

<table name="RHQ_RESOURCE_GROUP">
<column name="ID" default="sequence-only" initial="10001"
primarykey="true" required="true" type="INTEGER"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2309,6 +2309,11 @@
<schema-addColumn table="RHQ_AGENT_INSTALL" column="SSH_PASSWORD" columnType="VARCHAR2" precision="4000" />
</schemaSpec>

<schemaSpec version="2.145">
<schema-addColumn table="RHQ_GROUP_DEF" column="CANNED_EXPRESSION" columnType="VARCHAR2" precision="100" />
<schema-alterColumn table="RHQ_GROUP_DEF" column="CANNED_EXPRESSION" nullable="true"/>
</schemaSpec>

</dbupgrade>
</target>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 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.core.domain.plugin;

import java.util.ArrayList;
import java.util.List;

/**
*
* @author lzoubek@redhat.com
*
*/
public class CannedGroupAddition {

private List<CannedGroupExpression> expressions;

public void setExpressions(List<CannedGroupExpression> expressions) {
this.expressions = expressions;
}

public List<CannedGroupExpression> getExpressions() {
if (expressions == null) {
expressions = new ArrayList<CannedGroupExpression>();
}
return expressions;
}
}

0 comments on commit 414a2a6

Please sign in to comment.