/**
* Global Sensor Networks (GSN) Source Code
* Copyright (c) 2006-2016, Ecole Polytechnique Federale de Lausanne (EPFL)
*
* This file is part of GSN.
*
* GSN 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 3 of the License, or
* (at your option) any later version.
*
* GSN 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 GSN. If not, see <http://www.gnu.org/licenses/>.
*
* File: src/ch/epfl/gsn/beans/InputStream.java
*
* @author Mehdi Riahi
* @author gsn_devs
* @author Ali Salehi
* @author Timotee Maret
*
*/
package ch.epfl.gsn.beans;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.TreeMap;
import org.slf4j.LoggerFactory;
import ch.epfl.gsn.Main;
import ch.epfl.gsn.VirtualSensor;
import ch.epfl.gsn.VirtualSensorInitializationFailedException;
import ch.epfl.gsn.beans.InputStream;
import ch.epfl.gsn.beans.StreamElement;
import ch.epfl.gsn.beans.StreamSource;
import ch.epfl.gsn.utils.CaseInsensitiveComparator;
import ch.epfl.gsn.vsensor.AbstractVirtualSensor;
import org.slf4j.Logger;
public class InputStream implements Serializable{
private static final long serialVersionUID = 6910141410904878762L;
public static final int INITIAL_DELAY_5000MSC = 5000;
private transient static final Logger logger = LoggerFactory.getLogger( InputStream.class );
//private transient StorageManager storageMan = StorageManager.getInstance();
private String inputStreamName;
private Long count /*= Long.MAX_VALUE*/;
private transient long currentCount = 1;
private int rate;
private String query;
private StreamSource[] sources;
private HashMap < CharSequence , StreamSource > streamSourceAliasNameToStreamSourceName = new HashMap < CharSequence , StreamSource >( );
private transient VirtualSensor pool;
private final transient TreeMap< CharSequence , CharSequence > rewritingData = new TreeMap < CharSequence , CharSequence >( new CaseInsensitiveComparator());
private transient long lastVisited = 0;
private StringBuilder rewrittenSQL;
private boolean queryCached;
/**
* For making one initial delay.
*/
public String getQuery ( ) {
return this.query;
}
public void setQuery ( final String sql ) {
this.query = sql;
}
public String getInputStreamName ( ) {
return this.inputStreamName;
}
public void setInputStreamName ( final String inputStreamName ) {
this.inputStreamName = inputStreamName;
}
public Long getCount ( ) {
if ( this.count == null || this.count == 0 ) this.count = Long.MAX_VALUE;
return this.count;
}
public void setCount ( final Long count ) {
this.count = count;
}
public int getRate ( ) {
return this.rate;
}
public void setRate(int rate){
this.rate = rate;
}
public StreamSource[] getSources ( ) {
return sources;
}
public StreamSource getSource ( final String streamSourceName ) {
return this.streamSourceAliasNameToStreamSourceName.get( streamSourceName );
}
public void setSources(StreamSource... ss) {
this.sources = ss;
}
/**
* This method is called by the Stream Source timed Stream-Source has new
* results.
*
* @param alias The alias of the StreamSource which has new data.
* @throws SQLException
*/
// public boolean dataAvailable ( final CharSequence alias ) throws SQLException {
// if ( logger.isDebugEnabled( ) ) logger.debug( new StringBuilder( ).append( "Notified by StreamSource on the alias: " ).append( alias ).toString( ) );
// if ( this.pool == null ) {
// logger.debug( "The input is dropped b/c the VSensorInstance is not set yet." );
// return false;
// }
//
// if ( this.currentCount > this.getCount( ) ) {
// if ( logger.isInfoEnabled( ) ) logger.info( "Maximum count reached, the value *discarded*" );
// return false;
// }
//
// final long currentTimeMillis = System.currentTimeMillis( );
// if ( this.rate > 0 && ( currentTimeMillis - this.lastVisited ) < this.rate ) {
// if ( logger.isInfoEnabled( ) ) logger.info( "Called by *discarded* b/c of the rate limit reached." );
// return false;
// }
// this.lastVisited = currentTimeMillis;
//
// if ( this.rewrittenSQL == null ) {
// this.rewrittenSQL = new StringBuilder( SQLUtils.newRewrite( getQuery( ).trim( ).toLowerCase( ), this.rewritingData ));
// if ( logger.isDebugEnabled( ) )
// logger.debug( new StringBuilder( ).append( "Rewritten SQL: " ).append( this.rewrittenSQL ).append( "(" ).append( this.storageMan.isThereAnyResult( this.rewrittenSQL ) ).append( ")" )
// .toString( ) );
// }
// if ( StorageManager.getInstance( ).isThereAnyResult( this.rewrittenSQL ) ) {
// this.currentCount++;
// AbstractVirtualSensor sensor = null;
// if ( logger.isDebugEnabled( ) ) logger.debug( new StringBuilder( ).append( "Executing the main query for InputStream : " ).append( this.getInputStreamName( ) ).toString( ) );
// int elementCounterForDebugging = -1;
// final Enumeration < StreamElement > resultOfTheQuery = StorageManager.getInstance( ).executeQuery( this.rewrittenSQL , false );
// try {
// sensor = pool.borrowVS( );
// while ( resultOfTheQuery.hasMoreElements( ) ) {
// elementCounterForDebugging++;
// StreamElement element= resultOfTheQuery.nextElement( );
// sensor.dataAvailable( this.getInputStreamName( ) , element );
// }
// } catch ( final PoolIsFullException e ) {
// logger.warn( "The stream element produced by the virtual sensor is dropped because of the following error : " );
// logger.warn( e.getMessage( ) , e );
// } catch ( final UnsupportedOperationException e ) {
// logger.warn( "The stream element produced by the virtual sensor is dropped because of the following error : " );
// logger.warn( e.getMessage( ) , e );
// } catch ( final VirtualSensorInitializationFailedException e ) {
// logger.error( "The stream element can't deliver its data to the virtual sensor " + sensor.getVirtualSensorConfiguration( ).getName( )
// + " because initialization of that virtual sensor failed" );
// logger.error(e.getMessage(),e);
// } finally {
// this.pool.returnVS( sensor );
// }
// if ( logger.isDebugEnabled( ) ) {
// logger.debug( new StringBuilder( ).append( "Input Stream's result has *" ).append( elementCounterForDebugging ).append( "* stream elements" ).toString( ) );
// }
// }
// return true;
// }
public void addToRenamingMapping ( final CharSequence aliasName , final CharSequence viewName ) {
rewritingData.put( aliasName , viewName );
}
public final TreeMap<CharSequence,CharSequence> getRenamingMapping() {
return rewritingData;
}
public void refreshAlias ( final String alias ) {
logger.info( "REFERES ALIAS CALEED" );
}
public boolean equals ( final Object o ) {
if ( this == o ) { return true; }
if ( !( o instanceof InputStream ) ) { return false; }
final InputStream inputStream = ( InputStream ) o;
if ( this.inputStreamName != null ? !this.inputStreamName.equals( inputStream.inputStreamName ) : inputStream.inputStreamName != null ) { return false; }
return true;
}
public int hashCode ( ) {
return ( this.inputStreamName != null ? this.inputStreamName.hashCode( ) : 0 );
}
public void release ( ) {
final HashMap map = new HashMap( );
this.release( map );
}
public void release ( final HashMap context ) {}
private transient boolean hasValidated = false;
private transient boolean cachedValidationResult = false;
public boolean validate ( ) {
if ( this.hasValidated ) return this.cachedValidationResult;
hasValidated=true;
if (sources==null || sources.length==0) {
logger.error("Input Stream "+getInputStreamName()+ " is not valid (No stream sources are specified), deployment failed !");
return false;
}
for ( StreamSource ss : sources ) {
if ( !ss.validate( ) ) {
logger.error("The Stream Source : "+ss.getAlias( )+" specified in the Input Stream : "+getInputStreamName( )+" is not valid.");
return (cachedValidationResult=false);
}
streamSourceAliasNameToStreamSourceName.put( ss.getAlias( ) , ss );
}
return (cachedValidationResult=true);
}
/**
* @return the pool
*/
public VirtualSensor getPool ( ) {
return pool;
}
/**
* @param pool the pool to set
*/
public void setPool ( VirtualSensor pool ) {
this.pool = pool;
}
public void invalidateCachedQuery(StreamSource streamSource){
queryCached = false;
rewrittenSQL = null;
}
public boolean executeQuery( final CharSequence alias ) throws SQLException{
logger.debug("Notified by StreamSource on the alias: " + alias );
if ( this.pool == null ) {
logger.debug( "The input is dropped b/c the VSensorInstance is not set yet." );
return false;
}
if ( this.currentCount > this.getCount( ) ) {
logger.info( "Maximum count reached, the value *discarded*" );
return false;
}
final long currentTimeMillis = System.currentTimeMillis( );
if ( this.rate > 0 && ( currentTimeMillis - this.lastVisited ) < this.rate ) {
logger.info( "Called by *discarded* b/c of the rate limit reached." );
return false;
}
this.lastVisited = currentTimeMillis;
if ( !queryCached ) {
rewriteQuery();
if ( queryCached)
logger.debug( new StringBuilder( ).append( "Rewritten SQL: " ).append( this.rewrittenSQL ).append( "(" ).append( Main.getWindowStorage().isThereAnyResult( this.rewrittenSQL ) ).append( ")" )
.toString( ) );
}
int elementCounterForDebugging = 0;
if ( queryCached && Main.getWindowStorage().isThereAnyResult( this.rewrittenSQL ) ) {
this.currentCount++;
AbstractVirtualSensor sensor = null;
logger.debug( new StringBuilder( ).append( "Executing the main query for InputStream : " ).append( this.getInputStreamName( ) ).toString( ) );
final Enumeration < StreamElement > resultOfTheQuery = Main.getWindowStorage().executeQuery( this.rewrittenSQL , false );
try {
sensor = pool.borrowVS( );
while ( resultOfTheQuery.hasMoreElements( ) ) {
elementCounterForDebugging++;
StreamElement element= resultOfTheQuery.nextElement( );
sensor.dataAvailable_decorated( this.getInputStreamName( ) , element );
}
} catch ( final UnsupportedOperationException e ) {
logger.warn( "The stream element produced by the virtual sensor is dropped because of the following error : "+ e.getMessage());
} catch ( final VirtualSensorInitializationFailedException e ) {
logger.error( "The stream element can't deliver its data to the virtual sensor " + sensor.getVirtualSensorConfiguration( ).getName( )
+ " because initialization of that virtual sensor failed: " + e.getMessage());
} finally {
this.pool.returnVS( sensor );
}
}
logger.debug( new StringBuilder( ).append( "Input Stream's result has *" ).append( elementCounterForDebugging ).append( "* stream elements" ).toString( ) );
return true;
}
private void rewriteQuery() {
String query = getQuery().trim().toLowerCase();
for (int i = 0; i < sources.length; i++) {
StringBuilder sb = sources[i].rewrite(query);
if(sb == null){
logger.error("Rewriting query failed. The rewrite() method of the stream source <" + sources[i].getAlias() + "> returned null.");
rewrittenSQL = null;
queryCached = false;
return;
}else{
query = sb.toString();
}
}
rewrittenSQL = new StringBuilder(query);
queryCached = true;
}
}