001/*
002 * JGrapes Event Driven Framework
003 * Copyright (C) 2016-2018 Michael N. Lipp
004 * 
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Affero General Public License as published by 
007 * the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 * 
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
013 * for more details.
014 * 
015 * You should have received a copy of the GNU Affero General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jgrapes.core.internal;
020
021import java.util.concurrent.ExecutorService;
022
023import org.jgrapes.core.Channel;
024import org.jgrapes.core.Components;
025import org.jgrapes.core.Event;
026import org.jgrapes.core.events.Start;
027
028/**
029 * The buffering event pipeline is used before a tree has been started. 
030 * It simply buffers all events until a {@link Start} event is added.
031 */
032public class BufferingEventPipeline implements InternalEventPipeline {
033
034    private final ComponentTree componentTree;
035    /** Buffered events. */
036    private EventQueue buffered = new EventQueue();
037    /** The event pipeline that we delegate to after the start
038     * event has been detected. */
039    private InternalEventPipeline activePipeline;
040
041    /**
042     * Instantiates a new buffering event pipeline.
043     *
044     * @param componentTree the component tree
045     */
046    /* default */ BufferingEventPipeline(ComponentTree componentTree) {
047        super();
048        this.componentTree = componentTree;
049    }
050
051    @Override
052    public void merge(InternalEventPipeline other) {
053        synchronized (this) {
054            if (!(other instanceof BufferingEventPipeline)) {
055                throw new IllegalArgumentException(
056                    "Can only merge events from an BufferingEventPipeline.");
057            }
058            buffered.addAll(((BufferingEventPipeline) other).retrieveEvents());
059        }
060    }
061
062    @Override
063    public <T extends Event<?>> T add(T event, Channel... channels) {
064        synchronized (this) {
065            // If thread1 adds the start event and thread2 gets here before we
066            // have changed the event processor for the tree, forward the
067            // event to the event processor that should already have been used.
068            if (activePipeline != null) {
069                activePipeline.add(event, channels);
070                return event;
071            }
072            // Invoke although argument is null!
073            ((EventBase<?>) event).generatedBy(null);
074            buffered.add(event, channels);
075            if (event instanceof Start) {
076                // Merge all events into a "standard" event processor
077                // and set it as default processor for the tree (with
078                // any thread specific pipelines taking precedence).
079                EventProcessor processor = new EventProcessor(componentTree);
080                activePipeline
081                    = new FeedBackPipelineFilter(componentTree, processor);
082                componentTree.setEventPipeline(activePipeline);
083                processor.add(buffered);
084            }
085            return event;
086        }
087    }
088
089    /* default */ EventQueue retrieveEvents() {
090        synchronized (this) {
091            EventQueue old = buffered;
092            buffered = new EventQueue();
093            return old;
094        }
095    }
096
097    /*
098     * (non-Javadoc)
099     * 
100     * @see org.jgrapes.core.internal.InternalEventPipeline#executorService()
101     */
102    @Override
103    public ExecutorService executorService() {
104        return Components.defaultExecutorService();
105    }
106
107    /*
108     * (non-Javadoc)
109     * 
110     * @see java.lang.Object#toString()
111     */
112    @Override
113    public String toString() {
114        StringBuilder builder = new StringBuilder(50);
115        builder.append("BufferingEventPipeline [");
116        if (buffered != null) {
117            builder.append("buffered=");
118            builder.append(buffered);
119        }
120        builder.append(']');
121        return builder.toString();
122    }
123}