public override ExprNode Validate(ExprValidationContext validationContext) { evaluator = ChildNodes[0].Forge.ExprEvaluator; // always valid return null; }
public override ExprNode Validate(ExprValidationContext validationContext) { return null; }
public abstract ExprNode Validate(ExprValidationContext validationContext);
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 = Arrays.CreateInstanceChecked(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); }
public static void PopulateObject( IDictionary<string, object> objectProperties, object top, ExprNodeOrigin exprNodeOrigin, ExprValidationContext exprValidationContext) { var applicableClass = top.GetType(); var writables = PropertyHelper.GetWritableProperties(applicableClass); var annotatedFields = TypeHelper.FindAnnotatedFields(top.GetType(), typeof(DataFlowOpParameterAttribute)); var annotatedMethods = TypeHelper.FindAnnotatedMethods(top.GetType(), typeof(DataFlowOpParameterAttribute)); // find catch-all methods ISet<MethodInfo> catchAllMethods = new LinkedHashSet<MethodInfo>(); if (annotatedMethods != null) { foreach (var method in annotatedMethods) { var anno = (DataFlowOpParameterAttribute) TypeHelper .GetAnnotations<DataFlowOpParameterAttribute>(method.UnwrapAttributes())[0]; if (anno.IsAll) { var parameters = method.GetParameters(); if (parameters.Length == 2 && (parameters[0].ParameterType == typeof(string)) && (parameters[1].ParameterType == typeof(object))) { catchAllMethods.Add(method); continue; } throw new ExprValidationException("Invalid annotation for catch-call"); } } } // map provided values foreach (var property in objectProperties) { var found = false; var propertyName = property.Key; // invoke catch-all setters foreach (var method in catchAllMethods) { try { method.Invoke(top, new[] {propertyName, property.Value}); } catch (MemberAccessException e) { throw new ExprValidationException( "Illegal access invoking method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + method.Name, e); } catch (TargetException e) { throw new ExprValidationException( "Exception invoking method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + method.Name + ": " + e.InnerException.Message, e); } found = true; } if (propertyName.ToLowerInvariant().Equals(CLASS_PROPERTY_NAME)) { continue; } // use the writeable property descriptor (appropriate setter method) from writing the property var descriptor = FindDescriptor(applicableClass, propertyName, writables); if (descriptor != null) { var coerceProperty = CoerceProperty( propertyName, applicableClass, property.Value, descriptor.PropertyType, exprNodeOrigin, exprValidationContext, false, true); try { var writeMember = descriptor.WriteMember; if (writeMember is MethodInfo writeMethod) { writeMethod.Invoke(top, new[] {coerceProperty}); } else if (writeMember is PropertyInfo writeProperty) { writeProperty.SetValue(top, coerceProperty); } else { throw new IllegalStateException("writeMember of invalid type"); } } catch (ArgumentException e) { throw new ExprValidationException( "Illegal argument invoking setter method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + descriptor.WriteMember.Name + " provided value " + coerceProperty, e); } catch (MemberAccessException e) { throw new ExprValidationException( "Illegal access invoking setter method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + descriptor.WriteMember.Name, e); } catch (TargetException e) { throw new ExprValidationException( "Exception invoking setter method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + descriptor.WriteMember.Name + ": " + e.InnerException.Message, e); } continue; } // find the field annotated with {@link @GraphOpProperty} foreach (var annotatedField in annotatedFields) { var anno = (DataFlowOpParameterAttribute) TypeHelper.GetAnnotations( typeof(DataFlowOpParameterAttribute), annotatedField.UnwrapAttributes())[0]; if (anno.Name.Equals(propertyName) || annotatedField.Name.Equals(propertyName)) { var coerceProperty = CoerceProperty( propertyName, applicableClass, property.Value, annotatedField.FieldType, exprNodeOrigin, exprValidationContext, true, true); try { annotatedField.SetValue(top, coerceProperty); } catch (Exception e) { throw new ExprValidationException( "Failed to set field '" + annotatedField.Name + "': " + e.Message, e); } found = true; break; } } if (found) { continue; } throw new ExprValidationException( "Failed to find writable property '" + propertyName + "' for class " + applicableClass.Name); } }
public static void PopulateObject( string operatorName, int operatorNum, string dataFlowName, IDictionary<string, object> objectProperties, object top, ExprNodeOrigin exprNodeOrigin, ExprValidationContext exprValidationContext, EPDataFlowOperatorParameterProvider optionalParameterProvider, IDictionary<string, object> optionalParameterURIs) { var applicableClass = top.GetType(); var writables = PropertyHelper.GetWritableProperties(applicableClass); var annotatedFields = TypeHelper.FindAnnotatedFields(top.GetType(), typeof(DataFlowOpParameterAttribute)); var annotatedMethods = TypeHelper.FindAnnotatedMethods(top.GetType(), typeof(DataFlowOpParameterAttribute)); // find catch-all methods ISet<MethodInfo> catchAllMethods = new LinkedHashSet<MethodInfo>(); if (annotatedMethods != null) { foreach (var method in annotatedMethods) { var anno = (DataFlowOpParameterAttribute) TypeHelper.GetAnnotations( typeof(DataFlowOpParameterAttribute), method.UnwrapAttributes())[0]; if (anno.IsAll) { var parameterTypes = method.GetParameterTypes(); if (parameterTypes.Length == 2 && parameterTypes[0] == typeof(string) && parameterTypes[1] == typeof(ExprNode)) { catchAllMethods.Add(method); continue; } throw new ExprValidationException("Invalid annotation for catch-call"); } } } // map provided values foreach (var property in objectProperties) { var found = false; var propertyName = property.Key; // invoke catch-all setters foreach (var method in catchAllMethods) { try { method.Invoke(top, new[] {propertyName, property.Value}); } catch (MemberAccessException e) { throw new ExprValidationException( "Illegal access invoking method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + method.Name, e); } catch (TargetException e) { throw new ExprValidationException( "Exception invoking method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + method.Name + ": " + e.InnerException.Message, e); } found = true; } if (propertyName.ToLowerInvariant().Equals(CLASS_PROPERTY_NAME)) { continue; } // use the writeable property descriptor (appropriate setter method) from writing the property var descriptor = FindDescriptor(applicableClass, propertyName, writables); if (descriptor != null) { var coerceProperty = CoerceProperty( propertyName, applicableClass, property.Value, descriptor.PropertyType, exprNodeOrigin, exprValidationContext, false, true); try { var writeMember = descriptor.WriteMember; if (writeMember is MethodInfo writeMethod) { writeMethod.Invoke(top, new[] {coerceProperty}); } else if (writeMember is PropertyInfo writeProperty) { writeProperty.SetValue(top, coerceProperty); } else { throw new IllegalStateException("writeMember of invalid type"); } } catch (ArgumentException e) { throw new ExprValidationException( "Illegal argument invoking setter method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + descriptor.WriteMember.Name + " provided value " + coerceProperty, e); } catch (MemberAccessException e) { throw new ExprValidationException( "Illegal access invoking setter method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + descriptor.WriteMember.Name, e); } catch (TargetException e) { throw new ExprValidationException( "Exception invoking setter method for property '" + propertyName + "' for class " + applicableClass.Name + " method " + descriptor.WriteMember.Name + ": " + e.InnerException.Message, e); } continue; } // find the field annotated with {@link @GraphOpProperty} foreach (var annotatedField in annotatedFields) { var anno = (DataFlowOpParameterAttribute) TypeHelper.GetAnnotations<DataFlowOpParameterAttribute>( annotatedField.UnwrapAttributes())[0]; if (anno.Name.Equals(propertyName) || annotatedField.Name.Equals(propertyName)) { var coerceProperty = CoerceProperty( propertyName, applicableClass, property.Value, annotatedField.FieldType, exprNodeOrigin, exprValidationContext, true, true); try { annotatedField.SetValue(top, coerceProperty); } catch (Exception e) { throw new ExprValidationException( "Failed to set field '" + annotatedField.Name + "': " + e.Message, e); } found = true; break; } } if (found) { continue; } throw new ExprValidationException( "Failed to find writable property '" + propertyName + "' for class " + applicableClass.Name); } // second pass: if a parameter URI - value pairs were provided, check that if (optionalParameterURIs != null) { foreach (var annotatedField in annotatedFields) { try { var uri = operatorName + "/" + annotatedField.Name; if (optionalParameterURIs.ContainsKey(uri)) { var value = optionalParameterURIs.Get(uri); annotatedField.SetValue(top, value); if (Log.IsDebugEnabled) { Log.Debug( "Found parameter '" + uri + "' for data flow " + dataFlowName + " setting " + value); } } else { if (Log.IsDebugEnabled) { Log.Debug("Not found parameter '" + uri + "' for data flow " + dataFlowName); } } } catch (Exception e) { throw new ExprValidationException( "Failed to set field '" + annotatedField.Name + "': " + e.Message, e); } } foreach (var method in annotatedMethods) { var anno = (DataFlowOpParameterAttribute) TypeHelper.GetAnnotations( typeof(DataFlowOpParameterAttribute), method.UnwrapAttributes())[0]; if (anno.IsAll) { var parameters = method.GetParameters(); var parameterTypes = method.GetParameterTypes(); if (parameterTypes.Length == 2 && parameterTypes[0] == typeof(string) && parameterTypes[1] == typeof(object)) { foreach (var entry in optionalParameterURIs) { var elements = URIUtil.ParsePathElements(new Uri(entry.Key)); if (elements.Length < 2) { throw new ExprValidationException( "Failed to parse URI '" + entry.Key + "', expected " + "'operator_name/property_name' format"); } if (elements[0].Equals(operatorName)) { try { method.Invoke(top, new[] {elements[1], entry.Value}); } catch (MemberAccessException e) { throw new ExprValidationException( "Illegal access invoking method for property '" + entry.Key + "' for class " + applicableClass.Name + " method " + method.Name, e); } catch (TargetException e) { throw new ExprValidationException( "Exception invoking method for property '" + entry.Key + "' for class " + applicableClass.Name + " method " + method.Name + ": " + e.InnerException.Message, e); } } } } } } } }
// Since static method calls such as "Class.method('a')" and mapped properties "Stream.property('key')" // look the same, however as the validation could not resolve "Stream.property('key')" before calling this method, // this method tries to resolve the mapped property as a static method. // Assumes that this is an ExprIdentNode. private static ExprNode ResolveStaticMethodOrField( ExprIdentNode identNode, ExprValidationException propertyException, ExprValidationContext validationContext) { // Reconstruct the original string StringBuilder mappedProperty = new StringBuilder(identNode.UnresolvedPropertyName); if (identNode.StreamOrPropertyName != null) { mappedProperty.Insert(0, identNode.StreamOrPropertyName + '.'); } // Parse the mapped property format into a class name, method and single string parameter MappedPropertyParseResult parse = ParseMappedProperty(mappedProperty.ToString()); if (parse == null) { ExprConstantNode constNode = ResolveIdentAsEnumConst( mappedProperty.ToString(), validationContext.ImportService); if (constNode == null) { throw propertyException; } else { return constNode; } } // If there is a class name, assume a static method is possible. if (parse.ClassName != null) { IList<ExprNode> parameters = Collections.SingletonList((ExprNode) new ExprConstantNodeImpl(parse.ArgString)); IList<ExprChainedSpec> chain = new List<ExprChainedSpec>(); chain.Add(new ExprChainedSpec(parse.ClassName, Collections.GetEmptyList<ExprNode>(), false)); chain.Add(new ExprChainedSpec(parse.MethodName, parameters, false)); ConfigurationCompilerExpression exprConfig = validationContext.StatementCompileTimeService.Configuration.Compiler.Expression; ExprNode result = new ExprDotNodeImpl(chain, exprConfig.IsDuckTyping, exprConfig.IsUdfCache); // Validate try { result.Validate(validationContext); } catch (ExprValidationException e) { throw new ExprValidationException( $"Failed to resolve enumeration method, date-time method or mapped property '{mappedProperty}': {e.Message}", e); } return result; } // There is no class name, try a single-row function string functionName = parse.MethodName; try { Pair<Type, ImportSingleRowDesc> classMethodPair = validationContext.ImportService.ResolveSingleRow(functionName); IList<ExprNode> parameters = Collections.SingletonList((ExprNode) new ExprConstantNodeImpl(parse.ArgString)); IList<ExprChainedSpec> chain = Collections.SingletonList( new ExprChainedSpec(classMethodPair.Second.MethodName, parameters, false)); ExprNode result = new ExprPlugInSingleRowNode( functionName, classMethodPair.First, chain, classMethodPair.Second); // Validate try { result.Validate(validationContext); } catch (EPException) { throw; } catch (Exception ex) { throw new ExprValidationException( "Plug-in aggregation function '" + parse.MethodName + "' failed validation: " + ex.Message); } return result; } catch (ImportUndefinedException) { // Not an single-row function } catch (ImportException e) { throw new IllegalStateException("Error resolving single-row function: " + e.Message, e); } // Try an aggregation function factory try { AggregationFunctionForge aggregationForge = validationContext.ImportService.ResolveAggregationFunction(parse.MethodName); ExprNode result = new ExprPlugInAggNode(false, aggregationForge, parse.MethodName); result.AddChildNode(new ExprConstantNodeImpl(parse.ArgString)); // Validate try { result.Validate(validationContext); } catch (EPException) { throw; } catch (Exception e) { throw new ExprValidationException( "Plug-in aggregation function '" + parse.MethodName + "' failed validation: " + e.Message); } return result; } catch (ImportUndefinedException) { // Not an aggregation function } catch (ImportException e) { throw new IllegalStateException("Error resolving aggregation: " + e.Message, e); } // absolutely cannot be resolved throw propertyException; }
private static ExprNode GetValidatedSubtreeInternal( ExprNode exprNode, ExprValidationContext validationContext, bool isTopLevel) { ExprNode result = exprNode; if (exprNode is ExprLambdaGoesNode) { return exprNode; } for (int i = 0; i < exprNode.ChildNodes.Length; i++) { ExprNode childNode = exprNode.ChildNodes[i]; if (childNode is ExprDeclaredOrLambdaNode node) { if (node.IsValidated) { continue; } } ExprNode childNodeValidated = GetValidatedSubtreeInternal(childNode, validationContext, false); exprNode.SetChildNode(i, childNodeValidated); } try { ExprNode optionalReplacement = exprNode.Validate(validationContext); if (optionalReplacement != null) { return GetValidatedSubtreeInternal(optionalReplacement, validationContext, isTopLevel); } } catch (ExprValidationException e) { if (exprNode is ExprIdentNode identNode) { try { result = ResolveStaticMethodOrField(identNode, e, validationContext); } catch (ExprValidationException) { var resolutionStream = ResolveAsStreamName(identNode, validationContext); if (resolutionStream.First == false) { throw; } result = resolutionStream.Second; } } else { throw; } } // For top-level expressions check if we perform audit if (isTopLevel) { if (validationContext.IsExpressionAudit) { return (ExprNode) ExprNodeProxy.NewInstance(result); } } else { if (validationContext.IsExpressionNestedAudit && !(result is ExprIdentNode) && !(ExprNodeUtilityQuery.IsConstant(result))) { return (ExprNode) ExprNodeProxy.NewInstance(result); } } return result; }