Package ch.uzh.ifi.ddis.ifp.esper.cassandra

Source Code of ch.uzh.ifi.ddis.ifp.esper.cassandra.CassandraVirtualDataWindow

package ch.uzh.ifi.ddis.ifp.esper.cassandra;

/*
* #%L
* Cassandra for Esper
* %%
* Copyright (C) 2013 University of Zurich
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program.  If not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>.
* #L%
*/

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.exceptions.InvalidQueryException;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.hook.VirtualDataWindow;
import com.espertech.esper.client.hook.VirtualDataWindowContext;
import com.espertech.esper.client.hook.VirtualDataWindowEvent;
import com.espertech.esper.client.hook.VirtualDataWindowLookupContext;

/**
* The virtual data window for Esper which stores results from a lookup to
* Cassandra.
*
* @author Thomas Scharrenbach
* @version 0.0.1
* @since 0.2.1
*
*/
public class CassandraVirtualDataWindow implements VirtualDataWindow {

  private static final Logger _log = LoggerFactory
      .getLogger(CassandraVirtualDataWindow.class);

  //
  //
  //

  //
  //
  //

  private final Session _session;

  private final VirtualDataWindowContext _context;

  private final String _table;

  private final PreparedStatement _insertStatement;

  private final PreparedStatement _deleteStatement;

  //
  //
  //

  /**
   * <p>
   * Initializes the {@link PreparedStatement} for the insert and the delete
   * operations for the {@link #update(EventBean[], EventBean[])} method. The
   * update statements depend on the the actual new values of the
   * {@link #update(EventBean[], EventBean[])} method and must hence be
   * computed on the fly.
   * </p>
   *
   * @param cluster
   *            the reference to the Cassandra cluster.
   * @param context
   *            the Esper context.
   * @param preparedStatementString
   */
  CassandraVirtualDataWindow(Session session, String table,
      VirtualDataWindowContext context) {
    _context = context;
    _session = session;
    _table = table;

    // Prepare the insert query.
    final String insertQuery = QueryStringBuilder
        .createInsertQuery(_context);
    _log.debug("Prepared insert query: {}", insertQuery);
    _insertStatement = _session.prepare(insertQuery);

    // Prepare the delete query.
    final String deleteQuery = QueryStringBuilder
        .createDeleteQuery(_context);
    _deleteStatement = _session.prepare(deleteQuery);
    _log.debug("Prepared delete query: {}", deleteQuery);

    // Update queries depend on the actual update values, so we have to
    // compute them on the fly.

  }

  //
  //
  //

  /**
   * <p>
   * Creates a new {@link CassandraVirtualDataWindowLookup} with a fresh
   * prepared statement.
   * </p>
   * <p>
   * <strong>Note: This method is thread-safe.</strong>
   * </p>
   *
   * @see VirtualDataWindow#getLookup(VirtualDataWindowLookupContext)
   * @return a new {@link CassandraVirtualDataWindowLookup} with this window's
   *         Cassandra session and Esper context.
   */
  @Override
  public CassandraVirtualDataWindowLookup getLookup(
      VirtualDataWindowLookupContext lookupContext) {

    final List<String> createIndexQueries = QueryStringBuilder
        .createIndexQueryStringList(lookupContext, _table);
    for (String createIndexQuery : createIndexQueries) {
      try {
        _log.info("Started creating index...");
        _session.execute(createIndexQuery);
        _log.info("Finished creating index.");
      } catch (InvalidQueryException e) {
        _log.warn("Index already exists");
      } catch (Exception e) {
        _log.error("Error creating index !", e);
        throw new RuntimeException(e);
      }
    }

    final String queryString = QueryStringBuilder.createSelectQueryString(
        _context, lookupContext, _table);
    _log.debug("Created query {}", queryString);
    CassandraVirtualDataWindowLookup result = null;
    synchronized (_session) {
      final PreparedStatement statement = _session.prepare(queryString);
      result = new CassandraVirtualDataWindowLookup(_session,
          lookupContext, statement, _context);
    }
    return result;
  }

  /**
   * Currently, this method performs nothing.
   */
  @Override
  public void handleEvent(VirtualDataWindowEvent theEvent) {
  }

  /**
   * <p>
   * Dependent on the values of the parameters, this method executes INSERT,
   * UPDATE, or DELETE operations on the Cassandra store.
   * </p>
   * <p>
   * <ul>
   * <li>oldData is null: INSERT.</li>
   * <li>newData is null: DELETE.</li>
   * <li>else: UPDATE.</li>
   * </ul>
   * </p>
   *
   * @see VirtualDataWindow#update(EventBean[], EventBean[])
   */
  @Override
  public void update(EventBean[] newData, EventBean[] oldData) {
    final String[] propertyNames = _context.getEventType()
        .getPropertyNames();

    // Insert events into window
    if (oldData == null) {
      if (newData.length > 0) {
        _log.debug("Starting insert...");
        final Object[] values = new Object[propertyNames.length];
        for (EventBean insertBean : newData) {
          for (int i = 0; i < propertyNames.length; ++i) {
            values[i] = insertBean.get(propertyNames[i]);
          }
          BoundStatement boundStatement = null;
          synchronized (_insertStatement) {
            boundStatement = _insertStatement.bind(values);
          }
          synchronized (_session) {
            _session.execute(boundStatement);
          }
        }

        _log.debug("Finished insert...");
      }
    }
    // Delete events from window
    else if (newData == null) {
      if (oldData.length > 0) {
        _log.debug("Starting delete...");
        for (EventBean deleteBean : oldData) {
          BoundStatement boundStatement = null;
          synchronized (_deleteStatement) {
            boundStatement = _deleteStatement.bind(deleteBean
                .get(QueryStringBuilder.TABLE_ID));
          }
          synchronized (_session) {
            _session.execute(boundStatement);
          }
        }

        _log.debug("Finished delete...");
      }
    }
    // Update events in window
    else {
      if (newData.length > 0) {
        _log.debug("Starting update...");
        EventBean newDataFirst = newData[0];
        List<String> propertiesToUpdateList = new ArrayList<String>();
        for (String propertyName : propertyNames) {
          if (newDataFirst.get(propertyName) != null) {
            propertiesToUpdateList.add(propertyName);
          }
        }

        String propertiesToUpdate[] = propertiesToUpdateList
            .toArray(new String[propertiesToUpdateList.size()]);
        final String query = QueryStringBuilder.createUpdateQuery(
            _context, propertiesToUpdate);
        PreparedStatement _updateStatement = _session.prepare(query);
        Object primaryKeyValue = null;
        for (EventBean updateBean : newData) {
          final List<Object> values = new ArrayList<Object>();
          for (int i = 0; i < propertiesToUpdate.length; ++i) {
            if (QueryStringBuilder.TABLE_ID
                .equals(propertiesToUpdate[i])) {
              primaryKeyValue = updateBean
                  .get(propertiesToUpdate[i]);
            } else {
              values.add(updateBean.get(propertiesToUpdate[i]));
            }
          }
          values.add(primaryKeyValue);
          BoundStatement boundStatement = null;
          synchronized (_updateStatement) {
            boundStatement = _updateStatement
                .bind(values.toArray());
          }
          synchronized (_session) {
            _session.execute(boundStatement);
          }

        }
        _log.debug("Finished update...");
      }
    }

    _context.getOutputStream().update(newData, oldData);
  }

  /**
   * <p>
   * Shutdown the Cassandra {@link Session} if it is not null.
   * </p>
   *
   * @throws RuntimeException
   *             in case shutting down the session fails.
   */
  @Override
  public void destroy() {
    if (_session != null) {
      try {
        _log.info("Started shutting down session to Cassandra cluster...");
        _session.shutdown();
        _log.info("Finished shutting down session to Cassandra cluster.");
      }
      //
      catch (Exception e) {
        _log.error("Error shutting down session to Cassandra cluster!",
            e);
        throw new RuntimeException(e);
      }
    }
  }

  /**
   * <p>
   * Performs a select * query to the Cassandra store.
   * </p>
   *
   *
   * @return the content of the Cassandra store or an empt list when the query
   *         execution was interrupted.
   * @throws RuntimeException
   *             if an {@link ExecutionException} happens during query
   *             execution.
   */
  @Override
  public Iterator<EventBean> iterator() {
    final String selectAllQuery = String.format("SELECT * FROM %s", _table);
    ResultSetFuture results;
    synchronized (_session) {
      results = _session.executeAsync(selectAllQuery);
    }
    try {
      final ResultSet cassandraResultList = results.get();
      return new EsperResultSetIterator(cassandraResultList,
          _context.getEventFactory());
    } catch (InterruptedException e) {
      _log.warn(
          "Query execution was interrupted, returning empty iterator.",
          e);
      return java.util.Collections.<EventBean> emptyList().iterator();
    } catch (ExecutionException e) {
      _log.error("Unexpected exception during execution!", e);
      throw new RuntimeException(e);
    }
  }

  //
  //
  //

}
TOP

Related Classes of ch.uzh.ifi.ddis.ifp.esper.cassandra.CassandraVirtualDataWindow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.