Java tutorial
/* * Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.siddhi.core.table; import org.apache.hadoop.util.bloom.CountingBloomFilter; import org.apache.hadoop.util.bloom.Key; import org.apache.hadoop.util.hash.Hash; import org.apache.log4j.Logger; import org.wso2.siddhi.core.config.SiddhiContext; import org.wso2.siddhi.core.event.*; import org.wso2.siddhi.core.event.in.InEvent; import org.wso2.siddhi.core.event.in.InStateEvent; import org.wso2.siddhi.core.executor.conditon.ConditionExecutor; import org.wso2.siddhi.core.table.cache.CachingTable; import org.wso2.siddhi.core.table.predicate.PredicateToken; import org.wso2.siddhi.core.table.predicate.PredicateTreeNode; import org.wso2.siddhi.core.table.predicate.sql.SQLPredicateBuilder; import org.wso2.siddhi.query.api.definition.Attribute; import org.wso2.siddhi.query.api.definition.TableDefinition; import org.wso2.siddhi.query.api.query.QueryEventSource; import javax.sql.DataSource; import java.nio.ByteBuffer; import java.sql.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class RDBMSEventTable implements EventTable { static final String PARAM_TABLE_NAME = "table.name"; static final String PARAM_DATASOURCE_NAME = "datasource.name"; static final String PARAM_CREATE_QUERY = "create.query"; static final String PARAM_CACHING_ALGORITHM = "caching.algorithm"; static final String PARAM_CACHE_SIZE = "cache.size"; static final String PARAM_CACHE_LOADING = "cache.loading"; static final String PARAM_BLOOM_FILTERS = "bloom.filters"; public static final int BLOOM_FILTER_SIZE = 10000; public static final int BLOOM_FILTER_HASH_FUNCTIONS = 4; static final Logger log = Logger.getLogger(RDBMSEventTable.class); private TableDefinition tableDefinition; private QueryEventSource queryEventSource; // attribute list used for accessing the table. private List<Attribute> attributeList; // full attribute list of the table private boolean eagerCacheLoading; private DataSource dataSource; private String databaseName; private String tableName; private String fullTableName; // schema.tableName private String tableColumnList; // for insertion queries. private boolean isInitialized; // db connection init status private String insertQuery; private boolean bloomFiltersEnabled; private CachingTable cachedTable; // private BloomFilter[] bloomFilters; // bloom filters for each column private CountingBloomFilter[] bloomFilters; public RDBMSEventTable() { } public void init(TableDefinition tableDefinition, SiddhiContext siddhiContext) { this.tableDefinition = tableDefinition; this.queryEventSource = new QueryEventSource( tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME), tableDefinition.getTableId(), tableDefinition, null, null, null); this.dataSource = siddhiContext .getDataSource(tableDefinition.getExternalTable().getParameter(PARAM_DATASOURCE_NAME)); this.attributeList = new ArrayList<Attribute>(); // caching is enabled by default. if ((tableDefinition.getExternalTable().getParameter(PARAM_CACHING_ALGORITHM) != null) && (!tableDefinition .getExternalTable().getParameter(PARAM_CACHING_ALGORITHM).equalsIgnoreCase("disable"))) { this.cachedTable = new CachingTable(tableDefinition.getTableId(), tableDefinition.getExternalTable().getParameter(PARAM_CACHING_ALGORITHM), tableDefinition.getExternalTable().getParameter(PARAM_CACHE_SIZE), siddhiContext); } // cache is by default loaded Lazily if (cachedTable != null && (tableDefinition.getExternalTable().getParameter(PARAM_CACHE_LOADING) != null) && (tableDefinition.getExternalTable().getParameter(PARAM_CACHE_LOADING) .equalsIgnoreCase("eager"))) { this.eagerCacheLoading = true; } // bloom filters are disabled by default if ((tableDefinition.getExternalTable().getParameter(PARAM_BLOOM_FILTERS) != null) && (tableDefinition .getExternalTable().getParameter(PARAM_BLOOM_FILTERS).equalsIgnoreCase("enabled"))) { this.bloomFiltersEnabled = true; } try { initializeConnection(); createPreparedStatementQueries(); if (eagerCacheLoading) { preloadCache(); } if (bloomFiltersEnabled) { buildBloomFilters(); } } catch (ClassNotFoundException e) { log.error("Class not found. Can't continue to initialize the table.", e); throw new RuntimeException(e); } catch (Exception e) { log.error("Unable to connect to the database.", e); } } private void initializeConnection() throws SQLException, ClassNotFoundException { if (!isInitialized) { synchronized (this) { // synchronized double checking to ensure this doesn't get hit when there are concurrent calls if (!isInitialized) { Connection con = null; Statement statement = null; try { tableName = tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME); if (dataSource == null) { throw new RuntimeException("Data source doesn't exist: " + tableDefinition.getExternalTable().getParameter(PARAM_DATASOURCE_NAME)); } con = dataSource.getConnection(); // default mysql jdbc driver databaseName = con.getCatalog(); fullTableName = databaseName + "." + tableName; statement = con.createStatement(); String createQuery = tableDefinition.getExternalTable().getParameter(PARAM_CREATE_QUERY); // table creation. if (createQuery == null || createQuery.length() < 1) { StringBuilder stringBuilder = new StringBuilder("CREATE TABLE IF NOT EXISTS "); stringBuilder.append(fullTableName); stringBuilder.append(" ("); boolean appendComma = false; for (Attribute column : tableDefinition.getAttributeList()) { if (appendComma) { stringBuilder.append(", "); } else { appendComma = true; } stringBuilder.append(column.getName()); stringBuilder.append(" "); switch (column.getType()) { case INT: stringBuilder.append("INT"); break; case LONG: stringBuilder.append("BIGINT"); break; case FLOAT: stringBuilder.append("DECIMAL(30,10)"); break; case DOUBLE: stringBuilder.append("DECIMAL(40,15)"); break; case BOOL: stringBuilder.append("BOOL"); break; default: stringBuilder.append("VARCHAR(255)"); break; } } stringBuilder.append(");"); createQuery = stringBuilder.toString(); statement.execute(createQuery); } else { // users may not use 'IF NOT EXISTS' clause, so need to check whether the table exists before // executing their create queries. try { statement.execute("SELECT 1 FROM " + fullTableName + " LIMIT 1"); } catch (SQLException e) { statement.execute(createQuery); } } StringBuilder builder = new StringBuilder("("); boolean appendComma = false; for (Attribute att : tableDefinition.getAttributeList()) { attributeList.add(att); if (appendComma) { builder.append(","); } builder.append(att.getName()); appendComma = true; } builder.append(")"); tableColumnList = builder.toString(); isInitialized = true; } finally { cleanUpConnections(statement, con); } } } } } private synchronized void buildBloomFilters() { this.bloomFilters = new CountingBloomFilter[tableDefinition.getAttributeList().size()]; for (int i = 0; i < bloomFilters.length; i++) { // number of hashes: 4 bloomFilters[i] = new CountingBloomFilter(BLOOM_FILTER_SIZE, BLOOM_FILTER_HASH_FUNCTIONS, Hash.MURMUR_HASH); } Connection con = null; Statement stmt = null; try { con = dataSource.getConnection(); stmt = con.createStatement(); ResultSet results = stmt.executeQuery("SELECT * FROM " + fullTableName); int count = 0; while (results.next()) { count++; for (int i = 0; i < bloomFilters.length; i++) { switch (tableDefinition.getAttributeList().get(i).getType()) { case INT: bloomFilters[i].add(new Key(Integer.toString(results.getInt(i + 1)).getBytes())); break; case LONG: bloomFilters[i].add(new Key(Long.toString(results.getLong(i + 1)).getBytes())); break; case FLOAT: bloomFilters[i].add(new Key(Float.toString(results.getFloat(i + 1)).getBytes())); break; case DOUBLE: bloomFilters[i].add(new Key(Double.toString(results.getDouble(i + 1)).getBytes())); break; case STRING: bloomFilters[i].add(new Key(results.getString(i + 1).getBytes())); break; case BOOL: bloomFilters[i].add(new Key(Boolean.toString(results.getBoolean(i + 1)).getBytes())); break; } } } results.close(); } catch (Exception ex) { log.error(ex); } finally { cleanUpConnections(stmt, con); } } @Override public TableDefinition getTableDefinition() { return tableDefinition; } @Override public void add(StreamEvent streamEvent) { Connection con = null; PreparedStatement statement = null; try { initializeConnection(); con = dataSource.getConnection(); con.setAutoCommit(false); statement = con.prepareStatement(insertQuery); ArrayList<Event> bloomFilterInsertionList = null; if (bloomFiltersEnabled) { bloomFilterInsertionList = new ArrayList<Event>(); } if (streamEvent instanceof AtomicEvent) { populateInsertQuery((Event) streamEvent, statement); statement.executeUpdate(); if (bloomFiltersEnabled) { bloomFilterInsertionList.add((Event) streamEvent); } } else { ListEvent listEvent = ((ListEvent) streamEvent); for (int i = 0, size = listEvent.getActiveEvents(); i < size; i++) { populateInsertQuery(listEvent.getEvent(i), statement); statement.addBatch(); if (bloomFiltersEnabled) { bloomFilterInsertionList.add(listEvent.getEvent(i)); } } statement.executeBatch(); } con.commit(); if (cachedTable != null) { cachedTable.add(streamEvent); } if (bloomFiltersEnabled) { addToBloomFilters(bloomFilterInsertionList); } } catch (SQLException e) { log.error("Unable to insert the records to the table", e); } catch (Exception e) { log.error("Error while inserting data.", e); } finally { cleanUpConnections(statement, con); } } private void addToBloomFilters(List<Event> eventList) { for (Event event : eventList) { for (int i = 0; i < attributeList.size(); i++) { Attribute at = attributeList.get(i); switch (at.getType()) { case INT: bloomFilters[i].add(new Key(Integer.toString((Integer) event.getData(i)).getBytes())); break; case LONG: bloomFilters[i].add(new Key(Long.toString((Long) event.getData(i)).getBytes())); break; case FLOAT: bloomFilters[i].add(new Key(Float.toString((Float) event.getData(i)).getBytes())); break; case DOUBLE: bloomFilters[i].add(new Key(Double.toString((Double) event.getData(i)).getBytes())); break; case STRING: bloomFilters[i].add(new Key(event.getData(i).toString().getBytes())); break; case BOOL: bloomFilters[i].add(new Key(Boolean.toString((Boolean) event.getData(i)).getBytes())); break; } } } } private void removeFromBloomFilters(List<Event> eventList) { for (Event event : eventList) { for (int i = 0; i < attributeList.size(); i++) { Attribute at = attributeList.get(i); switch (at.getType()) { case INT: bloomFilters[i] .delete(new Key(ByteBuffer.allocate(4).putInt((Integer) event.getData(i)).array())); break; case LONG: bloomFilters[i] .delete(new Key(ByteBuffer.allocate(8).putLong((Long) event.getData(i)).array())); break; case FLOAT: bloomFilters[i] .delete(new Key(ByteBuffer.allocate(4).putFloat((Float) event.getData(i)).array())); break; case DOUBLE: bloomFilters[i] .delete(new Key(ByteBuffer.allocate(8).putDouble((Double) event.getData(i)).array())); break; case STRING: bloomFilters[i].delete(new Key(event.getData(i).toString().getBytes())); break; case BOOL: bloomFilters[i].delete(new Key(Boolean.toString((Boolean) event.getData(i)).getBytes())); break; } } } } private void preloadCache() { Connection con = null; Statement statement = null; try { con = dataSource.getConnection(); statement = con.createStatement(); ResultSet resultSet = statement .executeQuery("SELECT * FROM " + fullTableName + " LIMIT 0, " + cachedTable.getCacheLimit()); resultSet.setFetchSize(cachedTable.getCacheLimit()); List<StreamEvent> eventList = new ArrayList<StreamEvent>(); long timestamp = System.currentTimeMillis(); while (resultSet.next()) { Object[] data = new Object[attributeList.size()]; for (int i = 0; i < attributeList.size(); i++) { switch (attributeList.get(i).getType()) { case BOOL: data[i] = resultSet.getBoolean(attributeList.get(i).getName()); break; case DOUBLE: data[i] = resultSet.getDouble(attributeList.get(i).getName()); break; case FLOAT: data[i] = resultSet.getFloat(attributeList.get(i).getName()); break; case INT: data[i] = resultSet.getInt(attributeList.get(i).getName()); break; case LONG: data[i] = resultSet.getLong(attributeList.get(i).getName()); break; case STRING: data[i] = resultSet.getString(attributeList.get(i).getName()); break; default: data[i] = resultSet.getObject(attributeList.get(i).getName()); } } Event event = new InEvent(tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME), timestamp, data); eventList.add(event); } if (cachedTable != null) { cachedTable.addAll(eventList); // checking whether the table size is equal to the current cache size ResultSet resultCount = statement.executeQuery("SELECT COUNT(*) FROM " + fullTableName); int rowCount = 0; while (resultCount.next()) { rowCount = resultCount.getInt(1); } if (rowCount <= cachedTable.getCacheLimit()) { // this is later used for optimizations when reading cachedTable.setFullyLoaded(true); } resultCount.close(); } resultSet.close(); } catch (SQLException e) { log.error("Unable to read the table: " + tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME), e); } finally { cleanUpConnections(statement, con); } } private void populateInsertQuery(Event event, PreparedStatement statement) throws SQLException { for (int i = 0; i < attributeList.size(); i++) { switch (attributeList.get(i).getType()) { case INT: statement.setInt(i + 1, ((Number) event.getData(i)).intValue()); break; case LONG: statement.setLong(i + 1, ((Number) event.getData(i)).longValue()); break; case FLOAT: statement.setFloat(i + 1, ((Number) event.getData(i)).floatValue()); break; case DOUBLE: statement.setDouble(i + 1, ((Number) event.getData(i)).doubleValue()); break; case BOOL: statement.setBoolean(i + 1, (Boolean) event.getData(i)); break; default: statement.setString(i + 1, event.getData(i).toString()); break; } } } private void createPreparedStatementQueries() { // only the insert query can be created since update, delete have query-specific predicates StringBuilder builder = new StringBuilder("INSERT INTO "); builder.append(fullTableName); builder.append(tableColumnList); builder.append(" VALUES ("); for (int i = 0; i < attributeList.size(); i++) { if (i > 0) { builder.append(", "); } builder.append("?"); } builder.append(")"); insertQuery = builder.toString(); } @Override public void delete(StreamEvent streamEvent, ConditionExecutor conditionExecutor) { PreparedStatement statement = null; Connection con = null; try { initializeConnection(); con = dataSource.getConnection(); con.setAutoCommit(false); StringBuilder statementBuilder = new StringBuilder("DELETE FROM "); statementBuilder.append(fullTableName); statementBuilder.append(" WHERE "); ArrayList<Event> bloomFilterDeletionList = null; if (bloomFiltersEnabled) { bloomFilterDeletionList = new ArrayList<Event>(); } if (streamEvent instanceof AtomicEvent) { PredicateTreeNode predicate = conditionExecutor.constructPredicate((Event) streamEvent, tableDefinition, new SQLPredicateBuilder()); statementBuilder.append(predicate.buildPredicateString()); statement = con.prepareStatement(statementBuilder.toString()); ArrayList paramList = new ArrayList(); predicate.populateParameters(paramList); for (int i = 0; i < paramList.size(); i++) { populateStatement(statement, i + 1, paramList.get(i)); } if (bloomFiltersEnabled) { bloomFilterDeletionList.add((Event) streamEvent); } statement.executeUpdate(); } else { for (int i = 0, size = ((ListEvent) streamEvent).getActiveEvents(); i < size; i++) { // deleting the entire event set using an aggregate query with OR conditions if (i > 0) { statementBuilder.append(" OR "); } statementBuilder.append("("); statementBuilder .append(conditionExecutor.constructPredicate(((ListEvent) streamEvent).getEvent(i), tableDefinition, new SQLPredicateBuilder()).buildPredicateString()); statementBuilder.append(")"); if (bloomFiltersEnabled) { bloomFilterDeletionList.add(((ListEvent) streamEvent).getEvent(i)); } } statement = con.prepareStatement(statementBuilder.toString()); statement.executeUpdate(); } con.commit(); if (cachedTable != null) { cachedTable.delete(streamEvent, conditionExecutor); } if (bloomFiltersEnabled) { removeFromBloomFilters(bloomFilterDeletionList); } } catch (SQLException e) { log.error("Unable to execute deletion.", e); } catch (ClassNotFoundException e) { log.error("Unable to load the database driver.", e); } finally { cleanUpConnections(statement, con); } } @Override public void update(StreamEvent streamEvent, ConditionExecutor conditionExecutor, int[] attributeUpdateMappingPosition) { Connection con = null; PreparedStatement statement = null; try { initializeConnection(); con = dataSource.getConnection(); con.setAutoCommit(false); Event atomicEvent = null; SQLPredicateBuilder predicateBuilder = new SQLPredicateBuilder(); if (streamEvent instanceof AtomicEvent) { atomicEvent = (Event) streamEvent; // used to execute the condition executor } else { if (((ListEvent) streamEvent).getActiveEvents() > 0) { atomicEvent = ((ListEvent) streamEvent).getEvent(0); } } PredicateTreeNode predicate = conditionExecutor.constructPredicate(atomicEvent, tableDefinition, predicateBuilder); String query = createUpdateQuery(predicate.buildPredicateString(), attributeUpdateMappingPosition); statement = con.prepareStatement(query); ArrayList paramList = new ArrayList(); if (streamEvent instanceof AtomicEvent) { for (int i = 0; i < attributeUpdateMappingPosition.length; i++) { populateStatement(statement, i + 1, atomicEvent.getData(i)); } predicate.populateParameters(paramList); for (int i = 0; i < paramList.size(); i++) { populateStatement(statement, attributeUpdateMappingPosition.length + i + 1, paramList.get(i)); } statement.executeUpdate(); } else { // streamEvent instanceof ListEvent statement.clearParameters(); for (int j = 0, size = ((ListEvent) streamEvent).getActiveEvents(); j < size; j++) { Event event = ((ListEvent) streamEvent).getEvent(j); predicate = conditionExecutor.constructPredicate(event, tableDefinition, predicateBuilder); paramList.clear(); predicate.populateParameters(paramList); for (int i = 0; i < attributeList.size(); i++) { populateStatement(statement, i + 1, event.getData(i)); } for (int i = 0; i < paramList.size(); i++) { populateStatement(statement, attributeList.size() + i + 1, paramList.get(i)); } statement.addBatch(); } statement.executeBatch(); } con.commit(); if (cachedTable != null) { cachedTable.update(streamEvent, conditionExecutor, attributeUpdateMappingPosition); } if (bloomFiltersEnabled) { buildBloomFilters(); } } catch (SQLException e) { log.error("Unable to execute update on " + streamEvent, e); } catch (ClassNotFoundException e) { log.error("Unable to load the database driver for " + tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME), e); } finally { cleanUpConnections(statement, con); } } @Override public boolean contains(AtomicEvent atomicEvent, ConditionExecutor conditionExecutor) { PredicateTreeNode predicate = null; if (bloomFiltersEnabled) { // bloom filters used only for the equal conditions. predicate = conditionExecutor.constructPredicate(atomicEvent, tableDefinition, new SQLPredicateBuilder()); ArrayList<PredicateToken> tokenList = new ArrayList<PredicateToken>(3); predicate.populateTokens(tokenList); // looking for two sided equals conditions (operators) only. if (tokenList.size() < 4) { // not using bloom filters for complex conditions for (int operatorIndex = 1; operatorIndex < tokenList.size() - 1; operatorIndex++) { // at this level the operator becomes '=' instead of '==' if (tokenList.get(operatorIndex).getGetTokenType() == PredicateToken.Type.OPERATOR && tokenList.get(operatorIndex).getTokenValue().trim().equals("=")) { // param and value can be in any order i.e. price = 3 or 1 = price. this is to handle such scenarios. String param = tokenList.get(operatorIndex - 1) .getGetTokenType() == PredicateToken.Type.VARIABLE ? tokenList.get(operatorIndex - 1).getTokenValue().trim() : tokenList.get(operatorIndex + 1).getTokenValue().toString().trim(); String value = tokenList.get(operatorIndex - 1) .getGetTokenType() == PredicateToken.Type.VARIABLE ? tokenList.get(operatorIndex + 1).getTokenValue().toString().trim() : tokenList.get(operatorIndex - 1).getTokenValue().trim(); for (int i = 0; i < attributeList.size(); i++) { if (attributeList.get(i).getName().equals(param)) { boolean mightContain = bloomFilters[i].membershipTest(new Key(value.getBytes())); if (!mightContain) { return false; } } } } } } } if ((cachedTable != null) && cachedTable.contains(atomicEvent, conditionExecutor)) { return true; } else { Connection con = null; PreparedStatement statement = null; try { initializeConnection(); if (predicate == null) { predicate = conditionExecutor.constructPredicate(atomicEvent, tableDefinition, new SQLPredicateBuilder()); } con = dataSource.getConnection(); // need to construct this each time since there are multiple queries and their predicates differ. statement = con.prepareStatement("SELECT * FROM " + fullTableName + " WHERE " + predicate.buildPredicateString() + " LIMIT 0,1"); ArrayList paramList = new ArrayList(); predicate.populateParameters(paramList); for (int i = 0; i < paramList.size(); i++) { populateStatement(statement, i + 1, paramList.get(i)); } ResultSet resultSet = statement.executeQuery(); boolean contains = false; long timestamp = System.currentTimeMillis(); while (resultSet.next()) { contains = true; if (cachedTable != null) { Object[] data = new Object[attributeList.size()]; for (int i = 0; i < attributeList.size(); i++) { switch (attributeList.get(i).getType()) { case BOOL: data[i] = resultSet.getBoolean(attributeList.get(i).getName()); break; case DOUBLE: data[i] = resultSet.getDouble(attributeList.get(i).getName()); break; case FLOAT: data[i] = resultSet.getFloat(attributeList.get(i).getName()); break; case INT: data[i] = resultSet.getInt(attributeList.get(i).getName()); break; case LONG: data[i] = resultSet.getLong(attributeList.get(i).getName()); break; case STRING: data[i] = resultSet.getString(attributeList.get(i).getName()); break; default: data[i] = resultSet.getObject(attributeList.get(i).getName()); } } // lazy loading caches since we've already read the event Event event = new InEvent(tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME), timestamp, data); cachedTable.add(event); } else { break; } } resultSet.close(); return contains; } catch (SQLException e) { log.error("Can't read the database table: " + tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME), e); } catch (Exception e) { log.error("Can't connect to the database.", e); } finally { cleanUpConnections(statement, con); } return false; } } private String createUpdateQuery(String predicate, int[] attributeMappingPositions) { StringBuilder statementBuilder = new StringBuilder("UPDATE "); statementBuilder.append(fullTableName); statementBuilder.append(" SET "); for (int i = 0; i < attributeMappingPositions.length; i++) { if (i > 0) { statementBuilder.append(", "); } statementBuilder.append(attributeList.get(attributeMappingPositions[i]).getName()); statementBuilder.append(" = ?"); } statementBuilder.append(" WHERE "); if (predicate != null) { statementBuilder.append(predicate); } return statementBuilder.toString(); } @Override public QueryEventSource getQueryEventSource() { return queryEventSource; } @Override public Iterator<StreamEvent> iterator(StreamEvent event, ConditionExecutor conditionExecutor) { if (cachedTable != null && cachedTable.isFullyLoaded()) { if (event instanceof AtomicEvent) { synchronized (this) { ArrayList<StreamEvent> resultEvents = new ArrayList<StreamEvent>(); Iterator<StreamEvent> iterator = cachedTable.iterator(); StateEvent stateEvent = new InStateEvent(new StreamEvent[2]); stateEvent.setStreamEvent(0, event); while (iterator.hasNext()) { StreamEvent cachedEvent = iterator.next(); stateEvent.setStreamEvent(1, cachedEvent); if (conditionExecutor.execute(stateEvent)) { resultEvents.add(cachedEvent); } } return resultEvents.iterator(); } } } PredicateTreeNode predicate = conditionExecutor.constructPredicate((AtomicEvent) event, tableDefinition, new SQLPredicateBuilder()); String sqlPredicate = predicate.buildPredicateString(); if (sqlPredicate.trim().equals("?")) { return iterator(); } ArrayList paramList = new ArrayList(); predicate.populateParameters(paramList); for (int i = 0; i < paramList.size(); i++) { Object value = paramList.get(i); if (value != null) { value = value.toString().replaceAll("'", "''"); } sqlPredicate = sqlPredicate.replaceFirst("\\?", "'" + value.toString() + "'"); // populate one by one. } return iterator(sqlPredicate); } @Override public Iterator<StreamEvent> iterator(String sqlPredicate) { Connection con = null; Statement statement = null; try { con = dataSource.getConnection(); statement = con.createStatement(); ResultSet resultSet = statement.executeQuery( "SELECT * FROM " + fullTableName + ((sqlPredicate == null) ? "" : (" WHERE " + sqlPredicate))); resultSet.setFetchSize(10000); ArrayList<StreamEvent> eventList = new ArrayList<StreamEvent>(); long timestamp = System.currentTimeMillis(); while (resultSet.next()) { Object[] data = new Object[attributeList.size()]; for (int i = 0; i < attributeList.size(); i++) { switch (attributeList.get(i).getType()) { case BOOL: data[i] = resultSet.getBoolean(attributeList.get(i).getName()); break; case DOUBLE: data[i] = resultSet.getDouble(attributeList.get(i).getName()); break; case FLOAT: data[i] = resultSet.getFloat(attributeList.get(i).getName()); break; case INT: data[i] = resultSet.getInt(attributeList.get(i).getName()); break; case LONG: data[i] = resultSet.getLong(attributeList.get(i).getName()); break; case STRING: data[i] = resultSet.getString(attributeList.get(i).getName()); break; default: data[i] = resultSet.getObject(attributeList.get(i).getName()); } } Event event = new InEvent(tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME), timestamp, data); eventList.add(event); } resultSet.close(); return eventList.iterator(); } catch (SQLException e) { log.error("Unable to read the table: " + tableDefinition.getExternalTable().getParameter(PARAM_TABLE_NAME), e); } finally { cleanUpConnections(statement, con); } return null; } @Override public Iterator<StreamEvent> iterator() { return iterator(null); } private void cleanUpConnections(Statement stmt, Connection con) { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { log.error("unable to release statement", e); } } if (con != null) { try { con.close(); } catch (SQLException e) { log.error("unable to release connection", e); } } } private void populateStatement(PreparedStatement stmt, int index, Object value) throws SQLException { if (value instanceof String) { stmt.setString(index, (String) value); } else if (value instanceof Integer) { stmt.setInt(index, (Integer) value); } else if (value instanceof Double) { stmt.setDouble(index, (Double) value); } else if (value instanceof Boolean) { stmt.setBoolean(index, (Boolean) value); } else if (value instanceof Float) { stmt.setFloat(index, (Float) value); } else if (value instanceof Long) { stmt.setLong(index, (Long) value); } else { stmt.setString(index, (String) value); } } }