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

com.cinchapi.concourse.server.plugin.RealTimePlugin Maven / Gradle / Ivy

/*
 * Copyright (c) 2013-2017 Cinchapi Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.cinchapi.concourse.server.plugin;

import java.nio.ByteBuffer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.cinchapi.common.reflect.Reflection;
import com.cinchapi.concourse.annotate.PackagePrivate;
import com.cinchapi.concourse.server.plugin.io.InterProcessCommunication;
import com.cinchapi.concourse.server.plugin.io.MessageQueue;

/**
 * A special {@link Plugin} that receives {@link Packet packets} of data for
 * real time {@link #handlePacket(Packet) processing}.
 * 
 * @author Jeff Nelson
 */
@PackagePrivate
abstract class RealTimePlugin extends Plugin {

    /**
     * The name of the fromServer attribute that contains the location of this
     * Plugin's real time stream.
     */
    final static String STREAM_ATTRIBUTE = "stream";

    /**
     * Construct a new instance.
     * 
     * @param station
     * @param notifier
     */
    public RealTimePlugin(String fromServer, String fromPlugin) {
        super(fromServer, fromPlugin);
    }

    /**
     * An {@link Executor} that contains worker threads to handle {@link Packet
     * packets} of data that is streamed to this plugin in real time.
     */
    private final ExecutorService workers = Executors.newCachedThreadPool();

    @Override
    public final void run() {
        Reflection.call(this, "setReadyState");
        // For a RealTimePlugin, the first fromServer message contains the
        // address for the stream channel
        ByteBuffer data = fromServer.read();
        RemoteMessage message = serializer.deserialize(data);
        if(message.type() == RemoteMessage.Type.ATTRIBUTE) {
            RemoteAttributeExchange attribute = (RemoteAttributeExchange) message;
            if(attribute.key().equalsIgnoreCase(STREAM_ATTRIBUTE)) {
                log.debug("Listening for streamed packets at {}",
                        attribute.value());
                @SuppressWarnings("resource") final InterProcessCommunication stream = new MessageQueue(
                        attribute.value());
                // Create a separate event loop to process Packets of writes
                // that come from the server.
                Thread loop = new Thread(() -> {
                    ByteBuffer bytes = null;
                    while ((bytes = stream.read()) != null) {
                        final Packet packet = serializer.deserialize(bytes);

                        // Each packet should be processed in a separate
                        // worker thread
                        workers.execute(() -> {
                            log.debug(
                                    "Received packet from Concourse Server: {}",
                                    packet);
                            handlePacket(packet);
                        });
                    }
                });
                loop.setDaemon(true);
                loop.start();

                // Start normal plugin operations
                super.run();
            }
            else {
                throw new IllegalStateException(
                        "Unsupported attribute " + attribute);
            }
        }
        else {
            throw new IllegalStateException();
        }
    }

    /**
     * Process a {@link Packet} that is streamed from the server.
     * 

* This method is called asynchronously by the parent class, so the subclass * doesn't need to fork the implementation to a separate thread. *

* * @param packet a {@link Packet} that contains one or more * {@link Packet.Data} objects. */ protected abstract void handlePacket(Packet packet); }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy