public ExprNode validate(ExprValidationContext validationContext) throws ExprValidationException {
    // Must have 2 child nodes
    if (this.getChildNodes().length < 1) {
      throw new IllegalStateException("Group relational op node must have 1 or more parameters");
    }
    evaluators = ExprNodeUtility.getEvaluators(this.getChildNodes());

    Class typeOne = JavaClassHelper.getBoxedType(evaluators[0].getType());

    // collections, array or map not supported
    if ((typeOne.isArray())
        || (JavaClassHelper.isImplementsInterface(typeOne, Collection.class))
        || (JavaClassHelper.isImplementsInterface(typeOne, Map.class))) {
      throw new ExprValidationException(
          "Collection or array comparison is not allowed for the IN, ANY, SOME or ALL keywords");
    }

    List<Class> comparedTypes = new ArrayList<Class>();
    comparedTypes.add(typeOne);
    hasCollectionOrArray = false;
    for (int i = 0; i < this.getChildNodes().length - 1; i++) {
      Class propType = evaluators[i + 1].getType();
      if (propType.isArray()) {
        hasCollectionOrArray = true;
        if (propType.getComponentType() != Object.class) {
          comparedTypes.add(propType.getComponentType());
        }
      } else if (JavaClassHelper.isImplementsInterface(propType, Collection.class)) {
        hasCollectionOrArray = true;
      } else if (JavaClassHelper.isImplementsInterface(propType, Map.class)) {
        hasCollectionOrArray = true;
      } else {
        comparedTypes.add(propType);
      }
    }

    // Determine common denominator type
    Class coercionType;
    try {
      coercionType =
          JavaClassHelper.getCommonCoercionType(
              comparedTypes.toArray(new Class[comparedTypes.size()]));
    } catch (CoercionException ex) {
      throw new ExprValidationException("Implicit conversion not allowed: " + ex.getMessage());
    }

    // Must be either numeric or string
    if (coercionType != String.class) {
      if (!JavaClassHelper.isNumeric(coercionType)) {
        throw new ExprValidationException(
            "Implicit conversion from datatype '"
                + coercionType.getSimpleName()
                + "' to numeric is not allowed");
      }
    }

    computer = relationalOpEnum.getComputer(coercionType, coercionType, coercionType);
    return null;
  }
  public EPServicesContext createServicesContext(
      EPServiceProvider epServiceProvider, ConfigurationInformation configSnapshot) {
    // JNDI context for binding resources
    EngineEnvContext jndiContext = new EngineEnvContext();

    EventTypeIdGenerator eventTypeIdGenerator;
    if (configSnapshot.getEngineDefaults().getAlternativeContext() == null
        || configSnapshot
                .getEngineDefaults()
                .getAlternativeContext()
                .getEventTypeIdGeneratorFactory()
            == null) {
      eventTypeIdGenerator = new EventTypeIdGeneratorImpl();
    } else {
      EventTypeIdGeneratorFactory eventTypeIdGeneratorFactory =
          (EventTypeIdGeneratorFactory)
              JavaClassHelper.instantiate(
                  EventTypeIdGeneratorFactory.class,
                  configSnapshot
                      .getEngineDefaults()
                      .getAlternativeContext()
                      .getEventTypeIdGeneratorFactory());
      eventTypeIdGenerator =
          eventTypeIdGeneratorFactory.create(
              new EventTypeIdGeneratorContext(epServiceProvider.getURI()));
    }

    // Make services that depend on snapshot config entries
    EventAdapterServiceImpl eventAdapterService =
        new EventAdapterServiceImpl(
            eventTypeIdGenerator,
            configSnapshot.getEngineDefaults().getEventMeta().getAnonymousCacheSize());
    init(eventAdapterService, configSnapshot);

    // New read-write lock for concurrent event processing
    ManagedReadWriteLock eventProcessingRWLock = new ManagedReadWriteLock("EventProcLock", false);

    TimeSourceService timeSourceService = makeTimeSource(configSnapshot);
    SchedulingServiceSPI schedulingService =
        SchedulingServiceProvider.newService(timeSourceService);
    SchedulingMgmtService schedulingMgmtService = new SchedulingMgmtServiceImpl();
    EngineImportService engineImportService = makeEngineImportService(configSnapshot);
    EngineSettingsService engineSettingsService =
        new EngineSettingsService(
            configSnapshot.getEngineDefaults(), configSnapshot.getPlugInEventTypeResolutionURIs());
    DatabaseConfigService databaseConfigService =
        makeDatabaseRefService(configSnapshot, schedulingService, schedulingMgmtService);

    PluggableObjectCollection plugInViews = new PluggableObjectCollection();
    plugInViews.addViews(
        configSnapshot.getPlugInViews(), configSnapshot.getPlugInVirtualDataWindows());
    PluggableObjectCollection plugInPatternObj = new PluggableObjectCollection();
    plugInPatternObj.addPatternObjects(configSnapshot.getPlugInPatternObjects());

    // exception handling
    ExceptionHandlingService exceptionHandlingService =
        initExceptionHandling(
            epServiceProvider.getURI(),
            configSnapshot.getEngineDefaults().getExceptionHandling(),
            configSnapshot.getEngineDefaults().getConditionHandling());

    // Statement context factory
    Class systemVirtualDWViewFactory = null;
    if (configSnapshot.getEngineDefaults().getAlternativeContext().getVirtualDataWindowViewFactory()
        != null) {
      try {
        systemVirtualDWViewFactory =
            Class.forName(
                configSnapshot
                    .getEngineDefaults()
                    .getAlternativeContext()
                    .getVirtualDataWindowViewFactory());
        if (!JavaClassHelper.isImplementsInterface(
            systemVirtualDWViewFactory, VirtualDataWindowFactory.class)) {
          throw new ConfigurationException(
              "Class "
                  + systemVirtualDWViewFactory.getName()
                  + " does not implement the interface "
                  + VirtualDataWindowFactory.class.getName());
        }
      } catch (ClassNotFoundException e) {
        throw new ConfigurationException("Failed to look up class " + systemVirtualDWViewFactory);
      }
    }
    StatementContextFactory statementContextFactory =
        new StatementContextFactoryDefault(
            plugInViews, plugInPatternObj, systemVirtualDWViewFactory);

    long msecTimerResolution =
        configSnapshot.getEngineDefaults().getThreading().getInternalTimerMsecResolution();
    if (msecTimerResolution <= 0) {
      throw new ConfigurationException(
          "Timer resolution configuration not set to a valid value, expecting a non-zero value");
    }
    TimerService timerService =
        new TimerServiceImpl(epServiceProvider.getURI(), msecTimerResolution);

    VariableService variableService =
        new VariableServiceImpl(
            configSnapshot.getEngineDefaults().getVariables().getMsecVersionRelease(),
            schedulingService,
            eventAdapterService,
            null);
    initVariables(variableService, configSnapshot.getVariables(), engineImportService);

    TableService tableService = new TableServiceImpl();

    StatementLockFactory statementLockFactory =
        new StatementLockFactoryImpl(
            configSnapshot.getEngineDefaults().getExecution().isFairlock(),
            configSnapshot.getEngineDefaults().getExecution().isDisableLocking());
    StreamFactoryService streamFactoryService =
        StreamFactoryServiceProvider.newService(
            epServiceProvider.getURI(),
            configSnapshot.getEngineDefaults().getViewResources().isShareViews());
    FilterServiceSPI filterService =
        FilterServiceProvider.newService(
            configSnapshot.getEngineDefaults().getExecution().getFilterServiceProfile(),
            configSnapshot.getEngineDefaults().getExecution().isAllowIsolatedService());
    MetricReportingServiceImpl metricsReporting =
        new MetricReportingServiceImpl(
            configSnapshot.getEngineDefaults().getMetricsReporting(), epServiceProvider.getURI());
    NamedWindowService namedWindowService =
        new NamedWindowServiceImpl(
            schedulingService,
            variableService,
            tableService,
            engineSettingsService.getEngineSettings().getExecution().isPrioritized(),
            eventProcessingRWLock,
            exceptionHandlingService,
            configSnapshot.getEngineDefaults().getLogging().isEnableQueryPlan(),
            metricsReporting);

    ValueAddEventService valueAddEventService = new ValueAddEventServiceImpl();
    valueAddEventService.init(
        configSnapshot.getRevisionEventTypes(),
        configSnapshot.getVariantStreams(),
        eventAdapterService,
        eventTypeIdGenerator);

    StatementEventTypeRef statementEventTypeRef = new StatementEventTypeRefImpl();
    StatementVariableRef statementVariableRef =
        new StatementVariableRefImpl(variableService, tableService);

    ThreadingService threadingService =
        new ThreadingServiceImpl(configSnapshot.getEngineDefaults().getThreading());

    InternalEventRouterImpl internalEventRouterImpl = new InternalEventRouterImpl();

    StatementIsolationServiceImpl statementIsolationService = new StatementIsolationServiceImpl();

    DeploymentStateService deploymentStateService = new DeploymentStateServiceImpl();

    StatementMetadataFactory stmtMetadataFactory;
    if (configSnapshot.getEngineDefaults().getAlternativeContext().getStatementMetadataFactory()
        == null) {
      stmtMetadataFactory = new StatementMetadataFactoryDefault();
    } else {
      stmtMetadataFactory =
          (StatementMetadataFactory)
              JavaClassHelper.instantiate(
                  StatementMetadataFactory.class,
                  configSnapshot
                      .getEngineDefaults()
                      .getAlternativeContext()
                      .getStatementMetadataFactory());
    }

    ContextManagementService contextManagementService = new ContextManagementServiceImpl();

    SchedulableAgentInstanceDirectory schedulableAgentInstanceDirectory =
        null; // not required for Non-HA.

    PatternSubexpressionPoolEngineSvc patternSubexpressionPoolSvc = null;
    if (configSnapshot.getEngineDefaults().getPatterns().getMaxSubexpressions() != null) {
      patternSubexpressionPoolSvc =
          new PatternSubexpressionPoolEngineSvc(
              configSnapshot.getEngineDefaults().getPatterns().getMaxSubexpressions(),
              configSnapshot.getEngineDefaults().getPatterns().isMaxSubexpressionPreventStart());
    }

    MatchRecognizeStatePoolEngineSvc matchRecognizeStatePoolEngineSvc = null;
    if (configSnapshot.getEngineDefaults().getMatchRecognize().getMaxStates() != null) {
      matchRecognizeStatePoolEngineSvc =
          new MatchRecognizeStatePoolEngineSvc(
              configSnapshot.getEngineDefaults().getMatchRecognize().getMaxStates(),
              configSnapshot.getEngineDefaults().getMatchRecognize().isMaxStatesPreventStart());
    }

    // New services context
    EPServicesContext services =
        new EPServicesContext(
            epServiceProvider.getURI(),
            schedulingService,
            eventAdapterService,
            engineImportService,
            engineSettingsService,
            databaseConfigService,
            plugInViews,
            statementLockFactory,
            eventProcessingRWLock,
            null,
            jndiContext,
            statementContextFactory,
            plugInPatternObj,
            timerService,
            filterService,
            streamFactoryService,
            namedWindowService,
            variableService,
            tableService,
            timeSourceService,
            valueAddEventService,
            metricsReporting,
            statementEventTypeRef,
            statementVariableRef,
            configSnapshot,
            threadingService,
            internalEventRouterImpl,
            statementIsolationService,
            schedulingMgmtService,
            deploymentStateService,
            exceptionHandlingService,
            new PatternNodeFactoryImpl(),
            eventTypeIdGenerator,
            stmtMetadataFactory,
            contextManagementService,
            schedulableAgentInstanceDirectory,
            patternSubexpressionPoolSvc,
            matchRecognizeStatePoolEngineSvc,
            new DataFlowServiceImpl(epServiceProvider, new DataFlowConfigurationStateServiceImpl()),
            new ExprDeclaredServiceImpl(),
            new ContextControllerFactoryFactorySvcImpl(),
            new ContextManagerFactoryServiceImpl(),
            new EPStatementFactoryDefault(),
            new RegexHandlerFactoryDefault(),
            new ViewableActivatorFactoryDefault() {});

    // Engine services subset available to statements
    statementContextFactory.setStmtEngineServices(services);

    // Circular dependency
    StatementLifecycleSvc statementLifecycleSvc =
        new StatementLifecycleSvcImpl(epServiceProvider, services);
    services.setStatementLifecycleSvc(statementLifecycleSvc);

    // Observers to statement events
    statementLifecycleSvc.addObserver(metricsReporting);

    // Circular dependency
    statementIsolationService.setEpServicesContext(services);

    return services;
  }