/* * StreamCruncher: Copyright (c) 2006-2008, Ashwin Jayaprakash. All Rights Reserved. * Contact: ashwin {dot} jayaprakash {at} gmail {dot} com * Web: http://www.StreamCruncher.com * * This file is part of StreamCruncher. * * StreamCruncher is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * StreamCruncher 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with StreamCruncher. If not, see <http://www.gnu.org/licenses/>. */ package streamcruncher.api; import java.lang.reflect.Constructor; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import streamcruncher.api.aggregator.AbstractAggregatorHelper; import streamcruncher.api.artifact.RowSpec; import streamcruncher.api.artifact.RunningQuery; import streamcruncher.boot.Main; import streamcruncher.boot.ProviderManager; import streamcruncher.boot.ProviderManagerException; import streamcruncher.boot.Registry; import streamcruncher.innards.core.partition.aggregate.AggregatorManager; import streamcruncher.innards.core.partition.aggregate.AggregatorManagerException; import streamcruncher.innards.db.DatabaseInterface; import streamcruncher.innards.db.cache.CacheManager; import streamcruncher.innards.db.cache.CachedData; import streamcruncher.innards.query.Parser; import streamcruncher.kernel.PrioritizedSchedulableQuery; import streamcruncher.kernel.QueryMaster; import streamcruncher.util.TimeKeeper; /* * Author: Ashwin Jayaprakash Date: Jul 2, 2006 Time: 4:49:12 PM */ /** * The main class provided by the Kernel to - register/unregister Event Streams, * Queries, hooks etc. It also provides methods to start and stop the Kernel. * * @author Ashwin Jayaprakash, Copyright 2005-2007. All Rights Reserved. */ public final class StreamCruncher { protected final Main main; /** * Any number of these instances can be created. However, the instances are * <b>not</b> Thread-safe. */ public StreamCruncher() { main = new Main(); } /** * Sets the lifecycle Listener. Must be invoked <b>before</b> invoking the * {@link #start(String)} method if the intention is to listen to Startup * events and/or <b>before</b> invoking the {@link #stop()} or before the * Kernel is issued a stop command via {@link #keepRunning()} if the * intention is to listen to Shutdown events. * * @param hook */ public void setStartupShutdownHook(StartupShutdownHook hook) { main.setStartupShutdownHook(hook); } /** * Removes the Listener from the Kernel. */ public void clearStartupShutdownHook() { main.setStartupShutdownHook(null); } /** * @return The Listener currently attached to the Kernel. */ public StartupShutdownHook getStartupShutdownHook() { return main.getStartupShutdownHook(); } /** * Starts the Kernel. Successful return from this method invocation * indicates that the Kernel has started and is ready to register, * unregister artifacts etc. If the Kernel is being restarted, then any * Queries that were registered in a previous run, will start executing. * <p> * The Kernel must be <b>started first</b> using this method, before * invoking <b>any method on any of the API Classes</b>. * </p> * * @param configFilePath * The path, including the name of the Kernel configuration file. * @throws StreamCruncherException */ public void start(String configFilePath) throws StreamCruncherException { try { main.start(configFilePath); } catch (Exception e) { throw new StreamCruncherException(e); } } /** * Once the Kernel has started, this method can be invoked, where the * <b>invoking Thread blocks and waits</b> for the stop-instruction to be * typed at the System Console. On receiving the correct instruction, the * Kernel will be stopped and the Thread will return from the method. * * @throws StreamCruncherException */ public void keepRunning() throws StreamCruncherException { try { main.keepRunning(); } catch (Exception e) { throw new StreamCruncherException(e); } } /** * This is an alternative way of stopping the Kernel (also see * {@link #keepRunning()}) * * @throws StreamCruncherException */ public void stop() throws StreamCruncherException { try { main.stop(true); } catch (Exception e) { throw new StreamCruncherException(e); } } // -------------------- /** * Register an Input Event Stream as described by the {@link RowSpec}. * * @param name * @param rowSpec * @param blockSize * This number is used by the Kernel to allocate blocks in memory * to accomodate the incoming Events. Input Streams with very * high rates of arrivals must use larger numbers (multiples of * <code>1024</code>). * @throws StreamCruncherException */ public void registerInStream(String name, RowSpec rowSpec, int blockSize) throws StreamCruncherException { try { main.registerInStream(name, rowSpec, blockSize, false); } catch (Exception e) { throw new StreamCruncherException(e); } } /** * Register an Input Event Stream as described by the {@link RowSpec} and * default Block size of <code>1024</code>. * * @param name * @param rowSpec * @throws StreamCruncherException * @see #registerInStream(String, RowSpec, int) */ public void registerInStream(String name, RowSpec rowSpec) throws StreamCruncherException { registerInStream(name, rowSpec, 1024); } /** * Unregisters the Input Event Stream. This operation will succeed only if * all the Queries that were using this Stream have been unregistered. * * @param name * @throws StreamCruncherException */ public void unregisterInStream(String name) throws StreamCruncherException { try { main.unregisterInStream(name); } catch (Exception e) { throw new StreamCruncherException(e); } } // -------------------- /** * The "Running Query" that will execute on the Event Stream has to be * parsed by the Kernel first. * * @param parserParameters * @return The handle to the parsed "Running Query" as the output of * successful parsing. * @throws StreamCruncherException */ public ParsedQuery parseQuery(ParserParameters parserParameters) throws StreamCruncherException { DatabaseInterface databaseInterface = Registry.getImplFor(DatabaseInterface.class); Class<? extends Parser> parserClass = databaseInterface.getParser(); RunningQuery runningQuery = null; try { Constructor<? extends Parser> constructor = parserClass .getConstructor(new Class[] { ParserParameters.class }); Parser parser = constructor.newInstance(new Object[] { parserParameters }); runningQuery = parser.parse(); PrioritizedSchedulableQuery psq = new PrioritizedSchedulableQuery(runningQuery); return new ParsedQuery(psq); } catch (Exception e) { throw new StreamCruncherException(e); } } /** * Registers the Query that was parsed using * {@link #parseQuery(ParserParameters)}. The Query execution will start * after this registration (based on the configurations provided using the * {@link QueryConfig}). * * @param parsedQuery * @throws StreamCruncherException */ public void registerQuery(ParsedQuery parsedQuery) throws StreamCruncherException { RunningQuery runningQuery = parsedQuery.getRunningQuery(); try { main.registerQuery(runningQuery, false); } catch (Exception e) { throw new StreamCruncherException(e); } } /** * Each Query has a unique config-object and this method returns a handle to * the same. It can also be accessed using the * {@link ParsedQuery#getQueryConfig()} method. This object must be * retrieved (if needed) afresh after every Kernel restart. * * @param queryName * @return <code>null</code> if there is no Query that has been registered * with this name. */ public QueryConfig getQueryConfig(String queryName) { QueryMaster queryMaster = Registry.getImplFor(QueryMaster.class); PrioritizedSchedulableQuery psq = queryMaster.getScheduledQuery(queryName); if (psq != null) { return psq.getQueryConfig(); } return null; } /** * Stops and unregisters the Query that is running on the Kernel. * * @param name * As provided in {@link ParserParameters#getQueryName()}. */ public void unregisterQuery(String name) { main.unregisterQuery(name); } // -------------------- /** * @return A pooled Connection. Must be <b>closed explicitly</b> when not * required anymore. * @throws SQLException */ public Connection createConnection() throws SQLException { DatabaseInterface databaseInterface = Registry.getImplFor(DatabaseInterface.class); return databaseInterface.createConnection(); } /** * @return The Database Schema which the Kernel has been configured to use. */ public String getDBSchema() { DatabaseInterface databaseInterface = Registry.getImplFor(DatabaseInterface.class); return databaseInterface.getSchema(); } // -------------------- /** * @return All the SQL Sub-Queries that have been cached by the Kernel. */ public Collection<String> getResultSetCacheConfigKeys() { CacheManager cacheManager = Registry.getImplFor(CacheManager.class); return new ArrayList<String>(cacheManager.getAllCachedData().keySet()); } /** * @param cachedSql * @return The config-object for the Cached SQL Query provided as the * parameter. If the Query that uses the SQL that is provided as the * parameter, has not been registered with the Kernel yet, then the * return value might be <code>null</code>. Since there could be * multiple Queries that use the same SQL as a Sub-Query, the Kernel * maintains only one cache that will be shared by all the * referrers. */ public ResultSetCacheConfig getResultSetCacheConfig(String cachedSql) { CacheManager cacheManager = Registry.getImplFor(CacheManager.class); CachedData cachedData = cacheManager.getCachedData(cachedSql); return cachedData.getCacheConfig(); } // -------------------- /** * Creates a helper object for the Input Event Stream. * * @param name * @return * @throws StreamCruncherException */ public InputSession createInputSession(String name) throws StreamCruncherException { return new InputSession(name); } /** * Creates a helper object for the Output Event Stream. * * @param queryName * @return * @throws StreamCruncherException */ public OutputSession createOutputSession(String queryName) throws StreamCruncherException { return new OutputSession(queryName); } // -------------------- /** * Registers an Aggregator function. If a Query uses a custom Aggregator, * then that Aggregator must be registered before the Query is registered. * * @param helper * @throws StreamCruncherException */ public void registerAggregator(AbstractAggregatorHelper helper) throws StreamCruncherException { AggregatorManager manager = Registry.getImplFor(AggregatorManager.class); try { manager.registerHelper(helper); } catch (AggregatorManagerException e) { throw new StreamCruncherException(e); } } /** * An Aggregator must be unregistered <b>only after all</b> the Queries * that use it have been unregistered. This method will unregister the * Aggregator without checking if Queries are still using it. * * @param functionName * As provided in * {@link AbstractAggregatorHelper#getFunctionName()} */ public void unregisterAggregator(String functionName) { AggregatorManager manager = Registry.getImplFor(AggregatorManager.class); manager.unregisterHelper(functionName); } // -------------------- /** * Registers a Provider. If a Query uses a custom Provider, then that * Provider must be registered before the Query is registered. * * @param providerName * @param providerClass * @throws StreamCruncherException */ public void registerProvider(String providerName, Class<? extends Provider> providerClass) throws StreamCruncherException { ProviderManager manager = Registry.getImplFor(ProviderManager.class); try { manager.registerProvider(providerName, providerClass); } catch (ProviderManagerException e) { throw new StreamCruncherException(e); } } /** * A Provider must be unregistered <b>only after all</b> the Queries that * use it have been unregistered. This method will unregister the Provider * without checking if Queries are still using it. * * @param providerName * As provided in {@link #registerProvider(String, Class)} */ public void unregisterProvider(String providerName) { ProviderManager manager = Registry.getImplFor(ProviderManager.class); manager.unregisterProvider(providerName); } // -------------------- /** * Forces the Kernel to add the number provided to the time it obtains from * the System clock. It affects Query execution times, Event expiry times, * Event generation timestamps etc. This operation <b>is Thread-safe</b>. * * @param timeBiasMsecs * Bias in milliseconds (+ve or -ve). */ public void setTimeBiasMsecs(long timeBiasMsecs) { TimeKeeper keeper = Registry.getImplFor(TimeKeeper.class); keeper.setTimeBiasMsecs(timeBiasMsecs); } /** * @return The current bias (default is 0) being used by the Kernel. */ public long getTimeBiasMsecs() { TimeKeeper keeper = Registry.getImplFor(TimeKeeper.class); return keeper.getTimeBiasMsecs(); } }