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)); }
/// <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); }
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); }