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

org.intellimate.izou.sdk.output.OutputPluginArgument Maven / Gradle / Ivy

package org.intellimate.izou.sdk.output;

import com.google.common.reflect.TypeToken;
import org.intellimate.izou.events.EventModel;
import org.intellimate.izou.identification.Identification;
import org.intellimate.izou.output.OutputPluginModel;
import org.intellimate.izou.resource.ResourceModel;
import org.intellimate.izou.sdk.Context;
import org.intellimate.izou.sdk.util.AddOnModule;
import org.intellimate.izou.sdk.util.ThreadPoolUser;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * The OutputPlugin class gets Event and then starts threads filled with output-extension tasks to create the final
 * output and then render it on its own medium
 * @param  the type of the Argument
 * @param  the return type
 */
@SuppressWarnings("UnusedDeclaration")
public abstract class OutputPluginArgument extends AddOnModule implements OutputPluginModel, ThreadPoolUser {

    /**
     * here are the events stored before they get processed
     */
    private final BlockingQueue eventBlockingQueue = new LinkedBlockingDeque<>();
    /**
     * the type argument for the Data you want to receive
     */
    private final TypeToken receivingTypeToken;
    /**
     * the type argument for the Data you want to give the OutputExtensions as an argument
     */
    private final TypeToken argumentTypeToken;

    /**
     * setting this boolean to true stops the while-loop
     */
    private boolean stop = false;

    /**
     * signals whether the OutputPlugin is working
     */
    private boolean isWorking = false;

    /**
     * creates a new output-plugin with a new id
     *
     * @param context context
     * @param id the id of the new output-plugin
     */
    public OutputPluginArgument(Context context, String id) {
        super(context, id);
        this.receivingTypeToken = new TypeToken(getClass()) {};
        this.argumentTypeToken = new TypeToken(getClass()) {};
    }

    /**
     * get the outputExtensionList
     *
     * @return gets the list of output-extensions in the output-plugin
     */
    public List getOutputExtensionList() {
        return getContext().getOutput().getAssociatedOutputExtension(this);
    }

    /**
     * gets the blocking-queue that stores the backlog of Events
     *
     * @return blocking-queue that stores Events
     */
    public BlockingQueue getEventBlockingQueue() {
        return eventBlockingQueue;
    }

    /**
     * callback method to notify that an OutputExtension was added
     *
     * @param identification the Identification of the OutputExtension added
     */
    @Override
    public void outputExtensionAdded(Identification identification) {}

    /**
     * callback method to notify that an OutputExtension was added
     *
     * @param identification the Identification of the OutputExtension added
     */
    @Override
    public void outputExtensionRemoved(Identification identification) {}

    /**
     * returns the Type of the one wants to receive from the OutputExtensions
     *
     * @return the type of the generic
     */
    @Override
    public TypeToken getReceivingType() {
        return receivingTypeToken;
    }

    /**
     * returns the Type of the argument for the OutputExtensions, or null if none
     *
     * @return the type of the Argument
     */
    @Override
    public TypeToken getArgumentType() {
        return argumentTypeToken;
    }

    /**
     * Adds an event to blockingQueue
     *
     * @param event the event to add
     * @throws IllegalStateException raised if problems adding an event to blockingQueue
     */
    @Override
    public void addToEventList(EventModel event) {
        eventBlockingQueue.add(event);
    }

    @Override
    public boolean isRunning() {
        return isWorking;
    }

    @Override
    public void stop() {
        Thread.currentThread().interrupt();
    }

    /**
     * @param event the current processed Event
     */
    public void isDone(EventModel event) {
        Optional resource = event.getListResourceContainer().provideResource(getID()).stream()
                .filter(resourceS -> resourceS.getProvider().getID()
                        .equals(getContext().getOutput().getManagerIdentification().getID()))
                .findFirst();
        if(!resource.isPresent()) return;
        if(resource.get().getResource() instanceof Consumer) {
            Consumer consumer = (Consumer) resource.get().getResource();
            //noinspection unchecked
            consumer.accept(null);
        }
    }

    /**
     * terminates the outputPlugin (will not listen to events anymore)
     */
    public void terminate() {
        stop = true;
        eventBlockingQueue.notify();
    }

    public void handleFutures(List> futures, EventModel eventModel) {
        List result = futures.stream()
                .map(future -> {
                    try {
                        return future.get();
                    } catch (InterruptedException e) {
                        getContext().getLogger().error("interrupted", e);
                        throw new RuntimeException(e);
                    } catch (ExecutionException e) {
                        getContext().getLogger().error("future finished exceptionally", e);
                        return null;
                    }
                })
                .collect(Collectors.toList());
        isWorking = true;
        renderFinalOutput(result, eventModel);
        isWorking = false;
    }

    /**
     * main method for outputPlugin, runs the data-conversion and output-renderer
     *
     * it will instruct the outputManager to let the outputExtensions generate the data. Wait for the time specified
     * in getTimeoutLimit() (standard is 1000 milliseconds) abd the call renderFinalOutput() with the resulting data.
     */
    @Override
    public void run() {
        while (!stop) {
            EventModel event;
            try {
                event = blockingQueueHandling();  //gets the new Event if one was added to the blockingQueue
            } catch (InterruptedException e) {
                getContext().getLogger().warn(e);
                continue;
            }

            List> outputExtensions = getContext().getOutput()
                    .generateAllOutputExtensions(this, getArgument(), event);

            try {
                outputExtensions = timeOut(outputExtensions, getTimeoutLimit());
            } catch (InterruptedException e) {
                getContext().getLogger().warn(e);
            }

            handleFutures(outputExtensions, event);

            //notifies output-manager when done processing
            isDone(event);
        }
    }

    /**
     * Default implementation waits until a new Event has been received and then processes it.
     *
     * This method is made to be overwritten as seen fit by the developer
     *
     * @throws InterruptedException if interrupted while waiting
     * @return the recently added Event-instance to be processed by the outputPlugin
     */
    public EventModel blockingQueueHandling() throws InterruptedException {
        return eventBlockingQueue.take();
    }

    /**
     * gets the timeout-limit in Milliseconds
     * @return timeout in milliseconds
     */
    public int getTimeoutLimit() {
        return 1000;
    }

    /**
     * method that uses tDoneList to generate a final output that will then be rendered.
     * @param data the data generated
     * @param eventModel the Event which caused the whole thing
     */
    public abstract void renderFinalOutput(List data, EventModel eventModel);

    /**
     * returns the argument for the OutputExtensions
     * @return the argument
     */
    public abstract T getArgument();
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy