Package com.espertech.esper.core.context.mgr

Source Code of com.espertech.esper.core.context.mgr.ContextManagerTemporalOverlap$ContextPlusSchedule

/*
* *************************************************************************************
*  Copyright (C) 2008 EsperTech, Inc. All rights reserved.                            *
*  http://esper.codehaus.org                                                          *
*  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.core.context.mgr;

import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.SafeIterator;
import com.espertech.esper.collection.SafeIteratorNull;
import com.espertech.esper.core.context.factory.StatementAgentInstanceFactoryResult;
import com.espertech.esper.core.context.stmt.AIRegistryAggregationMultiPerm;
import com.espertech.esper.core.context.stmt.AIRegistryExprMultiPerm;
import com.espertech.esper.core.context.stmt.StatementAIResourceRegistry;
import com.espertech.esper.core.context.stmt.StatementAIResourceRegistryFactory;
import com.espertech.esper.core.context.util.*;
import com.espertech.esper.core.service.EPServicesContext;
import com.espertech.esper.core.service.EPStatementHandleCallback;
import com.espertech.esper.core.service.ExtensionServicesContext;
import com.espertech.esper.core.service.StatementAgentInstanceFilterVersion;
import com.espertech.esper.epl.expression.ExprValidationException;
import com.espertech.esper.epl.spec.ContextDetailInitiatedTerminated;
import com.espertech.esper.filter.FilterHandleCallback;
import com.espertech.esper.filter.FilterValueSet;
import com.espertech.esper.pattern.*;
import com.espertech.esper.schedule.ScheduleHandleCallback;
import com.espertech.esper.schedule.ScheduleSlot;
import com.espertech.esper.util.CollectionUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;

public class ContextManagerTemporalOverlap implements ContextManager, PatternMatchCallback, ContextIteratorHandler {
    private static final Log log = LogFactory.getLog(ContextManagerTemporalOverlap.class);

    private final String contextName;
    private final EPServicesContext servicesContext;
    private final AgentInstanceContext createContextContext;
    private final ContextDetailInitiatedTerminated overlapSpec;
    private final ContextStateService contextStateService;
    private final ContextStateServiceBinding contextStateServiceBinding;

    private final ContextDescriptor contextDescriptor;

    private final Map<String, Set<AgentInstance>> statementInstances = new HashMap<String, Set<AgentInstance>>();
    private final Map<String, ContextManagedStatementBase> statements = new LinkedHashMap<String, ContextManagedStatementBase>(); // retain order of statement creation
    private final TreeMap<Integer, ContextPlusSchedule> agentInstances = new TreeMap<Integer, ContextPlusSchedule>();

    private PatternStopCallback patternStopCallback;
    private EPStatementHandleCallback filterHandle;

    public ContextManagerTemporalOverlap(String contextName, EPServicesContext servicesContext, AgentInstanceContext createContextContext, ContextDetailInitiatedTerminated overlapSpec, ContextStateService contextStateService) {
        this.contextName = contextName;
        this.servicesContext = servicesContext;
        this.createContextContext = createContextContext;
        this.overlapSpec = overlapSpec;
        this.contextStateService = contextStateService;

        StatementAIResourceRegistryFactory resourceRegistryFactory = new StatementAIResourceRegistryFactory() {
            public StatementAIResourceRegistry make() {
                return new StatementAIResourceRegistry(new AIRegistryAggregationMultiPerm(), new AIRegistryExprMultiPerm());
            }
        };
        EventType eventTypeContextProps = ContextPropertyEventType.getTemporalOverlapType(contextName, overlapSpec, servicesContext.getEventAdapterService());
        ContextPropertyRegistry contextProperties = new ContextPropertyRegistryImpl(eventTypeContextProps);
        contextDescriptor = new ContextDescriptor(contextName, false, contextProperties, resourceRegistryFactory, this);
        contextStateServiceBinding = contextStateService.getBinding(eventTypeContextProps);

        // restart
        List<ContextState> contextStates = contextStateService.getContexts(contextName, contextStateServiceBinding, servicesContext.getEventAdapterService());
        for (ContextState contextState : contextStates) {
            int instanceId = contextState.getAgentInstanceId();

            ContextPlusSchedule context = (ContextPlusSchedule) contextState.getAdditionalInfo();
            agentInstances.put(instanceId, context);
        }
    }

    public ContextDescriptor getContextDescriptor() {
        return contextDescriptor;
    }

    public synchronized Iterator<EventBean> iterator(String statementId) {
        Set<AgentInstance> list = statementInstances.get(statementId);
        if (list == null) {
            return CollectionUtil.NULL_EVENT_ITERATOR;
        }
        AgentInstance[] instances = list.toArray(new AgentInstance[list.size()]);
        return new AgentInstanceArrayIterator(instances);
    }

    public synchronized SafeIterator<EventBean> safeIterator(String statementId) {
        Set<AgentInstance> list = statementInstances.get(statementId);
        if (list == null) {
            return SafeIteratorNull.NULL_EVENT_ITER;
        }
        AgentInstance[] instances = list.toArray(new AgentInstance[list.size()]);
        return new AgentInstanceArraySafeIterator(instances);
    }

    public synchronized void addStatement(ContextManagedStatementBase statement) throws ExprValidationException {
        if (statements.isEmpty()) {
            activate();
        }
        statements.put(statement.getStatementContext().getStatementId(), statement);

        Set<AgentInstance> instanceList = new LinkedHashSet<AgentInstance>();
        statementInstances.put(statement.getStatementContext().getStatementId(), instanceList);

        // retro-actively create contexts for that statement
        for (Map.Entry<Integer, ContextPlusSchedule> entry : agentInstances.entrySet()) {
            Integer agentInstanceId = entry.getKey();
            ContextPlusSchedule scheduleAndContext = entry.getValue();

            AgentInstance result = startAgentInstance(statement, agentInstanceId, scheduleAndContext.getContextEvent());
            instanceList.add(result);

            // schedule a termination callback unless it is already scheduled
            if (scheduleAndContext.getContextScheduleCallbackHandle() == null) {
                ScheduleSlot scheduleSlot = createContextContext.getStatementContext().getScheduleBucket().allocateSlot();
                long timeOffset = servicesContext.getSchedulingService().getTime() - scheduleAndContext.getStartTime();
                EPStatementHandleCallback callback = scheduleCallback(agentInstanceId, scheduleSlot, timeOffset);
                scheduleAndContext.setContextScheduleCallbackHandle(callback, scheduleSlot);
            }
        }
    }

    public synchronized void stopStatement(String statementName, String statementId) {
        removeStatement(statementId);
    }

    public synchronized void destroyStatement(String statementName, String statementId) {
        removeStatement(statementId);
        if (statements.isEmpty()) {
            safeDestroy();
        }
    }

    public synchronized void safeDestroy() {
        deactivate();
    }

    public synchronized void matchFound(Map<String, Object> matchEvent) {
        processMatchFound(matchEvent, null);
    }

    private void activate() {
        if (overlapSpec.getInitiatedPattern() != null) {
            if (patternStopCallback != null) {
                patternStopCallback.stop();
            }

            PatternContext patternContext = new PatternContext(createContextContext.getStatementContext(), 0);

            EvalRootFactoryNode rootFactoryNode = servicesContext.getPatternNodeFactory().makeRootNode();
            rootFactoryNode.addChildNode(overlapSpec.getInitiatedPatternCompiled().getEvalFactoryNode());

            PatternAgentInstanceContext patternAgentInstanceContext = createContextContext.getStatementContext().getPatternContextFactory().createPatternAgentContext(patternContext, createContextContext, false);
            EvalRootNode rootNode = EvalNodeUtil.makeRootNodeFromFactory(rootFactoryNode, patternAgentInstanceContext);

            patternStopCallback = rootNode.start(this, patternContext);
        }
        else {
            FilterHandleCallback filterCallback = new FilterHandleCallback() {
                public String getStatementId() {
                    return createContextContext.getStatementContext().getStatementId();
                }

                public void matchFound(EventBean event, Collection<FilterHandleCallback> allStmtMatches) {
                    filterMatchFound(event);
                }

                public boolean isSubSelect() {
                    return false;
                }
            };
            filterHandle = new EPStatementHandleCallback(createContextContext.getEpStatementAgentInstanceHandle(), filterCallback);
            FilterValueSet filterValueSet = overlapSpec.getInitiatedFilterCompiled().getValueSet(null, null, null);
            servicesContext.getFilterService().add(filterValueSet, filterHandle);
        }
    }

    private void filterMatchFound(EventBean event) {
        processMatchFound(null, event);
    }

    private void processMatchFound(Map<String, Object> patternData, EventBean filterEvent) {

        if (statements.isEmpty()) {
            return;
        }

        int agentInstanceId = nextId(agentInstances);

        // determine context properties
        EventBean context = ContextPropertyEventType.getTempOverlapBean(servicesContext.getEventAdapterService(), contextDescriptor.getContextPropertyRegistry().getContextEventType(), contextName, agentInstanceId, patternData, filterEvent, overlapSpec.getInitiatedFilterAsName());

        // save id - for statements to be added
        ContextPlusSchedule scheduleAndContext = new ContextPlusSchedule(context, servicesContext.getSchedulingService().getTime());
        agentInstances.put(agentInstanceId, scheduleAndContext);

        // save state if required
        contextStateService.addContext(contextName, agentInstanceId, scheduleAndContext, contextStateServiceBinding);

        // schedule callback, save for removal
        ScheduleSlot scheduleSlot = createContextContext.getStatementContext().getScheduleBucket().allocateSlot();
        EPStatementHandleCallback scheduleHandle = scheduleCallback(agentInstanceId, scheduleSlot, 0);
        scheduleAndContext.setContextScheduleCallbackHandle(scheduleHandle, scheduleSlot);

        // for all current statements, start an instance
        for (ContextManagedStatementBase statement : statements.values()) {

            // obtain existing instances
            Set<AgentInstance> instanceList = statementInstances.get(statement.getStatementContext().getStatementId());
            if (instanceList == null) {
                instanceList = new LinkedHashSet<AgentInstance>();
                statementInstances.put(statement.getStatementContext().getStatementId(), instanceList);
            }

            // start
            AgentInstance ai = startAgentInstance(statement, agentInstanceId, context);

            // evaluate this event specifically for this statement
            // evaluate that event for that new agent instance
            if (filterEvent != null) {
                StatementAgentInstanceUtil.evaluateEventForStatement(servicesContext, createContextContext, filterEvent, ai.getAgentInstanceContext());
            }

            instanceList.add(ai);
        }
    }

    private AgentInstance startAgentInstance(ContextManagedStatementBase statement, int agentInstanceId, EventBean contextBean) {
        StatementAgentInstanceFactoryResult result = StatementAgentInstanceUtil.start(servicesContext, statement, false, agentInstanceId, contextBean, AgentInstanceFilterProxyNull.AGENT_INSTANCE_FILTER_PROXY_NULL);
        return new AgentInstance(result.getStopCallback(), result.getAgentInstanceContext(), result.getFinalView());
    }

    private void deactivate() {
        if (patternStopCallback != null) {
            patternStopCallback.stop();
            patternStopCallback = null;
        }
        if (filterHandle != null) {
            servicesContext.getFilterService().remove(filterHandle);
            filterHandle = null;
        }

        for (Map.Entry<Integer, ContextPlusSchedule> entry : agentInstances.entrySet()) {
            if (entry.getValue().getContextScheduleCallbackHandle() != null) {
                servicesContext.getSchedulingService().remove(entry.getValue().getContextScheduleCallbackHandle(), entry.getValue().getScheduleSlot());
            }
        }
        agentInstances.clear();
    }

    private void removeStatement(String statementId) {
        Set<AgentInstance> instanceList = statementInstances.get(statementId);
        if (instanceList != null) {
            for (AgentInstance entry : instanceList) {
                StatementAgentInstanceUtil.stop(entry.getStopCallback(), entry.getAgentInstanceContext(), entry.getFinalView(), servicesContext);
            }
        }

        statementInstances.remove(statementId);
        statements.remove(statementId);
        if (statements.isEmpty()) {
            agentInstances.clear();
        }
    }

    private static int nextId(TreeMap<Integer, ContextPlusSchedule> instanceIds) {
        if (instanceIds.isEmpty()) {
            return 0;
        }
        if (instanceIds.lastKey() == (instanceIds.size() - 1)) {
            return instanceIds.lastKey() + 1;
        }
        for (int i = 0; i < instanceIds.size(); i++) {
            if (instanceIds.containsKey(i)) {
                continue;
            }
            return i;
        }
        return instanceIds.lastKey() + 1;
    }

    private EPStatementHandleCallback scheduleCallback(final int agentInstanceId, ScheduleSlot scheduleSlot, long timeOffset) {

        ScheduleHandleCallback callback = new ScheduleHandleCallback() {
            public void scheduledTrigger(ExtensionServicesContext extensionServicesContext) {
                stopAgentInstanceCallback(agentInstanceId);
            }
        };

        // callback for expiry
        EPStatementAgentInstanceHandle agentHandle = new EPStatementAgentInstanceHandle(createContextContext.getStatementContext().getEpStatementHandle(), createContextContext.getStatementContext().getDefaultAgentInstanceLock(), null, new StatementAgentInstanceFilterVersion());
        EPStatementHandleCallback contextScheduleCallbackHandle = new EPStatementHandleCallback(agentHandle, callback);
        Double interval = (Double) overlapSpec.getTerminatedTimePeriod().evaluate(null, true, createContextContext);
        if (interval == null) {
            log.warn("Time period expression in context '" + contextName + "' returned a null value, not scheduling time period");
        }
        else {
            long msec = (long) (interval * 1000L) - timeOffset;
            servicesContext.getSchedulingService().add(msec, contextScheduleCallbackHandle, scheduleSlot);
        }

        return contextScheduleCallbackHandle;
    }

    private void stopAgentInstanceCallback(int agentInstanceId) {
        for (Map.Entry<String, Set<AgentInstance>> entry : statementInstances.entrySet()) {
            Iterator<AgentInstance> agentInstanceIterator = entry.getValue().iterator();
            for (;agentInstanceIterator.hasNext();) {
                AgentInstance agentInstance = agentInstanceIterator.next();
                if (agentInstance.getAgentInstanceContext().getAgentInstanceIds()[0] != agentInstanceId) {
                    continue;
                }

                agentInstanceIterator.remove();

                StatementAgentInstanceUtil.stop(agentInstance.getStopCallback(), agentInstance.getAgentInstanceContext(), agentInstance.getFinalView(), servicesContext);
            }
        }

        agentInstances.remove(agentInstanceId);
        contextStateService.removeContextAgentInstance(contextName, agentInstanceId);
    }


    public static class ContextPlusSchedule {
        private final EventBean contextEvent;
        private final long startTime;
        private EPStatementHandleCallback contextScheduleCallbackHandle;
        private ScheduleSlot scheduleSlot;

        public ContextPlusSchedule(EventBean contextEvent, long startTime) {
            this.contextEvent = contextEvent;
            this.startTime = startTime;
        }

        public EventBean getContextEvent() {
            return contextEvent;
        }

        public EPStatementHandleCallback getContextScheduleCallbackHandle() {
            return contextScheduleCallbackHandle;
        }

        public void setContextScheduleCallbackHandle(EPStatementHandleCallback contextScheduleCallbackHandle, ScheduleSlot scheduleSlot) {
            this.contextScheduleCallbackHandle = contextScheduleCallbackHandle;
            this.scheduleSlot = scheduleSlot;
        }

        public ScheduleSlot getScheduleSlot() {
            return scheduleSlot;
        }

        public long getStartTime() {
            return startTime;
        }
    }
}
TOP

Related Classes of com.espertech.esper.core.context.mgr.ContextManagerTemporalOverlap$ContextPlusSchedule

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.