All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.weld.xml.BeansXmlHandler Maven / Gradle / Ivy

There is a newer version: 3.0.0.Alpha1
Show newest version
package org.jboss.weld.xml;

import static java.util.Arrays.asList;

import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.jboss.weld.bootstrap.spi.BeanDiscoveryMode;
import org.jboss.weld.bootstrap.spi.BeansXml;
import org.jboss.weld.bootstrap.spi.ClassAvailableActivation;
import org.jboss.weld.bootstrap.spi.Filter;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.bootstrap.spi.SystemPropertyActivation;
import org.jboss.weld.logging.XmlLogger;
import org.jboss.weld.metadata.BeansXmlImpl;
import org.jboss.weld.metadata.ClassAvailableActivationImpl;
import org.jboss.weld.metadata.FilterImpl;
import org.jboss.weld.metadata.ScanningImpl;
import org.jboss.weld.metadata.SystemPropertyActivationImpl;
import org.jboss.weld.metadata.WeldFilterImpl;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import com.google.common.collect.ImmutableSet;

/**
 * An implementation of the beans.xml parser written using SAX
 * 

* This class is NOT threadsafe, and should only be called in a single thread * * @author Pete Muir */ public class BeansXmlHandler extends DefaultHandler { private static final String VALUE_ATTRIBUTE_QUALIFIED_NAME = "value"; private static final String PATTERN_ATTRIBUTE_QUALIFIED_NAME = "pattern"; private static final String NAME_ATTRIBUTE_QUALIFIED_NAME = "name"; protected static String trim(String str) { if (str == null) { return null; } else { return str.trim(); } } public abstract class Container { private final Set uris; private final String localName; private final Collection nestedElements; public Container(Set uris, String localName, String... nestedElements) { this.uris = uris; this.localName = localName; this.nestedElements = asList(nestedElements); } public String getLocalName() { return localName; } public Set getUris() { return uris; } /** * Called by startElement, the nested content is not available */ public void processStartChildElement(String uri, String localName, String qName, Attributes attributes) { } /** * Called by endElement, the nested content is not available */ public void processEndChildElement(String uri, String localName, String qName, String nestedText) { } public void handleMultiple() { } public Collection getNestedElements() { return nestedElements; } @Override public String toString() { return "<" + localName + " />"; } protected boolean isInNamespace(String namespace) { if (namespace.length() == 0) { return true; } return getUris().contains(namespace); } } private abstract class SpecContainer extends Container { public SpecContainer(String localName, String... nestedElements) { super(JAVAEE_URIS, localName, nestedElements); } } public static final String JAVAEE_LEGACY_URI = "http://java.sun.com/xml/ns/javaee"; public static final String JAVAEE_URI = "http://xmlns.jcp.org/xml/ns/javaee"; public static final Set JAVAEE_URIS = ImmutableSet.of(JAVAEE_LEGACY_URI, JAVAEE_URI); public static final String WELD_URI = "http://jboss.org/schema/weld/beans"; public static final Set SCANNING_URI = ImmutableSet.of(WELD_URI, JAVAEE_URI, JAVAEE_LEGACY_URI); private static final String VERSION_ATTRIBUTE_NAME = "version"; private static final String BEAN_DISCOVERY_MODE_ATTRIBUTE_NAME = "bean-discovery-mode"; private static final String ROOT_ELEMENT_NAME = "beans"; private static final String IF_CLASS_AVAILABLE = "if-class-available"; private static final String IF_CLASS_NOT_AVAILABLE = "if-class-not-available"; private static final String IF_SYSTEM_PROPERTY = "if-system-property"; private static final String CLASS = "class"; private static final String STEREOTYPE = "stereotype"; private static final String INCLUDE = "include"; private static final String EXCLUDE = "exclude"; // See also http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/#cvc-elt private static final String VALIDATION_ERROR_CODE_CVC_ELT_1 = "cvc-elt.1"; /* * The containers we are parsing */ private final Collection containers; /* * Storage for parsed info */ private final List> interceptors; private final List> decorators; private final List> alternativesClasses; private final List> alternativeStereotypes; private final List> includes; private final List> excludes; protected final URL file; private BeanDiscoveryMode discoveryMode; private String version; /* * Parser State */ private Collection seenContainers; private Container currentContainer; private StringBuilder buffer; private Locator locator; public BeansXmlHandler(final URL file) { this.file = file; this.interceptors = new ArrayList>(); this.decorators = new ArrayList>(); this.alternativesClasses = new ArrayList>(); this.alternativeStereotypes = new ArrayList>(); this.includes = new ArrayList>(); this.excludes = new ArrayList>(); this.seenContainers = new ArrayList(); this.containers = new ArrayList(); this.discoveryMode = BeanDiscoveryMode.ALL; // this is the default value for a beans.xml file containers.add(new SpecContainer("interceptors", CLASS) { @Override public void processEndChildElement(String uri, String localName, String qName, String nestedText) { if (isInNamespace(uri) && CLASS.equals(localName)) { interceptors.add(new XmlMetadata(qName, trim(nestedText), file, locator.getLineNumber())); } } @Override public void handleMultiple() { throw XmlLogger.LOG.multipleInterceptors(file + "@" + locator.getLineNumber()); } }); containers.add(new SpecContainer("decorators", CLASS) { @Override public void processEndChildElement(String uri, String localName, String qName, String nestedText) { if (isInNamespace(uri) && CLASS.equals(localName)) { decorators.add(new XmlMetadata(qName, trim(nestedText), file, locator.getLineNumber())); } } @Override public void handleMultiple() { throw XmlLogger.LOG.multipleDecorators(file + "@" + locator.getLineNumber()); } }); containers.add(new SpecContainer("alternatives", CLASS, STEREOTYPE) { @Override public void processEndChildElement(String uri, String localName, String qName, String nestedText) { if (isInNamespace(uri) && CLASS.equals(localName)) { alternativesClasses.add(new XmlMetadata(qName, trim(nestedText), file, locator.getLineNumber())); } else if (isInNamespace(uri) && STEREOTYPE.equals(localName)) { alternativeStereotypes.add(new XmlMetadata(qName, trim(nestedText), file, locator.getLineNumber())); } } @Override public void handleMultiple() { throw XmlLogger.LOG.multipleAlternatives(file + "@" + locator.getLineNumber()); } }); containers.add(new Container(SCANNING_URI, "scan") { String name; String pattern; Collection> systemPropertyActivations; Collection> classAvailableActivations; @Override public void processStartChildElement(String uri, String localName, String qName, Attributes attributes) { if (isFilterElement(uri, localName)) { name = interpolateAttributeValue(attributes, NAME_ATTRIBUTE_QUALIFIED_NAME); pattern = interpolateAttributeValue(attributes, PATTERN_ATTRIBUTE_QUALIFIED_NAME); systemPropertyActivations = new ArrayList>(); classAvailableActivations = new ArrayList>(); } else if (isInNamespace(uri)) { if (IF_CLASS_AVAILABLE.equals(localName) || IF_CLASS_NOT_AVAILABLE.equals(localName)) { String className = interpolateAttributeValue(attributes, NAME_ATTRIBUTE_QUALIFIED_NAME); Metadata classAvailableActivation = new XmlMetadata(qName, new ClassAvailableActivationImpl(className, IF_CLASS_NOT_AVAILABLE.equals(localName)), file, locator.getLineNumber()); classAvailableActivations.add(classAvailableActivation); } else if (IF_SYSTEM_PROPERTY.equals(localName)) { String systemPropertyName = interpolateAttributeValue(attributes, NAME_ATTRIBUTE_QUALIFIED_NAME); String systemPropertyValue = interpolateAttributeValue(attributes, VALUE_ATTRIBUTE_QUALIFIED_NAME); Metadata systemPropertyActivation = new XmlMetadata(qName, new SystemPropertyActivationImpl(systemPropertyName, systemPropertyValue), file, locator.getLineNumber()); systemPropertyActivations.add(systemPropertyActivation); } } } private String interpolateAttributeValue(Attributes attributes, String qName) { String value = trim(attributes.getValue(qName)); return value == null ? null : interpolate(value); } @Override public void processEndChildElement(String uri, String localName, String qName, String nestedText) { if (isFilterElement(uri, localName)) { Filter filter = null; if (WELD_URI.equals(uri)) { filter = new WeldFilterImpl(name, systemPropertyActivations, classAvailableActivations, pattern); } else { filter = new FilterImpl(name, systemPropertyActivations, classAvailableActivations); } Metadata filterMetadata = new XmlMetadata(qName, filter, file, locator.getLineNumber()); if (INCLUDE.equals(localName)) { includes.add(filterMetadata); } else if (EXCLUDE.equals(localName)) { excludes.add(filterMetadata); } // reset name = null; pattern = null; systemPropertyActivations = null; classAvailableActivations = null; } } private boolean isFilterElement(String uri, String localName) { return isInNamespace(uri) && (INCLUDE.equals(localName) || EXCLUDE.equals(localName)); } @Override public void handleMultiple() { throw XmlLogger.LOG.multipleScanning(file + "@" + locator.getLineNumber()); } }); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName.equals(ROOT_ELEMENT_NAME) && ("".equals(uri) || JAVAEE_URIS.contains(uri))) { processRootElement(attributes); return; } if (currentContainer == null) { Container container = getContainer(uri, localName); if (container != null) { if (seenContainers.contains(container)) { container.handleMultiple(); } currentContainer = container; } } else { currentContainer.processStartChildElement(uri, localName, qName, attributes); // The current container is interested in the content of this element if (currentContainer.getNestedElements().contains(localName)) { buffer = new StringBuilder(); } } } private void processRootElement(Attributes attributes) { String discoveryMode = attributes.getValue(BEAN_DISCOVERY_MODE_ATTRIBUTE_NAME); if (discoveryMode != null) { this.discoveryMode = BeanDiscoveryMode.valueOf(discoveryMode.toUpperCase()); } String version = attributes.getValue(VERSION_ATTRIBUTE_NAME); if (version != null) { this.version = version; } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (currentContainer != null) { currentContainer.processEndChildElement(uri, localName, qName, buffer != null ? buffer.toString() : null); // The current container was interested in this element if (currentContainer.getNestedElements().contains(localName)) { buffer = null; } Container container = getContainer(uri, localName); if (container != null) { // We are exiting the container, record it so we know it's already been declared (for error reporting) seenContainers.add(container); // And stop work until we find another container of interest currentContainer = null; } } } private Container getContainer(String uri, String localName) { return getContainer(uri, localName, containers); } private static Container getContainer(String uri, String localName, Collection containers) { for (Container container : containers) { if (uri.length() == 0) { if (container.getLocalName().equals(localName)) { return container; } } else { if (container.getLocalName().equals(localName) && container.getUris().contains(uri)) { return container; } } } return null; } public BeansXml createBeansXml() { return new BeansXmlImpl(alternativesClasses, alternativeStereotypes, decorators, interceptors, new ScanningImpl(includes, excludes), file, discoveryMode, version); } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (buffer != null) { buffer.append(ch, start, length); } } @Override public void setDocumentLocator(Locator locator) { this.locator = locator; } @Override public void warning(SAXParseException e) throws SAXException { XmlLogger.LOG.xsdValidationWarning(file, e.getLineNumber(), e.getMessage()); } @Override public void error(SAXParseException e) throws SAXException { if (e.getMessage().startsWith(VALIDATION_ERROR_CODE_CVC_ELT_1) && e.getMessage().contains(ROOT_ELEMENT_NAME)) { // Ignore the errors we get when there is no schema defined return; } XmlLogger.LOG.xsdValidationError(file, e.getLineNumber(), e.getMessage()); } protected String interpolate(String string) { return string; // noop by default, integrators may override } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy