org.jboss.system.metadata.ServiceMetaDataParser Maven / Gradle / Ivy
The newest version!
/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.system.metadata;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import javax.management.ObjectName;
import org.jboss.dependency.spi.ControllerMode;
import org.jboss.dependency.spi.ControllerState;
import org.jboss.logging.Logger;
import org.jboss.util.StringPropertyReplacer;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/**
* ServiceMetaDataParser
*
* This class is based on the old ServiceConfigurator/Creator.
*
* @author Marc Fleury
* @author Hiram Chirino
* @author David Jencks
* @author Jason Dillon
* @author Dimitris Andreadis
* @author Adrian Brock
* @version $Revision: 82920 $
*/
public class ServiceMetaDataParser
{
/** The log */
private static final Logger log = Logger.getLogger(ServiceMetaDataParser.class);
/** The element config */
private Element config;
/** The mode */
private ControllerMode serverMode;
/**
* Create a new service meta data parser
*
* @param config the xml config
*/
public ServiceMetaDataParser(Element config)
{
if (config == null)
throw new IllegalArgumentException("Null config");
this.config = config;
}
/**
* Rethrow an error as an exception
*
* @param context the context
* @param t the original throwable
* @return never
* @throws Exception always
*/
public static Exception rethrow(String context, Throwable t) throws Exception
{
if (t instanceof Error)
throw (Error) t;
else if (t instanceof Exception)
throw (Exception) t;
throw new RuntimeException(context, t);
}
/**
* Parse the xml
*
* @return the list of service meta data
* @throws Exception for any error
*/
public List parse() throws Exception
{
List services = new ArrayList();
try
{
String tagName = config.getTagName();
if ("mbean".equals(tagName))
internalParse(services, config, true);
else
{
if ("server".equals(tagName))
parseServer(config);
NodeList nl = config.getChildNodes();
for (int i = 0; i < nl.getLength(); ++i)
{
if (nl.item(i).getNodeType() == Node.ELEMENT_NODE)
{
Element element = (Element) nl.item(i);
if ("mbean".equals(element.getTagName()))
{
Element mbean = (Element) nl.item(i);
internalParse(services, mbean, true);
}
}
}
}
}
catch (Throwable t)
{
throw rethrow("Unable to parse service configuration", t);
}
return services;
}
/**
* Parse the server element
*
* @param serverElement the server element
* @throws Exception for any error
*/
private void parseServer(Element serverElement) throws Exception
{
String modeString = serverElement.getAttribute("mode");
if (modeString != null)
{
modeString = modeString.trim();
if (modeString.length() != 0)
serverMode = ControllerMode.getInstance(modeString);
}
}
/**
* Internal parse
*
* @param services the list of service meta data
* @param mbeanElement the mbean configuration
* @param replace whether to replace system properties
* @return the ObjectName of the parsed mbean
* @throws Exception for any error
*/
private ObjectName internalParse(List services, Element mbeanElement, boolean replace) throws Exception
{
ServiceMetaData service = new ServiceMetaData();
ObjectName mbeanName = parseObjectName(mbeanElement, replace);
service.setObjectName(mbeanName);
String code = parseCode(mbeanName, mbeanElement);
service.setCode(code);
ControllerMode mode = parseMode(mbeanName, mbeanElement);
if (mode == null)
mode = serverMode;
service.setMode(mode);
ServiceConstructorMetaData constructor = parseConstructor(mbeanName, mbeanElement, replace);
service.setConstructor(constructor);
String interfaceName = parseInterface(mbeanName, mbeanElement);
service.setInterfaceName(interfaceName);
String xmbeandd = parseXMBeanDD(mbeanName, mbeanElement);
service.setXMBeanDD(xmbeandd);
String xmbeanCode = parseXMBeanCode(mbeanName, mbeanElement);
service.setXMBeanCode(xmbeanCode);
if (xmbeandd != null && xmbeandd.length() == 0)
{
Element xmbeanDescriptor = parseXMBeanDescriptor(mbeanName, mbeanElement);
service.setXMBeanDescriptor(xmbeanDescriptor);
}
List annotations = new ArrayList();
List attributes = new ArrayList();
List dependencies = new ArrayList();
NodeList attrs = mbeanElement.getChildNodes();
for (int j = 0; j < attrs.getLength(); j++)
{
// skip over non-element nodes
if (attrs.item(j).getNodeType() != Node.ELEMENT_NODE)
continue;
Element element = (Element) attrs.item(j);
boolean replaceAttribute = true;
// Set attributes
if (element.getTagName().equals("attribute"))
{
String attributeName = element.getAttribute("name");
if (attributeName == null)
throw new RuntimeException("No attribute name for " + mbeanName);
boolean trim = true;
String replaceAttr = element.getAttribute("replace");
if (replaceAttr.length() > 0)
replaceAttribute = Boolean.valueOf(replaceAttr).booleanValue();
String trimAttr = element.getAttribute("trim");
if (trimAttr.length() > 0)
trim = Boolean.valueOf(trimAttr).booleanValue();
String serialDataType = element.getAttribute("serialDataType");
if (element.hasChildNodes())
{
// Unmarshall the attribute value based on the serialDataType
ServiceValueMetaData value = null;
if (serialDataType.equals("javaBean"))
{
value = new ServiceJavaBeanValueMetaData(element);
}
else if (serialDataType.equals("jbxb"))
{
value = new ServiceJBXBValueMetaData(element);
}
else
{
NodeList nl = element.getChildNodes();
for (int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE)
{
Element el = (Element) n;
String tagName = el.getTagName();
if ("inject".equals(tagName))
{
value = parseInject(el);
}
else if ("value-factory".equals(tagName))
{
value = parseValueFactory(el);
}
else
{
value = new ServiceElementValueMetaData((Element) n);
}
break;
}
}
if (value == null)
value = new ServiceTextValueMetaData(getElementTextContent(element, trim, replaceAttribute));
}
ServiceAttributeMetaData attribute = new ServiceAttributeMetaData();
attribute.setName(attributeName);
attribute.setReplace(replaceAttribute);
attribute.setTrim(trim);
attribute.setValue(value);
attributes.add(attribute);
}
}
else if (element.getTagName().equals("depends"))
{
String mbeanRefName = element.getAttribute("optional-attribute-name");
if ("".equals(mbeanRefName))
mbeanRefName = null;
else
mbeanRefName = StringPropertyReplacer.replaceProperties(mbeanRefName);
String proxyType = element.getAttribute("proxy-type");
if ("".equals(proxyType))
proxyType = null;
else
proxyType = StringPropertyReplacer.replaceProperties(proxyType);
// Get the mbeanRef value
String dependsObjectName = processDependency(mbeanName, mbeanRefName, element, services, replace);
if (mbeanRefName != null)
{
ServiceValueMetaData value = new ServiceDependencyValueMetaData(dependsObjectName, proxyType);
ServiceAttributeMetaData attribute = new ServiceAttributeMetaData();
attribute.setName(mbeanRefName);
attribute.setValue(value);
attributes.add(attribute);
}
else
{
ServiceDependencyMetaData dependency = new ServiceDependencyMetaData();
dependency.setIDependOn(dependsObjectName);
dependencies.add(dependency);
}
}
else if (element.getTagName().equals("depends-list"))
{
String dependsListName = element.getAttribute("optional-attribute-name");
if ("".equals(dependsListName))
dependsListName = null;
NodeList dependsList = element.getChildNodes();
ArrayList dependsListNames = new ArrayList();
for (int l = 0; l < dependsList.getLength(); ++l)
{
if (dependsList.item(l).getNodeType() != Node.ELEMENT_NODE)
continue;
Element dependsElement = (Element) dependsList.item(l);
if (dependsElement.getTagName().equals("depends-list-element"))
{
// Get the depends value
String dependsObjectName = processDependency(mbeanName, dependsListName, dependsElement, services, replace);
if (dependsListNames.contains(dependsObjectName) == false)
dependsListNames.add(dependsObjectName);
if (dependsListName == null)
{
ServiceDependencyMetaData dependency = new ServiceDependencyMetaData();
dependency.setIDependOn(dependsObjectName);
dependencies.add(dependency);
}
}
}
if (dependsListName != null)
{
ServiceValueMetaData value = new ServiceDependencyListValueMetaData(dependsListNames);
ServiceAttributeMetaData attribute = new ServiceAttributeMetaData();
attribute.setName(dependsListName);
attribute.setValue(value);
attributes.add(attribute);
}
}
else if (element.getTagName().equals("alias"))
{
List aliases = service.getAliases();
if (aliases == null)
{
aliases = new ArrayList();
service.setAliases(aliases);
}
aliases.add(getElementTextContent(element, true, true));
}
else if (element.getTagName().equals("annotation"))
{
String ann = getElementTextContent(element, true, true);
ServiceAnnotationMetaData amd = new ServiceAnnotationMetaData(ann);
annotations.add(amd);
}
}
service.setAttributes(attributes);
service.setDependencies(dependencies);
service.setAnnotations(annotations);
services.add(service);
return mbeanName;
}
/**
* Parse an object name from the given element attribute 'name'.
*
* @param mbeanElement the element to parse name from.
* @return the ObjectName
* @throws Exception for any error
*/
private ObjectName parseObjectName(final Element mbeanElement, boolean replace) throws Exception
{
String name = mbeanElement.getAttribute("name");
if (name == null || name.trim().length() == 0)
throw new RuntimeException("Missing or empty 'name' attribute for mbean.");
if (replace)
name = StringPropertyReplacer.replaceProperties(name);
return new ObjectName(name);
}
/**
* Parse a class name from the given element attribute 'code'.
*
* @param name the mbean name
* @param mbeanElement the element to parse name from.
* @return the class name
* @throws Exception for any error
*/
private String parseCode(final ObjectName name, final Element mbeanElement) throws Exception
{
return mbeanElement.getAttribute("code");
}
/**
* Parse the mode
*
* @param name the mbean name
* @param mbeanElement the element to parse name from.
* @return the mode
* @throws Exception for any error
*/
private ControllerMode parseMode(final ObjectName name, final Element mbeanElement) throws Exception
{
String modeString = mbeanElement.getAttribute("mode");
if (modeString == null)
return null;
modeString = modeString.trim();
if (modeString.length() == 0)
return null;
return ControllerMode.getInstance(modeString);
}
/**
* Parse the constructor element of the given element
*
* @param name the mbean name
* @param mbeanElement the element to parse name from.
* @param replace whether to replace system properties
* @return the constructor meta data
* @throws Exception for any error
*/
private ServiceConstructorMetaData parseConstructor(final ObjectName name, final Element mbeanElement, boolean replace) throws Exception
{
ServiceConstructorMetaData result = new ServiceConstructorMetaData();
NodeList list = mbeanElement.getElementsByTagName("constructor");
if (list.getLength() > 1 && list.item(0).getParentNode() == mbeanElement)
throw new RuntimeException("only one element may be defined for " + name);
if (list.getLength() == 1)
{
Element element = (Element) list.item(0);
// get all of the "arg" elements
list = element.getElementsByTagName("arg");
int length = list.getLength();
String[] params = new String[length];
String[] signature = new String[length];
// decode the values into params & signature
for (int j=0; j parameters = new ArrayList();
attr = el.getAttributeNode("parameter");
if (attr != null)
{
parameters.add(new ServiceValueFactoryParameterMetaData(attr.getValue()));
}
else
{
NodeList children = el.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
// skip over non-element nodes
if (children.item(j).getNodeType() != Node.ELEMENT_NODE)
continue;
Element child = (Element) children.item(j);
if ("parameter".equals(child.getTagName()))
{
parameters.add(parseValueFactoryParameter(child));
}
}
}
ServiceTextValueMetaData defaultValue = null;
attr = el.getAttributeNode("default");
if (attr != null)
{
defaultValue = new ServiceTextValueMetaData(attr.getValue());
}
value = new ServiceValueFactoryValueMetaData(dependency, method, parameters, requiredState, defaultValue);
return value;
}
private ServiceValueFactoryParameterMetaData parseValueFactoryParameter(Element el) throws Exception
{
String parameterType = null;
Attr attr = el.getAttributeNode("class");
if (attr != null)
parameterType = attr.getValue();
String textValue = null;
String valueType = null;
Node child = el.getFirstChild();
if (child.getNodeType() == Node.ELEMENT_NODE)
{
Element valueEl = (Element) child;
if ("value".equals(valueEl.getTagName()))
{
valueType = ((Element)child).getAttribute("class");
if (valueType.length() == 0)
valueType = null;
textValue = getElementTextContent(valueEl);
// Deal with any trim/replace from the outer element
textValue = trimAndReplace(textValue, getTrim(el), getReplace(el));
}
else if ("null".equals(valueEl.getTagName()) == false)
{
throw new RuntimeException("Element " + ((Element)child).getTagName() + " not supported as a child of value-factory/parameter in a -service.xml");
}
}
else
{
textValue = getElementTextContent(el);
}
return new ServiceValueFactoryParameterMetaData(textValue, parameterType, valueType);
}
/**
* Process a dependency
*
* @param mbeanName the surronding mbean
* @param attributeName the attribute name
* @param element the element
* @param services the list of services
* @param replace whether to replace properties
* @return the dependent object name
* @throws Exception for any error
*/
private String processDependency(ObjectName mbeanName, String attributeName, Element element, List services, boolean replace) throws Exception
{
String dependsObjectName = null;
NodeList nl = element.getChildNodes();
for (int i = 0; i < nl.getLength(); i++)
{
Node childNode = nl.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE)
{
Element child = (Element) childNode;
String tagName = child.getTagName();
if ("mbean".equals(tagName))
{
dependsObjectName = internalParse(services, child, replace).getCanonicalName();
break;
}
else
{
if (attributeName != null)
log.warn("Non mbean child <" + tagName + "/> in depends tag for " + mbeanName + " attribute: " + attributeName);
else
log.warn("Non mbean child <" + tagName + "/> in depends tag for " + mbeanName);
}
}
}
if (dependsObjectName == null)
dependsObjectName = getElementTextContent(element, true, replace);
return dependsObjectName;
}
/**
* Get an element's text content, looking for "trim" and "replace" attributes
* on the element to determine whether to trim the text and/or perform
* system property substitution.
*
* @param element the element
* @return the concatentation of the text nodes
* @throws Exception for any error
*/
public static String getElementTextContent(Element element) throws Exception
{
boolean replace = getReplace(element);
boolean trim = getTrim(element);
String rawText = getRawElementTextContent(element);
return trimAndReplace(rawText, trim, replace);
}
public static boolean getTrim(Element element)
{
boolean trim = true;
String trimAttr = element.getAttribute("trim");
if (trimAttr.length() > 0)
trim = Boolean.valueOf(trimAttr).booleanValue();
return trim;
}
public static boolean getReplace(Element element)
{
boolean replace = true;
String replaceAttr = element.getAttribute("replace");
if (replaceAttr.length() > 0)
replace = Boolean.valueOf(replaceAttr).booleanValue();
return replace;
}
/**
* Get an elements text content
*
* @param element the element
* @param trim whether to trim
* @param replace whetehr to replace properties
* @return the concatentation of the text nodes
* @throws Exception for any error
*/
public static String getElementTextContent(Element element, boolean trim, boolean replace) throws Exception
{
String rawText = getRawElementTextContent(element);
return trimAndReplace(rawText, trim, replace);
}
public static String getRawElementTextContent(Element element)
{
NodeList nl = element.getChildNodes();
String rawText = "";
for (int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if (n instanceof Text)
{
rawText += ((Text) n).getData();
}
}
return rawText;
}
public static String trimAndReplace(String rawText, boolean trim, boolean replace)
{
if (trim)
rawText = rawText.trim();
if (replace)
{
SecurityManager manager = System.getSecurityManager();
if (manager == null)
{
rawText = StringPropertyReplacer.replaceProperties(rawText);
}
else
{
final String input = rawText;
rawText = AccessController.doPrivileged(new PrivilegedAction()
{
public String run()
{
return StringPropertyReplacer.replaceProperties(input);
}
});
}
}
return rawText;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy