/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* 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.esperio.representation.axiom;
import com.espertech.esper.client.*;
import com.espertech.esper.epl.generated.EsperEPL2GrammarParser;
import com.espertech.esper.event.*;
import com.espertech.esper.event.property.PropertyParser;
import com.espertech.esper.event.xml.SimpleXMLPropertyParser;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.jaxen.JaxenException;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import java.util.*;
/**
* Apache Axiom event type provides event metadata for Axiom OMDocument events.
* <p>
* Optimistic try to resolve the property string into an appropiate xPath, and
* use it as getter. Mapped and Indexed properties supported. Because no type
* information is given, all property are resolved to String. No namespace
* support. Cannot access to xml attributes, only elements content.
* <p>
* See {@link AxiomEventRepresentation} for more details.
*/
public class AxiomXMLEventType implements EventTypeSPI {
private EventTypeMetadata metadata;
private int eventTypeId;
private String defaultNamespacePrefix;
private ConfigurationEventTypeAxiom config;
private AxiomXPathNamespaceContext namespaceContext;
private Map<String, TypedEventPropertyGetter> propertyGetterCache;
private Map<String, EventPropertyDescriptor> propertyDescriptorsMap;
private EventPropertyDescriptor[] propertyDescriptors;
public AxiomXMLEventType(EventTypeMetadata metadata, int eventTypeId, ConfigurationEventTypeAxiom configurationEventTypeAxiom) {
this.metadata = metadata;
this.eventTypeId = eventTypeId;
this.config = configurationEventTypeAxiom;
this.propertyGetterCache = new HashMap<String, TypedEventPropertyGetter>();
// Set up a namespace context for XPath expressions
namespaceContext = new AxiomXPathNamespaceContext();
for (Map.Entry<String, String> entry : configurationEventTypeAxiom.getNamespacePrefixes().entrySet()) {
namespaceContext.addPrefix(entry.getKey(), entry.getValue());
}
// add namespaces
if (configurationEventTypeAxiom.getDefaultNamespace() != null) {
String defaultNamespace = configurationEventTypeAxiom.getDefaultNamespace();
namespaceContext.setDefaultNamespace(defaultNamespace);
// determine a default namespace prefix to use to construct XPath
// expressions from pure property names
defaultNamespacePrefix = null;
for (Map.Entry<String, String> entry : configurationEventTypeAxiom.getNamespacePrefixes().entrySet()) {
if (entry.getValue().equals(defaultNamespace)) {
defaultNamespacePrefix = entry.getKey();
break;
}
}
}
// determine XPath properties that are predefined
propertyDescriptorsMap = new HashMap<String, EventPropertyDescriptor>();
List<EventPropertyDescriptor> descriptors = new ArrayList<EventPropertyDescriptor>();
String xpathExpression = null;
try {
for (ConfigurationEventTypeAxiom.XPathPropertyDesc property : config.getXPathProperties().values()) {
TypedEventPropertyGetter getter = resolvePropertyGetter(property.getName(), property.getXpath(), property.getType(), property.getOptionalCastToType());
propertyGetterCache.put(property.getName(), getter);
EventPropertyDescriptor desc = new EventPropertyDescriptor(property.getName(), getter.getResultClass(), null, false, false, false, false, false);
propertyDescriptorsMap.put(property.getName(), desc);
descriptors.add(desc);
}
} catch (XPathExpressionException ex) {
throw new EPException("XPath expression could not be compiled for expression '" + xpathExpression + '\'', ex);
}
propertyDescriptors = descriptors.toArray(new EventPropertyDescriptor[descriptors.size()]);
}
public int getEventTypeId() {
return eventTypeId;
}
public Class getPropertyType(String property) {
TypedEventPropertyGetter getter = propertyGetterCache.get(property);
if (getter != null)
return getter.getResultClass();
return String.class; // all other types are assumed to exist and be of type String
}
public Class getUnderlyingType() {
return OMNode.class;
}
public EventPropertyGetter getGetter(String property) {
EventPropertyGetter getter = propertyGetterCache.get(property);
if (getter != null)
return getter;
try {
return resolveDynamicProperty(property);
} catch (XPathExpressionException e) {
return null;
}
}
public String[] getPropertyNames() {
Set<String> properties = propertyGetterCache.keySet();
return properties.toArray(new String[properties.size()]);
}
public boolean isProperty(String property) {
return getGetter(property) != null;
}
public EventType[] getSuperTypes() {
return null;
}
public Iterator<EventType> getDeepSuperTypes() {
return null;
}
public String getStartTimestampPropertyName() {
return null;
}
public String getEndTimestampPropertyName() {
return null;
}
/**
* Returns the configuration for the name.
*
* @return configuration details underlying the type
*/
public ConfigurationEventTypeAxiom getConfig() {
return config;
}
public EventTypeMetadata getMetadata() {
return metadata;
}
private TypedEventPropertyGetter resolveDynamicProperty(String property) throws XPathExpressionException {
// not defined, come up with an XPath
EsperEPL2GrammarParser.StartEventPropertyRuleContext ast = PropertyParser.parse(property);
String xPathExpr = SimpleXMLPropertyParser.walk(ast, property, config.getRootElementName(), defaultNamespacePrefix, config.isResolvePropertiesAbsolute());
return resolvePropertyGetter(property, xPathExpr, XPathConstants.STRING, null);
}
private TypedEventPropertyGetter resolvePropertyGetter(String propertyName, String xPathExpr, QName type, Class optionalCastToType) throws XPathExpressionException {
AXIOMXPath axXPath;
try {
axXPath = new AXIOMXPath(xPathExpr);
} catch (JaxenException e) {
throw new EPException("Error constructing XPath expression from property name '" + propertyName + '\'', e);
}
axXPath.setNamespaceContext(namespaceContext);
return new AxiomXPathPropertyGetter(propertyName, axXPath, type, optionalCastToType);
}
public String getName() {
return metadata.getPublicName();
}
public FragmentEventType getFragmentType(String propertyExpression) {
return null; // Does not allow fragments
}
public EventPropertyDescriptor[] getPropertyDescriptors() {
return propertyDescriptors;
}
public EventPropertyDescriptor getPropertyDescriptor(String propertyName) {
return propertyDescriptorsMap.get(propertyName);
}
public EventPropertyWriter getWriter(String propertyName) {
return null;
}
public EventPropertyDescriptor[] getWriteableProperties() {
return new EventPropertyDescriptor[0];
}
public EventBeanCopyMethod getCopyMethod(String[] properties) {
return null;
}
public EventPropertyDescriptor getWritableProperty(String propertyName) {
return null;
}
public EventBeanWriter getWriter(String[] properties) {
return null;
}
public EventBeanReader getReader() {
return null;
}
public EventPropertyGetterMapped getGetterMapped(String mappedPropertyName) {
return null;
}
public EventPropertyGetterIndexed getGetterIndexed(String indexedPropertyName) {
return null;
}
public boolean equalsCompareType(EventType eventType) {
return this == eventType;
}
}