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

com.tangosol.config.xml.AbstractNamespaceHandler Maven / Gradle / Ivy

There is a newer version: 24.03
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.config.xml;

import com.tangosol.config.ConfigurationException;

import com.tangosol.run.xml.XmlAttribute;
import com.tangosol.run.xml.XmlElement;

import com.tangosol.util.Base;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

import java.net.URI;

import java.util.HashMap;

/**
 * An {@link AbstractNamespaceHandler} provides a base implementation of a {@link NamespaceHandler}
 * with support for implicit and explicit registration of {@link ElementProcessor}s and
 * {@link AttributeProcessor}s for those xml attributes and elements occurring in the associated xml namespace.
 *
 * @author bo 2011.06.20
 * @since Coherence 12.1.2
 */
public abstract class AbstractNamespaceHandler
        implements NamespaceHandler
    {
    // ----- constructors ---------------------------------------------------

    /**
     * Construct an {@link AbstractNamespaceHandler}.
     */
    public AbstractNamespaceHandler()
        {
        m_documentPreprocessor   = null;
        m_mapElementProcessors   = new HashMap>();
        m_mapAttributeProcessors = new HashMap>();

        // attempt to automatically register all Element and Attribute Processors
        // that are declared as non-abstract static inner classes
        autoRegisterInnerClassProcessors();
        }

    // ----- NamespaceHandler interface -------------------------------------

    /**
     * {@inheritDoc}
     */
    public DocumentPreprocessor getDocumentPreprocessor()
        {
        return m_documentPreprocessor;
        }

    /**
     * {@inheritDoc}
     */
    public AttributeProcessor getAttributeProcessor(XmlAttribute attribute)
        {
        AttributeProcessor processor = m_mapAttributeProcessors.get(attribute.getQualifiedName().getLocalName());

        return (processor == null) ? onUnknownAttribute(attribute) : processor;
        }

    /**
     * {@inheritDoc}
     */
    @Override
    public ElementProcessor getElementProcessor(XmlElement element)
        {
        ElementProcessor processor = m_mapElementProcessors.get(element.getQualifiedName().getLocalName());

        return (processor == null) ? onUnknownElement(element) : processor;
        }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onStartNamespace(ProcessingContext context, XmlElement element, String prefix, URI uri)
        {
        /**
         * Override this method to provide specific NamespaceHandler declaration semantics.
         */
        }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onEndNamespace(ProcessingContext context, XmlElement element, String prefix, URI uri)
        {
        /**
         * Override this method to provide specific NamespaceHandler disposal semantics
         */
        }

    // ----- AbstractNamespaceHandler interface -----------------------------

    /**
     * Sets the {@link DocumentPreprocessor} for the {@link NamespaceHandler}.
     *
     * @param preprocessor  the {@link DocumentPreprocessor}
     */
    public void setDocumentPreprocessor(DocumentPreprocessor preprocessor)
        {
        m_documentPreprocessor = preprocessor;
        }

    /**
     * Registers the specified processor as an {@link ElementProcessor} or 
     * {@link AttributeProcessor} (based on the interfaces it implements) 
     * using the {@link XmlSimpleName} annotation to determine the localName
     * of the said processor.
     * 

* Note: The specified class must have a no-args constructor. * * @param clzProcessor A class that implements either (or both) * {@link ElementProcessor} or {@link AttributeProcessor} * that is annotated with @{@link XmlSimpleName} to * specify it's localName. */ public void registerProcessor(Class clzProcessor) { if (clzProcessor.isAnnotationPresent(XmlSimpleName.class) && (ElementProcessor.class.isAssignableFrom(clzProcessor) || AttributeProcessor.class.isAssignableFrom(clzProcessor))) { try { String sLocalName = clzProcessor.getAnnotation(XmlSimpleName.class).value(); Object oProcessor = clzProcessor.newInstance(); if (oProcessor instanceof ElementProcessor) { registerProcessor(sLocalName, (ElementProcessor) oProcessor); } if (oProcessor instanceof AttributeProcessor) { registerProcessor(sLocalName, (AttributeProcessor) oProcessor); } } catch (InstantiationException e) { Base.ensureRuntimeException(e, "Specified processor class requires a no-args constructor."); } catch (IllegalAccessException e) { Base.ensureRuntimeException(e); } } } /** * Registers an {@link ElementProcessor} for {@link XmlElement}s with a name with in the context of * the {@link NamespaceHandler} namespace. * * @param sLocalName The local name of the {@link XmlElement} to be processed with the {@link ElementProcessor} * @param processor The {@link ElementProcessor} */ public void registerProcessor(String sLocalName, ElementProcessor processor) { m_mapElementProcessors.put(sLocalName, processor); } /** * Registers an {@link AttributeProcessor} for {@link XmlAttribute}s with the specified name. * * @param sLocalName The local name of the {@link XmlAttribute} to be processed with the {@link AttributeProcessor} * @param processor The {@link AttributeProcessor} */ public void registerProcessor(String sLocalName, AttributeProcessor processor) { m_mapAttributeProcessors.put(sLocalName, processor); } /** * Registers (internally creates) an appropriate {@link ElementProcessor} for {@link XmlElement}s with * the specified local name so that they produce the specified type of value when processed. * * @param the type of value the registered {@link ElementProcessor} will produce * @param sLocalName The local name of the {@link XmlElement}s to be associated with the type * @param clzType The {@link Class} of value that should be produced for the {@link XmlElement} */ @SuppressWarnings("unchecked") public void registerElementType(String sLocalName, Class clzType) { if (ElementProcessor.class.isAssignableFrom(clzType)) { try { ElementProcessor processor = (ElementProcessor) clzType.newInstance(); registerProcessor(sLocalName, processor); } catch (Exception exception) { throw new RuntimeException(String.format("Can't instantiate the ElementProcessor [%s]\n", clzType), exception); } } else { // default to the SimpleElementHandler with specified type registerProcessor(sLocalName, new SimpleElementProcessor(clzType)); } } /** * Registers (internally creates) an appropriate {@link AttributeProcessor} for {@link XmlAttribute}s with * the specified local name so that they produce the specified type of value when processed. * * @param the type of value the registered {@link AttributeProcessor} will produce * @param sLocalName The local name of the {@link XmlElement}s to be associated with the type * @param clzType The {@link Class} of value that should be produced for the {@link XmlAttribute} */ @SuppressWarnings("unchecked") public void registerAttributeType(String sLocalName, Class clzType) { if (AttributeProcessor.class.isAssignableFrom(clzType)) { try { AttributeProcessor processor = (AttributeProcessor) clzType.newInstance(); registerProcessor(sLocalName, processor); } catch (Exception exception) { throw new RuntimeException(String.format("Can't instantiate the AttributeProcessor [%s]\n", clzType), exception); } } else { registerProcessor(sLocalName, new SimpleAttributeProcessor(clzType)); } } /** * A call-back to handle when an {@link XmlAttribute} is unknown to the {@link NamespaceHandler}. *

* Override this method to provide specialized foreign {@link XmlAttribute} processing. By default, * null will be returned for unknown {@link XmlAttribute}s. * * @param attribute The {@link XmlAttribute} that was unknown. * * @return An appropriate {@link AttributeProcessor} that may be used to process the unknown {@link XmlAttribute} * or null if no special processing should occur. */ protected AttributeProcessor onUnknownAttribute(XmlAttribute attribute) { // SKIP: by default we don't do anything if the attribute is unknown return null; } /** * A call-back to handle when an {@link XmlElement} is unknown to the {@link NamespaceHandler}. *

* Override this method to provide specialized foreign {@link XmlElement} processing. * By default, unknown {@link XmlElement} will return an {@link ElementProcessor} that when attempting * to process the said element, will throw a {@link ConfigurationException}. * * @param element The {@link XmlElement} that was unknown. * * @return An appropriate {@link ElementProcessor} that may be used to process the unknown {@link XmlElement} * or null if no special processing should occur. */ protected ElementProcessor onUnknownElement(XmlElement element) { // SKIP: by default we don't do anything if the element is unknown return null; } /** * Obtains the {@link AttributeProcessor} registered with the specified * localName (in the namespace). * * @param localName the name of the {@link AttributeProcessor} to return * * @return the {@link AttributeProcessor} or null if not found */ public AttributeProcessor getAttributeProcessor(String localName) { return m_mapAttributeProcessors.get(localName); } /** * Obtains the {@link ElementProcessor} registered with the specified * localName (in the namespace). * * @param localName the name of the {@link ElementProcessor} to return * * @return the {@link ElementProcessor} or null if not found */ public ElementProcessor getElementProcessor(String localName) { return m_mapElementProcessors.get(localName); } /** * Using reflection, automatically locates and registers each of the inner-class {@link ElementProcessor} * and {@link AttributeProcessor} definitions with the {@link NamespaceHandler} namespace. */ void autoRegisterInnerClassProcessors() { for (Class clzDeclared : getClass().getDeclaredClasses()) { if (!clzDeclared.isInterface() && !clzDeclared.isAnnotation()) { String sProcessorName = getProcessorName(clzDeclared); if (sProcessorName != null && !sProcessorName.isEmpty() && (ElementProcessor.class.isAssignableFrom(clzDeclared) || AttributeProcessor.class.isAssignableFrom(clzDeclared))) { try { Object oProcessor; if (Modifier.isStatic(clzDeclared.getModifiers())) { // static inner class oProcessor = clzDeclared.newInstance(); } else { // non-static inner class Constructor constructor = clzDeclared.getConstructor(new Class[] {getClass()}); oProcessor = constructor.newInstance(new Object[] {this}); } if (ElementProcessor.class.isAssignableFrom(clzDeclared)) { registerProcessor(sProcessorName, (ElementProcessor) oProcessor); } if (AttributeProcessor.class.isAssignableFrom(clzDeclared)) { registerProcessor(sProcessorName, (AttributeProcessor) oProcessor); } } catch (Exception exception) { throw new RuntimeException(String.format("Can't instantiate the Processor [%s]\n", clzDeclared), exception); } } } } } /** * Determine xml element/attribute name of the specified {@link ElementProcessor} * / {@link AttributeProcessor} non-abstract {@link Class} that has * been annotated by {@link XmlSimpleName}. *

* A name for the processor is only returned if the specified class either * implements the {@link ElementProcessor} or {@link AttributeProcessor} interfaces * and is non-abstract with an {@link XmlSimpleName} annotation. Should any * of these conditions fail, null is returned. * * @param clzProcessor The {@link Class} from which to determine an appropriate name. * * @return The name of the processor */ String getProcessorName(Class clzProcessor) { if (clzProcessor != null && clzProcessor.isAnnotationPresent(XmlSimpleName.class)) { // use the name as specified by the annotation String sProcessorName = ((XmlSimpleName) clzProcessor.getAnnotation(XmlSimpleName.class)).value(); // now ensure that the class is non-abstract, static with a no-args constructor int nModifiers = clzProcessor.getModifiers(); if (Modifier.isAbstract(nModifiers) || clzProcessor.isAnnotation() || clzProcessor.isInterface()) { return null; } else { return sProcessorName; } } else { return null; } } // ----- data members --------------------------------------------------- /** * The registered {@link DocumentPreprocessor} for the {@link NamespaceHandler}. */ private DocumentPreprocessor m_documentPreprocessor; /** * The registered {@link AttributeProcessor}(s) for the {@link NamespaceHandler}. */ private HashMap> m_mapAttributeProcessors; /** * The registered {@link ElementProcessor}(s) for the {@link NamespaceHandler}. */ private HashMap> m_mapElementProcessors; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy