All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.espertech.esper.epl.db.DatabasePollingViewable Maven / Gradle / Ivy

/*
 ***************************************************************************************
 *  Copyright (C) 2006 EsperTech, Inc. All rights reserved.                            *
 *  http://www.espertech.com/esper                                                     *
 *  http://www.espertech.com                                                           *
 *  ---------------------------------------------------------------------------------- *
 *  The software in this package is published under the terms of the GPL license       *
 *  a copy of which has been included with this distribution in the license.txt file.  *
 ***************************************************************************************
 */
package com.espertech.esper.epl.db;

import com.espertech.esper.client.ConfigurationInformation;
import com.espertech.esper.client.EPException;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.collection.IterablesArrayIterator;
import com.espertech.esper.core.service.StatementContext;
import com.espertech.esper.epl.core.EngineImportService;
import com.espertech.esper.epl.core.StreamTypeService;
import com.espertech.esper.epl.expression.core.*;
import com.espertech.esper.epl.expression.visitor.ExprNodeIdentifierCollectVisitor;
import com.espertech.esper.epl.join.pollindex.PollResultIndexingStrategy;
import com.espertech.esper.epl.join.table.EventTable;
import com.espertech.esper.epl.join.table.UnindexedEventTableList;
import com.espertech.esper.epl.table.mgmt.TableService;
import com.espertech.esper.epl.variable.VariableService;
import com.espertech.esper.event.EventAdapterService;
import com.espertech.esper.schedule.SchedulingService;
import com.espertech.esper.schedule.TimeProvider;
import com.espertech.esper.view.HistoricalEventViewable;
import com.espertech.esper.view.View;
import com.espertech.esper.view.ViewSupport;

import java.util.*;

/**
 * Implements a poller viewable that uses a polling strategy, a cache and
 * some input parameters extracted from event streams to perform the polling.
 */
public class DatabasePollingViewable implements HistoricalEventViewable {
    private final int myStreamNumber;
    private final PollExecStrategy pollExecStrategy;
    private final List inputParameters;
    private final DataCache dataCache;
    private final EventType eventType;
    private final ThreadLocal dataCacheThreadLocal = new ThreadLocal();

    private ExprEvaluator[] evaluators;
    private SortedSet subordinateStreams;
    private ExprEvaluatorContext exprEvaluatorContext;
    private StatementContext statementContext;

    private static final EventBean[][] NULL_ROWS;

    static {
        NULL_ROWS = new EventBean[1][];
        NULL_ROWS[0] = new EventBean[1];
    }

    private static final PollResultIndexingStrategy ITERATOR_INDEXING_STRATEGY = new PollResultIndexingStrategy() {
        public EventTable[] index(List pollResult, boolean isActiveCache, StatementContext statementContext) {
            return new EventTable[]{new UnindexedEventTableList(pollResult, -1)};
        }

        public String toQueryPlan() {
            return this.getClass().getSimpleName() + " unindexed";
        }
    };

    /**
     * Ctor.
     *
     * @param myStreamNumber   is the stream number of the view
     * @param inputParameters  are the event property names providing input parameter keys
     * @param pollExecStrategy is the strategy to use for retrieving results
     * @param dataCache        is looked up before using the strategy
     * @param eventType        is the type of events generated by the view
     */
    public DatabasePollingViewable(int myStreamNumber,
                                   List inputParameters,
                                   PollExecStrategy pollExecStrategy,
                                   DataCache dataCache,
                                   EventType eventType) {
        this.myStreamNumber = myStreamNumber;
        this.inputParameters = inputParameters;
        this.pollExecStrategy = pollExecStrategy;
        this.dataCache = dataCache;
        this.eventType = eventType;
    }

    public void stop() {
        pollExecStrategy.destroy();
        dataCache.destroy();
    }

    public DataCache getOptionalDataCache() {
        return dataCache;
    }

    public void validate(EngineImportService engineImportService,
                         StreamTypeService streamTypeService,
                         TimeProvider timeProvider,
                         VariableService variableService,
                         TableService tableService,
                         ExprEvaluatorContext exprEvaluatorContext,
                         ConfigurationInformation configSnapshot,
                         SchedulingService schedulingService,
                         String engineURI,
                         Map> sqlParameters,
                         EventAdapterService eventAdapterService,
                         StatementContext statementContext) throws ExprValidationException {
        this.statementContext = statementContext;
        evaluators = new ExprEvaluator[inputParameters.size()];
        subordinateStreams = new TreeSet();
        this.exprEvaluatorContext = exprEvaluatorContext;

        int count = 0;
        ExprValidationContext validationContext = new ExprValidationContext(streamTypeService, engineImportService, statementContext.getStatementExtensionServicesContext(), null, timeProvider, variableService, tableService, exprEvaluatorContext, eventAdapterService, statementContext.getStatementName(), statementContext.getStatementId(), statementContext.getAnnotations(), null, false, false, true, false, null, false);
        for (String inputParam : inputParameters) {
            ExprNode raw = findSQLExpressionNode(myStreamNumber, count, sqlParameters);
            if (raw == null) {
                throw new ExprValidationException("Internal error find expression for historical stream parameter " + count + " stream " + myStreamNumber);
            }
            ExprNode evaluator = ExprNodeUtility.getValidatedSubtree(ExprNodeOrigin.DATABASEPOLL, raw, validationContext);
            evaluators[count++] = evaluator.getExprEvaluator();

            ExprNodeIdentifierCollectVisitor visitor = new ExprNodeIdentifierCollectVisitor();
            visitor.visit(evaluator);
            for (ExprIdentNode identNode : visitor.getExprProperties()) {
                if (identNode.getStreamId() == myStreamNumber) {
                    throw new ExprValidationException("Invalid expression '" + inputParam + "' resolves to the historical data itself");
                }
                subordinateStreams.add(identNode.getStreamId());
            }
        }
    }

    public EventTable[][] poll(EventBean[][] lookupEventsPerStream, PollResultIndexingStrategy indexingStrategy, ExprEvaluatorContext exprEvaluatorContext) {
        DataCache localDataCache = dataCacheThreadLocal.get();
        boolean strategyStarted = false;

        EventTable[][] resultPerInputRow = new EventTable[lookupEventsPerStream.length][];

        // Get input parameters for each row
        EventBean[] eventsPerStream;
        for (int row = 0; row < lookupEventsPerStream.length; row++) {
            Object[] lookupValues = new Object[inputParameters.size()];

            // Build lookup keys
            for (int valueNum = 0; valueNum < inputParameters.size(); valueNum++) {
                eventsPerStream = lookupEventsPerStream[row];
                Object lookupValue = evaluators[valueNum].evaluate(eventsPerStream, true, exprEvaluatorContext);
                lookupValues[valueNum] = lookupValue;
            }

            EventTable[] result = null;

            // try the threadlocal iteration cache, if set
            if (localDataCache != null) {
                EventTable[] tables = localDataCache.getCached(lookupValues, lookupValues.length);
                result = tables;
            }

            // try the connection cache
            if (result == null) {
                EventTable[] multi = dataCache.getCached(lookupValues, lookupValues.length);
                if (multi != null) {
                    result = multi;
                    if (localDataCache != null) {
                        localDataCache.put(lookupValues, lookupValues.length, multi);
                    }
                }
            }

            // use the result from cache
            if (result != null) {
                // found in cache
                resultPerInputRow[row] = result;
            } else {
                // not found in cache, get from actual polling (db query)
                try {
                    if (!strategyStarted) {
                        pollExecStrategy.start();
                        strategyStarted = true;
                    }

                    // Poll using the polling execution strategy and lookup values
                    List pollResult = pollExecStrategy.poll(lookupValues, exprEvaluatorContext);

                    // index the result, if required, using an indexing strategy
                    EventTable[] indexTable = indexingStrategy.index(pollResult, dataCache.isActive(), statementContext);

                    // assign to row
                    resultPerInputRow[row] = indexTable;

                    // save in cache
                    dataCache.put(lookupValues, lookupValues.length, indexTable);

                    if (localDataCache != null) {
                        localDataCache.put(lookupValues, lookupValues.length, indexTable);
                    }
                } catch (EPException ex) {
                    if (strategyStarted) {
                        pollExecStrategy.done();
                    }
                    throw ex;
                }
            }
        }

        if (strategyStarted) {
            pollExecStrategy.done();
        }

        return resultPerInputRow;
    }

    public View addView(View view) {
        view.setParent(this);
        return view;
    }

    public View[] getViews() {
        return ViewSupport.EMPTY_VIEW_ARRAY;
    }

    public boolean removeView(View view) {
        throw new UnsupportedOperationException("Subviews not supported");
    }

    public boolean hasViews() {
        return false;
    }

    public EventType getEventType() {
        return eventType;
    }

    public Iterator iterator() {
        EventTable[][] tablesPerRow = poll(NULL_ROWS, ITERATOR_INDEXING_STRATEGY, exprEvaluatorContext);
        return new IterablesArrayIterator(tablesPerRow);
    }

    public SortedSet getRequiredStreams() {
        return subordinateStreams;
    }

    public boolean hasRequiredStreams() {
        return !subordinateStreams.isEmpty();
    }

    public ThreadLocal getDataCacheThreadLocal() {
        return dataCacheThreadLocal;
    }

    public void removeAllViews() {
        throw new UnsupportedOperationException("Subviews not supported");
    }

    private static ExprNode findSQLExpressionNode(int myStreamNumber, int count, Map> sqlParameters) {
        if ((sqlParameters == null) || (sqlParameters.isEmpty())) {
            return null;
        }
        List parameters = sqlParameters.get(myStreamNumber);
        if ((parameters == null) || (parameters.isEmpty()) || (parameters.size() < (count + 1))) {
            return null;
        }
        return parameters.get(count);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy