eu.planets_project.tb.impl.AdminManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for eu.planets_project.tb.impl.AdminManagerImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2010 The Planets Project Partners.
 *
 * All rights reserved. This program and the accompanying 
 * materials are made available under the terms of the 
 * Apache License, Version 2.0 which accompanies 
 * this distribution, and is available at 
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *******************************************************************************/
/**
 * 
 */
package eu.planets_project.tb.impl;

import java.io.StringWriter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.VelocityException;

import eu.planets_project.ifr.core.common.conf.PlanetsServerConfig;
import eu.planets_project.ifr.core.common.mail.PlanetsMailMessage;
import eu.planets_project.ifr.core.security.api.model.User;

import eu.planets_project.tb.api.AdminManager;
import eu.planets_project.tb.api.TestbedManager;
import eu.planets_project.tb.api.model.Experiment;
import eu.planets_project.tb.api.model.ExperimentPhase;
import eu.planets_project.tb.api.model.ExperimentSetup;
import eu.planets_project.tb.gui.UserBean;
import eu.planets_project.tb.gui.util.JSFUtil;
import eu.planets_project.tb.impl.system.BackendProperties;

/**
 * @author alindley
 *
 */
public class AdminManagerImpl implements AdminManager {
    private static Log log = LogFactory.getLog(AdminManagerImpl.class);

    private static AdminManagerImpl instance;

    public static final String IDENTIFY = "identify";
    public static final String VALIDATE = "validate";
    public static final String CHARACTERISE = "characterise";
    public static final String MIGRATE = "migrate";
    public static final String EMULATE = "emulate";
    public static final String EXECUTABLEPP = "executablepp";

    //e.g. key:"identify" -> "Identify"
    private static HashMap<String, String> hmExperimentTypes;
    // No longer read from XML, by statically coded:
    static {
        hmExperimentTypes = new HashMap<String, String>();
        //hmExperimentTypes.put(IDENTIFY, "Identify");
        hmExperimentTypes.put(MIGRATE, "Migrate");
        //hmExperimentTypes.put(VALIDATE, "Validate");
        //hmExperimentTypes.put(CHARACTERISE, "Characterise");
        hmExperimentTypes.put(EMULATE, "View in Emulator");
        hmExperimentTypes.put(EXECUTABLEPP, "Executable Preservation Plan");
    }

    private static HashMap<String, String> hmOldExperimentTypes;
    static {
        hmOldExperimentTypes = new HashMap<String, String>();
        hmOldExperimentTypes.put("experimentType.simpleMigration", "simple migration");
        hmOldExperimentTypes.put("experimentType.simpleCharacterisation", "simple characterisation");
    }

    private AdminManagerImpl() {
        // Also read basic properties:
        BackendProperties bp = new BackendProperties();
        APPROVAL_THRESHOLD_NUMBER_OF_INPUTS = bp.getExpAdminNoInputs();
        log.info("Set number of inputs before admin approval required at: " + APPROVAL_THRESHOLD_NUMBER_OF_INPUTS);
    }

    /**
     * This class is implemented following the Java Singleton Pattern.
     * Use this method to retrieve the instance of this class.
     * @return
     */
    public static synchronized AdminManagerImpl getInstance() {
        if (instance == null) {
            instance = new AdminManagerImpl();
        }
        return instance;
    }

    /* ----------------------------------------------------------- */

    public Collection<String> getExperimentTypeIDs() {
        return hmExperimentTypes.keySet();
    }

    public Collection<String> getExperimentTypesNames() {
        return hmExperimentTypes.values();
    }

    public Map<String, String> getExperimentTypeIDsandNames() {
        return hmExperimentTypes;
    }

    public String getExperimentTypeID(String expTypeName) {
        if (hmExperimentTypes.containsValue(expTypeName)) {
            return getKeyFromHashMap(expTypeName, hmExperimentTypes);
        }
        if (hmOldExperimentTypes.containsValue(expTypeName)) {
            return getKeyFromHashMap(expTypeName, hmOldExperimentTypes);
        }
        return null;
    }

    public String getExperimentTypeName(String typeID) {
        if (hmExperimentTypes.containsKey(typeID)) {
            return hmExperimentTypes.get(typeID);
        }
        if (hmOldExperimentTypes.containsKey(typeID)) {
            return hmOldExperimentTypes.get(typeID);
        }
        return null;
    }

    private String getKeyFromHashMap(String expTypeName, HashMap<String, String> experimentTypes) {
        Iterator<String> itKeys = experimentTypes.keySet().iterator();
        while (itKeys.hasNext()) {
            String sKey = itKeys.next();
            if (experimentTypes.get(sKey).equals(expTypeName)) {
                return sKey;
            }
        }
        return null;
    }

    /**
     * @param etype
     * @return
     */
    public boolean isDeprecated(String typeID) {
        if (hmOldExperimentTypes.containsKey(typeID)) {
            return true;
        }
        return false;
    }

    /**
     * Code for Experiment Approval:
     */

    /**
     * Threshold for the number of inputs before approval is required.
     * Can be overridden from BackendProperties. See constructor.
     */
    public static int APPROVAL_THRESHOLD_NUMBER_OF_INPUTS = 0;

    /**
     * Decision flags:
     */
    public static final String APPROVAL_DECISION_AWAITING = null;
    public static final String APPROVAL_DECISION_APPROVED = "Approved";
    public static final String APPROVAL_DECISION_DENIED = "Denied";
    public static final String APPROVAL_AUTOMATIC_USER = "{automatic}";

    /**
     * Does this experiment require administrator approval?
     * @param exp The Experiment to evaluate.
     * @return TRUE if experimental approval is required to execute it, false in all other cases.
     */
    public static boolean experimentRequiresApproval(Experiment exp) {
        if (exp == null)
            return false;
        if (exp.getExperimentExecutable() == null)
            return false;

        // Go thru reasons for requiring approval:
        if (exp.getExperimentExecutable().getInputData() != null
                && exp.getExperimentExecutable().getInputData().size() > APPROVAL_THRESHOLD_NUMBER_OF_INPUTS) {
            // Requires Approval:
            return true;
        }
        // Otherwise, approve the experiment:
        return false;
    }

    public static void requestExperimentApproval(Experiment exp) {
        // Check if approval is require:
        if (!experimentRequiresApproval(exp))
            return;

        // Store the 'Asking for approval' status as a NULL decision:
        exp.getExperimentApproval().setDecision(APPROVAL_DECISION_AWAITING);

        TestbedManager testbedMan = (TestbedManager) JSFUtil.getManagedObject("TestbedManager");
        testbedMan.updateExperiment(exp);

        // Mail the administrator:
        sendApprovalRequest(exp);
        log.info("The experiment '" + exp.getExperimentSetup().getBasicProperties().getExperimentName()
                + "' requires administrator approval.");
    }

    public static void approveExperimentAutomatically(Experiment exp) {
        if (exp == null)
            return;
        if (exp.getExperimentExecutable() == null)
            ;

        exp.getExperimentApproval().setExplanation("Experiment was approved automatically.");
        exp.getExperimentApproval().setDecision(APPROVAL_DECISION_APPROVED);
        exp.getExperimentApproval().setGo(true);
        exp.getExperimentApproval().setState(Experiment.STATE_COMPLETED);
        exp.getExperimentExecution().setState(Experiment.STATE_IN_PROGRESS);
        exp.getExperimentApproval().addApprovalUser(APPROVAL_AUTOMATIC_USER);

        TestbedManager testbedMan = (TestbedManager) JSFUtil.getManagedObject("TestbedManager");
        testbedMan.updateExperiment(exp);

        log.info("The experiment '" + exp.getExperimentSetup().getBasicProperties().getExperimentName()
                + "' was automaticallu approved for execution.");
    }

    public static void approveExperimentManually(Experiment exp) {
        if (exp == null)
            return;
        if (exp.getExperimentExecutable() == null)
            return;

        // Find out who is responsible:
        UserBean currentUser = (UserBean) JSFUtil.getManagedObject("UserBean");

        // Approve it
        if (exp.getExperimentApproval().getExplanation() == null
                || "".equals(exp.getExperimentApproval().getExplanation()))
            exp.getExperimentApproval().setExplanation("Experiment was approved for execution.");
        exp.getExperimentApproval().setDecision(APPROVAL_DECISION_APPROVED);
        exp.getExperimentApproval().setGo(true);
        exp.getExperimentApproval().addApprovalUser(currentUser.getUserid());
        exp.getExperimentApproval().setState(Experiment.STATE_COMPLETED);
        exp.getExperimentExecution().setState(Experiment.STATE_IN_PROGRESS);

        TestbedManager testbedMan = (TestbedManager) JSFUtil.getManagedObject("TestbedManager");
        testbedMan.updateExperiment(exp);

        // Mail the user:
        sendApprovalNotice(exp);
        log.info("The experiment '" + exp.getExperimentSetup().getBasicProperties().getExperimentName()
                + "' was approved for execution.");
    }

    public static void denyExperimentManually(Experiment exp) {
        if (exp == null)
            return;
        if (exp.getExperimentExecutable() == null)
            return;

        // Find out who is responsible:
        UserBean currentUser = (UserBean) JSFUtil.getManagedObject("UserBean");

        // Deny approval
        if (exp.getExperimentApproval().getExplanation() == null
                || "".equals(exp.getExperimentApproval().getExplanation()))
            exp.getExperimentApproval().setExplanation("Experiment was denied approval for execution.");
        exp.getExperimentApproval().setDecision(APPROVAL_DECISION_DENIED);
        exp.getExperimentApproval().setGo(false);
        exp.getExperimentApproval().addApprovalUser(currentUser.getUserid());

        TestbedManager testbedMan = (TestbedManager) JSFUtil.getManagedObject("TestbedManager");
        testbedMan.updateExperiment(exp);

        // Mail the user:
        sendDenialNotice(exp);
        log.info("The experiment '" + exp.getExperimentSetup().getBasicProperties().getExperimentName()
                + "' was denied approval for execution.");
    }

    public static boolean experimentAwaitingApproval(Experiment exp) {
        if (exp.getCurrentPhasePointer() != ExperimentPhase.PHASE_EXPERIMENTAPPROVAL)
            return false;
        if (exp.getExperimentApproval().getDecision() == null)
            return true;
        if ("".equals(exp.getExperimentApproval().getDecision()))
            return true;
        return false;
    }

    public static boolean experimentWasApproved(Experiment exp) {
        if (exp.getCurrentPhasePointer() <= ExperimentPhase.PHASE_EXPERIMENTAPPROVAL)
            return false;
        if (APPROVAL_DECISION_APPROVED.equals(exp.getExperimentApproval().getDecision()))
            return true;
        return false;
    }

    public static boolean experimentWasDenied(Experiment exp) {
        if (exp.getCurrentPhasePointer() != ExperimentPhase.PHASE_EXPERIMENTAPPROVAL)
            return false;
        return !experimentWasApproved(exp);
    }

    public static void toEditFromDenied(Experiment exp) {
        if (exp == null)
            return;
        if (exp.getExperimentExecutable() == null)
            ;

        exp.getExperimentApproval().setExplanation("");
        exp.getExperimentApproval().setDecision("");
        exp.getExperimentApproval().setGo(false);
        exp.getExperimentSetup().setState(Experiment.STATE_IN_PROGRESS);
        exp.getExperimentSetup().setSubStage(ExperimentSetup.SUBSTAGE3);
        exp.getExperimentApproval().setState(Experiment.STATE_NOT_STARTED);
        exp.getExperimentExecution().setState(Experiment.STATE_NOT_STARTED);
        List<String> approvalUsers = exp.getExperimentApproval().getApprovalUsersIDs();
        // Need to clone to avoid a 'java.util.ConcurrentModificationException':
        List<String> usersToRemove = new ArrayList<String>();
        for (String user : approvalUsers)
            usersToRemove.add(user);
        exp.getExperimentApproval().removeApprovalUsers(usersToRemove);

        TestbedManager testbedMan = (TestbedManager) JSFUtil.getManagedObject("TestbedManager");
        testbedMan.updateExperiment(exp);

        log.info("The experiment '" + exp.getExperimentSetup().getBasicProperties().getExperimentName()
                + "' was made editable again.");
    }

    /**
     * Code for emails related to Approval.
     * 
     */
    private static void sendNotification(String username, String templateName, Experiment exp) {

        VelocityEngine velocityEngine = new VelocityEngine();
        Properties props = new Properties();
        props.setProperty("resource.loader", "class");
        props.setProperty("class.resource.loader.class",
                "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        props.setProperty("velocimacro.library", "");
        try {
            velocityEngine.init(props);
        } catch (Exception e) {
            log.error("Failed to initialise the Velocity engine. :: " + e);
        }

        // Look up the user.
        User user = UserBean.getUser(username);
        if (user == null)
            return;

        // Create a message:
        PlanetsMailMessage message = new PlanetsMailMessage();

        // Add the recipient in properly.
        message.addRecipient(user.getFullName() + "<" + user.getEmail() + ">");

        // Determine the Testbed URL:
        // FIXME This is a HACK for the TB Service URL in emails:
        String testbedURL = "http://testbed.planets-project.eu/testbed/";
        //        String testbedURL = "http://"+AdminManagerImpl.getAuthority()+"/testbed/";

        Map<String, Object> model = new HashMap<String, Object>();
        model.put("user", user);
        model.put("exp", exp);
        model.put("expName", exp.getExperimentSetup().getBasicProperties().getExperimentName());
        model.put("applicationURL", testbedURL);

        VelocityContext velocityContext;
        StringWriter result = new StringWriter();
        try {
            velocityContext = new VelocityContext(model);
            velocityEngine.mergeTemplate("eu/planets_project/tb/" + templateName + ".vm", velocityContext, result);
        } catch (VelocityException ex) {
            log.error("Mailing failed! :: " + ex);
            return;
        } catch (RuntimeException ex) {
            log.error("Mailing failed! :: " + ex);
            return;
        } catch (Exception ex) {
            log.error("Mailing failed! :: " + ex);
            return;
        }
        message.setSubject(velocityContext.get("subject").toString());
        message.setBody(result.toString());

        try {
            message.send();
        } catch (Exception e) {
            log.error("An error occured while trying to send an email to " + user.getFullName() + "! :: " + e);
            e.printStackTrace();
        }
    }

    private static void sendApprovalRequest(Experiment exp) {
        sendNotification("admin", "RequestApproval", exp);
    }

    private static void sendApprovalNotice(Experiment exp) {
        if (exp.getExperimentSetup().getBasicProperties().getInvolvedUserIds() == null)
            return;
        String username = exp.getExperimentSetup().getBasicProperties().getInvolvedUserIds().get(0);
        if (username == null)
            return;
        sendNotification(username, "ApprovalGranted", exp);
    }

    private static void sendDenialNotice(Experiment exp) {
        if (exp.getExperimentSetup().getBasicProperties().getInvolvedUserIds() == null)
            return;
        String username = exp.getExperimentSetup().getBasicProperties().getInvolvedUserIds().get(0);
        if (username == null)
            return;
        sendNotification(username, "ApprovalDenied", exp);
    }

    /**
     * Helper function that looks up the actual authority for this server.
     * Could also be done via the DR I think.
     * @return The authority in the form 'server:port'.
     */
    public static String getAuthority() {
        return PlanetsServerConfig.getHostname() + ":" + PlanetsServerConfig.getPort();
    }

    /**
     * @param selectedExperiment
     * @return
     */
    public static boolean isExperimentDeprecated(Experiment exp) {
        log.info("Checking if " + exp.getExperimentSetup().getExperimentTypeID() + " is a deprecated type");
        if (AdminManagerImpl.hmOldExperimentTypes.containsKey(exp.getExperimentSetup().getExperimentTypeID())) {
            return true;
        }
        return false;
    }

}