Example #1
0
        public VariantPropertyDesc ResolveProperty(String propertyName, EventType[] variants)
        {
            // property numbers should start at zero since the serve as array index
            int assignedPropertyNumber = currentPropertyNumber;

            currentPropertyNumber++;
            propertyGetterCache.AddGetters(assignedPropertyNumber, propertyName);

            EventPropertyGetter getter = new ProxyEventPropertyGetter(
                delegate(EventBean eventBean) {
                var variant = (VariantEvent)eventBean;
                var _getter = propertyGetterCache.GetGetter(assignedPropertyNumber, variant.UnderlyingEventBean.EventType);
                if (_getter == null)
                {
                    return(null);
                }
                return(_getter.Get(variant.UnderlyingEventBean));
            },
                delegate {
                return(null);    // no fragments provided as the type is not known in advance
            },
                delegate(EventBean eventBean) {
                var variant = (VariantEvent)eventBean;
                var _getter = propertyGetterCache.GetGetter(assignedPropertyNumber, variant.UnderlyingEventBean.EventType);
                if (_getter == null)
                {
                    return(false);
                }
                return(_getter.IsExistsProperty(variant.UnderlyingEventBean));
            });

            return(new VariantPropertyDesc(typeof(Object), getter, true));
        }
Example #2
0
        /// <summary>Creates property descriptors for revision. </summary>
        /// <param name="spec">specifies revision</param>
        /// <param name="groups">the groups that group properties</param>
        /// <returns>map of property and descriptor</returns>
        public static IDictionary <String, RevisionPropertyTypeDesc> CreatePropertyDescriptors(RevisionSpec spec, PropertyGroupDesc[] groups)
        {
            IDictionary <String, int[]> propsPerGroup = PropertyUtility.GetGroupsPerProperty(groups);

            IDictionary <String, RevisionPropertyTypeDesc> propertyDesc = new Dictionary <String, RevisionPropertyTypeDesc>();
            int count = 0;

            foreach (String property in spec.ChangesetPropertyNames)
            {
                var fullGetter         = spec.BaseEventType.GetGetter(property);
                var propertyNumber     = count;
                var propGroupsProperty = propsPerGroup.Get(property);
                var paramList          = new RevisionGetterParameters(property, propertyNumber, fullGetter, propGroupsProperty);

                // if there are no groups (full event property only), then simply use the full event getter
                EventPropertyGetter revisionGetter = new ProxyEventPropertyGetter(
                    eventBean => ((RevisionEventBeanDeclared)eventBean).GetVersionedValue(paramList),
                    eventBean => null,
                    eventBean => true);

                var type             = spec.BaseEventType.GetPropertyType(property);
                var propertyTypeDesc = new RevisionPropertyTypeDesc(revisionGetter, paramList, type);
                propertyDesc.Put(property, propertyTypeDesc);
                count++;
            }

            foreach (String property in spec.BaseEventOnlyPropertyNames)
            {
                EventPropertyGetter fullGetter = spec.BaseEventType.GetGetter(property);

                // if there are no groups (full event property only), then simply use the full event getter
                EventPropertyGetter revisionGetter = new ProxyEventPropertyGetter(
                    eventBean =>
                {
                    var riv  = (RevisionEventBeanDeclared)eventBean;
                    var bean = riv.LastBaseEvent;
                    return(bean == null ? null : fullGetter.Get(bean));
                },
                    eventBean => null,
                    eventBean => true);

                var type             = spec.BaseEventType.GetPropertyType(property);
                var propertyTypeDesc = new RevisionPropertyTypeDesc(revisionGetter, null, type);
                propertyDesc.Put(property, propertyTypeDesc);
                count++;
            }

            count = 0;
            foreach (String property in spec.KeyPropertyNames)
            {
                int keyPropertyNumber = count;

                EventPropertyGetter revisionGetter;
                if (spec.KeyPropertyNames.Length == 1)
                {
                    revisionGetter = new ProxyEventPropertyGetter
                    {
                        ProcGet = eventBean => ((RevisionEventBeanDeclared)eventBean).Key,
                        ProcIsExistsProperty = eventBean => true,
                        ProcGetFragment      = eventBean => null
                    };
                }
                else
                {
                    revisionGetter = new ProxyEventPropertyGetter
                    {
                        ProcGet = eventBean =>
                        {
                            var riv = (RevisionEventBeanDeclared)eventBean;
                            return(((MultiKeyUntyped)riv.Key).Keys[keyPropertyNumber]);
                        },
                        ProcIsExistsProperty = eventBean => true,
                        ProcGetFragment      = eventBean => null
                    };
                }

                var type             = spec.BaseEventType.GetPropertyType(property);
                var propertyTypeDesc = new RevisionPropertyTypeDesc(revisionGetter, null, type);
                propertyDesc.Put(property, propertyTypeDesc);
                count++;
            }

            return(propertyDesc);
        }
Example #3
0
        public EventPropertyGetter GetGetter(String property)
        {
            EventPropertyGetter cachedGetter = _propertyGetterCache.Get(property);

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

            if (_underlyingMapType.IsProperty(property) && (property.IndexOf('?') == -1))
            {
                EventPropertyGetter mapGetter = _underlyingMapType.GetGetter(property);
                EventPropertyGetter getter    = new ProxyEventPropertyGetter
                {
                    ProcGet = theEvent =>
                    {
                        if (!(theEvent is DecoratingEventBean))
                        {
                            throw new PropertyAccessException("Mismatched property getter to EventBean type");
                        }
                        var wrapperEvent = (DecoratingEventBean)theEvent;
                        var map          = wrapperEvent.DecoratingProperties;
                        return(mapGetter.Get(_eventAdapterService.AdapterForTypedMap(map, _underlyingMapType)));
                    },
                    ProcIsExistsProperty = eventBean => true,
                    ProcGetFragment      = theEvent =>
                    {
                        if (!(theEvent is DecoratingEventBean))
                        {
                            throw new PropertyAccessException("Mismatched property getter to EventBean type");
                        }
                        var wrapperEvent = (DecoratingEventBean)theEvent;
                        var map          = wrapperEvent.DecoratingProperties;
                        return(mapGetter.GetFragment(_eventAdapterService.AdapterForTypedMap(map, _underlyingMapType)));
                    }
                };
                _propertyGetterCache.Put(property, getter);
                return(getter);
            }
            else if (_underlyingEventType.IsProperty(property))
            {
                EventPropertyGetter getter = new ProxyEventPropertyGetter()
                {
                    ProcGet = theEvent =>
                    {
                        if (!(theEvent is DecoratingEventBean))
                        {
                            throw new PropertyAccessException("Mismatched property getter to EventBean type");
                        }
                        var wrapperEvent = (DecoratingEventBean)theEvent;
                        var wrappedEvent = wrapperEvent.UnderlyingEvent;
                        if (wrappedEvent == null)
                        {
                            return(null);
                        }

                        var underlyingGetter = _underlyingEventType.GetGetter(property);
                        return(underlyingGetter.Get(wrappedEvent));
                    },
                    ProcIsExistsProperty = eventBean => true,
                    ProcGetFragment      = theEvent =>
                    {
                        if (!(theEvent is DecoratingEventBean))
                        {
                            throw new PropertyAccessException("Mismatched property getter to EventBean type");
                        }
                        var wrapperEvent = (DecoratingEventBean)theEvent;
                        var wrappedEvent = wrapperEvent.UnderlyingEvent;
                        if (wrappedEvent == null)
                        {
                            return(null);
                        }

                        var underlyingGetter = _underlyingEventType.GetGetter(property);
                        return(underlyingGetter.GetFragment(wrappedEvent));
                    }
                };
                _propertyGetterCache.Put(property, getter);
                return(getter);
            }
            else
            {
                return(null);
            }
        }
        public VariantPropertyDesc ResolveProperty(String propertyName, EventType[] variants)
        {
            bool existsInAll = true;
            Type commonType  = null;
            bool mustCoerce  = false;

            for (int i = 0; i < variants.Length; i++)
            {
                Type type = variants[i].GetPropertyType(propertyName); //.GetBoxedType();
                if (type == null)
                {
                    existsInAll = false;
                    continue;
                }

                if (commonType == null)
                {
                    commonType = type;
                    continue;
                }

                // compare types
                if (type == commonType)
                {
                    continue;
                }

                if (type.GetBoxedType() == commonType.GetBoxedType())
                {
                    commonType = commonType.GetBoxedType();
                    continue;
                }

                // coercion
                if (type.IsNumeric())
                {
                    if (TypeHelper.CanCoerce(type, commonType))
                    {
                        mustCoerce = true;
                        continue;
                    }
                    if (TypeHelper.CanCoerce(commonType, type))
                    {
                        mustCoerce = true;
                        commonType = type;
                    }
                }
                else if (commonType == typeof(Object))
                {
                    continue;
                }
                // common interface or base class
                else if (!type.IsBuiltinDataType())
                {
                    var supersForType = new FIFOHashSet <Type>();
                    TypeHelper.GetBase(type, supersForType);
                    supersForType.Remove(typeof(Object));

                    if (supersForType.Contains(commonType))
                    {
                        continue;   // type, or : common type
                    }
                    if (TypeHelper.IsSubclassOrImplementsInterface(commonType, type))
                    {
                        commonType = type;  // common type : type
                        continue;
                    }

                    // find common interface or type both implement
                    var supersForCommonType = new FIFOHashSet <Type>();
                    TypeHelper.GetBase(commonType, supersForCommonType);
                    supersForCommonType.Remove(typeof(Object));

                    // Take common classes first, ignoring interfaces
                    bool found = false;
                    foreach (Type superClassType in supersForType)
                    {
                        if (!superClassType.IsInterface && (supersForCommonType.Contains(superClassType)))
                        {
                            break;
                        }
                    }
                    if (found)
                    {
                        continue;
                    }
                    // Take common interfaces
                    foreach (var superClassType in supersForType)
                    {
                        if (superClassType.IsInterface && supersForCommonType.Contains(superClassType))
                        {
                            commonType = superClassType;
                            found      = true;
                            break;
                        }
                    }
                }

                commonType = typeof(Object);
            }

            if (!existsInAll)
            {
                return(null);
            }

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

            // property numbers should start at zero since the serve as array index
            var assignedPropertyNumber = currentPropertyNumber;

            currentPropertyNumber++;
            propertyGetterCache.AddGetters(assignedPropertyNumber, propertyName);

            EventPropertyGetter getter;

            if (mustCoerce)
            {
                SimpleTypeCaster caster = SimpleTypeCasterFactory.GetCaster(null, commonType);
                getter = new ProxyEventPropertyGetter
                {
                    ProcGet = eventBean =>
                    {
                        var variant        = (VariantEvent)eventBean;
                        var propertyGetter = propertyGetterCache.GetGetter(assignedPropertyNumber, variant.UnderlyingEventBean.EventType);
                        if (propertyGetter == null)
                        {
                            return(null);
                        }
                        var value = propertyGetter.Get(variant.UnderlyingEventBean);
                        if (value == null)
                        {
                            return(value);
                        }
                        return(caster.Invoke(value));
                    },
                    ProcGetFragment      = eventBean => null,
                    ProcIsExistsProperty = eventBean =>
                    {
                        var variant        = (VariantEvent)eventBean;
                        var propertyGetter = propertyGetterCache.GetGetter(assignedPropertyNumber, variant.UnderlyingEventBean.EventType);
                        if (propertyGetter == null)
                        {
                            return(false);
                        }
                        return(propertyGetter.IsExistsProperty(variant.UnderlyingEventBean));
                    }
                };
            }
            else
            {
                getter = new ProxyEventPropertyGetter
                {
                    ProcGet = eventBean =>
                    {
                        var variant        = (VariantEvent)eventBean;
                        var propertyGetter = propertyGetterCache.GetGetter(assignedPropertyNumber, variant.UnderlyingEventBean.EventType);
                        if (propertyGetter == null)
                        {
                            return(null);
                        }
                        return(propertyGetter.Get(variant.UnderlyingEventBean));
                    },
                    ProcGetFragment      = eventBean => null,
                    ProcIsExistsProperty = eventBean =>
                    {
                        var variant        = (VariantEvent)eventBean;
                        var propertyGetter = propertyGetterCache.GetGetter(assignedPropertyNumber, variant.UnderlyingEventBean.EventType);
                        if (propertyGetter == null)
                        {
                            return(false);
                        }
                        return(propertyGetter.IsExistsProperty(variant.UnderlyingEventBean));
                    }
                };
            }

            return(new VariantPropertyDesc(commonType, getter, true));
        }
        /// <summary>
        /// Ctor.
        /// </summary>
        /// <param name="revisioneventTypeName">name</param>
        /// <param name="spec">specification</param>
        /// <param name="statementStopService">for stop handling</param>
        /// <param name="eventAdapterService">for nested property handling</param>
        /// <param name="eventTypeIdGenerator">The event type id generator.</param>
        public VAERevisionProcessorMerge(String revisioneventTypeName, RevisionSpec spec, StatementStopService statementStopService, EventAdapterService eventAdapterService, EventTypeIdGenerator eventTypeIdGenerator)
            : base(spec, revisioneventTypeName, eventAdapterService)
        {
            // on statement stop, remove versions
            statementStopService.StatementStopped += () => _statePerKey.Clear();
            _statePerKey = new Dictionary <Object, RevisionStateMerge>();

            // For all changeset properties, add type descriptors (property number, getter etc)
            var propertyDesc = new Dictionary <String, RevisionPropertyTypeDesc>();
            var count        = 0;

            foreach (String property in spec.ChangesetPropertyNames)
            {
                var fullGetter     = spec.BaseEventType.GetGetter(property);
                var propertyNumber = count;
                var paramList      = new RevisionGetterParameters(property, propertyNumber, fullGetter, null);

                // if there are no groups (full event property only), then simply use the full event getter
                EventPropertyGetter revisionGetter = new ProxyEventPropertyGetter(
                    eventBean =>
                {
                    var riv = (RevisionEventBeanMerge)eventBean;
                    return(riv.GetVersionedValue(paramList));
                },
                    eventBean => null,
                    eventBean => true);

                var type = spec.BaseEventType.GetPropertyType(property);
                if (type == null)
                {
                    foreach (EventType deltaType in spec.DeltaTypes)
                    {
                        var dtype = deltaType.GetPropertyType(property);
                        if (dtype != null)
                        {
                            type = dtype;
                            break;
                        }
                    }
                }

                var propertyTypeDesc = new RevisionPropertyTypeDesc(revisionGetter, paramList, type);
                propertyDesc.Put(property, propertyTypeDesc);
                count++;
            }

            count = 0;
            foreach (String property in spec.KeyPropertyNames)
            {
                var keyPropertyNumber = count;
                EventPropertyGetter revisionGetter;
                if (spec.KeyPropertyNames.Length == 1)
                {
                    revisionGetter = new ProxyEventPropertyGetter
                    {
                        ProcGet = eventBean => ((RevisionEventBeanMerge)eventBean).Key,
                        ProcIsExistsProperty = eventBean => true,
                        ProcGetFragment      = eventBean => null
                    };
                }
                else
                {
                    revisionGetter = new ProxyEventPropertyGetter
                    {
                        ProcGet = eventBean =>
                        {
                            var riv = (RevisionEventBeanMerge)eventBean;
                            return(((MultiKeyUntyped)riv.Key).Keys[keyPropertyNumber]);
                        },
                        ProcIsExistsProperty = eventBean => true,
                        ProcGetFragment      = eventBean => null
                    };
                }

                var type = spec.BaseEventType.GetPropertyType(property);
                if (type == null)
                {
                    foreach (EventType deltaType in spec.DeltaTypes)
                    {
                        var dtype = deltaType.GetPropertyType(property);
                        if (dtype != null)
                        {
                            type = dtype;
                            break;
                        }
                    }
                }
                var propertyTypeDesc = new RevisionPropertyTypeDesc(revisionGetter, null, type);
                propertyDesc.Put(property, propertyTypeDesc);
                count++;
            }

            // compile for each event type a list of getters and indexes within the overlay
            foreach (EventType deltaType in spec.DeltaTypes)
            {
                RevisionTypeDesc typeDesc = MakeTypeDesc(deltaType, spec.PropertyRevision);
                TypeDescriptors.Put(deltaType, typeDesc);
            }
            _infoFullType = MakeTypeDesc(spec.BaseEventType, spec.PropertyRevision);

            // how to handle updates to a full event
            if (spec.PropertyRevision == PropertyRevisionEnum.MERGE_DECLARED)
            {
                _updateStrategy = new UpdateStrategyDeclared(spec);
            }
            else if (spec.PropertyRevision == PropertyRevisionEnum.MERGE_NON_NULL)
            {
                _updateStrategy = new UpdateStrategyNonNull(spec);
            }
            else if (spec.PropertyRevision == PropertyRevisionEnum.MERGE_EXISTS)
            {
                _updateStrategy = new UpdateStrategyExists(spec);
            }
            else
            {
                throw new ArgumentException("Unknown revision type '" + spec.PropertyRevision + "'");
            }

            EventTypeMetadata metadata = EventTypeMetadata.CreateValueAdd(revisioneventTypeName, TypeClass.REVISION);

            RevisionEventType = new RevisionEventType(metadata, eventTypeIdGenerator.GetTypeId(revisioneventTypeName), propertyDesc, eventAdapterService);
        }