/**
  * 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);
     }
   }
 }
 private static Map<String, Set<String>> toTypesReferences(
     Map<String, ? extends ConfigurationEventTypeWithSupertype> mapTypeConfigurations) {
   Map<String, Set<String>> result = new LinkedHashMap<String, Set<String>>();
   for (Map.Entry<String, ? extends ConfigurationEventTypeWithSupertype> entry :
       mapTypeConfigurations.entrySet()) {
     result.put(entry.getKey(), entry.getValue().getSuperTypes());
   }
   return result;
 }
 private static Map<String, Object> resolveClassesForStringPropertyTypes(
     Map<String, Object> properties) {
   Map<String, Object> propertyTypes = new LinkedHashMap<String, Object>();
   for (Map.Entry entry : properties.entrySet()) {
     String property = (String) entry.getKey();
     propertyTypes.put(property, entry.getValue());
     if (!(entry.getValue() instanceof String)) {
       continue;
     }
     String className = (String) entry.getValue();
     Class clazz = resolveClassForTypeName(className);
     if (clazz != null) {
       propertyTypes.put(property, clazz);
     }
   }
   return propertyTypes;
 }
  private List<EventBean> execute(
      PreparedStatement preparedStatement, Object[] lookupValuePerStream) {
    if (ExecutionPathDebugLog.isDebugEnabled && log.isInfoEnabled()) {
      log.info(".execute Executing prepared statement '" + preparedStatementText + "'");
    }

    // set parameters
    SQLInputParameterContext inputParameterContext = null;
    if (columnTypeConversionHook != null) {
      inputParameterContext = new SQLInputParameterContext();
    }

    int count = 1;
    for (int i = 0; i < lookupValuePerStream.length; i++) {
      try {
        Object parameter = lookupValuePerStream[i];
        if (ExecutionPathDebugLog.isDebugEnabled && log.isInfoEnabled()) {
          log.info(
              ".execute Setting parameter "
                  + count
                  + " to "
                  + parameter
                  + " typed "
                  + ((parameter == null) ? "null" : parameter.getClass()));
        }

        if (columnTypeConversionHook != null) {
          inputParameterContext.setParameterNumber(i + 1);
          inputParameterContext.setParameterValue(parameter);
          parameter = columnTypeConversionHook.getParameterValue(inputParameterContext);
        }

        setObject(preparedStatement, count, parameter);
      } catch (SQLException ex) {
        throw new EPException("Error setting parameter " + count, ex);
      }

      count++;
    }

    // execute
    ResultSet resultSet;
    if (enableJDBCLogging && jdbcPerfLog.isInfoEnabled()) {
      long startTimeNS = System.nanoTime();
      long startTimeMS = System.currentTimeMillis();
      try {
        resultSet = preparedStatement.executeQuery();
      } catch (SQLException ex) {
        throw new EPException("Error executing statement '" + preparedStatementText + '\'', ex);
      }
      long endTimeNS = System.nanoTime();
      long endTimeMS = System.currentTimeMillis();
      jdbcPerfLog.info(
          "Statement '"
              + preparedStatementText
              + "' delta nanosec "
              + (endTimeNS - startTimeNS)
              + " delta msec "
              + (endTimeMS - startTimeMS));
    } else {
      try {
        resultSet = preparedStatement.executeQuery();
      } catch (SQLException ex) {
        throw new EPException("Error executing statement '" + preparedStatementText + '\'', ex);
      }
    }

    // generate events for result set
    List<EventBean> rows = new LinkedList<EventBean>();
    try {
      SQLColumnValueContext valueContext = null;
      if (columnTypeConversionHook != null) {
        valueContext = new SQLColumnValueContext();
      }

      SQLOutputRowValueContext rowContext = null;
      if (outputRowConversionHook != null) {
        rowContext = new SQLOutputRowValueContext();
      }

      int rowNum = 0;
      while (resultSet.next()) {
        int colNum = 1;
        Map<String, Object> row = new HashMap<String, Object>();
        for (Map.Entry<String, DBOutputTypeDesc> entry : outputTypes.entrySet()) {
          String columnName = entry.getKey();

          Object value;
          DatabaseTypeBinding binding = entry.getValue().getOptionalBinding();
          if (binding != null) {
            value = binding.getValue(resultSet, columnName);
          } else {
            value = resultSet.getObject(columnName);
          }

          if (columnTypeConversionHook != null) {
            valueContext.setColumnName(columnName);
            valueContext.setColumnNumber(colNum);
            valueContext.setColumnValue(value);
            valueContext.setResultSet(resultSet);
            value = columnTypeConversionHook.getColumnValue(valueContext);
          }

          row.put(columnName, value);
          colNum++;
        }

        EventBean eventBeanRow = null;
        if (this.outputRowConversionHook == null) {
          eventBeanRow = eventAdapterService.adapterForTypedMap(row, eventType);
        } else {
          rowContext.setValues(row);
          rowContext.setRowNum(rowNum);
          rowContext.setResultSet(resultSet);
          Object rowData = outputRowConversionHook.getOutputRow(rowContext);
          if (rowData != null) {
            eventBeanRow =
                eventAdapterService.adapterForTypedBean(rowData, (BeanEventType) eventType);
          }
        }

        if (eventBeanRow != null) {
          rows.add(eventBeanRow);
          rowNum++;
        }
      }
    } catch (SQLException ex) {
      throw new EPException(
          "Error reading results for statement '" + preparedStatementText + '\'', ex);
    }

    if (enableJDBCLogging && jdbcPerfLog.isInfoEnabled()) {
      jdbcPerfLog.info("Statement '" + preparedStatementText + "' " + rows.size() + " rows");
    }

    try {
      resultSet.close();
    } catch (SQLException ex) {
      throw new EPException("Error closing statement '" + preparedStatementText + '\'', ex);
    }

    return rows;
  }
  /**
   * Initialize event adapter service for config snapshot.
   *
   * @param eventAdapterService is events adapter
   * @param configSnapshot is the config snapshot
   */
  protected static void init(
      EventAdapterService eventAdapterService, ConfigurationInformation configSnapshot) {
    // Extract legacy event type definitions for each event type name, if supplied.
    //
    // We supply this information as setup information to the event adapter service
    // to allow discovery of superclasses and interfaces during event type construction for bean
    // events,
    // such that superclasses and interfaces can use the legacy type definitions.
    Map<String, ConfigurationEventTypeLegacy> classLegacyInfo =
        new HashMap<String, ConfigurationEventTypeLegacy>();
    for (Map.Entry<String, String> entry : configSnapshot.getEventTypeNames().entrySet()) {
      String typeName = entry.getKey();
      String className = entry.getValue();
      ConfigurationEventTypeLegacy legacyDef = configSnapshot.getEventTypesLegacy().get(typeName);
      if (legacyDef != null) {
        classLegacyInfo.put(className, legacyDef);
      }
    }
    eventAdapterService.setClassLegacyConfigs(classLegacyInfo);
    eventAdapterService.setDefaultPropertyResolutionStyle(
        configSnapshot.getEngineDefaults().getEventMeta().getClassPropertyResolutionStyle());
    eventAdapterService.setDefaultAccessorStyle(
        configSnapshot.getEngineDefaults().getEventMeta().getDefaultAccessorStyle());

    for (String javaPackage : configSnapshot.getEventTypeAutoNamePackages()) {
      eventAdapterService.addAutoNamePackage(javaPackage);
    }

    // Add from the configuration the Java event class names
    Map<String, String> javaClassNames = configSnapshot.getEventTypeNames();
    for (Map.Entry<String, String> entry : javaClassNames.entrySet()) {
      // Add Java class
      try {
        String typeName = entry.getKey();
        eventAdapterService.addBeanType(typeName, entry.getValue(), false, true, true, true);
      } catch (EventAdapterException ex) {
        throw new ConfigurationException("Error configuring engine: " + ex.getMessage(), ex);
      }
    }

    // Add from the configuration the XML DOM names and type def
    Map<String, ConfigurationEventTypeXMLDOM> xmlDOMNames = configSnapshot.getEventTypesXMLDOM();
    for (Map.Entry<String, ConfigurationEventTypeXMLDOM> entry : xmlDOMNames.entrySet()) {
      SchemaModel schemaModel = null;
      if ((entry.getValue().getSchemaResource() != null)
          || (entry.getValue().getSchemaText() != null)) {
        try {
          schemaModel =
              XSDSchemaMapper.loadAndMap(
                  entry.getValue().getSchemaResource(), entry.getValue().getSchemaText(), 2);
        } catch (Exception ex) {
          throw new ConfigurationException(ex.getMessage(), ex);
        }
      }

      // Add XML DOM type
      try {
        eventAdapterService.addXMLDOMType(entry.getKey(), entry.getValue(), schemaModel, true);
      } catch (EventAdapterException ex) {
        throw new ConfigurationException("Error configuring engine: " + ex.getMessage(), ex);
      }
    }

    // Add maps in dependency order such that supertypes are added before subtypes
    Set<String> dependentMapOrder;
    try {
      Map<String, Set<String>> typesReferences =
          toTypesReferences(configSnapshot.getMapTypeConfigurations());
      dependentMapOrder = GraphUtil.getTopDownOrder(typesReferences);
    } catch (GraphCircularDependencyException e) {
      throw new ConfigurationException(
          "Error configuring engine, dependency graph between map type names is circular: "
              + e.getMessage(),
          e);
    }

    Map<String, Properties> mapNames = configSnapshot.getEventTypesMapEvents();
    Map<String, Map<String, Object>> nestableMapNames =
        configSnapshot.getEventTypesNestableMapEvents();
    dependentMapOrder.addAll(mapNames.keySet());
    dependentMapOrder.addAll(nestableMapNames.keySet());
    try {
      for (String mapName : dependentMapOrder) {
        ConfigurationEventTypeMap mapConfig =
            configSnapshot.getMapTypeConfigurations().get(mapName);
        Properties propertiesUnnested = mapNames.get(mapName);
        if (propertiesUnnested != null) {
          Map<String, Object> propertyTypes = createPropertyTypes(propertiesUnnested);
          Map<String, Object> propertyTypesCompiled =
              EventTypeUtility.compileMapTypeProperties(propertyTypes, eventAdapterService);
          eventAdapterService.addNestableMapType(
              mapName, propertyTypesCompiled, mapConfig, true, true, true, false, false);
        }

        Map<String, Object> propertiesNestable = nestableMapNames.get(mapName);
        if (propertiesNestable != null) {
          Map<String, Object> propertiesNestableCompiled =
              EventTypeUtility.compileMapTypeProperties(propertiesNestable, eventAdapterService);
          eventAdapterService.addNestableMapType(
              mapName, propertiesNestableCompiled, mapConfig, true, true, true, false, false);
        }
      }
    } catch (EventAdapterException ex) {
      throw new ConfigurationException("Error configuring engine: " + ex.getMessage(), ex);
    }

    // Add object-array in dependency order such that supertypes are added before subtypes
    Set<String> dependentObjectArrayOrder;
    try {
      Map<String, Set<String>> typesReferences =
          toTypesReferences(configSnapshot.getObjectArrayTypeConfigurations());
      dependentObjectArrayOrder = GraphUtil.getTopDownOrder(typesReferences);
    } catch (GraphCircularDependencyException e) {
      throw new ConfigurationException(
          "Error configuring engine, dependency graph between object array type names is circular: "
              + e.getMessage(),
          e);
    }
    Map<String, Map<String, Object>> nestableObjectArrayNames =
        configSnapshot.getEventTypesNestableObjectArrayEvents();
    dependentObjectArrayOrder.addAll(nestableObjectArrayNames.keySet());
    try {
      for (String objectArrayName : dependentObjectArrayOrder) {
        ConfigurationEventTypeObjectArray objectArrayConfig =
            configSnapshot.getObjectArrayTypeConfigurations().get(objectArrayName);
        Map<String, Object> propertyTypes = nestableObjectArrayNames.get(objectArrayName);
        propertyTypes = resolveClassesForStringPropertyTypes(propertyTypes);
        Map<String, Object> propertyTypesCompiled =
            EventTypeUtility.compileMapTypeProperties(propertyTypes, eventAdapterService);
        eventAdapterService.addNestableObjectArrayType(
            objectArrayName,
            propertyTypesCompiled,
            objectArrayConfig,
            true,
            true,
            true,
            false,
            false,
            false,
            null);
      }
    } catch (EventAdapterException ex) {
      throw new ConfigurationException("Error configuring engine: " + ex.getMessage(), ex);
    }

    // Add plug-in event representations
    Map<URI, ConfigurationPlugInEventRepresentation> plugInReps =
        configSnapshot.getPlugInEventRepresentation();
    for (Map.Entry<URI, ConfigurationPlugInEventRepresentation> entry : plugInReps.entrySet()) {
      String className = entry.getValue().getEventRepresentationClassName();
      Class eventRepClass;
      try {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        eventRepClass = Class.forName(className, true, cl);
      } catch (ClassNotFoundException ex) {
        throw new ConfigurationException(
            "Failed to load plug-in event representation class '" + className + "'", ex);
      }

      Object pluginEventRepObj;
      try {
        pluginEventRepObj = eventRepClass.newInstance();
      } catch (InstantiationException ex) {
        throw new ConfigurationException(
            "Failed to instantiate plug-in event representation class '"
                + className
                + "' via default constructor",
            ex);
      } catch (IllegalAccessException ex) {
        throw new ConfigurationException(
            "Illegal access to instantiate plug-in event representation class '"
                + className
                + "' via default constructor",
            ex);
      }

      if (!(pluginEventRepObj instanceof PlugInEventRepresentation)) {
        throw new ConfigurationException(
            "Plug-in event representation class '"
                + className
                + "' does not implement the required interface "
                + PlugInEventRepresentation.class.getName());
      }

      URI eventRepURI = entry.getKey();
      PlugInEventRepresentation pluginEventRep = (PlugInEventRepresentation) pluginEventRepObj;
      Serializable initializer = entry.getValue().getInitializer();
      PlugInEventRepresentationContext context =
          new PlugInEventRepresentationContext(eventAdapterService, eventRepURI, initializer);

      try {
        pluginEventRep.init(context);
        eventAdapterService.addEventRepresentation(eventRepURI, pluginEventRep);
      } catch (Throwable t) {
        throw new ConfigurationException(
            "Plug-in event representation class '"
                + className
                + "' and URI '"
                + eventRepURI
                + "' did not initialize correctly : "
                + t.getMessage(),
            t);
      }
    }

    // Add plug-in event type names
    Map<String, ConfigurationPlugInEventType> plugInNames = configSnapshot.getPlugInEventTypes();
    for (Map.Entry<String, ConfigurationPlugInEventType> entry : plugInNames.entrySet()) {
      String name = entry.getKey();
      ConfigurationPlugInEventType config = entry.getValue();
      eventAdapterService.addPlugInEventType(
          name, config.getEventRepresentationResolutionURIs(), config.getInitializer());
    }
  }