public DataFlowOpInitializeResult Initialize(DataFlowOpInitializateContext context) { _initialDelayMSec = (long)(initialDelay * 1000); _periodDelayMSec = (long)(interval * 1000); if (context.OutputPorts.Count != 1) { throw new ArgumentException( "BeaconSource operator requires one output stream but produces " + context.OutputPorts.Count + " streams"); } // Check if a type is declared var port = context.OutputPorts[0]; ICollection <string> props; if (port.OptionalDeclaredType != null && port.OptionalDeclaredType.EventType != null) { var outputEventType = port.OptionalDeclaredType.EventType; _produceEventBean = port.OptionalDeclaredType != null && !port.OptionalDeclaredType.IsUnderlying; // compile properties to populate props = _allProperties.Keys; props.RemoveAll(PARAMETER_PROPERTIES); var writables = SetupProperties(props.ToArray(), outputEventType, context.StatementContext); _manufacturer = context.ServicesContext.EventAdapterService.GetManufacturer( outputEventType, writables, context.ServicesContext.EngineImportService, false); var index = 0; _evaluators = new ExprEvaluator[writables.Length]; TypeWidenerCustomizer typeWidenerCustomizer = context.ServicesContext.EventAdapterService.GetTypeWidenerCustomizer(outputEventType); foreach (var writeable in writables) { var providedProperty = _allProperties.Get(writeable.PropertyName); if (providedProperty is ExprNode) { var exprNode = (ExprNode)providedProperty; var validated = ExprNodeUtility.ValidateSimpleGetSubtree( ExprNodeOrigin.DATAFLOWBEACON, exprNode, context.StatementContext, null, false); var exprEvaluator = validated.ExprEvaluator; var widener = TypeWidenerFactory.GetCheckPropertyAssignType( ExprNodeUtility.ToExpressionStringMinPrecedenceSafe(validated), exprEvaluator.ReturnType, writeable.PropertyType, writeable.PropertyName, false, typeWidenerCustomizer, context.StatementContext.StatementName, context.Engine.URI); if (widener != null) { _evaluators[index] = new ProxyExprEvaluator { ProcEvaluate = evaluateParams => { var value = exprEvaluator.Evaluate(evaluateParams); return(widener.Invoke(value)); }, ProcReturnType = () => null }; } else { _evaluators[index] = exprEvaluator; } } else if (providedProperty == null) { _evaluators[index] = new ProxyExprEvaluator { ProcEvaluate = evaluateParams => null, ProcReturnType = () => null }; } else { _evaluators[index] = new ProxyExprEvaluator { ProcEvaluate = evaluateParams => providedProperty, ProcReturnType = () => providedProperty.GetType() }; } index++; } return(null); // no changing types } // No type has been declared, we can create one var anonymousTypeName = context.DataflowName + "-beacon"; var types = new LinkedHashMap <string, Object>(); props = _allProperties.Keys; props.RemoveAll(PARAMETER_PROPERTIES); var count = 0; _evaluators = new ExprEvaluator[props.Count]; foreach (var propertyName in props) { var exprNode = (ExprNode)_allProperties.Get(propertyName); var validated = ExprNodeUtility.ValidateSimpleGetSubtree(ExprNodeOrigin.DATAFLOWBEACON, exprNode, context.StatementContext, null, false); var evaluateParamsX = new EvaluateParams(null, true, context.AgentInstanceContext); var value = validated.ExprEvaluator.Evaluate(evaluateParamsX); if (value == null) { types.Put(propertyName, null); } else { types.Put(propertyName, value.GetType()); } _evaluators[count] = new ProxyExprEvaluator() { ProcEvaluate = (evaluateParams) => value, ProcReturnType = () => null }; count++; } EventType type = context.ServicesContext.EventAdapterService.CreateAnonymousObjectArrayType(anonymousTypeName, types); return(new DataFlowOpInitializeResult( new GraphTypeDesc[] { new GraphTypeDesc(false, true, type) })); }
/// <summary> /// Returns the widener. /// </summary> /// <param name="columnName">name of column</param> /// <param name="columnType">type of column</param> /// <param name="writeablePropertyType">property type</param> /// <param name="writeablePropertyName">propery name</param> /// <param name="allowObjectArrayToCollectionConversion">whether we widen object-array to collection</param> /// <param name="customizer">customization if any</param> /// <param name="statementName">statement name</param> /// <returns>type widener</returns> /// <throws>TypeWidenerException if type validation fails</throws> public static TypeWidenerSPI GetCheckPropertyAssignType( string columnName, Type columnType, Type writeablePropertyType, string writeablePropertyName, bool allowObjectArrayToCollectionConversion, TypeWidenerCustomizer customizer, string statementName) { var columnTypeBoxed = columnType.GetBoxedType(); var targetTypeBoxed = writeablePropertyType.GetBoxedType(); var custom = customizer?.WidenerFor( columnName, columnType, writeablePropertyType, writeablePropertyName, statementName); if (custom != null) { return custom; } if (columnType == null) { if (writeablePropertyType.CanNotBeNull()) { var message = "Invalid assignment of column '" + columnName + "' of null type to event property '" + writeablePropertyName + "' typed as '" + writeablePropertyType.CleanName() + "', nullable type mismatch"; throw new TypeWidenerException(message); } } else if (columnTypeBoxed != targetTypeBoxed) { if (columnTypeBoxed == typeof(string) && targetTypeBoxed == typeof(char?)) { return STRING_TO_CHAR_COERCER; } if (allowObjectArrayToCollectionConversion && columnTypeBoxed.IsArray && !columnTypeBoxed.GetElementType().IsValueType && targetTypeBoxed.IsImplementsInterface(typeof(ICollection<object>))) { return OBJECT_ARRAY_TO_COLLECTION_COERCER; } // Boxed types tend to be incompatible from an assignment perspective. We have both // the boxed and unboxed values. The problem is that the boxed values will always // be unboxed prior to assignment, so looking for assignment of boxed types is not // a winning approach. var columnTypeUnboxed = columnType.GetUnboxedType(); var targetTypeUnboxed = targetTypeBoxed.GetUnboxedType(); if (!columnType.IsAssignmentCompatible(writeablePropertyType) && !columnTypeUnboxed.IsAssignmentCompatible(targetTypeUnboxed)) { // Arrays can be assigned to each other if the underlying target types // can be assigned from one another. if (columnType.IsArray && targetTypeBoxed.IsArray && columnType.GetArrayRank() == targetTypeBoxed.GetArrayRank()) { var columnElementType = columnType.GetElementType(); var targetElementType = targetTypeBoxed.GetElementType(); if (columnElementType.IsAssignmentCompatible(targetElementType)) { return new TypeWidenerCompatibleArrayCoercer( columnElementType, targetElementType); } } var writablePropName = writeablePropertyType.CleanName(); if (writeablePropertyType.IsArray) { writablePropName = writeablePropertyType.GetElementType().CleanName() + "[]"; } var columnTypeName = columnType.CleanName(); if (columnType.IsArray) { columnTypeName = columnType.GetElementType().CleanName() + "[]"; } var message = "Invalid assignment of column '" + columnName + "' of type '" + columnTypeName + "' to event property '" + writeablePropertyName + "' typed as '" + writablePropName + "', column and parameter types mismatch"; throw new TypeWidenerException(message); } if (writeablePropertyType.IsNumeric()) { return new TypeWidenerBoxedNumeric( SimpleNumberCoercerFactory.GetCoercer(columnTypeBoxed, targetTypeBoxed)); } } return null; }
public static EventBeanUpdateHelperForge Make( string updatedWindowOrTableName, EventTypeSPI eventTypeSPI, IList <OnTriggerSetAssignment> assignments, string updatedAlias, EventType optionalTriggeringEventType, bool isCopyOnWrite, string statementName, EventTypeAvroHandler avroHandler) { IList <EventBeanUpdateItemForge> updateItems = new List <EventBeanUpdateItemForge>(); IList <string> properties = new List <string>(); TypeWidenerCustomizer typeWidenerCustomizer = avroHandler.GetTypeWidenerCustomizer(eventTypeSPI); for (int i = 0; i < assignments.Count; i++) { OnTriggerSetAssignment desc = assignments[i]; ExprAssignment assignment = desc.Validated; if (assignment == null) { throw new IllegalStateException("Assignment has not been validated"); } try { EventBeanUpdateItemForge updateItem; if (assignment is ExprAssignmentStraight) { ExprAssignmentStraight straight = (ExprAssignmentStraight)assignment; // handle assignment "property = value" if (straight.Lhs is ExprAssignmentLHSIdent) { ExprAssignmentLHSIdent ident = (ExprAssignmentLHSIdent)straight.Lhs; string propertyName = ident.Ident; EventPropertyDescriptor writableProperty = eventTypeSPI.GetWritableProperty(propertyName); // check assignment to indexed or mapped property if (writableProperty == null) { Pair <string, EventPropertyDescriptor> nameWriteablePair = CheckIndexedOrMappedProp( propertyName, updatedWindowOrTableName, updatedAlias, eventTypeSPI); propertyName = nameWriteablePair.First; writableProperty = nameWriteablePair.Second; } ExprNode rhsExpr = straight.Rhs; ExprForge rhsForge = rhsExpr.Forge; EventPropertyWriterSPI writer = eventTypeSPI.GetWriter(propertyName); bool notNullableField = writableProperty.PropertyType.IsPrimitive; properties.Add(propertyName); TypeWidenerSPI widener; try { widener = TypeWidenerFactory.GetCheckPropertyAssignType( ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(rhsExpr), rhsForge.EvaluationType, writableProperty.PropertyType, propertyName, false, typeWidenerCustomizer, statementName); } catch (TypeWidenerException ex) { throw new ExprValidationException(ex.Message, ex); } // check event type assignment bool useUntypedAssignment = false; bool useTriggeringEvent = false; if (optionalTriggeringEventType != null) { // handle RHS is ident node if (rhsExpr is ExprIdentNode) { ExprIdentNode node = (ExprIdentNode)rhsExpr; FragmentEventType fragmentRHS = optionalTriggeringEventType.GetFragmentType(node.ResolvedPropertyName); FragmentEventType fragmentLHS = eventTypeSPI.GetFragmentType(propertyName); if (fragmentRHS != null && fragmentLHS != null) { if (!EventTypeUtility.IsTypeOrSubTypeOf(fragmentRHS.FragmentType, fragmentLHS.FragmentType)) { throw MakeEventTypeMismatch(propertyName, fragmentLHS.FragmentType, fragmentRHS.FragmentType); } } // we don't need to cast if it is a self-assignment and LHS is an event and target needs no writer if (node.StreamId == 0 && fragmentLHS != null && eventTypeSPI is BaseNestableEventType) { useUntypedAssignment = true; } } // handle RHS is a stream of the triggering event itself if (rhsExpr is ExprStreamUnderlyingNode) { ExprStreamUnderlyingNode und = (ExprStreamUnderlyingNode)rhsExpr; if (und.StreamId == 1) { FragmentEventType fragmentLHS = eventTypeSPI.GetFragmentType(propertyName); if (fragmentLHS != null && optionalTriggeringEventType is BaseNestableEventType && !EventTypeUtility.IsTypeOrSubTypeOf(optionalTriggeringEventType, fragmentLHS.FragmentType)) { throw MakeEventTypeMismatch(propertyName, fragmentLHS.FragmentType, optionalTriggeringEventType); } // we use the event itself for assignment and target needs no writer if (eventTypeSPI is BaseNestableEventType) { useUntypedAssignment = true; useTriggeringEvent = true; } } } } updateItem = new EventBeanUpdateItemForge( rhsForge, propertyName, writer, notNullableField, widener, useUntypedAssignment, useTriggeringEvent, null); } else if (straight.Lhs is ExprAssignmentLHSArrayElement) { // handle "property[expr] = value" ExprAssignmentLHSArrayElement arrayElementLHS = (ExprAssignmentLHSArrayElement)straight.Lhs; string arrayPropertyName = arrayElementLHS.Ident; ExprNode rhs = straight.Rhs; Type evaluationType = rhs.Forge.EvaluationType; Type propertyType = eventTypeSPI.GetPropertyType(arrayPropertyName); if (!eventTypeSPI.IsProperty(arrayPropertyName)) { throw new ExprValidationException("Property '" + arrayPropertyName + "' could not be found"); } if (propertyType == null || !propertyType.IsArray) { throw new ExprValidationException("Property '" + arrayPropertyName + "' is not an array"); } EventPropertyGetterSPI getter = eventTypeSPI.GetGetterSPI(arrayPropertyName); Type componentType = propertyType.GetElementType(); if (!TypeHelper.IsAssignmentCompatible(evaluationType, componentType)) { throw new ExprValidationException( "Invalid assignment to property '" + arrayPropertyName + "' component type '" + componentType.CleanName() + "' from expression returning '" + evaluationType.CleanName() + "'"); } TypeWidenerSPI widener; try { widener = TypeWidenerFactory.GetCheckPropertyAssignType( ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(straight.Rhs), evaluationType, componentType, arrayPropertyName, false, typeWidenerCustomizer, statementName); } catch (TypeWidenerException ex) { throw new ExprValidationException(ex.Message, ex); } EventBeanUpdateItemArray arrayInfo = new EventBeanUpdateItemArray( arrayPropertyName, arrayElementLHS.IndexExpression, propertyType, getter); updateItem = new EventBeanUpdateItemForge( rhs.Forge, arrayPropertyName, null, false, widener, false, false, arrayInfo); } else { throw new IllegalStateException("Unrecognized LHS assignment " + straight); } } else if (assignment is ExprAssignmentCurly) { // handle non-assignment, i.e. UDF or other expression ExprAssignmentCurly dot = (ExprAssignmentCurly)assignment; updateItem = new EventBeanUpdateItemForge( dot.Expression.Forge, null, null, false, null, false, false, null); } else { throw new IllegalStateException("Unrecognized assignment " + assignment); } updateItems.Add(updateItem); } catch (ExprValidationException ex) { throw new ExprValidationException( "Failed to validate assignment expression '" + ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(assignment.OriginalExpression) + "': " + ex.Message, ex); } } // copy-on-write is the default event semantics as events are immutable EventBeanCopyMethodForge copyMethod; if (isCopyOnWrite) { // obtain copy method List <string> propertiesUniqueList = new List <string>(new HashSet <string>(properties)); string[] propertiesArray = propertiesUniqueList.ToArray(); copyMethod = eventTypeSPI.GetCopyMethodForge(propertiesArray); if (copyMethod == null) { throw new ExprValidationException("Event type does not support event bean copy"); } } else { // for in-place update, determine assignment expressions to use "initial" to access prior-change values // the copy-method is optional copyMethod = null; ISet <string> propertiesInitialValue = DeterminePropertiesInitialValue(assignments); if (!propertiesInitialValue.IsEmpty()) { string[] propertiesInitialValueArray = propertiesInitialValue.ToArray(); copyMethod = eventTypeSPI.GetCopyMethodForge(propertiesInitialValueArray); } } EventBeanUpdateItemForge[] updateItemsArray = updateItems.ToArray(); return(new EventBeanUpdateHelperForge(eventTypeSPI, copyMethod, updateItemsArray)); }
/// <summary>Returns the widener. </summary> /// <param name="columnName">name of column</param> /// <param name="columnType">type of column</param> /// <param name="writeablePropertyType">property type</param> /// <param name="writeablePropertyName">propery name</param> /// <param name="allowObjectArrayToCollectionConversion">whether we widen object-array to collection</param> /// <param name="customizer">customization if any</param> /// <param name="engineURI">engine URI</param> /// <param name="statementName">statement name</param> /// <exception cref="ExprValidationException">if type validation fails</exception> /// <returns>type widender</returns> /// <throws>ExprValidationException if type validation fails</throws> public static TypeWidener GetCheckPropertyAssignType( String columnName, Type columnType, Type writeablePropertyType, String writeablePropertyName, bool allowObjectArrayToCollectionConversion, TypeWidenerCustomizer customizer, string statementName, string engineURI) { Type columnClassBoxed = TypeHelper.GetBoxedType(columnType); Type targetClassBoxed = TypeHelper.GetBoxedType(writeablePropertyType); if (customizer != null) { TypeWidener custom = customizer.WidenerFor(columnName, columnType, writeablePropertyType, writeablePropertyName, statementName, engineURI); if (custom != null) { return(custom); } } if (columnType == null) { if (writeablePropertyType.IsPrimitive) { String message = "Invalid assignment of column '" + columnName + "' of null type to event property '" + writeablePropertyName + "' typed as '" + writeablePropertyType.FullName + "', nullable type mismatch"; throw new ExprValidationException(message); } } else if (columnClassBoxed != targetClassBoxed) { if (columnClassBoxed == typeof(string) && targetClassBoxed == typeof(char?)) { return(TypeWidenerStringToCharCoercer.Widen); } if (allowObjectArrayToCollectionConversion && columnClassBoxed.IsArray && !columnClassBoxed.GetElementType().IsPrimitive && targetClassBoxed.IsGenericCollection()) { return(OBJECT_ARRAY_TO_COLLECTION_COERCER); } if (columnClassBoxed.IsGenericDictionary() && targetClassBoxed.IsGenericDictionary()) { var columnClassGenerics = columnClassBoxed.GetGenericArguments(); var targetClassGenerics = targetClassBoxed.GetGenericArguments(); var transformMethod = typeof(TransformDictionaryFactory) .GetMethod("Create", new[] { typeof(object) }) .MakeGenericMethod(targetClassGenerics[0], targetClassGenerics[1], columnClassGenerics[0], columnClassGenerics[1]); return(source => { var parameters = new object[] { source }; return transformMethod.Invoke(null, BindingFlags.Static | BindingFlags.Public, null, parameters, null); }); } if ((columnClassBoxed == typeof(string)) && (targetClassBoxed == typeof(char[]))) { return(source => { var sourceAsString = (string)source; return sourceAsString != null?sourceAsString.ToCharArray() : null; }); } if ((columnClassBoxed == typeof(char[])) && (targetClassBoxed == typeof(string))) { return(source => { var sourceAsCharArray = (char[])source; return sourceAsCharArray != null ? new string(sourceAsCharArray) : null; }); } if (columnClassBoxed.IsArray && targetClassBoxed.IsArray) { var columnClassElement = columnClassBoxed.GetElementType(); var targetClassElement = targetClassBoxed.GetElementType(); if (columnClassElement.IsAssignmentCompatible(targetClassElement)) { // By definition, columnClassElement and targetClassElement should be // incompatible. Question is, can we find a coercer between them? var coercer = CoercerFactory.GetCoercer(columnClassElement, targetClassElement); return(source => WidenArray(source, targetClassElement, coercer)); } } if (!columnClassBoxed.IsAssignmentCompatible(targetClassBoxed)) { var writablePropName = writeablePropertyType.FullName; if (writeablePropertyType.IsArray) { writablePropName = writeablePropertyType.GetElementType().FullName + "[]"; } var columnTypeName = columnType.FullName; if (columnType.IsArray) { columnTypeName = columnType.GetElementType().FullName + "[]"; } String message = "Invalid assignment of column '" + columnName + "' of type '" + columnTypeName + "' to event property '" + writeablePropertyName + "' typed as '" + writablePropName + "', column and parameter types mismatch"; throw new ExprValidationException(message); } if (writeablePropertyType.IsNumeric()) { var instance = new TypeWidenerBoxedNumeric( CoercerFactory.GetCoercer(columnClassBoxed, targetClassBoxed)); return(instance.Widen); } } return(null); }