Package com.espertech.esper.event.xml

Source Code of com.espertech.esper.event.xml.SchemaXMLEventType

/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved.                            *
* http://esper.codehaus.org                                                          *
* http://www.espertech.com                                                           *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license       *
* a copy of which has been included with this distribution in the license.txt file.  *
**************************************************************************************/
package com.espertech.esper.event.xml;

import com.espertech.esper.client.*;
import com.espertech.esper.epl.parse.ASTFilterSpecHelper;
import com.espertech.esper.event.EventAdapterService;
import com.espertech.esper.event.EventTypeMetadata;
import com.espertech.esper.event.ExplicitPropertyDescriptor;
import com.espertech.esper.event.property.IndexedProperty;
import com.espertech.esper.event.property.Property;
import com.espertech.esper.event.property.PropertyParser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* EventType for xml events that have a Schema.
* Mapped and Indexed properties are supported.
* All property types resolved via the declared xsd types.
* Can access attributes.
* Validates the property string at construction time.
* @author pablo
*
*/
public class SchemaXMLEventType extends BaseXMLEventType
{
    private static final Log log = LogFactory.getLog(SchemaXMLEventType.class);

    private final SchemaModel schemaModel;
    private final SchemaElementComplex schemaModelRoot;
    private final String rootElementNamespace;
    private final Map<String, EventPropertyGetter> propertyGetterCache;
    private final boolean isPropertyExpressionXPath;

    /**
     * Ctor.
     * @param config - configuration for type
     * @param eventTypeMetadata - event type metadata
     * @param schemaModel - the schema representation
     * @param eventAdapterService - type lookup and registration
     */
    public SchemaXMLEventType(EventTypeMetadata eventTypeMetadata, int eventTypeId, ConfigurationEventTypeXMLDOM config, SchemaModel schemaModel, EventAdapterService eventAdapterService)
    {
        super(eventTypeMetadata, eventTypeId, config, eventAdapterService);

        this.propertyGetterCache = new HashMap<String, EventPropertyGetter>();
        this.schemaModel = schemaModel;
        this.rootElementNamespace = config.getRootElementNamespace();
        this.schemaModelRoot = SchemaUtil.findRootElement(schemaModel, rootElementNamespace, this.getRootElementName());
        this.isPropertyExpressionXPath = config.isXPathPropertyExpr();

        // Set of namespace context for XPath expressions
        XPathNamespaceContext ctx = new XPathNamespaceContext();
        if (config.getDefaultNamespace() != null)
        {
            ctx.setDefaultNamespace(config.getDefaultNamespace());
        }
        for (Map.Entry<String, String> entry : config.getNamespacePrefixes().entrySet())
        {
            ctx.addPrefix(entry.getKey(), entry.getValue());
        }
        super.setNamespaceContext(ctx);

        // add properties for the root element
        List<ExplicitPropertyDescriptor> additionalSchemaProps = new ArrayList<ExplicitPropertyDescriptor>();

        // Add a property for each complex child element
        for (SchemaElementComplex complex : schemaModelRoot.getChildren())
        {
            String propertyName = complex.getName();
            Class returnType = Node.class;

            if (complex.getOptionalSimpleType() != null)
            {
                returnType = SchemaUtil.toReturnType(complex);
            }
            if (complex.isArray())
            {
                returnType = Node[].class;      // We use Node[] for arrays and NodeList for XPath-Expressions returning Nodeset
            }

            boolean isFragment = false;
            if (this.getConfigurationEventTypeXMLDOM().isAutoFragment() && (!this.getConfigurationEventTypeXMLDOM().isXPathPropertyExpr()))
            {
                isFragment = canFragment(complex);
            }

            EventPropertyGetter getter = doResolvePropertyGetter(propertyName, true);
            EventPropertyDescriptor desc = new EventPropertyDescriptor(propertyName, returnType, null, false, false, complex.isArray(), false, isFragment);
            ExplicitPropertyDescriptor explicit = new ExplicitPropertyDescriptor(desc, getter, false, null);
            additionalSchemaProps.add(explicit);
        }

        // Add a property for each simple child element
        for (SchemaElementSimple simple : schemaModelRoot.getSimpleElements())
        {
            String propertyName = simple.getName();
            Class returnType = SchemaUtil.toReturnType(simple);
            EventPropertyGetter getter = doResolvePropertyGetter(propertyName, true);
            EventPropertyDescriptor desc = new EventPropertyDescriptor(propertyName, returnType, null, false, false, simple.isArray(), false, false);
            ExplicitPropertyDescriptor explicit = new ExplicitPropertyDescriptor(desc, getter, false, null);
            additionalSchemaProps.add(explicit);
        }

        // Add a property for each attribute
        for (SchemaItemAttribute attribute : schemaModelRoot.getAttributes())
        {
            String propertyName = attribute.getName();
            Class returnType = SchemaUtil.toReturnType(attribute);
            EventPropertyGetter getter = doResolvePropertyGetter(propertyName, true);
            EventPropertyDescriptor desc = new EventPropertyDescriptor(propertyName, returnType, null, false, false, false, false, false);
            ExplicitPropertyDescriptor explicit = new ExplicitPropertyDescriptor(desc, getter, false, null);
            additionalSchemaProps.add(explicit);
        }

        // Finally add XPath properties as that may depend on the rootElementNamespace
        super.initialize(config.getXPathProperties().values(), additionalSchemaProps);
    }

    public SchemaModel getSchemaModel() {
        return schemaModel;
    }

    protected FragmentEventType doResolveFragmentType(String property)
    {
        if ((!this.getConfigurationEventTypeXMLDOM().isAutoFragment()) || (this.getConfigurationEventTypeXMLDOM().isXPathPropertyExpr()))
        {
            return null;
        }

        Property prop = PropertyParser.parse(property, false);

        SchemaItem item = prop.getPropertyTypeSchema(schemaModelRoot, this.getEventAdapterService());
        if ((item == null) || (!canFragment(item)))
        {
            return null;
        }
        SchemaElementComplex complex = (SchemaElementComplex) item;

        // build name of event type
        String[] atomicProps = prop.toPropertyArray();
        String delimiterDot = ".";
        StringBuilder eventTypeNameBuilder = new StringBuilder(this.getName());
        for (String atomic : atomicProps)
        {
            eventTypeNameBuilder.append(delimiterDot);
            eventTypeNameBuilder.append(atomic);
        }
        String eventTypeName = eventTypeNameBuilder.toString();

        // check if the type exists, use the existing type if found
        EventType existingType = this.getEventAdapterService().getExistsTypeByName(eventTypeName);
        if (existingType != null)
        {
            return new FragmentEventType(existingType, complex.isArray(), false);
        }

        // add a new type
        ConfigurationEventTypeXMLDOM xmlDom = new ConfigurationEventTypeXMLDOM();
        xmlDom.setRootElementName("//" + complex.getName());    // such the reload of the type can resolve it
        xmlDom.setRootElementNamespace(complex.getNamespace());
        xmlDom.setAutoFragment(this.getConfigurationEventTypeXMLDOM().isAutoFragment());
        xmlDom.setEventSenderValidatesRoot(this.getConfigurationEventTypeXMLDOM().isEventSenderValidatesRoot());
        xmlDom.setXPathPropertyExpr(this.getConfigurationEventTypeXMLDOM().isXPathPropertyExpr());
        xmlDom.setXPathResolvePropertiesAbsolute(this.getConfigurationEventTypeXMLDOM().isXPathResolvePropertiesAbsolute());
        xmlDom.setSchemaResource(this.getConfigurationEventTypeXMLDOM().getSchemaResource());
        xmlDom.setSchemaText(this.getConfigurationEventTypeXMLDOM().getSchemaText());
        xmlDom.setXPathFunctionResolver(this.getConfigurationEventTypeXMLDOM().getXPathFunctionResolver());
        xmlDom.setXPathVariableResolver(this.getConfigurationEventTypeXMLDOM().getXPathVariableResolver());
        xmlDom.setDefaultNamespace(this.getConfigurationEventTypeXMLDOM().getDefaultNamespace());
        xmlDom.addNamespacePrefixes(this.getConfigurationEventTypeXMLDOM().getNamespacePrefixes());

        EventType newType;
        try
        {
            newType = this.getEventAdapterService().addXMLDOMType(eventTypeName, xmlDom, schemaModel, true);
        }
        catch (Exception ex)
        {
            log.error("Failed to add dynamic event type for fragment of XML schema for property '" + property + "' :" + ex.getMessage(), ex);
            return null;
        }
        return new FragmentEventType(newType, complex.isArray(), false);
    }

    protected Class doResolvePropertyType(String propertyExpression) {
        return doResolvePropertyType(propertyExpression, false);
    }

    private Class doResolvePropertyType(String propertyExpression, boolean allowSimpleProperties) {

        // see if this is an indexed property
        int index = ASTFilterSpecHelper.unescapedIndexOfDot(propertyExpression);
        if ((!allowSimpleProperties) && (index == -1))
        {
            // parse, can be an indexed property
            Property property = PropertyParser.parse(propertyExpression, false);
            if (!property.isDynamic())
            {
                if (!(property instanceof IndexedProperty))
                {
                    return null;
                }
                IndexedProperty indexedProp = (IndexedProperty) property;
                EventPropertyDescriptor descriptor = propertyDescriptorMap.get(indexedProp.getPropertyNameAtomic());
                if (descriptor == null)
                {
                    return null;
                }
                return descriptor.getPropertyType();
            }
        }

        Property prop = PropertyParser.parse(propertyExpression, false);
        if (prop.isDynamic())
        {
            return Node.class;
        }
       
        SchemaItem item = prop.getPropertyTypeSchema(schemaModelRoot, this.getEventAdapterService());
        if (item == null)
        {
            return null;
        }

        return SchemaUtil.toReturnType(item);
    }

    protected EventPropertyGetter doResolvePropertyGetter(String property) {
        return doResolvePropertyGetter(property, false);
    }

    private EventPropertyGetter doResolvePropertyGetter(String propertyExpression, boolean allowSimpleProperties) {
        EventPropertyGetter getter = propertyGetterCache.get(propertyExpression);
        if (getter != null)
        {
            return getter;
        }

        if (!allowSimpleProperties)
        {
            // see if this is an indexed property
            int index = ASTFilterSpecHelper.unescapedIndexOfDot(propertyExpression);
            if (index == -1)
            {
                // parse, can be an indexed property
                Property property = PropertyParser.parse(propertyExpression, false);
                if (!property.isDynamic())
                {
                    if (!(property instanceof IndexedProperty))
                    {
                        return null;
                    }
                    IndexedProperty indexedProp = (IndexedProperty) property;
                    getter = this.propertyGetters.get(indexedProp.getPropertyNameAtomic());
                    if (null == getter)
                    {
                        return null;
                    }
                    EventPropertyDescriptor descriptor = this.propertyDescriptorMap.get(indexedProp.getPropertyNameAtomic());
                    if (descriptor == null)
                    {
                        return null;
                    }
                    if (!descriptor.isIndexed())
                    {
                        return null;
                    }
                    if (descriptor.getPropertyType() == NodeList.class)
                    {
                        FragmentFactory fragmentFactory = new FragmentFactoryDOMGetter(this.getEventAdapterService(), this, indexedProp.getPropertyNameAtomic());
                        return new XPathPropertyArrayItemGetter(getter, indexedProp.getIndex(), fragmentFactory);
                    }
                }
            }
        }

        if (!isPropertyExpressionXPath)
        {
            Property prop = PropertyParser.parse(propertyExpression, false);
            boolean isDynamic = prop.isDynamic();

            if (!isDynamic)
            {
                SchemaItem item = prop.getPropertyTypeSchema(schemaModelRoot, this.getEventAdapterService());
                if (item == null)
                {
                    return null;
                }

                getter = prop.getGetterDOM(schemaModelRoot, this.getEventAdapterService(), this, propertyExpression);
                if (getter == null)
                {
                    return null;
                }

                Class returnType = SchemaUtil.toReturnType(item);
                if ((returnType != Node.class) && (returnType != NodeList.class))
                {
                    if (!returnType.isArray())
                    {
                        getter = new DOMConvertingGetter(propertyExpression, (DOMPropertyGetter) getter, returnType);
                    }
                    else
                    {
                        getter = new DOMConvertingArrayGetter((DOMPropertyGetter) getter, returnType.getComponentType());
                    }
                }
            }
            else
            {
                return prop.getGetterDOM();
            }
        }
        else
        {
            boolean allowFragments = !this.getConfigurationEventTypeXMLDOM().isXPathPropertyExpr();
            getter = SchemaXMLPropertyParser.getXPathResolution(propertyExpression,getXPathFactory(),getRootElementName(),rootElementNamespace, schemaModel, this.getEventAdapterService(), this, allowFragments, this.getConfigurationEventTypeXMLDOM().getDefaultNamespace());
        }

        propertyGetterCache.put(propertyExpression, getter);
        return getter;
    }

    private boolean canFragment(SchemaItem item)
    {
        if (!(item instanceof SchemaElementComplex))
        {
            return false;
        }

        SchemaElementComplex complex = (SchemaElementComplex) item;
        if (complex.getOptionalSimpleType() != null)
        {
            return false;    // no transposing if the complex type also has a simple value else that is hidden
        }

        return true;
    }
}
TOP

Related Classes of com.espertech.esper.event.xml.SchemaXMLEventType

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.