/* * 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.util; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; 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.resource.CreateResourceStatus; import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; import org.rhq.core.pluginapi.inventory.CreateResourceReport; import org.rhq.core.pluginapi.util.SelectiveSkippingEntityResolver; /** * Common base class for MessagingConfig related stuff * @author Heiko W. Rupp */ public class AbstractMessagingConfigurationEditor { protected static final Log LOG = LogFactory.getLog(JBossMessagingConfigurationEditor.class); private static final String JNDI_NAME = "JNDIName"; protected static final String DEPENDS = "depends"; /** * Holds the type of JMS */ protected String type; protected String code; /** * Root Element of the xml file. The component should be a child element of the root element */ protected String rootElementString = "server"; /** * Root Element of the XML File. Always check for NPE in your code. This is assigned in the main interface methods. * There are not getters or setters for this attribute. */ protected Element root; /** * Configuration object for the resource. Always check for NPE in your code. Configuration object is assigned in the * update methods of the public interface, so there are no setters or getters needed The configuration is retrieved * directly from either the @see CreateResourceReport or * * @see org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport objects */ protected Configuration config; protected CreateResourceReport createReport; protected ConfigurationUpdateReport updateReport; /** * File object of the XML file that will store the resource's configuration values. Always check for NPE in your * code. The File object is assigned in the public interface methods, so there are no setters or getters needed. The * File object is passed in through the APIs parameters */ protected File deploymentFile; protected String securityConfig; private static final String MBEAN_NAME = "MBeanName"; protected static final String ATTRIBUTE = "attribute"; public AbstractMessagingConfigurationEditor() { super(); } public void deleteComponent(File deploymentFile, String name) { this.deploymentFile = deploymentFile; Document doc; if (deploymentFile.exists()) { try { SAXBuilder builder = new SAXBuilder(); SelectiveSkippingEntityResolver entityResolver = SelectiveSkippingEntityResolver.getDtdAndXsdSkippingInstance(); builder.setEntityResolver(entityResolver); doc = builder.build(deploymentFile); root = doc.getRootElement(); if (root != null) { if (!root.getName().equals(rootElementString)) { throw new RuntimeException(rootElementString + " file format exception on [" + deploymentFile + "], expected [" + rootElementString + "] element but found [" + root.getName() + "]"); } Element datasourceElement = findComponentElement(name); root.removeContent(datasourceElement); } updateFile(doc); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } /** * Takes the child elements of the componentElement and loops through them to find the particular property via the * looped elements attribute and creates the PropertySimple objects to attach to the @see Configuration object * * @param elementName String representing the type of Element to get. * @param attributeName What is the property name to find within the children * @param componentElement Element representing this Topic or Queue */ protected void bindSimplePropertiesToXML(String elementName, String attributeName, Element componentElement) { List<Element> children = componentElement.getChildren(elementName); for (Element element : children) { Attribute attribute = element.getAttribute(attributeName); String propertyName = null; if (attribute != null) { propertyName = attribute.getValue(); } String elementValue = element.getValue(); if ((propertyName != null) && (elementValue != null)) { PropertySimple dependProperty = new PropertySimple(propertyName, elementValue); config.put(dependProperty); } } } protected void bindSimplePropertiesToConfiguration(String[] properties, String elementName, String attributeName, Element componentElement) { for (String simpleAttribute : properties) { PropertySimple property = config.getSimple(simpleAttribute); if (property != null) { String value = property.getStringValue(); if (value != null) { if (elementName.equals(DEPENDS)) { try { ObjectName.getInstance(value); } catch (MalformedObjectNameException e) { LOG .error("Dependency to " + value + " does not exist or is not deployed. Because of this invalid dependency, this Topic/Queue will not be deployed."); property.setErrorMessage("'" + value + "' is not a valid JMX object name."); if (updateReport != null) { updateReport.setStatus(ConfigurationUpdateStatus.FAILURE); } if (createReport != null) { createReport.setStatus(CreateResourceStatus.FAILURE); } } } Element element = new Element(elementName); Attribute attribute = new Attribute(attributeName, simpleAttribute); element.setAttribute(attribute); element.setText(value); componentElement.addContent(element); } } } } /** * Finds the main Element object that holds all the configuration for the particular component. For example in JMS * the tag will be <mbean> with a name attribute for the particular Topic or Queue name * * @param name String Topic or Queue name * * @return The Element object that holds the entire configuration. */ protected Element findComponentElement(String name) { for (Object child : root.getChildren()) { Element childElement = (Element) child; String tagValue = childElement.getName(); if (tagValue.equals("mbean")) { String mBeanName = childElement.getAttribute("name").getValue(); Element jndiElement = childElement.getChild(JNDI_NAME); if (jndiElement != null) { if (name.equals(jndiElement.getValue())) { return childElement; } } else { String nameWithinMBean = type + ",name=" + name; if (nameWithinMBean.equals(mBeanName)) { return childElement; } } } } return null; } /** * Gets the Element for the component that holds the Security Confs for Roles. * * @param componentElement components main Element * * @return SecurityConf Element */ protected Element findSecurityConf(Element componentElement) { List<Element> attributeElements = componentElement.getChildren("attribute"); if (attributeElements != null) { for (Element attributeElement : attributeElements) { Attribute attributeName = attributeElement.getAttribute("name"); if (attributeName.getValue().equals(securityConfig)) { return attributeElement; } } } return null; } private void checkDependencies(String value, Property property) { try { ObjectName name = ObjectName.getInstance(value); } catch (MalformedObjectNameException e) { LOG .error("Dependency to " + value + " does not exist or is not deployed. because of this dependency this Topic/Queue will not deploy either."); property.setErrorMessage(value + " is not a valid value."); if (updateReport != null) { updateReport.setStatus(ConfigurationUpdateStatus.FAILURE); } if (createReport != null) { createReport.setStatus(CreateResourceStatus.FAILURE); } } } protected void loadNameProperty(Element mbeanElement) { String name = getNameFromMBeanElement(mbeanElement); PropertySimple dependProperty = new PropertySimple("MBeanName", name); config.put(dependProperty); } protected String getNameProperty() { String name = ""; PropertySimple property = config.getSimple(MBEAN_NAME); if (property != null) { name = property.getStringValue(); } return name; } protected void updateIfNameChanged(Element mbeanElement) { String nameInXML = getNameFromMBeanElement(mbeanElement); String nameInConfiguration = getNameProperty(); if (!nameInXML.equals(nameInConfiguration)) { addNameAttributeToMBeanElement(mbeanElement, nameInConfiguration); } } protected void addNameAttributeToMBeanElement(Element mbeanElement, String name) { Attribute nameAttribute = new Attribute("name", ""); nameAttribute.setValue(type + ",name=" + name); mbeanElement.removeAttribute("name"); // If it exists we need to remove it mbeanElement.setAttribute(nameAttribute); } private String getNameFromMBeanElement(Element mbeanElement) { Attribute name = mbeanElement.getAttribute("name"); String attributeValue = name.getValue(); String[] piecesOfAttribute = attributeValue.split(",name="); String valueInAttribute = piecesOfAttribute[1]; return valueInAttribute; } /** * Updates the file. * * @param doc JDom Document object for the file * * @throws org.jdom.JDOMException If JDOM cannot process the Document object * @throws java.io.IOException If there is an exception when dealing with the File object. */ protected void updateFile(Document doc) throws JDOMException, IOException { if (!isSetToFailure()) { FileOutputStream fos = new FileOutputStream(deploymentFile); XMLOutputter outp = new XMLOutputter(Format.getPrettyFormat()); outp.output(doc, fos); fos.flush(); fos.close(); } } /** * Used to determine if we should be updating the actual file if there is a failure. * * @return boolean whether the update or create report is set to Failure status. */ private boolean isSetToFailure() { boolean isFailure = false; if (updateReport != null) { isFailure = (updateReport.getStatus().equals(ConfigurationUpdateStatus.FAILURE)); } if (createReport != null) { isFailure = (createReport.getStatus().equals(CreateResourceStatus.FAILURE)); } return isFailure; } /** * Getter method * * @return String root Element name. i.e. "datasources" */ public String getRootElementString() { return rootElementString; } /** * Setter method * * @param rootElement root element name. i.e. "datasources" */ public void setRootElementString(String rootElement) { this.rootElementString = rootElement; } /** * Getter method * * @return String component type. i.e. "local-tx-datasource" */ public String getType() { return type; } /** * Setter method * * @param type component type. i.e. "local-tx-datasource" */ public void setType(String type) { this.type = type; } public Configuration loadConfiguration(File file, String name) { if (file==null) return null; deploymentFile = file; try { SAXBuilder builder = new SAXBuilder(); SelectiveSkippingEntityResolver entityResolver = SelectiveSkippingEntityResolver.getDtdAndXsdSkippingInstance(); builder.setEntityResolver(entityResolver); Document doc = builder.build(deploymentFile); // Get the root element root = doc.getRootElement(); if (!root.getName().equals(rootElementString)) { return null; } Element componentElement = findComponentElement(name); if (componentElement == null) { return null; } config = new Configuration(); bindSimplePropertiesToXML(DEPENDS, "optional-attribute-name", componentElement); bindSimplePropertiesToXML(ATTRIBUTE, "name", componentElement); loadNameProperty(componentElement); //Got to get the elements Element securityConf = findSecurityConf(componentElement); if (securityConf != null) { Element security = securityConf.getChild("security"); List<Element> roles = security.getChildren(); PropertyList rolesList = new PropertyList(securityConfig); for (Element role : roles) { PropertyMap map = new PropertyMap("role"); List<Attribute> attributes = role.getAttributes(); for (Attribute attribute : attributes) { PropertySimple property = new PropertySimple(attribute.getName(), attribute.getValue()); map.put(property); } rolesList.add(map); } config.put(rolesList); } return config; } catch (IOException e) { LOG.error("IOException when trying to read xml file for type " + type + " component " + name, e); } catch (JDOMException e) { LOG.error("Unable to convert resource into xml file elements", e); } return null; } }