public EventPropertyDescriptor getWritableProperty(String propertyName) {
    if (writablePropertyDescriptors == null) {
      initializeWriters();
    }
    Pair<EventPropertyDescriptor, ? extends EventPropertyWriter> pair =
        propertyWriters.get(propertyName);
    if (pair != null) {
      return pair.getFirst();
    }

    Property property = PropertyParser.parse(propertyName, false);
    if (property instanceof MappedProperty) {
      EventPropertyWriter writer = getWriter(propertyName);
      if (writer == null) {
        return null;
      }
      MappedProperty mapProp = (MappedProperty) property;
      return new EventPropertyDescriptor(
          mapProp.getPropertyNameAtomic(), Object.class, null, false, true, false, true, false);
    }
    if (property instanceof IndexedProperty) {
      EventPropertyWriter writer = getWriter(propertyName);
      if (writer == null) {
        return null;
      }
      IndexedProperty indexedProp = (IndexedProperty) property;
      return new EventPropertyDescriptor(
          indexedProp.getPropertyNameAtomic(), Object.class, null, true, false, true, false, false);
    }
    return null;
  }
  public EventBeanWriter getWriter(String[] properties) {
    if (writablePropertyDescriptors == null) {
      initializeWriters();
    }

    boolean allSimpleProps = true;
    MapEventBeanPropertyWriter[] writers = new MapEventBeanPropertyWriter[properties.length];
    for (int i = 0; i < properties.length; i++) {
      Pair<EventPropertyDescriptor, MapEventBeanPropertyWriter> writerPair =
          propertyWriters.get(properties[i]);
      if (writerPair != null) {
        writers[i] = writerPair.getSecond();
      } else {
        writers[i] = getWriter(properties[i]);
        if (writers[i] == null) {
          return null;
        }
        allSimpleProps = false;
      }
    }

    if (allSimpleProps) {
      return new MapEventBeanWriterSimpleProps(properties);
    } else {
      return new MapEventBeanWriterPerProp(writers);
    }
  }
  public MapEventBeanPropertyWriter getWriter(String propertyName) {
    if (writablePropertyDescriptors == null) {
      initializeWriters();
    }
    Pair<EventPropertyDescriptor, MapEventBeanPropertyWriter> pair =
        propertyWriters.get(propertyName);
    if (pair != null) {
      return pair.getSecond();
    }

    Property property = PropertyParser.parse(propertyName, false);
    if (property instanceof MappedProperty) {
      MappedProperty mapProp = (MappedProperty) property;
      return new MapEventBeanPropertyWriterMapProp(
          mapProp.getPropertyNameAtomic(), mapProp.getKey());
    }

    if (property instanceof IndexedProperty) {
      IndexedProperty indexedProp = (IndexedProperty) property;
      return new MapEventBeanPropertyWriterIndexedProp(
          indexedProp.getPropertyNameAtomic(), indexedProp.getIndex());
    }

    return null;
  }
예제 #4
0
  private void handleEvent(EventBean theEvent, boolean isNew) {
    Object groupByValuesKey = getGroupKey(theEvent);

    // Get child views that belong to this group-by value combination
    Object subViews = this.subViewsPerKey.get(groupByValuesKey);

    // If this is a new group-by value, the list of subviews is null and we need to make clone
    // sub-views
    if (subViews == null) {
      subViews = makeSubViews(this, propertyNames, groupByValuesKey, agentInstanceContext);
      subViewsPerKey.put(groupByValuesKey, subViews);
    }

    // Construct a pair of lists to hold the events for the grouped value if not already there
    Pair<Object, Object> pair = groupedEvents.get(subViews);
    if (pair == null) {
      pair = new Pair<Object, Object>(null, null);
      groupedEvents.put(subViews, pair);
    }

    // Add event to a child view event list for later child update that includes new and old events
    if (isNew) {
      pair.setFirst(addUpgradeToDequeIfPopulated(pair.getFirst(), theEvent));
    } else {
      pair.setSecond(addUpgradeToDequeIfPopulated(pair.getSecond(), theEvent));
    }
  }
 /**
  * Adds configured variables to the variable service.
  *
  * @param variableService service to add to
  * @param variables configured variables
  */
 protected static void initVariables(
     VariableService variableService,
     Map<String, ConfigurationVariable> variables,
     EngineImportService engineImportService) {
   for (Map.Entry<String, ConfigurationVariable> entry : variables.entrySet()) {
     try {
       Pair<String, Boolean> arrayType =
           JavaClassHelper.isGetArrayType(entry.getValue().getType());
       variableService.createNewVariable(
           null,
           entry.getKey(),
           arrayType.getFirst(),
           entry.getValue().isConstant(),
           arrayType.getSecond(),
           false,
           entry.getValue().getInitializationValue(),
           engineImportService);
       variableService.allocateVariableState(entry.getKey(), 0, null);
     } catch (VariableExistsException e) {
       throw new ConfigurationException("Error configuring variables: " + e.getMessage(), e);
     } catch (VariableTypeException e) {
       throw new ConfigurationException("Error configuring variables: " + e.getMessage(), e);
     }
   }
 }
 public void testGetPropertyNameEscaped() throws Exception {
   final String PROPERTY = "a\\.b\\.c";
   Pair<Tree, CommonTokenStream> parsed = SupportParserHelper.parseEventProperty(PROPERTY);
   Tree propertyNameExprNode = parsed.getFirst();
   ASTUtil.dumpAST(propertyNameExprNode);
   String propertyName = ASTFilterSpecHelper.getPropertyName(propertyNameExprNode, 0);
   assertEquals(PROPERTY, propertyName);
 }
예제 #7
0
 public EventPropertyDescriptor getWritableProperty(String propertyName) {
   if (writableProperties == null) {
     initializeWriters();
   }
   Pair<EventPropertyDescriptor, EventPropertyWriter> pair = writers.get(propertyName);
   if (pair == null) {
     return null;
   }
   return pair.getFirst();
 }
  public void testGetPropertyName() throws Exception {
    final String PROPERTY = "a('aa').b[1].c";

    // Should parse and result in the exact same property name
    Pair<Tree, CommonTokenStream> parsed = SupportParserHelper.parseEventProperty(PROPERTY);
    Tree propertyNameExprNode = parsed.getFirst();
    ASTUtil.dumpAST(propertyNameExprNode);
    String propertyName = ASTFilterSpecHelper.getPropertyName(propertyNameExprNode, 0);
    assertEquals(PROPERTY, propertyName);

    // Try AST with tokens separated, same property name
    parsed = SupportParserHelper.parseEventProperty("a(    'aa'   ). b [ 1 ] . c");
    propertyNameExprNode = parsed.getFirst();
    propertyName = ASTFilterSpecHelper.getPropertyName(propertyNameExprNode, 0);
    assertEquals(PROPERTY, propertyName);
  }
 public Pair<IndexMultiKey, EventTableAndNamePair> findTable(
     Set<String> keyPropertyNames,
     Set<String> rangePropertyNames,
     List<IndexHintInstruction> optionalIndexHintInstructions) {
   Pair<IndexMultiKey, EventTableIndexEntryBase> pair =
       EventTableIndexUtil.findIndexBestAvailable(
           tableIndexesRefCount,
           keyPropertyNames,
           rangePropertyNames,
           optionalIndexHintInstructions);
   if (pair == null) {
     return null;
   }
   EventTable tableFound = ((EventTableIndexRepositoryEntry) pair.getSecond()).getTable();
   return new Pair<IndexMultiKey, EventTableAndNamePair>(
       pair.getFirst(),
       new EventTableAndNamePair(tableFound, pair.getSecond().getOptionalIndexName()));
 }
예제 #10
0
  /**
   * Close resources.
   *
   * @param pair is the resources to close.
   */
  protected static void close(Pair<Connection, PreparedStatement> pair) {
    log.info(".close Closing statement and connection");
    try {
      pair.getSecond().close();
    } catch (SQLException ex) {
      try {
        pair.getFirst().close();
      } catch (SQLException e) {
        log.error("Error closing JDBC connection:" + e.getMessage(), e);
      }
      throw new EPException("Error closing statement", ex);
    }

    try {
      pair.getFirst().close();
    } catch (SQLException ex) {
      throw new EPException("Error closing statement", ex);
    }
  }
  public List<EventBean> poll(Object[] lookupValues) {
    List<EventBean> result;
    try {
      result = execute(resources.getSecond(), lookupValues);
    } catch (EPException ex) {
      connectionCache.doneWith(resources);
      throw ex;
    }

    return result;
  }
 public void addVariable(
     String variableName, String type, Object initializationValue, boolean constant)
     throws ConfigurationException {
   try {
     Pair<String, Boolean> arrayType = JavaClassHelper.isGetArrayType(type);
     variableService.createNewVariable(
         variableName,
         arrayType.getFirst(),
         initializationValue,
         constant,
         arrayType.getSecond(),
         null,
         engineImportService);
     statementVariableRef.addConfiguredVariable(variableName);
   } catch (VariableExistsException e) {
     throw new ConfigurationException("Error creating variable: " + e.getMessage(), e);
   } catch (VariableTypeException e) {
     throw new ConfigurationException("Error creating variable: " + e.getMessage(), e);
   }
 }
  public Pair<Class, String> resolveSingleRow(String name)
      throws EngineImportException, EngineImportUndefinedException {
    Pair<String, String> pair = singleRowFunctions.get(name);
    if (pair == null) {
      pair = singleRowFunctions.get(name.toLowerCase());
    }
    if (pair == null) {
      throw new EngineImportUndefinedException("A function named '" + name + "' is not defined");
    }

    Class clazz;
    try {
      ClassLoader cl = Thread.currentThread().getContextClassLoader();
      clazz = Class.forName(pair.getFirst(), true, cl);
    } catch (ClassNotFoundException ex) {
      throw new EngineImportException(
          "Could not load single-row function class by name '" + pair.getFirst() + "'", ex);
    }
    return new Pair<Class, String>(clazz, pair.getSecond());
  }
예제 #14
0
  public TableMetadata(
      String tableName,
      String eplExpression,
      String statementName,
      Class[] keyTypes,
      Map<String, TableMetadataColumn> tableColumns,
      TableStateRowFactory rowFactory,
      int numberMethodAggregations,
      StatementResourceService createTableResources,
      String contextName,
      ObjectArrayEventType internalEventType,
      ObjectArrayEventType publicEventType,
      TableMetadataInternalEventToPublic eventToPublic,
      boolean queryPlanLogging,
      String createTableStatementName)
      throws ExprValidationException {
    this.tableName = tableName;
    this.eplExpression = eplExpression;
    this.statementName = statementName;
    this.keyTypes = keyTypes;
    this.tableColumns = tableColumns;
    this.rowFactory = rowFactory;
    this.numberMethodAggregations = numberMethodAggregations;
    this.createTableResources = createTableResources;
    this.contextName = contextName;
    this.internalEventType = internalEventType;
    this.publicEventType = publicEventType;
    this.eventToPublic = eventToPublic;
    this.queryPlanLogging = queryPlanLogging;

    if (keyTypes.length > 0) {
      Pair<int[], IndexMultiKey> pair =
          TableServiceUtil.getIndexMultikeyForKeys(tableColumns, internalEventType);
      eventTableIndexMetadataRepo.addIndex(
          true, pair.getSecond(), tableName, createTableStatementName, true);
      tableRowKeyFactory = new TableRowKeyFactory(pair.getFirst());
    }
  }
  public void validateAddExplicitIndex(
      boolean unique,
      String indexName,
      List<CreateIndexItem> columns,
      EventType eventType,
      Iterable<EventBean> dataWindowContents)
      throws ExprValidationException {
    if (explicitIndexes.containsKey(indexName)) {
      throw new ExprValidationException("Index by name '" + indexName + "' already exists");
    }

    EventTableCreateIndexDesc desc =
        EventTableIndexUtil.validateCompileExplicitIndex(unique, columns, eventType);
    Pair<IndexMultiKey, EventTableAndNamePair> pair =
        addExplicitIndexOrReuse(
            unique,
            desc.getHashProps(),
            desc.getBtreeProps(),
            dataWindowContents,
            eventType,
            indexName);
    explicitIndexes.put(indexName, pair.getSecond().getEventTable());
  }
  public void testNestedPojo() {
    Pair<String[], Object[]> pair = getTestDefTwo();
    EPServiceProvider epService =
        getEngineInitialized("NestedObjectArr", pair.getFirst(), pair.getSecond());

    String statementText =
        "select "
            + "simple, object, nodefmap, map, "
            + "object.id as a1, nodefmap.key1? as a2, nodefmap.key2? as a3, nodefmap.key3?.key4 as a4, "
            + "map.objectOne as b1, map.simpleOne as b2, map.nodefmapOne.key2? as b3, map.mapOne.simpleTwo? as b4, "
            + "map.objectOne.indexed[1] as c1, map.objectOne.nested.nestedValue as c2,"
            + "map.mapOne.simpleTwo as d1, map.mapOne.objectTwo as d2, map.mapOne.nodefmapTwo as d3, "
            + "map.mapOne.mapTwo as e1, map.mapOne.mapTwo.simpleThree as e2, map.mapOne.mapTwo.objectThree as e3, "
            + "map.mapOne.objectTwo.array[1].mapped('1ma').value as f1, map.mapOne.mapTwo.objectThree.id as f2"
            + " from NestedObjectArr";
    EPStatement statement = epService.getEPAdministrator().createEPL(statementText);
    SupportUpdateListener listener = new SupportUpdateListener();
    statement.addListener(listener);

    Object[] testdata = getTestDataTwo();
    epService.getEPRuntime().sendEvent(testdata, "NestedObjectArr");

    // test all properties exist
    EventBean received = listener.assertOneGetNewAndReset();
    EPAssertionUtil.assertProps(
        received,
        "simple,object,nodefmap,map".split(","),
        new Object[] {"abc", new SupportBean_A("A1"), testdata[2], testdata[3]});
    EPAssertionUtil.assertProps(
        received, "a1,a2,a3,a4".split(","), new Object[] {"A1", "val1", null, null});
    EPAssertionUtil.assertProps(
        received,
        "b1,b2,b3,b4".split(","),
        new Object[] {getNestedKey(testdata, 3, "objectOne"), 10, "val2", 300});
    EPAssertionUtil.assertProps(received, "c1,c2".split(","), new Object[] {2, "nestedValue"});
    EPAssertionUtil.assertProps(
        received,
        "d1,d2,d3".split(","),
        new Object[] {
          300,
          getNestedKey(testdata, 3, "mapOne", "objectTwo"),
          getNestedKey(testdata, 3, "mapOne", "nodefmapTwo")
        });
    EPAssertionUtil.assertProps(
        received,
        "e1,e2,e3".split(","),
        new Object[] {
          getNestedKey(testdata, 3, "mapOne", "mapTwo"), 4000L, new SupportBean_B("B1")
        });
    EPAssertionUtil.assertProps(received, "f1,f2".split(","), new Object[] {"1ma0", "B1"});

    // assert type info
    EPStatement stmt = epService.getEPAdministrator().createEPL(("select * from NestedObjectArr"));
    EventType eventType = stmt.getEventType();

    String[] propertiesReceived = eventType.getPropertyNames();
    String[] propertiesExpected = new String[] {"simple", "object", "nodefmap", "map"};
    EPAssertionUtil.assertEqualsAnyOrder(propertiesReceived, propertiesExpected);
    assertEquals(String.class, eventType.getPropertyType("simple"));
    assertEquals(Map.class, eventType.getPropertyType("map"));
    assertEquals(Map.class, eventType.getPropertyType("nodefmap"));
    assertEquals(SupportBean_A.class, eventType.getPropertyType("object"));

    assertNull(eventType.getPropertyType("map.mapOne.simpleOne"));

    // nested POJO with generic return type
    listener.reset();
    epService
        .getEPAdministrator()
        .getConfiguration()
        .addEventType("MyNested", new String[] {"bean"}, new Object[] {MyNested.class});
    EPStatement stmtTwo =
        epService
            .getEPAdministrator()
            .createEPL("select * from MyNested(bean.insides.anyOf(i=>id = 'A'))");
    stmtTwo.addListener(listener);

    epService
        .getEPRuntime()
        .sendEvent(
            new Object[] {new MyNested(Arrays.asList(new MyInside[] {new MyInside("A")}))},
            "MyNested");
    assertTrue(listener.isInvoked());
  }
예제 #17
0
  /**
   * Ctor.
   *
   * @param assignments the list of variable assignments
   * @param variableService variable service
   * @param eventAdapterService event adapters
   * @throws com.espertech.esper.epl.expression.core.ExprValidationException when variables cannot
   *     be found
   */
  public VariableReadWritePackage(
      List<OnTriggerSetAssignment> assignments,
      VariableService variableService,
      EventAdapterService eventAdapterService)
      throws ExprValidationException {
    this.metaData = new VariableMetaData[assignments.size()];
    this.readersForGlobalVars = new VariableReader[assignments.size()];
    this.mustCoerce = new boolean[assignments.size()];
    this.writers = new WriteDesc[assignments.size()];

    this.variableTypes = new HashMap<String, Object>();
    this.eventAdapterService = eventAdapterService;
    this.variableService = variableService;

    Map<EventTypeSPI, CopyMethodDesc> eventTypeWrittenProps =
        new HashMap<EventTypeSPI, CopyMethodDesc>();
    int count = 0;
    List<VariableTriggerSetDesc> assignmentList = new ArrayList<VariableTriggerSetDesc>();

    for (OnTriggerSetAssignment expressionWithAssignments : assignments) {
      Pair<String, ExprNode> possibleVariableAssignment =
          ExprNodeUtility.checkGetAssignmentToVariableOrProp(
              expressionWithAssignments.getExpression());
      if (possibleVariableAssignment == null) {
        throw new ExprValidationException(
            "Missing variable assignment expression in assignment number " + count);
      }
      assignmentList.add(
          new VariableTriggerSetDesc(
              possibleVariableAssignment.getFirst(),
              possibleVariableAssignment.getSecond().getExprEvaluator()));

      String fullVariableName = possibleVariableAssignment.getFirst();
      String variableName = fullVariableName;
      String subPropertyName = null;

      int indexOfDot = variableName.indexOf('.');
      if (indexOfDot != -1) {
        subPropertyName = variableName.substring(indexOfDot + 1, variableName.length());
        variableName = variableName.substring(0, indexOfDot);
      }

      VariableMetaData variableMetadata = variableService.getVariableMetaData(variableName);
      metaData[count] = variableMetadata;
      if (variableMetadata == null) {
        throw new ExprValidationException(
            "Variable by name '" + variableName + "' has not been created or configured");
      }
      if (variableMetadata.isConstant()) {
        throw new ExprValidationException(
            "Variable by name '" + variableName + "' is declared constant and may not be set");
      }
      if (variableMetadata.getContextPartitionName() == null) {
        readersForGlobalVars[count] =
            variableService.getReader(variableName, VariableService.NOCONTEXT_AGENTINSTANCEID);
      }

      if (subPropertyName != null) {
        if (variableMetadata.getEventType() == null) {
          throw new ExprValidationException(
              "Variable by name '"
                  + variableName
                  + "' does not have a property named '"
                  + subPropertyName
                  + "'");
        }
        EventType type = variableMetadata.getEventType();
        if (!(type instanceof EventTypeSPI)) {
          throw new ExprValidationException(
              "Variable by name '"
                  + variableName
                  + "' event type '"
                  + type.getName()
                  + "' not writable");
        }
        EventTypeSPI spi = (EventTypeSPI) type;
        EventPropertyWriter writer = spi.getWriter(subPropertyName);
        EventPropertyGetter getter = spi.getGetter(subPropertyName);
        if (writer == null) {
          throw new ExprValidationException(
              "Variable by name '"
                  + variableName
                  + "' the property '"
                  + subPropertyName
                  + "' is not writable");
        }

        variableTypes.put(fullVariableName, spi.getPropertyType(subPropertyName));
        CopyMethodDesc writtenProps = eventTypeWrittenProps.get(spi);
        if (writtenProps == null) {
          writtenProps = new CopyMethodDesc(variableName, new ArrayList<String>());
          eventTypeWrittenProps.put(spi, writtenProps);
        }
        writtenProps.getPropertiesCopied().add(subPropertyName);

        writers[count] = new WriteDesc(spi, variableName, writer, getter);
      } else {

        // determine types
        Class expressionType = possibleVariableAssignment.getSecond().getExprEvaluator().getType();

        if (variableMetadata.getEventType() != null) {
          if ((expressionType != null)
              && (!JavaClassHelper.isSubclassOrImplementsInterface(
                  expressionType, variableMetadata.getEventType().getUnderlyingType()))) {
            throw new VariableValueException(
                "Variable '"
                    + variableName
                    + "' of declared event type '"
                    + variableMetadata.getEventType().getName()
                    + "' underlying type '"
                    + variableMetadata.getEventType().getUnderlyingType().getName()
                    + "' cannot be assigned a value of type '"
                    + expressionType.getName()
                    + "'");
          }
          variableTypes.put(variableName, variableMetadata.getEventType().getUnderlyingType());
        } else {

          Class variableType = variableMetadata.getType();
          variableTypes.put(variableName, variableType);

          // determine if the expression type can be assigned
          if (variableType != java.lang.Object.class) {
            if ((JavaClassHelper.getBoxedType(expressionType) != variableType)
                && (expressionType != null)) {
              if ((!JavaClassHelper.isNumeric(variableType))
                  || (!JavaClassHelper.isNumeric(expressionType))) {
                throw new ExprValidationException(
                    VariableServiceUtil.getAssigmentExMessage(
                        variableName, variableType, expressionType));
              }

              if (!(JavaClassHelper.canCoerce(expressionType, variableType))) {
                throw new ExprValidationException(
                    VariableServiceUtil.getAssigmentExMessage(
                        variableName, variableType, expressionType));
              }

              mustCoerce[count] = true;
            }
          }
        }
      }

      count++;
    }

    this.assignments = assignmentList.toArray(new VariableTriggerSetDesc[assignmentList.size()]);

    if (eventTypeWrittenProps.isEmpty()) {
      copyMethods = Collections.EMPTY_MAP;
      return;
    }

    copyMethods = new HashMap<EventTypeSPI, EventBeanCopyMethod>();
    for (Map.Entry<EventTypeSPI, CopyMethodDesc> entry : eventTypeWrittenProps.entrySet()) {
      List<String> propsWritten = entry.getValue().getPropertiesCopied();
      String[] props = propsWritten.toArray(new String[propsWritten.size()]);
      EventBeanCopyMethod copyMethod = entry.getKey().getCopyMethod(props);
      if (copyMethod == null) {
        throw new ExprValidationException(
            "Variable '"
                + entry.getValue().getVariableName()
                + "' of declared type "
                + JavaClassHelper.getClassNameFullyQualPretty(entry.getKey().getUnderlyingType())
                + "' cannot be assigned to");
      }
      copyMethods.put(entry.getKey(), copyMethod);
    }
  }
예제 #18
0
  private static void recursiveCompile(
      EvalNode evalNode,
      StatementContext context,
      Set<String> eventTypeReferences,
      boolean isInsertInto,
      MatchEventSpec tags,
      Deque<Integer> subexpressionIdStack)
      throws ExprValidationException {
    int counter = 0;
    for (EvalNode child : evalNode.getChildNodes()) {
      subexpressionIdStack.addLast(counter++);
      recursiveCompile(
          child, context, eventTypeReferences, isInsertInto, tags, subexpressionIdStack);
      subexpressionIdStack.removeLast();
    }

    LinkedHashMap<String, Pair<EventType, String>> newTaggedEventTypes = null;
    LinkedHashMap<String, Pair<EventType, String>> newArrayEventTypes = null;

    if (evalNode instanceof EvalFilterNode) {
      EvalFilterNode filterNode = (EvalFilterNode) evalNode;
      String eventName = filterNode.getRawFilterSpec().getEventTypeName();
      EventType resolvedEventType =
          FilterStreamSpecRaw.resolveType(
              context.getEngineURI(),
              eventName,
              context.getEventAdapterService(),
              context.getPlugInTypeResolutionURIs());
      EventType finalEventType = resolvedEventType;
      String optionalTag = filterNode.getEventAsName();
      boolean isPropertyEvaluation = false;

      // obtain property event type, if final event type is properties
      if (filterNode.getRawFilterSpec().getOptionalPropertyEvalSpec() != null) {
        PropertyEvaluator optionalPropertyEvaluator =
            PropertyEvaluatorFactory.makeEvaluator(
                filterNode.getRawFilterSpec().getOptionalPropertyEvalSpec(),
                resolvedEventType,
                filterNode.getEventAsName(),
                context.getEventAdapterService(),
                context.getMethodResolutionService(),
                context.getSchedulingService(),
                context.getVariableService(),
                context.getEngineURI(),
                context.getStatementId(),
                context.getStatementName(),
                context.getAnnotations(),
                subexpressionIdStack);
        finalEventType = optionalPropertyEvaluator.getFragmentEventType();
        isPropertyEvaluation = true;
      }

      if (finalEventType instanceof EventTypeSPI) {
        eventTypeReferences.add(((EventTypeSPI) finalEventType).getMetadata().getPrimaryName());
      }

      // If a tag was supplied for the type, the tags must stay with this type, i.e. a=BeanA ->
      // b=BeanA -> a=BeanB is a no
      if (optionalTag != null) {
        Pair<EventType, String> pair = tags.getTaggedEventTypes().get(optionalTag);
        EventType existingType = null;
        if (pair != null) {
          existingType = pair.getFirst();
        }
        if (existingType == null) {
          pair = tags.getArrayEventTypes().get(optionalTag);
          if (pair != null) {
            throw new ExprValidationException(
                "Tag '"
                    + optionalTag
                    + "' for event '"
                    + eventName
                    + "' used in the repeat-until operator cannot also appear in other filter expressions");
          }
        }
        if ((existingType != null) && (existingType != finalEventType)) {
          throw new ExprValidationException(
              "Tag '"
                  + optionalTag
                  + "' for event '"
                  + eventName
                  + "' has already been declared for events of type "
                  + existingType.getUnderlyingType().getName());
        }
        pair = new Pair<EventType, String>(finalEventType, eventName);

        // add tagged type
        if (isPropertyEvaluation) {
          newArrayEventTypes = new LinkedHashMap<String, Pair<EventType, String>>();
          newArrayEventTypes.put(optionalTag, pair);
        } else {
          newTaggedEventTypes = new LinkedHashMap<String, Pair<EventType, String>>();
          newTaggedEventTypes.put(optionalTag, pair);
        }
      }

      // For this filter, filter types are all known tags at this time,
      // and additionally stream 0 (self) is our event type.
      // Stream type service allows resolution by property name event if that name appears in other
      // tags.
      // by defaulting to stream zero.
      // Stream zero is always the current event type, all others follow the order of the map
      // (stream 1 to N).
      String selfStreamName = optionalTag;
      if (selfStreamName == null) {
        selfStreamName = "s_" + UuidGenerator.generate();
      }
      LinkedHashMap<String, Pair<EventType, String>> filterTypes =
          new LinkedHashMap<String, Pair<EventType, String>>();
      Pair<EventType, String> typePair = new Pair<EventType, String>(finalEventType, eventName);
      filterTypes.put(selfStreamName, typePair);
      filterTypes.putAll(tags.getTaggedEventTypes());

      // for the filter, specify all tags used
      LinkedHashMap<String, Pair<EventType, String>> filterTaggedEventTypes =
          new LinkedHashMap<String, Pair<EventType, String>>(tags.getTaggedEventTypes());
      filterTaggedEventTypes.remove(optionalTag);

      // handle array tags (match-until clause)
      LinkedHashMap<String, Pair<EventType, String>> arrayCompositeEventTypes = null;
      if (tags.getArrayEventTypes() != null) {
        arrayCompositeEventTypes = new LinkedHashMap<String, Pair<EventType, String>>();
        String patternSubexEventType =
            getPatternSubexEventType(context.getStatementId(), "pattern", subexpressionIdStack);
        EventType arrayTagCompositeEventType =
            context
                .getEventAdapterService()
                .createSemiAnonymousMapType(
                    patternSubexEventType, new HashMap(), tags.getArrayEventTypes(), isInsertInto);
        for (Map.Entry<String, Pair<EventType, String>> entry :
            tags.getArrayEventTypes().entrySet()) {
          String tag = entry.getKey();
          if (!filterTypes.containsKey(tag)) {
            Pair<EventType, String> pair =
                new Pair<EventType, String>(arrayTagCompositeEventType, tag);
            filterTypes.put(tag, pair);
            arrayCompositeEventTypes.put(tag, pair);
          }
        }
      }

      StreamTypeService streamTypeService =
          new StreamTypeServiceImpl(filterTypes, context.getEngineURI(), true, false);
      List<ExprNode> exprNodes = filterNode.getRawFilterSpec().getFilterExpressions();

      FilterSpecCompiled spec =
          FilterSpecCompiler.makeFilterSpec(
              resolvedEventType,
              eventName,
              exprNodes,
              filterNode.getRawFilterSpec().getOptionalPropertyEvalSpec(),
              filterTaggedEventTypes,
              arrayCompositeEventTypes,
              streamTypeService,
              context.getMethodResolutionService(),
              context.getSchedulingService(),
              context.getVariableService(),
              context.getEventAdapterService(),
              context.getEngineURI(),
              null,
              context,
              subexpressionIdStack);
      filterNode.setFilterSpec(spec);
    } else if (evalNode instanceof EvalObserverNode) {
      EvalObserverNode observerNode = (EvalObserverNode) evalNode;
      try {
        ObserverFactory observerFactory =
            context.getPatternResolutionService().create(observerNode.getPatternObserverSpec());

        StreamTypeService streamTypeService =
            getStreamTypeService(
                context.getEngineURI(),
                context.getStatementId(),
                context.getEventAdapterService(),
                tags.taggedEventTypes,
                tags.arrayEventTypes,
                subexpressionIdStack,
                "observer");
        ExprValidationContext validationContext =
            new ExprValidationContext(
                streamTypeService,
                context.getMethodResolutionService(),
                null,
                context.getSchedulingService(),
                context.getVariableService(),
                context,
                context.getEventAdapterService(),
                context.getStatementName(),
                context.getStatementId(),
                context.getAnnotations());
        List<ExprNode> validated =
            validateExpressions(
                observerNode.getPatternObserverSpec().getObjectParameters(), validationContext);

        MatchedEventConvertor convertor =
            new MatchedEventConvertorImpl(
                tags.taggedEventTypes, tags.arrayEventTypes, context.getEventAdapterService());

        observerNode.setObserverFactory(observerFactory);
        observerFactory.setObserverParameters(validated, convertor);
      } catch (ObserverParameterException e) {
        throw new ExprValidationException(
            "Invalid parameter for pattern observer: " + e.getMessage(), e);
      } catch (PatternObjectException e) {
        throw new ExprValidationException(
            "Failed to resolve pattern observer: " + e.getMessage(), e);
      }
    } else if (evalNode instanceof EvalGuardNode) {
      EvalGuardNode guardNode = (EvalGuardNode) evalNode;
      try {
        GuardFactory guardFactory =
            context.getPatternResolutionService().create(guardNode.getPatternGuardSpec());

        StreamTypeService streamTypeService =
            getStreamTypeService(
                context.getEngineURI(),
                context.getStatementId(),
                context.getEventAdapterService(),
                tags.taggedEventTypes,
                tags.arrayEventTypes,
                subexpressionIdStack,
                "guard");
        ExprValidationContext validationContext =
            new ExprValidationContext(
                streamTypeService,
                context.getMethodResolutionService(),
                null,
                context.getSchedulingService(),
                context.getVariableService(),
                context,
                context.getEventAdapterService(),
                context.getStatementName(),
                context.getStatementId(),
                context.getAnnotations());
        List<ExprNode> validated =
            validateExpressions(
                guardNode.getPatternGuardSpec().getObjectParameters(), validationContext);

        MatchedEventConvertor convertor =
            new MatchedEventConvertorImpl(
                tags.taggedEventTypes, tags.arrayEventTypes, context.getEventAdapterService());

        guardNode.setGuardFactory(guardFactory);
        guardFactory.setGuardParameters(validated, convertor);
      } catch (GuardParameterException e) {
        throw new ExprValidationException(
            "Invalid parameter for pattern guard: " + e.getMessage(), e);
      } catch (PatternObjectException e) {
        throw new ExprValidationException("Failed to resolve pattern guard: " + e.getMessage(), e);
      }
    } else if (evalNode instanceof EvalEveryDistinctNode) {
      EvalEveryDistinctNode distinctNode = (EvalEveryDistinctNode) evalNode;
      MatchEventSpec matchEventFromChildNodes = analyzeMatchEvent(distinctNode);
      StreamTypeService streamTypeService =
          getStreamTypeService(
              context.getEngineURI(),
              context.getStatementId(),
              context.getEventAdapterService(),
              matchEventFromChildNodes.getTaggedEventTypes(),
              matchEventFromChildNodes.getArrayEventTypes(),
              subexpressionIdStack,
              "every-distinct");
      ExprValidationContext validationContext =
          new ExprValidationContext(
              streamTypeService,
              context.getMethodResolutionService(),
              null,
              context.getSchedulingService(),
              context.getVariableService(),
              context,
              context.getEventAdapterService(),
              context.getStatementName(),
              context.getStatementId(),
              context.getAnnotations());
      List<ExprNode> validated;
      try {
        validated = validateExpressions(distinctNode.getExpressions(), validationContext);
      } catch (ExprValidationPropertyException ex) {
        throw new ExprValidationPropertyException(
            ex.getMessage()
                + ", every-distinct requires that all properties resolve from sub-expressions to the every-distinct",
            ex.getCause());
      }

      MatchedEventConvertor convertor =
          new MatchedEventConvertorImpl(
              matchEventFromChildNodes.getTaggedEventTypes(),
              matchEventFromChildNodes.getArrayEventTypes(),
              context.getEventAdapterService());

      distinctNode.setConvertor(convertor);

      // Determine whether some expressions are constants or time period
      List<ExprNode> distinctExpressions = new ArrayList<ExprNode>();
      Long msecToExpire = null;
      for (ExprNode expr : validated) {
        if (expr instanceof ExprTimePeriod) {
          Double secondsExpire = (Double) ((ExprTimePeriod) expr).evaluate(null, true, context);
          if ((secondsExpire != null) && (secondsExpire > 0)) {
            msecToExpire = Math.round(1000d * secondsExpire);
          }
          log.debug("Setting every-distinct msec-to-expire to " + msecToExpire);
        } else if (expr.isConstantResult()) {
          log.warn(
              "Every-distinct node utilizes an expression returning a constant value, please check expression '"
                  + expr.toExpressionString()
                  + "', not adding expression to distinct-value expression list");
        } else {
          distinctExpressions.add(expr);
        }
      }
      if (distinctExpressions.isEmpty()) {
        throw new ExprValidationException(
            "Every-distinct node requires one or more distinct-value expressions that each return non-constant result values");
      }
      distinctNode.setExpressions(distinctExpressions, msecToExpire);
    } else if (evalNode instanceof EvalMatchUntilNode) {
      EvalMatchUntilNode matchUntilNode = (EvalMatchUntilNode) evalNode;

      // compile bounds expressions, if any
      MatchEventSpec untilMatchEventSpec =
          new MatchEventSpec(tags.getTaggedEventTypes(), tags.getArrayEventTypes());
      StreamTypeService streamTypeService =
          getStreamTypeService(
              context.getEngineURI(),
              context.getStatementId(),
              context.getEventAdapterService(),
              untilMatchEventSpec.getTaggedEventTypes(),
              untilMatchEventSpec.getArrayEventTypes(),
              subexpressionIdStack,
              "until");
      ExprValidationContext validationContext =
          new ExprValidationContext(
              streamTypeService,
              context.getMethodResolutionService(),
              null,
              context.getSchedulingService(),
              context.getVariableService(),
              context,
              context.getEventAdapterService(),
              context.getStatementName(),
              context.getStatementId(),
              context.getAnnotations());

      String message = "Match-until bounds value expressions must return a numeric value";
      if (matchUntilNode.getLowerBounds() != null) {
        ExprNode validated =
            ExprNodeUtility.getValidatedSubtree(matchUntilNode.getLowerBounds(), validationContext);
        matchUntilNode.setLowerBounds(validated);
        if ((validated.getExprEvaluator().getType() == null)
            || (!JavaClassHelper.isNumeric(validated.getExprEvaluator().getType()))) {
          throw new ExprValidationException(message);
        }
      }

      if (matchUntilNode.getUpperBounds() != null) {
        ExprNode validated =
            ExprNodeUtility.getValidatedSubtree(matchUntilNode.getUpperBounds(), validationContext);
        matchUntilNode.setUpperBounds(validated);
        if ((validated.getExprEvaluator().getType() == null)
            || (!JavaClassHelper.isNumeric(validated.getExprEvaluator().getType()))) {
          throw new ExprValidationException(message);
        }
      }

      MatchedEventConvertor convertor =
          new MatchedEventConvertorImpl(
              untilMatchEventSpec.getTaggedEventTypes(),
              untilMatchEventSpec.getArrayEventTypes(),
              context.getEventAdapterService());
      matchUntilNode.setConvertor(convertor);

      // compile new tag lists
      Set<String> arrayTags = null;
      EvalNodeAnalysisResult matchUntilAnalysisResult =
          EvalNodeUtil.recursiveAnalyzeChildNodes(matchUntilNode.getChildNodes().get(0));
      for (EvalFilterNode filterNode : matchUntilAnalysisResult.getFilterNodes()) {
        String optionalTag = filterNode.getEventAsName();
        if (optionalTag != null) {
          if (arrayTags == null) {
            arrayTags = new HashSet<String>();
          }
          arrayTags.add(optionalTag);
        }
      }

      if (arrayTags != null) {
        for (String arrayTag : arrayTags) {
          if (!tags.arrayEventTypes.containsKey(arrayTag)) {
            tags.arrayEventTypes.put(arrayTag, tags.taggedEventTypes.get(arrayTag));
            tags.taggedEventTypes.remove(arrayTag);
          }
        }
      }
      matchUntilNode.setTagsArrayedSet(arrayTags);
    } else if (evalNode instanceof EvalFollowedByNode) {
      EvalFollowedByNode followedByNode = (EvalFollowedByNode) evalNode;
      StreamTypeService streamTypeService =
          new StreamTypeServiceImpl(context.getEngineURI(), false);
      ExprValidationContext validationContext =
          new ExprValidationContext(
              streamTypeService,
              context.getMethodResolutionService(),
              null,
              context.getSchedulingService(),
              context.getVariableService(),
              context,
              context.getEventAdapterService(),
              context.getStatementName(),
              context.getStatementId(),
              context.getAnnotations());

      if (followedByNode.getOptionalMaxExpressions() != null) {
        List<ExprNode> validated = new ArrayList<ExprNode>();
        for (ExprNode maxExpr : followedByNode.getOptionalMaxExpressions()) {
          if (maxExpr == null) {
            validated.add(null);
          } else {
            ExprNodeSummaryVisitor visitor = new ExprNodeSummaryVisitor();
            maxExpr.accept(visitor);
            if (!visitor.isPlain()) {
              String errorMessage =
                  "Invalid maximum expression in followed-by, "
                      + visitor.getMessage()
                      + " are not allowed within the expression";
              log.error(errorMessage);
              throw new ExprValidationException(errorMessage);
            }

            ExprNode validatedExpr =
                ExprNodeUtility.getValidatedSubtree(maxExpr, validationContext);
            validated.add(validatedExpr);
            if ((validatedExpr.getExprEvaluator().getType() == null)
                || (!JavaClassHelper.isNumeric(validatedExpr.getExprEvaluator().getType()))) {
              String message =
                  "Invalid maximum expression in followed-by, the expression must return an integer value";
              throw new ExprValidationException(message);
            }
          }
        }
        followedByNode.setOptionalMaxExpressions(validated);
      }
    }

    if (newTaggedEventTypes != null) {
      tags.getTaggedEventTypes().putAll(newTaggedEventTypes);
    }
    if (newArrayEventTypes != null) {
      tags.getArrayEventTypes().putAll(newArrayEventTypes);
    }
  }