예제 #1
0
        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)
            }));
        }
예제 #2
0
        /// <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));
        }
예제 #4
0
        /// <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);
        }