Example #1
0
        protected override FragmentEventType DoResolveFragmentType(String property)
        {
            if ((!ConfigurationEventTypeXMLDOM.IsAutoFragment) || (ConfigurationEventTypeXMLDOM.IsXPathPropertyExpr))
            {
                return(null);
            }

            Property prop = PropertyParser.ParseAndWalkLaxToSimple(property);

            SchemaItem item = prop.GetPropertyTypeSchema(_schemaModelRoot, EventAdapterService);

            if ((item == null) || (!CanFragment(item)))
            {
                return(null);
            }
            var complex = (SchemaElementComplex)item;

            // build name of event type
            String[] atomicProps          = prop.ToPropertyArray();
            String   delimiterDot         = ".";
            var      eventTypeNameBuilder = new StringBuilder(Name);

            foreach (String atomic in atomicProps)
            {
                eventTypeNameBuilder.Append(delimiterDot);
                eventTypeNameBuilder.Append(atomic);
            }
            String eventTypeName = eventTypeNameBuilder.ToString();

            // check if the type exists, use the existing type if found
            EventType existingType = EventAdapterService.GetEventTypeByName(eventTypeName);

            if (existingType != null)
            {
                return(new FragmentEventType(existingType, complex.IsArray, false));
            }

            // add a new type
            var xmlDom = new ConfigurationEventTypeXMLDOM();

            xmlDom.RootElementName                  = "//" + complex.Name; // such the reload of the type can resolve it
            xmlDom.RootElementNamespace             = complex.Namespace;
            xmlDom.IsAutoFragment                   = ConfigurationEventTypeXMLDOM.IsAutoFragment;
            xmlDom.IsEventSenderValidatesRoot       = ConfigurationEventTypeXMLDOM.IsEventSenderValidatesRoot;
            xmlDom.IsXPathPropertyExpr              = ConfigurationEventTypeXMLDOM.IsXPathPropertyExpr;
            xmlDom.IsXPathResolvePropertiesAbsolute = ConfigurationEventTypeXMLDOM.IsXPathResolvePropertiesAbsolute;
            xmlDom.SchemaResource                   = ConfigurationEventTypeXMLDOM.SchemaResource;
            xmlDom.SchemaText            = ConfigurationEventTypeXMLDOM.SchemaText;
            xmlDom.XPathFunctionResolver = ConfigurationEventTypeXMLDOM.XPathFunctionResolver;
            xmlDom.XPathVariableResolver = ConfigurationEventTypeXMLDOM.XPathVariableResolver;
            xmlDom.DefaultNamespace      = ConfigurationEventTypeXMLDOM.DefaultNamespace;
            xmlDom.AddNamespacePrefixes(ConfigurationEventTypeXMLDOM.NamespacePrefixes);

            EventType newType;

            try
            {
                newType = EventAdapterService.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.Message, ex);
                return(null);
            }
            return(new FragmentEventType(newType, complex.IsArray, false));
        }
Example #2
0
        /// <summary>
        /// Return the xPath corresponding to the given property. The PropertyName String
        /// may be simple, nested, indexed or mapped.
        /// </summary>
        /// <param name="propertyName">is the event property name</param>
        /// <param name="namespace">is the default namespace</param>
        /// <param name="schemaModel">is the schema model</param>
        /// <param name="xPathContext">is the xpath factory instance to use</param>
        /// <param name="rootElementName">is the name of the root element</param>
        /// <param name="eventAdapterService">for type lookup and creation</param>
        /// <param name="xmlEventType">the resolving type</param>
        /// <param name="isAllowFragment">whether fragmenting is allowed</param>
        /// <param name="defaultNamespace">default namespace</param>
        /// <returns>
        /// xpath expression
        /// </returns>
        /// <throws>EPException is there are XPath errors</throws>
        public static EventPropertyGetterSPI GetXPathResolution(
            String propertyName,
            XPathNamespaceContext xPathContext,
            String rootElementName,
            String @namespace,
            SchemaModel schemaModel,
            EventAdapterService eventAdapterService,
            BaseXMLEventType xmlEventType,
            bool isAllowFragment,
            String defaultNamespace)
        {
            if (Log.IsDebugEnabled)
            {
                Log.Debug("Determining XPath expression for property '" + propertyName + "'");
            }

            var ctx        = new XPathNamespaceContext();
            var namespaces = schemaModel.Namespaces;

            string defaultNamespacePrefix = null;

            for (int i = 0; i < namespaces.Count; i++)
            {
                var namespacePrefix = "n" + i;
                ctx.AddNamespace(namespacePrefix, namespaces[i]);
                if ((defaultNamespace != null) && (defaultNamespace == namespaces[i]))
                {
                    defaultNamespacePrefix = namespacePrefix;
                }
            }

            var property  = PropertyParser.ParseAndWalkLaxToSimple(propertyName);
            var isDynamic = property.IsDynamic;

            var    rootComplexElement = SchemaUtil.FindRootElement(schemaModel, @namespace, rootElementName);
            string prefix             = ctx.LookupPrefix(rootComplexElement.Namespace);

            if (prefix == null)
            {
                prefix = "";
            }
            else
            {
                prefix += ':';
            }

            var xPathBuf = new StringBuilder();

            xPathBuf.Append('/');
            xPathBuf.Append(prefix);
            if (rootElementName.StartsWith("//"))
            {
                xPathBuf.Append(rootElementName.Substring(2));
            }
            else
            {
                xPathBuf.Append(rootElementName);
            }

            var parentComplexElement            = rootComplexElement;
            Pair <String, XPathResultType> pair = null;

            if (!(property is NestedProperty))
            {
                pair = MakeProperty(rootComplexElement, property, ctx, true, isDynamic, defaultNamespacePrefix);
                if (pair == null)
                {
                    throw new PropertyAccessException("Failed to locate property '" + propertyName + "' in schema");
                }
                xPathBuf.Append(pair.First);
            }
            else
            {
                NestedProperty nestedProperty = (NestedProperty)property;
                int            indexLast      = nestedProperty.Properties.Count - 1;

                for (int i = 0; i < indexLast + 1; i++)
                {
                    var isLast         = i == indexLast;
                    var propertyNested = nestedProperty.Properties[i];
                    pair = MakeProperty(parentComplexElement, propertyNested, ctx, isLast, isDynamic, defaultNamespacePrefix);
                    if (pair == null)
                    {
                        throw new PropertyAccessException("Failed to locate property '" + propertyName + "' nested property part '" + property.PropertyNameAtomic + "' in schema");
                    }

                    var text = propertyNested.PropertyNameAtomic;
                    var obj  = SchemaUtil.FindPropertyMapping(parentComplexElement, text);
                    if (obj is SchemaElementComplex)
                    {
                        parentComplexElement = (SchemaElementComplex)obj;
                    }
                    xPathBuf.Append(pair.First);
                }
            }

            var xPath = xPathBuf.ToString();

            if ((ExecutionPathDebugLog.IsEnabled) && (Log.IsDebugEnabled))
            {
                Log.Debug(".parse XPath for property '" + propertyName + "' is expression=" + xPath);
            }

            // Compile assembled XPath expression
            if (Log.IsDebugEnabled)
            {
                Log.Debug("Compiling XPath expression '" + xPath + "' for property '" + propertyName + "' using namespace context :" + ctx);
            }

            XPathExpression expr;

            try
            {
                expr = XPathExpression.Compile(xPath, ctx);
            }
            catch (XPathException e)
            {
                String detail = "Error constructing XPath expression from property expression '" + propertyName + "' expression '" + xPath + "'";
                if (e.Message != null)
                {
                    throw new EPException(detail + " :" + e.Message, e);
                }
                throw new EPException(detail, e);
            }

            // get type
            var item = property.GetPropertyTypeSchema(rootComplexElement, eventAdapterService);

            if ((item == null) && (!isDynamic))
            {
                return(null);
            }

            var resultType = isDynamic ? typeof(XmlNode) : SchemaUtil.ToReturnType(item);

            FragmentFactory fragmentFactory = null;

            if (isAllowFragment)
            {
                fragmentFactory = new FragmentFactoryDOMGetter(eventAdapterService, xmlEventType, propertyName);
            }

            return(new XPathPropertyGetter(propertyName, xPath, expr, pair.Second, resultType, fragmentFactory));
        }
Example #3
0
        public FragmentEventType GetFragmentType(string propertyName)
        {
            var item = _propertyItems.Get(propertyName);
            if (item != null) {
                // may contain null values
                return item.FragmentEventType;
            }

            // see if this is a nested property
            var index = StringValue.UnescapedIndexOfDot(propertyName);
            if (index == -1) {
                // dynamic simple property
                if (propertyName.EndsWith("?")) {
                    return null;
                }

                // parse, can be an indexed property
                var property = PropertyParser.ParseAndWalkLaxToSimple(propertyName);
                if (property is IndexedProperty indexedProp) {
                    var type = _nestableTypes.Get(indexedProp.PropertyNameAtomic);
                    if (type == null) {
                        return null;
                    }

                    if (type is EventType[] eventTypesArray) {
                        var eventType = eventTypesArray[0];
                        return new FragmentEventType(eventType, false, false);
                    }

                    if (type is TypeBeanOrUnderlying[] beanOrUnderlyings) {
                        var innerType = beanOrUnderlyings[0].EventType;
                        if (!(innerType is BaseNestableEventType)) {
                            return null;
                        }

                        return new FragmentEventType(innerType, false, false); // false since an index is present
                    }

                    if (!(type is Type)) {
                        return null;
                    }

                    if (!((Type) type).IsArray) {
                        return null;
                    }

                    // its an array
                    return EventBeanUtility.CreateNativeFragmentType(
                        ((Type) type).GetElementType(),
                        null,
                        _beanEventTypeFactory,
                        _publicFields);
                }

                if (property is MappedProperty) {
                    // No type information available for the inner event
                    return null;
                }

                return null;
            }

            // Map event types allow 2 types of properties inside:
            //   - a property that is a object is interrogated via bean property getters and BeanEventType
            //   - a property that is a Map itself is interrogated via map property getters
            // The property getters therefore act on

            // Take apart the nested property into a map key and a nested value class property name
            var propertyMap = StringValue.UnescapeDot(propertyName.Substring(0, index));
            var propertyNested = propertyName.Substring(index + 1);

            // If the property is dynamic, it cannot be a fragment
            if (propertyMap.EndsWith("?")) {
                return null;
            }

            var nestedType = _nestableTypes.Get(propertyMap);
            if (nestedType == null) {
                // parse, can be an indexed property
                var property = PropertyParser.ParseAndWalkLaxToSimple(propertyMap);
                if (property is IndexedProperty indexedProp) {
                    var type = _nestableTypes.Get(indexedProp.PropertyNameAtomic);
                    if (type == null) {
                        return null;
                    }

                    // handle map-in-map case
                    if (type is TypeBeanOrUnderlying[] beanOrUnderlyings) {
                        var innerType = beanOrUnderlyings[0].EventType;
                        if (!(innerType is BaseNestableEventType)) {
                            return null;
                        }

                        return innerType.GetFragmentType(propertyNested);
                    }

                    if (type is EventType[] innerEventTypeArray) {
                        // handle EventType[] in map
                        var innerType = innerEventTypeArray[0];
                        return innerType.GetFragmentType(propertyNested);
                    }

                    // handle array class in map case
                    if (!(type is Type)) {
                        return null;
                    }

                    if (!((Type) type).IsArray) {
                        return null;
                    }

                    var fragmentParent = EventBeanUtility.CreateNativeFragmentType(
                        (Type) type,
                        null,
                        _beanEventTypeFactory,
                        _publicFields);

                    return fragmentParent?.FragmentType.GetFragmentType(propertyNested);
                }

                if (property is MappedProperty) {
                    // No type information available for the property's map value
                    return null;
                }

                return null;
            }

            // If there is a map value in the map, return the Object value if this is a dynamic property
            if (ReferenceEquals(nestedType, typeof(IDictionary<string, object>))) {
                return null;
            }

            if (nestedType is IDictionary<string, object>) {
                return null;
            }

            if (nestedType is Type simpleClass) {
                if (!simpleClass.IsFragmentableType()) {
                    return null;
                }

                EventType nestedEventType = _beanEventTypeFactory.GetCreateBeanType(simpleClass, _publicFields);
                return nestedEventType.GetFragmentType(propertyNested);
            }

            if (nestedType is EventType innerEventType) {
                return innerEventType.GetFragmentType(propertyNested);
            }

            if (nestedType is EventType[] eventTypeArray) {
                return eventTypeArray[0].GetFragmentType(propertyNested);
            }

            if (nestedType is TypeBeanOrUnderlying typeBeanOrUnderlying) {
                var innerType = typeBeanOrUnderlying.EventType;
                if (!(innerType is BaseNestableEventType)) {
                    return null;
                }

                return innerType.GetFragmentType(propertyNested);
            }

            if (nestedType is TypeBeanOrUnderlying[] typeBeanOrUnderlyings) {
                var innerType = typeBeanOrUnderlyings[0].EventType;
                if (!(innerType is BaseNestableEventType)) {
                    return null;
                }

                return innerType.GetFragmentType(propertyNested);
            }

            var message = "Nestable map type configuration encountered an unexpected value type of '" +
                          nestedType.GetType() +
                          " for property '" +
                          propertyName +
                          "', expected Class, Map.class or Map<String, Object> as value type";
            throw new PropertyAccessException(message);
        }
Example #4
0
        private EventPropertyGetterSPI DoResolvePropertyGetter(
            string propertyExpression,
            bool allowSimpleProperties)
        {
            var getter = propertyGetterCache.Get(propertyExpression);
            if (getter != null) {
                return getter;
            }

            if (!allowSimpleProperties) {
                // see if this is an indexed property
                var index = StringValue.UnescapedIndexOfDot(propertyExpression);
                if (index == -1) {
                    // parse, can be an indexed property
                    var property = PropertyParser.ParseAndWalkLaxToSimple(propertyExpression);
                    if (!property.IsDynamic) {
                        if (!(property is IndexedProperty)) {
                            return null;
                        }

                        var indexedProp = (IndexedProperty) property;
                        getter = propertyGetters.Get(indexedProp.PropertyNameAtomic);
                        if (null == getter) {
                            return null;
                        }

                        var descriptor = PropertyDescriptorMap.Get(indexedProp.PropertyNameAtomic);
                        if (descriptor == null) {
                            return null;
                        }

                        if (!descriptor.IsIndexed) {
                            return null;
                        }

                        if (descriptor.PropertyType == typeof(XmlNodeList)) {
                            FragmentFactorySPI fragmentFactory = new FragmentFactoryDOMGetter(
                                EventBeanTypedEventFactory,
                                this,
                                indexedProp.PropertyNameAtomic);
                            return new XPathPropertyArrayItemGetter(getter, indexedProp.Index, fragmentFactory);
                        } else if (descriptor.PropertyType == typeof(string)) {
                            FragmentFactorySPI fragmentFactory = new FragmentFactoryDOMGetter(
                                EventBeanTypedEventFactory,
                                this,
                                indexedProp.PropertyNameAtomic);
                            return new XPathPropertyArrayItemGetter(getter, indexedProp.Index, fragmentFactory);
                        }
                    }
                }
            }

            if (!isPropertyExpressionXPath) {
                var prop = PropertyParser.ParseAndWalkLaxToSimple(propertyExpression);
                var isDynamic = prop.IsDynamic;

                if (!isDynamic) {
                    var item = prop.GetPropertyTypeSchema(schemaModelRoot);
                    if (item == null) {
                        return null;
                    }

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

                    var returnType = SchemaUtil.ToReturnType(item);
                    if (returnType != typeof(XmlNode) && returnType != typeof(XmlNodeList)) {
                        if (!returnType.IsArray) {
                            getter = new DOMConvertingGetter((DOMPropertyGetter) getter, returnType);
                        }
                        else {
                            getter = new DOMConvertingArrayGetter(
                                (DOMPropertyGetter) getter,
                                returnType.GetElementType());
                        }
                    }
                }
                else {
                    return prop.GetterDOM;
                }
            }
            else {
                var allowFragments = !ConfigurationEventTypeXMLDOM.IsXPathPropertyExpr;
                getter = SchemaXMLPropertyParser.GetXPathResolution(
                    propertyExpression,
                    NamespaceContext,
                    RootElementName,
                    rootElementNamespace,
                    SchemaModel,
                    EventBeanTypedEventFactory,
                    this,
                    allowFragments,
                    ConfigurationEventTypeXMLDOM.DefaultNamespace);
            }

            propertyGetterCache.Put(propertyExpression, getter);
            return getter;
        }
Example #5
0
        public EventPropertyWriter GetWriter(string propertyName)
        {
            if (_writeablePropertyDescriptors == null)
            {
                InitializeWriters();
            }
            var pair = _writerMap.Get(propertyName);
            if (pair != null)
            {
                return pair.Second;
            }

            var property = PropertyParser.ParseAndWalkLaxToSimple(propertyName);
            if (property is MappedProperty)
            {
                var mapProp = (MappedProperty)property;
                var methodName = PropertyHelper.GetSetterMethodName(mapProp.PropertyNameAtomic);
                MethodInfo setterMethod;
                try
                {
                    setterMethod = MethodResolver.ResolveMethod(
                        _clazz, methodName, new Type[] { typeof(string), typeof(object) }, true, new bool[2], new bool[2]);
                }
                catch (EngineNoSuchMethodException)
                {
                    Log.Info(
                        "Failed to find mapped property setter method '" + methodName + "' for writing to property '" +
                        propertyName + "' taking {string, Object} as parameters");
                    return null;
                }
                if (setterMethod == null)
                {
                    return null;
                }
                var fastMethod = _fastClass.GetMethod(setterMethod);
                return new BeanEventPropertyWriterMapProp(_clazz, fastMethod, mapProp.Key);
            }

            if (property is IndexedProperty)
            {
                var indexedProp = (IndexedProperty)property;
                var methodName = PropertyHelper.GetSetterMethodName(indexedProp.PropertyNameAtomic);
                MethodInfo setterMethod;
                try
                {
                    // setterMethod = UnderlyingType.GetMethod(
                    //    methodName, BindingFlags.Public | BindingFlags.Instance, null,
                    //    new Type[] { typeof(int), typeof(object) }, null);

                    setterMethod = MethodResolver.ResolveMethod(
                        _clazz, methodName, new Type[] { typeof(int), typeof(object) }, true, new bool[2], new bool[2]);
                }
                catch (EngineNoSuchMethodException)
                {
                    Log.Info(
                        "Failed to find indexed property setter method '" + methodName + "' for writing to property '" +
                        propertyName + "' taking {int, Object} as parameters");
                    return null;
                }
                if (setterMethod == null)
                {
                    return null;
                }
                var fastMethod = _fastClass.GetMethod(setterMethod);
                return new BeanEventPropertyWriterIndexedProp(_clazz, fastMethod, indexedProp.Index);
            }

            return null;
        }
Example #6
0
        public FragmentEventType GetFragmentType(String propertyName)
        {
            var item = _propertyItems.Get(propertyName);

            if (item != null) // may contain null values
            {
                return(item.FragmentEventType);
            }

            // see if this is a nested property
            var index = ASTUtil.UnescapedIndexOfDot(propertyName);

            if (index == -1)
            {
                // dynamic simple property
                if (propertyName.EndsWith("?"))
                {
                    return(null);
                }

                // parse, can be an indexed property
                var property = PropertyParser.ParseAndWalkLaxToSimple(propertyName);
                if (property is IndexedProperty)
                {
                    var indexedProp = (IndexedProperty)property;
                    var type        = NestableTypes.Get(indexedProp.PropertyNameAtomic);
                    if (type == null)
                    {
                        return(null);
                    }
                    else if (type is EventType[])
                    {
                        var eventType = ((EventType[])type)[0];
                        return(new FragmentEventType(eventType, false, false));
                    }
                    else if (type is String)
                    {
                        var propTypeName = type.ToString();
                        var isArray      = EventTypeUtility.IsPropertyArray(propTypeName);
                        if (!isArray)
                        {
                            return(null);
                        }
                        propTypeName = EventTypeUtility.GetPropertyRemoveArray(propTypeName);
                        EventType innerType = _eventAdapterService.GetEventTypeByName(propTypeName);
                        if (!(innerType is BaseNestableEventType))
                        {
                            return(null);
                        }
                        return(new FragmentEventType(innerType, false, false)); // false since an index is present
                    }
                    if (!(type is Type))
                    {
                        return(null);
                    }
                    if (!((Type)type).IsArray)
                    {
                        return(null);
                    }
                    // its an array
                    return(EventBeanUtility.CreateNativeFragmentType(((Type)type).GetElementType(), null, _eventAdapterService));
                }
                else if (property is MappedProperty)
                {
                    // No type information available for the inner event
                    return(null);
                }
                else
                {
                    return(null);
                }
            }

            // Map event types allow 2 types of properties inside:
            //   - a property that is a object is interrogated via bean property getters and BeanEventType
            //   - a property that is a Map itself is interrogated via map property getters
            // The property getters therefore act on

            // Take apart the nested property into a map key and a nested value class property name
            var propertyMap    = ASTUtil.UnescapeDot(propertyName.Substring(0, index));
            var propertyNested = propertyName.Substring(index + 1);

            // If the property is dynamic, it cannot be a fragment
            if (propertyMap.EndsWith("?"))
            {
                return(null);
            }

            var nestedType = NestableTypes.Get(propertyMap);

            if (nestedType == null)
            {
                // parse, can be an indexed property
                var property = PropertyParser.ParseAndWalkLaxToSimple(propertyMap);
                if (property is IndexedProperty)
                {
                    var indexedProp = (IndexedProperty)property;
                    var type        = NestableTypes.Get(indexedProp.PropertyNameAtomic);
                    if (type == null)
                    {
                        return(null);
                    }
                    // handle map-in-map case
                    if (type is String)
                    {
                        var propTypeName = type.ToString();
                        var isArray      = EventTypeUtility.IsPropertyArray(propTypeName);
                        if (isArray)
                        {
                            propTypeName = EventTypeUtility.GetPropertyRemoveArray(propTypeName);
                        }
                        EventType innerType = _eventAdapterService.GetEventTypeByName(propTypeName);
                        if (!(innerType is BaseNestableEventType))
                        {
                            return(null);
                        }
                        return(innerType.GetFragmentType(propertyNested));
                    }
                    // handle eventtype[] in map
                    else if (type is EventType[])
                    {
                        var innerType = ((EventType[])type)[0];
                        return(innerType.GetFragmentType(propertyNested));
                    }
                    // handle array class in map case
                    else
                    {
                        if (!(type is Type))
                        {
                            return(null);
                        }
                        if (!((Type)type).IsArray)
                        {
                            return(null);
                        }
                        var fragmentParent = EventBeanUtility.CreateNativeFragmentType(
                            (Type)type, null, _eventAdapterService);
                        if (fragmentParent == null)
                        {
                            return(null);
                        }
                        return(fragmentParent.FragmentType.GetFragmentType(propertyNested));
                    }
                }
                else if (property is MappedProperty)
                {
                    // No type information available for the property's map value
                    return(null);
                }
                else
                {
                    return(null);
                }
            }

            // If there is a map value in the map, return the Object value if this is a dynamic property
            if (ReferenceEquals(nestedType, typeof(IDictionary <string, object>)))
            {
                return(null);
            }
            else if (nestedType is IDictionary <string, object> )
            {
                return(null);
            }
            else if (nestedType is Type)
            {
                var simpleClass = (Type)nestedType;
                if (!TypeHelper.IsFragmentableType(simpleClass))
                {
                    return(null);
                }
                EventType nestedEventType =
                    _eventAdapterService.BeanEventTypeFactory.CreateBeanTypeDefaultName(simpleClass);
                return(nestedEventType.GetFragmentType(propertyNested));
            }
            else if (nestedType is EventType)
            {
                var innerType = (EventType)nestedType;
                return(innerType.GetFragmentType(propertyNested));
            }
            else if (nestedType is EventType[])
            {
                var innerType = (EventType[])nestedType;
                return(innerType[0].GetFragmentType(propertyNested));
            }
            else if (nestedType is String)
            {
                var nestedName = nestedType.ToString();
                var isArray    = EventTypeUtility.IsPropertyArray(nestedName);
                if (isArray)
                {
                    nestedName = EventTypeUtility.GetPropertyRemoveArray(nestedName);
                }
                var innerType = _eventAdapterService.GetEventTypeByName(nestedName);
                if (!(innerType is BaseNestableEventType))
                {
                    return(null);
                }
                return(innerType.GetFragmentType(propertyNested));
            }
            else
            {
                var message = "Nestable map type configuration encountered an unexpected value type of '"
                              + nestedType.GetType() + " for property '" + propertyName +
                              "', expected Class, typeof(Map) or IDictionary<String, Object> as value type";
                throw new PropertyAccessException(message);
            }
        }
Example #7
0
        public static EventPropertyGetter GetGetter(
            Schema avroSchema,
            Dictionary <string, EventPropertyGetter> propertyGetterCache,
            IDictionary <string, PropertySetDescriptorItem> propertyDescriptors,
            string propertyName,
            bool addToCache,
            EventAdapterService eventAdapterService)
        {
            var getter = propertyGetterCache.Get(propertyName);

            if (getter != null)
            {
                return(getter);
            }

            var unescapePropName = ASTUtil.UnescapeDot(propertyName);
            var item             = propertyDescriptors.Get(unescapePropName);

            if (item != null)
            {
                getter = item.PropertyGetter;
                MayAddToGetterCache(propertyName, propertyGetterCache, getter, true);
                return(getter);
            }

            // see if this is a nested property
            var index = ASTUtil.UnescapedIndexOfDot(propertyName);

            if (index == -1)
            {
                var prop = PropertyParser.ParseAndWalkLaxToSimple(propertyName);
                if (prop is IndexedProperty)
                {
                    var   indexedProp = (IndexedProperty)prop;
                    Field field       = avroSchema.GetField(prop.PropertyNameAtomic);
                    if (field == null)
                    {
                        return(null);
                    }
                    switch (field.Schema.Tag)
                    {
                    case Schema.Type.Array:
                        var fragmentEventType = AvroFragmentTypeUtil.GetFragmentEventTypeForField(
                            field.Schema, eventAdapterService);
                        getter = new AvroEventBeanGetterIndexed(
                            field, indexedProp.Index,
                            fragmentEventType == null ? null : fragmentEventType.FragmentType, eventAdapterService);
                        MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                        return(getter);

                    case Schema.Type.String:
                        getter = new AvroEventBeanGetterStringIndexed(field, indexedProp.Index);
                        MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                        return(getter);

                    default:
                        return(null);
                    }
                }
                else if (prop is MappedProperty)
                {
                    var   mappedProp = (MappedProperty)prop;
                    Field field      = avroSchema.GetField(prop.PropertyNameAtomic);
                    if (field == null || field.Schema.Tag != Schema.Type.Map)
                    {
                        return(null);
                    }
                    getter = new AvroEventBeanGetterMapped(field, mappedProp.Key);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return(getter);
                }
                if (prop is DynamicIndexedProperty)
                {
                    var dynamicIndexedProp = (DynamicIndexedProperty)prop;
                    getter = new AvroEventBeanGetterIndexedDynamic(prop.PropertyNameAtomic, dynamicIndexedProp.Index);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return(getter);
                }
                if (prop is DynamicMappedProperty)
                {
                    var dynamicMappedProp = (DynamicMappedProperty)prop;
                    getter = new AvroEventBeanGetterMappedDynamic(prop.PropertyNameAtomic, dynamicMappedProp.Key);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return(getter);
                }
                else if (prop is DynamicSimpleProperty)
                {
                    getter = new AvroEventBeanGetterSimpleDynamic(prop.PropertyNameAtomic);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return(getter);
                }
                return(null); // simple property already cached
            }

            // Take apart the nested property into a map key and a nested value class property name
            var propertyTop     = ASTUtil.UnescapeDot(propertyName.Substring(0, index));
            var propertyNested  = propertyName.Substring(index + 1);
            var isRootedDynamic = false;

            // If the property is dynamic, remove the ? since the property type is defined without
            if (propertyTop.EndsWith("?"))
            {
                propertyTop     = propertyTop.Substring(0, propertyTop.Length - 1);
                isRootedDynamic = true;
            }

            var   propTop  = PropertyParser.ParseAndWalkLaxToSimple(propertyTop);
            Field fieldTop = avroSchema.GetField(propTop.PropertyNameAtomic);

            // field is known and is a record
            if (fieldTop != null && fieldTop.Schema.Tag == Schema.Type.Record && propTop is SimpleProperty)
            {
                var factory  = new GetterNestedFactoryRootedSimple(eventAdapterService, fieldTop);
                var property = PropertyParser.ParseAndWalk(propertyNested, isRootedDynamic);
                getter = PropertyGetterNested(factory, fieldTop.Schema, property, eventAdapterService);
                MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                return(getter);
            }

            // field is known and is a record
            if (fieldTop != null && fieldTop.Schema.Tag == Schema.Type.Array && propTop is IndexedProperty)
            {
                var factory = new GetterNestedFactoryRootedIndexed(
                    eventAdapterService, fieldTop, ((IndexedProperty)propTop).Index);
                var property = PropertyParser.ParseAndWalk(propertyNested, isRootedDynamic);
                getter = PropertyGetterNested(factory, fieldTop.Schema.GetElementType(), property, eventAdapterService);
                MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                return(getter);
            }

            // field is not known or is not a record
            if (!isRootedDynamic)
            {
                return(null);
            }
            var propertyX   = PropertyParser.ParseAndWalk(propertyNested, true);
            var innerGetter = GetDynamicGetter(propertyX);

            getter = new AvroEventBeanGetterNestedDynamicPoly(propertyTop, innerGetter);
            MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
            return(getter);
        }
Example #8
0
        public static EventPropertyGetterSPI GetGetter(
            Schema avroSchema,
            string moduleName,
            Dictionary<string, EventPropertyGetterSPI> propertyGetterCache,
            IDictionary<string, PropertySetDescriptorItem> propertyDescriptors,
            string propertyName,
            bool addToCache,
            EventBeanTypedEventFactory eventAdapterService,
            EventTypeAvroHandler eventTypeAvroHandler,
            AvroEventTypeFragmentTypeCache fragmentTypeCache)
        {
            var getter = propertyGetterCache.Get(propertyName);
            if (getter != null) {
                return getter;
            }

            var unescapePropName = StringValue.UnescapeDot(propertyName);
            var item = propertyDescriptors.Get(unescapePropName);
            if (item != null) {
                getter = item.PropertyGetter;
                MayAddToGetterCache(propertyName, propertyGetterCache, getter, true);
                return getter;
            }

            // see if this is a nested property
            var index = StringValue.UnescapedIndexOfDot(propertyName);
            if (index == -1) {
                var prop = PropertyParser.ParseAndWalkLaxToSimple(propertyName);
                if (prop is IndexedProperty indexedProp) {
                    var field = avroSchema.GetField(indexedProp.PropertyNameAtomic);
                    if (field == null) {
                        return null;
                    }

                    if ((field.Schema.Tag != Schema.Type.Array) &&
                        (field.Schema.Tag != Schema.Type.String)) {
                        return null;
                    }

                    var fragmentEventType = AvroFragmentTypeUtil.GetFragmentEventTypeForField(
                        field.Schema,
                        moduleName,
                        eventAdapterService,
                        eventTypeAvroHandler,
                        fragmentTypeCache);
                    getter = new AvroEventBeanGetterIndexed(
                        field,
                        indexedProp.Index,
                        fragmentEventType?.FragmentType,
                        eventAdapterService);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return getter;
                }

                if (prop is MappedProperty mappedProp) {
                    Field field = avroSchema.GetField(mappedProp.PropertyNameAtomic);
                    if (field == null || field.Schema.Tag != Schema.Type.Map) {
                        return null;
                    }

                    getter = new AvroEventBeanGetterMapped(field, mappedProp.Key);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return getter;
                }

                if (prop is DynamicIndexedProperty dynamicIndexedProp) {
                    getter = new AvroEventBeanGetterIndexedDynamic(
                        dynamicIndexedProp.PropertyNameAtomic,
                        dynamicIndexedProp.Index);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return getter;
                }

                if (prop is DynamicMappedProperty dynamicMappedProp) {
                    getter = new AvroEventBeanGetterMappedDynamic(
                        dynamicMappedProp.PropertyNameAtomic,
                        dynamicMappedProp.Key);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return getter;
                }

                if (prop is DynamicSimpleProperty) {
                    getter = new AvroEventBeanGetterSimpleDynamic(prop.PropertyNameAtomic);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return getter;
                }

                return null; // simple property already cached
            }

            // Take apart the nested property into a map key and a nested value class property name
            var propertyTop = StringValue.UnescapeDot(propertyName.Substring(0, index));
            var propertyNested = propertyName.Substring(index + 1);
            var isRootedDynamic = false;

            // If the property is dynamic, remove the ? since the property type is defined without
            if (propertyTop.EndsWith("?")) {
                propertyTop = propertyTop.Substring(0, propertyTop.Length - 1);
                isRootedDynamic = true;
            }

            var propTop = PropertyParser.ParseAndWalkLaxToSimple(propertyTop);
            Field fieldTop = avroSchema.GetField(propTop.PropertyNameAtomic);

            // field is known and is a record
            if (fieldTop != null && fieldTop.Schema.Tag == Schema.Type.Record && propTop is SimpleProperty) {
                var factory = new GetterNestedFactoryRootedSimple(eventAdapterService, fieldTop);
                var property = PropertyParser.ParseAndWalk(propertyNested, isRootedDynamic);
                getter = PropertyGetterNested(
                    factory,
                    fieldTop.Schema,
                    property,
                    moduleName,
                    eventAdapterService,
                    eventTypeAvroHandler,
                    fragmentTypeCache);
                MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                return getter;
            }

            // field is known and is a record
            if (fieldTop != null && propTop is IndexedProperty indexedProperty) {
                if ((fieldTop.Schema.Tag == Schema.Type.Array) ||
                    (fieldTop.Schema.Tag == Schema.Type.String)) {
                    var factory = new GetterNestedFactoryRootedIndexed(
                        eventAdapterService,
                        fieldTop,
                        indexedProperty.Index);
                    var property = PropertyParser.ParseAndWalk(propertyNested, isRootedDynamic);
                    getter = PropertyGetterNested(
                        factory,
                        fieldTop.Schema.AsArraySchema().ItemSchema,
                        property,
                        moduleName,
                        eventAdapterService,
                        eventTypeAvroHandler,
                        fragmentTypeCache);
                    MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
                    return getter;
                }
            }

            // field is not known or is not a record
            if (!isRootedDynamic) {
                return null;
            }

            var propertyX = PropertyParser.ParseAndWalk(propertyNested, true);
            var innerGetter = GetDynamicGetter(propertyX);
            getter = new AvroEventBeanGetterNestedDynamicPoly(propertyTop, innerGetter);
            MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache);
            return getter;
        }
Example #9
0
        public static object CoerceProperty(
            string propertyName,
            Type containingType,
            object value,
            Type type,
            ExprNodeOrigin exprNodeOrigin,
            ExprValidationContext exprValidationContext,
            bool forceNumeric,
            bool includeClassNameInEx)
        {
            // handle system-property exception
            if (value is ExprNode) {
                if (value is ExprIdentNode) {
                    var identNode = (ExprIdentNode) value;
                    Property prop;
                    try {
                        prop = PropertyParser.ParseAndWalkLaxToSimple(identNode.FullUnresolvedName);
                    }
                    catch (Exception) {
                        throw new ExprValidationException(
                            "Failed to parse property '" + identNode.FullUnresolvedName + "'");
                    }

                    if (!(prop is MappedProperty)) {
                        throw new ExprValidationException(
                            "Unrecognized property '" + identNode.FullUnresolvedName + "'");
                    }

                    var mappedProperty = (MappedProperty) prop;
                    if (string.Equals(
                        mappedProperty.PropertyNameAtomic,
                        ExprEvalSystemProperty.SYSTEM_PROPETIES_NAME,
                        StringComparison.InvariantCultureIgnoreCase)) {
                        if (type == typeof(ExprNode)) {
                            return new ExprEvalSystemProperty(mappedProperty.Key);
                        }

                        return Environment.GetEnvironmentVariable(mappedProperty.Key);
                    }
                }
                else {
                    var exprNode = (ExprNode) value;
                    if (type == typeof(ExprNode)) {
                        return exprNode;
                    }

                    if (!exprNode.Forge.ForgeConstantType.IsCompileTimeConstant) {
                        throw new ExprValidationException(
                            "Failed to determine parameter for property '" +
                            propertyName +
                            "' as the parameter is not a compile-time constant expression");
                    }

                    value = exprNode.Forge.ExprEvaluator.Evaluate(null, true, null);
                }
            }

            if (value == null) {
                return null;
            }

            var valueType = value.GetType();
            if (valueType == type) {
                return value;
            }

            
            var typeUnboxed = type.GetUnboxedType();
            if (valueType.GetUnboxedType().IsAssignmentCompatible(typeUnboxed)) {
                if (forceNumeric &&
                    value.GetType().GetBoxedType() != type.GetBoxedType() &&
                    type.IsNumeric() &&
                    value.GetType().IsNumeric()) {
                    value = TypeHelper.CoerceBoxed(value, type.GetBoxedType());
                }

                return value;
            }

            if (TypeHelper.IsSubclassOrImplementsInterface(value.GetType(), type)) {
                return value;
            }

            if (type.IsArray) {
                if (!value.GetType().IsGenericCollection()) {
                    var detail = "expects an array but receives a value of type " + value.GetType().Name;
                    throw new ExprValidationException(
                        GetExceptionText(propertyName, containingType, includeClassNameInEx, detail));
                }

                var items = value.UnwrapIntoArray<object>();
                var coercedArray = Array.CreateInstance(type.GetElementType(), items.Length);
                for (var i = 0; i < items.Length; i++) {
                    var coercedValue = CoerceProperty(
                        propertyName + " (array element)",
                        type,
                        items[i],
                        type.GetElementType(),
                        exprNodeOrigin,
                        exprValidationContext,
                        false,
                        includeClassNameInEx);
                    coercedArray.SetValue(coercedValue, i);
                }

                return coercedArray;
            }

            if (!(value is IDictionary<string, object>)) {
                var detail = "expects an " +
                             type.CleanName() +
                             " but receives a value of type " +
                             value.GetType().CleanName();
                throw new ExprValidationException(
                    GetExceptionText(propertyName, containingType, includeClassNameInEx, detail));
            }

            var props = (IDictionary<string, object>) value;
            return InstantiatePopulateObject(props, type, exprNodeOrigin, exprValidationContext);
        }
Example #10
0
        public static Object CoerceProperty(
            string propertyName,
            Type containingType,
            Object value,
            Type type,
            ExprNodeOrigin exprNodeOrigin,
            ExprValidationContext exprValidationContext,
            bool forceNumeric,
            bool includeClassNameInEx)
        {
            if (value is ExprNode && type != typeof(ExprNode))
            {
                if (value is ExprIdentNode)
                {
                    var      identNode = (ExprIdentNode)value;
                    Property prop;
                    try {
                        prop = PropertyParser.ParseAndWalkLaxToSimple(identNode.FullUnresolvedName);
                    }
                    catch (Exception) {
                        throw new ExprValidationException(
                                  "Failed to parse property '" + identNode.FullUnresolvedName + "'");
                    }

                    if (!(prop is MappedProperty))
                    {
                        throw new ExprValidationException(
                                  "Unrecognized property '" + identNode.FullUnresolvedName + "'");
                    }

                    var mappedProperty = (MappedProperty)prop;
                    if (string.Equals(
                            mappedProperty.PropertyNameAtomic, SYSTEM_PROPETIES_NAME,
                            StringComparison.InvariantCultureIgnoreCase))
                    {
                        return(Environment.GetEnvironmentVariable(mappedProperty.Key));
                    }
                }
                else
                {
                    var exprNode  = (ExprNode)value;
                    var validated = ExprNodeUtility.GetValidatedSubtree(
                        exprNodeOrigin, exprNode, exprValidationContext);
                    exprValidationContext.VariableService.SetLocalVersion();
                    var evaluator = validated.ExprEvaluator;
                    if (evaluator == null)
                    {
                        throw new ExprValidationException(
                                  "Failed to evaluate expression '" +
                                  ExprNodeUtility.ToExpressionStringMinPrecedenceSafe(exprNode) + "'");
                    }

                    value = evaluator.Evaluate(EvaluateParams.EmptyTrue);
                }
            }

            if (value == null)
            {
                return(null);
            }

            var valueType = value.GetType();

            if (valueType == type)
            {
                return(value);
            }

            if (valueType.IsAssignmentCompatible(type))
            {
                if (forceNumeric &&
                    (valueType.GetBoxedType() != type.GetBoxedType()) &&
                    type.IsNumeric() &&
                    valueType.IsNumeric())
                {
                    value = CoercerFactory.CoerceBoxed(value, type.GetBoxedType());
                }

                return(value);
            }

#if false
            // numerical coercion between non-boxed types and incompatible boxed types
            if ((valueType.IsNumeric()) &&
                (valueType.IsNullable() == false) &&
                (type.IsNumeric()) &&
                (type.IsNullable()))
            {
                var typeNonGeneric = Nullable.GetUnderlyingType(type);
                if (valueType.IsAssignmentCompatible(typeNonGeneric))
                {
                    value = CoercerFactory.CoerceBoxed(value, type);
                }

                return(value);
            }
#endif

            if (TypeHelper.IsSubclassOrImplementsInterface(valueType, type))
            {
                return(value);
            }

            if (type.IsArray)
            {
                if (!(valueType.IsGenericCollection()))
                {
                    var detail = "expects an array but receives a value of type " + valueType.GetCleanName();
                    throw new ExprValidationException(
                              GetExceptionText(propertyName, containingType, includeClassNameInEx, detail));
                }

                var items        = value.UnwrapIntoArray <object>();
                var coercedArray = Array.CreateInstance(type.GetElementType(), items.Length);
                for (var i = 0; i < items.Length; i++)
                {
                    var coercedValue = CoerceProperty(
                        propertyName + " (array element)", type, items[i], type.GetElementType(), exprNodeOrigin,
                        exprValidationContext, false, includeClassNameInEx);
                    coercedArray.SetValue(coercedValue, i);
                }

                return(coercedArray);
            }

            if (type.IsNullable() && !valueType.IsNullable())
            {
                var typeNonGeneric = Nullable.GetUnderlyingType(type);
                if (valueType.IsAssignmentCompatible(typeNonGeneric))
                {
                    return(CoercerFactory.CoerceBoxed(value, type));
                }
            }

            if (!(value is IDictionary <String, Object>))
            {
                var detail = "expects an " + type.GetCleanName() + " but receives a value of type " +
                             valueType.GetCleanName();
                throw new ExprValidationException(
                          GetExceptionText(propertyName, containingType, includeClassNameInEx, detail));
            }

            var props = (IDictionary <string, Object>)value;
            return(InstantiatePopulateObject(props, type, exprNodeOrigin, exprValidationContext));
        }