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

com.freedomotic.api.Plugin Maven / Gradle / Ivy

/**
 *
 * Copyright (c) 2009-2014 Freedomotic team http://freedomotic.com
 *
 * This file is part of Freedomotic
 *
 * This Program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2, or (at your option) any later version.
 *
 * This Program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * Freedomotic; see the file COPYING. If not, see
 * .
 */
package com.freedomotic.api;

import com.freedomotic.exceptions.PluginShutdownException;
import com.freedomotic.exceptions.PluginStartupException;
import com.freedomotic.app.ConfigPersistence;
import com.freedomotic.app.Freedomotic;
import com.freedomotic.bus.BusConsumer;
import com.freedomotic.bus.BusMessagesListener;
import com.freedomotic.bus.BusService;
import com.freedomotic.events.MessageEvent;
import com.freedomotic.events.PluginHasChanged;
import com.freedomotic.events.PluginHasChanged.PluginActions;
import com.freedomotic.model.ds.Config;
import com.freedomotic.util.EqualsUtil;
import com.freedomotic.util.Info;
import com.google.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jms.ObjectMessage;
import javax.swing.JFrame;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 *
 * @author nicoletti
 */
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Plugin implements Client, BusConsumer {

    final static int SAME_VERSION = 0;
    final static int FIRST_IS_OLDER = -1;
    final static int LAST_IS_OLDER = 1;
    private static final String ACTUATORS_QUEUE_DOMAIN = "app.actuators.";
    private static final Logger LOG = Logger.getLogger(Plugin.class.getName());
    @XmlElement
    private String pluginName;
    @XmlElement
    private final String type = "Plugin";
    @XmlElement
    private volatile PluginStatus currentPluginStatus = PluginStatus.STOPPED;
    @XmlElement
    public Config configuration;
    @Deprecated
    protected JFrame gui;
    @XmlElement
    protected String description;
    @XmlElement
    protected String version;
    @XmlElement
    protected String requiredVersion;
    @XmlElement
    protected String category;
    @XmlElement
    protected String shortName;
    @XmlElement
    protected String listenOn;
    @XmlElement
    protected String sendOn;
    @XmlElement
    private File path;

    protected BusMessagesListener listener;

    @Inject
    private API api;
    @Inject
    private BusService busService;

    /**
     *
     * @param pluginName
     * @param manifestPath
     */
    public Plugin(String pluginName, String manifestPath) {
        Freedomotic.INJECTOR.injectMembers(this);
        setName(pluginName);
        path = new File(Info.PATHS.PATH_DEVICES_FOLDER + manifestPath);
        init();
    }

    /**
     * Used to create a Plugin placeholder for things
     */
    public Plugin(String pluginName) {
        Freedomotic.INJECTOR.injectMembers(this);
        setName(pluginName);
        init();
    }

    /**
     * User by JoinPlugin to instantiate a new plugin
     *
     * @param pluginName
     * @param manifest
     */
    public Plugin(String pluginName, Config manifest) {
        Freedomotic.INJECTOR.injectMembers(this);
        setName(pluginName);
        init();
    }

    /**
     *
     * @return
     */
    public File getFile() {
        return path;
    }

    /**
     *
     * @return
     */
    public API getApi() {
        return api;
    }

    /**
     *
     * @throws com.freedomotic.exceptions.PluginStartupException
     */
    protected void onStart() throws PluginStartupException {
    }

    /**
     *
     * @throws com.freedomotic.exceptions.PluginShutdownException
     */
    protected void onStop() throws PluginShutdownException {
    }

    /**
     *
     * @param description
     */
    @Override
    public final void setDescription(String description) {
        if (!getDescription().equalsIgnoreCase(description)) {
            this.description = description;

            try {
                PluginHasChanged event = new PluginHasChanged(this,
                        this.getName(),
                        PluginActions.DESCRIPTION);
                busService.send(event);
            } catch (Exception e) {
                LOG.log(Level.WARNING, "Cannot notify new plugin description for " + getName(), e);
            }
        }
    }

    public void notifyError(String message) {
        //Log the error on console/logfiles
        LOG.warning(message);
        //write something on the GUI
        MessageEvent callout = new MessageEvent(this, message);
        callout.setType("callout"); //display as callout on frontends
        callout.setLevel("warning");
        callout.setExpiration(10 * 1000);//message lasts 10 seconds
        busService.send(callout);
    }

    public void notifyCriticalError(String message) {
        //Log the error on console/logfiles
        LOG.warning(message);
        //write something on the GUI
        MessageEvent callout = new MessageEvent(this, message);
        callout.setType("callout"); //display as callout on frontends
        callout.setLevel("warning");
        callout.setExpiration(10 * 1000);//message lasts 10 seconds
        busService.send(callout);
        //stop this plugin
        stop();
        //override plugin description
        setDescription(message);
        //plugin is now set as STOPPED, but should be marked as FAILED
        currentPluginStatus = PluginStatus.FAILED;
    }

    protected void notifyCriticalError(String message, Exception ex) {
        //Log and keep stack trace
        LOG.log(Level.SEVERE, message, ex);
        notifyCriticalError(message);
    }

    /**
     *
     * @return
     */
    @Override
    public String getDescription() {
        if (description == null) {
            return getName();
        } else {
            return description;
        }
    }

    /**
     *
     * @return
     */
    @Override
    public final Config getConfiguration() {
        return configuration;
    }

    /**
     *
     * @return
     */
    public final String getReadQueue() {
        return listenOn;
    }

    /**
     *
     * @return
     */
    public final String getCategory() {
        return category;
    }

    /**
     *
     * @return
     */
    public String getRequiredVersion() {
        return requiredVersion;
    }

    /**
     *
     * @return
     */
    public String getVersion() {
        return version;
    }

    /**
     *
     * @param window
     */
    public void bindGuiToPlugin(JFrame window) {
        gui = window;
        gui.setVisible(false);
        gui.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

    /**
     *
     */
    @Override
    @Deprecated
    public void showGui() {
        if (!isRunning()) {
            start();
        }

        onShowGui();

        if (gui != null) {
            gui.setVisible(true);
        } else {
            LOG.warning("ERROR: plugin gui is null");
        }
    }

    /**
     *
     */
    @Override
    @Deprecated
    public void hideGui() {
        onHideGui();

        if (gui != null) {
            gui.setVisible(false);
        }
    }

    /**
     *
     * @return
     */
    @Override
    public String getName() {
        return pluginName;
    }

    public String getStatus() {
        return currentPluginStatus.name();
    }

    /**
     *
     * @return
     */
    @Override
    public String getType() {
        return type;
    }

    /**
     *
     * @return
     */
    @Override
    public boolean isRunning() {
        return currentPluginStatus.equals(PluginStatus.RUNNING);
    }

    public boolean isAllowedToSend() {
        return currentPluginStatus.equals(PluginStatus.STARTING) || currentPluginStatus.equals(PluginStatus.RUNNING);
    }

    public boolean isAllowedToStart() {
        return PluginStatus.isAllowedToStart(currentPluginStatus);
    }

    /**
     *
     * @return
     */
    @XmlElement(name = "uuid")
    public String getClassName() {
        return (this.getClass().getSimpleName().toLowerCase());
    }

    /**
     *
     * @param name
     */
    @Override
    public final void setName(String name) {
        pluginName = name;
    }

    protected final void setStatus(PluginStatus newStatus) {
        currentPluginStatus = newStatus;

    }

//    public boolean isConnected() {
//        return isConnected;
//    }
//
//    public void setConnected() {
//        isConnected = true;
//    }
    /**
     *
     * @param aThat
     * @return
     */
    @Override
    public boolean equals(Object aThat) {
        //check for self-comparison
        if (this == aThat) {
            return true;
        }

        //use instanceof instead of getClass here for two reasons
        //1. if need be, it can match any supertype, and not just one class;
        //2. it renders an explict check for "that == null" redundant, since
        //it does the check for null already - "null instanceof [type]" always
        //returns false. (See Effective Java by Joshua Bloch.)
        if (!(aThat instanceof Plugin)) {
            return false;
        }

        //Alternative to the above line :
        //if ( aThat == null || aThat.getClass() != this.getClass() ) return false;
        //cast to native object is now safe
        Plugin that = (Plugin) aThat;

        //now a proper field-by-field evaluation can be made
        return EqualsUtil.areEqual(this.getName().toLowerCase(),
                that.getName().toLowerCase());
    }

    /**
     *
     * @return
     */
    @Override
    public int hashCode() {
        int hash = 5;
        hash = (53 * hash) + ((this.pluginName != null) ? this.pluginName.hashCode() : 0);

        return hash;
    }

    private void init() {
        if (configuration == null) {
            //try to load it from file
            deserializeManifest(path);
        }
        description = configuration.getStringProperty("description", "Missing plugin manifest");
        setDescription(description);
        category = configuration.getStringProperty("category", "undefined");
        shortName = configuration.getStringProperty("short-name", "undefined");
        listenOn = configuration.getStringProperty("listen-on", "undefined");
        sendOn = configuration.getStringProperty("send-on", "undefined");
        register();
    }

    private void deserializeManifest(File manifest) {
        try {
            configuration = ConfigPersistence.deserialize(manifest);
        } catch (IOException ex) {
            LOG.severe("Missing manifest " + manifest.toString() + " for plugin " + getName());
            setDescription("Missing manifest file " + manifest.toString());
        }

    }

    private void register() {
        listener = new BusMessagesListener(this, getBusService());
        listener.consumeCommandFrom(getCommandsChannelToListen());
    }

    private String getCommandsChannelToListen() {
        String defaultQueue = ACTUATORS_QUEUE_DOMAIN + category + "." + shortName;
        String customizedQueue = ACTUATORS_QUEUE_DOMAIN + listenOn;

        if (getReadQueue().equalsIgnoreCase("undefined")) {
            listenOn = defaultQueue + ".in";

            return listenOn;
        } else {
            return customizedQueue;
        }
    }

    /**
     *
     */
    @Deprecated
    protected void onShowGui() {
    }

    /**
     *
     */
    @Deprecated
    protected void onHideGui() {
    }

    /**
     *
     */
    @Override
    public void start() {
        LOG.log(Level.INFO, "Starting plugin {0}", getName());
        //do not add code here
    }

    /**
     *
     */
    @Override
    public void stop() {
        LOG.log(Level.INFO, "Stopping plugin {0}", getName());
        //do not add code here
    }

    /**
     *
     * @return
     */
    @Override
    public String toString() {
        return getName();
    }

    /**
     *
     */
    public void loadPermissionsFromManifest() {
        getApi().getAuth().setPluginPrivileges(this, configuration.getStringProperty("permissions", getApi().getAuth().getPluginDefaultPermission()));
    }

    public BusService getBusService() {
        return busService;
    }

    @Override
    public void onMessage(ObjectMessage message) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void destroy() {
        stop();
        // Destroy the messaging channel
        listener.unsubscribe();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy