Package eu.planets_project.pp.plato.action.project

Source Code of eu.planets_project.pp.plato.action.project.LoadPlanAction

/*******************************************************************************
* Copyright (c) 2006-2010 Vienna University of Technology,
* Department of Software Technology and Interactive Systems
*
* 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.pp.plato.action.project;

import java.io.Serializable;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.List;

import javax.annotation.PreDestroy;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.hibernate.Hibernate;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.RaiseEvent;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.datamodel.DataModelSelection;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.faces.FacesMessages;

import eu.planets_project.pp.plato.action.TestDataLoader;
import eu.planets_project.pp.plato.action.interfaces.IAnalyseResults;
import eu.planets_project.pp.plato.action.interfaces.ICreateExecutablePlan;
import eu.planets_project.pp.plato.action.interfaces.IDefineAlternatives;
import eu.planets_project.pp.plato.action.interfaces.IDefineBasis;
import eu.planets_project.pp.plato.action.interfaces.IDefinePlan;
import eu.planets_project.pp.plato.action.interfaces.IDefineSampleRecords;
import eu.planets_project.pp.plato.action.interfaces.IDevelopExperiments;
import eu.planets_project.pp.plato.action.interfaces.IEvaluateExperiments;
import eu.planets_project.pp.plato.action.interfaces.IFastTrackAnalyseResults;
import eu.planets_project.pp.plato.action.interfaces.IFastTrackDefineRequirements;
import eu.planets_project.pp.plato.action.interfaces.IFastTrackEvaluateAlternatives;
import eu.planets_project.pp.plato.action.interfaces.IGoNoGo;
import eu.planets_project.pp.plato.action.interfaces.IIdentifyRequirements;
import eu.planets_project.pp.plato.action.interfaces.IRunExperiments;
import eu.planets_project.pp.plato.action.interfaces.ISetImportanceFactorsAction;
import eu.planets_project.pp.plato.action.interfaces.ITransformMeasuredValues;
import eu.planets_project.pp.plato.action.interfaces.IUtilAction;
import eu.planets_project.pp.plato.action.interfaces.IValidatePlan;
import eu.planets_project.pp.plato.model.Plan;
import eu.planets_project.pp.plato.model.PlanProperties;
import eu.planets_project.pp.plato.model.PlanState;
import eu.planets_project.pp.plato.model.User;
import eu.planets_project.pp.plato.model.Values;
import eu.planets_project.pp.plato.model.transform.OrdinalTransformer;
import eu.planets_project.pp.plato.model.transform.Transformer;
import eu.planets_project.pp.plato.model.tree.Leaf;
import eu.planets_project.pp.plato.model.tree.Node;
import eu.planets_project.pp.plato.model.tree.TreeNode;
import eu.planets_project.pp.plato.util.IDownloadManagerHelperBean;
import eu.planets_project.pp.plato.util.PlatoLogger;

/**
* Loads PPs
*
* Implements operations specified in {@link eu.planets_project.pp.plato.action.interfaces.LoadPlanAction}
*
* @author Hannes Kulovits
*/

@Name("loadPlan")
@Scope(ScopeType.SESSION)
public class LoadPlanAction implements Serializable {

    private static final long serialVersionUID = -5699231548828633148L;

    private enum WhichProjects {
        ALLPROJECTS,
        PUBLICPROJECTS,
        MYPROJECTS,
        FTEPROJECTS,
        PUBLICFTEPROJECTS;
    }
   
    private static final Log log = PlatoLogger.getLogger(LoadPlanAction.class);
   
    @In(required = false, create = true)
    @Out(scope = ScopeType.APPLICATION)
    private IUtilAction utilAction;

   
    @In
    private FacesContext facesContext;

    /**
     * This download manager <b>helper</b> bean is used in the DownloadServlet because
     * injecting or looking up the EntityManager in a http servlet is just pain.
     *
     * @see eu.planets_project.pp.plato.util.DownloadServlet
     */
    @In(create=true)
    @Out(required=true)
    private IDownloadManagerHelperBean downloadManagerHelperBean;

    /**
     * we also have to inject the selected project because of our newProject
     * observer. When a new project is created, selectedPlan must be injected
     * into LoadPlanAction. If we would not inject it, selectedPlan would
     * be outjected as null.
     */
    @In(required = false)
    @Out(required = false, scope = ScopeType.SESSION)
    private Plan selectedPlan;

    /**
     * Contains projects from database.
     */
    @DataModel
    private List<PlanProperties> projectList;

   

    /**
     * Entity manager for persistence.
     */
    @In
    EntityManager em;

    public void setEm(EntityManager em) {
        this.em = em;
    }

    /**
     * Plan selected by user from list {@link #projectList}.
     */
    @DataModelSelection(value = "projectList")
    private PlanProperties selection;

    /**
     * if the session ends, open projects must be closed but it is not sure that
     * the selectedPlan is still in the session context therefore keep the id
     * of the planProperties separately
     */
    private int planPropertiesId = 0;

    @In(create = true)
    private TestDataLoader testDataLoader;

 
    private WhichProjects lastLoadMode = WhichProjects.MYPROJECTS;

    public WhichProjects getLastLoadMode() {
        return lastLoadMode;
    }


    public void setLastLoadMode(WhichProjects lastLoadMode) {
        this.lastLoadMode = lastLoadMode;
    }


    @Observer("projectListChanged")
    public String relist() {
        list(lastLoadMode);
        log.debug("reloading  in "+lastLoadMode+": number of projects loaded: " + projectList.size());
        return "success";
    }

    @Transactional
    @PreDestroy
    public void preDestroy() {
        // maybe there is an open project left - close it
        unlockProject();      
    }
   
    @Destroy
    public void destroy() {
    }

    /**
     * Initializes the user and loads the project from database when session
     * component is created.
     * This is called when this bean is created.
     */
    @Create
    public void onCreate() {
        listMyProjects();
    }
   
    public String listFTEProjects() {
        list(WhichProjects.FTEPROJECTS);
        return "success";
    }

    public String listAllProjects() {
        list(WhichProjects.ALLPROJECTS);
        return "success";
    }
   
    public String listMyProjects() {
        list(WhichProjects.MYPROJECTS);
        return "success";
    }
   
    public String listPublicProjects() {
        list(WhichProjects.PUBLICPROJECTS);
        return "success";
    }
   
    public String listPublicFTEResults() {
        list(WhichProjects.PUBLICFTEPROJECTS);
        return "success";
    }
   
  
    @Out
    private String planlist = "my plans";

    /**
     * Load projects from data:
     * <ul>
     *   <li>When administrator is logged in, all projects are loaded from database.</li>
     *   <li>For any other user, only projects are loaded that are <b>not</b> set to private by another user.</li>
     * </ul>
     *
     * Furthermore, checks if project is locked by the current user, who may thus be allowed to unlock the project.
     * In this case the {@link PlanProperties#isAllowReload()} is set. In the user interface this flag means
     * that an 'Unlock' button is displayed.
     */
    public void list(WhichProjects whichProjects) {

        Contexts.getSessionContext().remove("projectList");

        // changed flag needs to be initialized here because list is the first method that is called
        // when Plato is accessed.
        // Injecting it as a member variable with create=true didn't work for some reason.
        String changed = (String) Contexts.getSessionContext().get("changed");
        if (changed == null)
            Contexts.getSessionContext().set("changed", "");

        String projectListQuery;
       
        if (whichProjects == WhichProjects.MYPROJECTS) {
            // load user's projects
            //projectListQuery = "select p from PlanProperties p where (p.owner = '"+ user.getUsername() + "' and not (p.projectBasis.identificationCode LIKE 'FAST-TRACK-%'))" + " order by p.id" ;
            projectListQuery = "select p.planProperties from Plan p where" +
            " (p.planProperties.owner = '"+ user.getUsername() + "')" +
            " and (p.projectBasis.identificationCode = null or p.projectBasis.identificationCode NOT LIKE 'FAST-TRACK-%')" +
            " order by p.planProperties.id";
           
            setPlanlist("my preservation plans");
        } else if (whichProjects == WhichProjects.ALLPROJECTS && (user.isAdmin())) {
            // load all projects, public and private,
            // but ONLY if the user is an admin
            projectListQuery = "select p from PlanProperties p order by p.id";
            setPlanlist("all preservation plans");
        } else if (whichProjects == WhichProjects.FTEPROJECTS) {
           
            projectListQuery = "select p.planProperties from Plan p where" +
            " (p.planProperties.owner = '"+ user.getUsername() + "')" +
            " and (p.projectBasis.identificationCode LIKE 'FAST-TRACK-%')" +
            " order by p.planProperties.id";
           
            setPlanlist("fast track plans");
        } else if (whichProjects == WhichProjects.PUBLICFTEPROJECTS) {
           
            projectListQuery = "select p.planProperties from Plan p where" +
            " (p.planProperties.privateProject = false )" +
            " and (p.projectBasis.identificationCode LIKE 'FAST-TRACK-%')" +
            " order by p.planProperties.id";
           
            setPlanlist("public fast track plans");
           
        } else {
           // load all public projects, which includes those with published reports
            projectListQuery = "select p.planProperties from Plan p where ((p.planProperties.privateProject = false)" +
            " or (p.planProperties.privateProject = true and p.planProperties.reportPublic = true)) and p.projectBasis.identificationCode NOT LIKE 'FAST-TRACK-%' " +
            " order by p.planProperties.id" ;           
            setPlanlist("public preservation plans");
       }
       
              
        projectList = em.createQuery(projectListQuery).getResultList();
        try {
            // if there are no PUBLIC projects, we want to load them:
            if (projectList.size() == 0 && (whichProjects != WhichProjects.MYPROJECTS && whichProjects != WhichProjects.FTEPROJECTS)) {
                testDataLoader.importAutoloadPlans();
                projectList = em.createQuery(projectListQuery).getResultList();
            }
        } catch (Exception e) {
            FacesMessages.instance().add(FacesMessage.SEVERITY_ERROR, "Failed to insert testdata.");
            log.fatal("Testdataloader failed.", e);
        }

        //
        // readOnly in PlanProperties is *transient*, it is used in loadPlan.xhtml
        // to determine if a user is allowed to load a project
        //
        for (PlanProperties pp : projectList) {
           
            //
            // a project may not be loaded when
            //   ... it is set to private
            //   ... AND the user currently logged in is not the administrator
            //   ... AND the user currently logged in is not the owner of that project
            boolean readOnly = pp.isPrivateProject()
                && !user.isAdmin()
                && !user.getUsername().equals(pp.getOwner());

            boolean allowReload = pp.getOpenedByUser().equals(user.getUsername())
                && selectedPlan == null;

            pp.setReadOnly(readOnly);
            pp.setAllowReload(allowReload);
        }
        setLastLoadMode(whichProjects);
    }

    public void setPlanlist(String planlist) {
        this.planlist = planlist;
    }

    @In(create = true)
    ProjectSettings projectSettings;
   
    @In(create = true)
    IFastTrackDefineRequirements FTrequirements;
   
    @In(create = true)
    IFastTrackEvaluateAlternatives FTevaluate;

    @In(create = true)
    IFastTrackAnalyseResults FTanalyse;
   
    @In(create = true)
    IDefineBasis defineBasis;

    @In(create = true)
    IDefineSampleRecords defineSampleRecords;

    @In(create = true)
    IIdentifyRequirements identifyRequirements;

    @In(create = true)
    IDefineAlternatives defineAlternatives;

    @In(create = true)
    IGoNoGo gonogo;

    @In(create = true)
    IDevelopExperiments devexperiments;

    @In(create = true)
    IRunExperiments runexperiments;

    @In(create = true)
    IEvaluateExperiments evalexperiments;

    @In(create = true)
    ITransformMeasuredValues transform;

    @In(create = true)
    ISetImportanceFactorsAction importanceFactors;

    @In(create = true)
    IAnalyseResults analyseResults;

    @In(create = true)
    ICreateExecutablePlan createExecutablePlan;

    @In(create = true)
    IDefinePlan definePlan;

    @In(create = true)
    IValidatePlan validatePlan;

    @In
    private User user;

    public void setPlanPropertiesID(int id){
        planPropertiesId = id;
    }

    /**
     * Loads a project from database that was selected by the user.
     *
     * Previously loaded project is unlocked.
     *
     * Forwards the user to respective workflowstep by calling the workflow step's
     * <code>enter</code> method.
     */
    @RaiseEvent("reload")
    public String load() {
        String id = "";
        try {
            id = ((HttpServletRequest) facesContext.getExternalContext()
                    .getRequest()).getSession().getId();
        } catch (RuntimeException e) {
            log.debug("Couldn't get SessionID");
        }
        log.info("Session="+id+" of user "+user.getUsername()
                + " is loading project "+selection.getId()
                + " - "+selection.getName());

        // try to lock the project
        Query q = em
                .createQuery("update PlanProperties pp set pp.openHandle = 1, pp.openedByUser = '" + user.getUsername() + "' where (pp.openHandle is null or pp.openHandle = 0) and pp.id = "
                        + selection.getId());
        int num = q.executeUpdate();
        if (num < 1) {
            FacesMessages
                    .instance()
                    .add(
                            FacesMessage.SEVERITY_INFO,
                            "In the meantime the plan has been loaded by an other user. Please choose another plan.");
            relist();
            log.debug("Locking plan failed");
            return null;
        }
        List<Plan> list = em.createQuery(
                "select p from Plan p where p.planProperties.id = "
                        + selection.getId()).getResultList();

        // we locked the project before be we now cannot load it. not good.
        if (list.size() != 1) {
            FacesMessages.instance().add(FacesMessage.SEVERITY_ERROR,
                    "An unexpected error has occured while loading the plan.");

            return null;
        }
        // ok - the selected project is free - unlock the old project
        unlockProject();
        // load the selected project (and keep the id!)
        setPlanPropertiesID(selection.getId());
        selectedPlan = em.find(Plan.class, list.get(0).getId());

        // Strangely enough the outjection doesnt work here, so to be sure we set the member explicitly
        Contexts.getSessionContext().set("selectedPlan", selectedPlan);

        this.initializeProject(selectedPlan);
        log.info("Plan " + selectedPlan.getPlanProperties().getName()
                + " loaded!");

        String msg = "The plan you loaded has reached the state "
                + selectedPlan.getState().getStateName()
                + ". Therefore you have been directed to the subsequent workflow step.";
        FacesMessages.instance().add(FacesMessage.SEVERITY_INFO, msg);
       
        if (selectedPlan.isFastTrackEvaluationPlan()) {
           
            switch (selectedPlan.getState().getValue()) {
            case PlanState.FTE_INITIALISED:
                return FTrequirements.enter();
            case PlanState.FTE_REQUIREMENTS_DEFINED:
                return FTevaluate.enter();
            case PlanState.FTE_ALTERNATIVES_EVALUATED:
                return FTanalyse.enter();
            case PlanState.FTE_RESULTS_ANALYSED:
                return FTanalyse.enter();
            }
        }

        // redirect to step corresponding to the project's state:
        switch (selectedPlan.getState().getValue()) {
        case PlanState.BASIS_DEFINED:
            return defineSampleRecords.enter();
        case PlanState.RECORDS_CHOSEN:
            return identifyRequirements.enter();
        case PlanState.TREE_DEFINED:
            return defineAlternatives.enter();
        case PlanState.ALTERNATIVES_DEFINED:
            return gonogo.enter();
        case PlanState.GO_CHOSEN:
            return devexperiments.enter();
        case PlanState.EXPERIMENT_DEFINED:
            return runexperiments.enter();
        case PlanState.EXPERIMENT_PERFORMED:
            return evalexperiments.enter();
        case PlanState.RESULTS_CAPTURED:
            return transform.enter();
        case PlanState.TRANSFORMATION_DEFINED:
            return importanceFactors.enter();
        case PlanState.WEIGHTS_SET:
            return analyseResults.enter();
        case PlanState.ANALYSED:
            return createExecutablePlan.enter();
        case PlanState.EXECUTEABLE_PLAN_CREATED:
            return definePlan.enter();
        case PlanState.PLAN_DEFINED:
            return validatePlan.enter();
        case PlanState.PLAN_VALIDATED:
            return validatePlan.enter();
        default:
            return defineBasis.enter();
        }
    }
   
    public String startFastTrackEvaluation() {
        unlockProject();

        selectedPlan = new Plan();
        selectedPlan.getPlanProperties().setAuthor(user.getFullName());
        selectedPlan.getPlanProperties().setPrivateProject(true);
        selectedPlan.getPlanProperties().setOwner(user.getUsername());

        // set Fast Track properties
        selectedPlan.getState().setValue(PlanState.FTE_INITIALISED);
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-kkmmss");
        String timestamp = format.format(new Date(System.currentTimeMillis()));
        String identificationCode = Plan.fastTrackEvaluationPrefix + timestamp;
        selectedPlan.getProjectBasis().setIdentificationCode(identificationCode);
       
        // We have to prevent the user from navigating to the step 'Load plan'
        // because the user wouldn't be able to leave this step: Going to 'Define
        // Basis' is not possible as the project hasn't been saved so far.
        //
        // We 'activate' the changed flag so that the user is asked to either
        // save the project or discard changes.
        TreeNode root = new Node();
        root.setName("Root");
        selectedPlan.getTree().setRoot(root);
       
        // ok - the selected project is free - unlock the old project
        unlockProject();
       
       
       
        // load the selected project (and keep the id!)
        setPlanPropertiesID(selectedPlan.getPlanProperties().getId());
       
        // Strangely enough the outjection doesnt work here, so to be sure we set the member explicitly
        Contexts.getSessionContext().set("selectedPlan", selectedPlan);

        this.initializeProject(selectedPlan);
       
        FTrequirements.enter();
       
        return "success";
    }

    /**
     * Hibernate initializes project and its parts.
     */
    public void initializeProject(Plan p) {
        Hibernate.initialize(p);
        Hibernate.initialize(p.getAlternativesDefinition());
        Hibernate.initialize(p.getSampleRecordsDefinition());
        Hibernate.initialize(p.getTree());
        initializeNodeRec(p.getTree().getRoot());
        log.debug("plan initialised");
    }

    /**
     * Traverses down the nodes in the tree and calls <code>Hibernate.initialize</code>
     * for each leaf. This is necessary to provide the application with a convenient
     * way of working with lazily initialized collections or proxies.
     *
     * @param node node from where initialization shall start
     */
    private void initializeNodeRec(TreeNode node) {

        Hibernate.initialize(node);
        if (node.isLeaf()) {
            Leaf leaf = (Leaf) node;
            Transformer t = leaf.getTransformer();
            Hibernate.initialize(t);
            if (t instanceof OrdinalTransformer) {
                OrdinalTransformer nt = (OrdinalTransformer) t;
                Hibernate.initialize(nt.getMapping());
            }
            //log.debug("hibernate initialising Transformer: " + leaf.getTransformer());
            for (Values value : leaf.getValueMap().values()) {
                Hibernate.initialize(value);
            }
        } else if (node instanceof Node) {
            Node recnode = (Node) node;
            Hibernate.initialize(node.getChildren());
            for (TreeNode newNode : recnode.getChildren()) {
                initializeNodeRec(newNode);
            }
        }
    }

    /**
     * Unlocks all projects in database.
     */
    public void unlockAll() {
        this.unlockQuery(false);
    }

    /**
     * Unlocks certain projects in database (dependent on parameter)
     *
     * @param useId If this is true, only project with id {@link #planPropertiesId} will be unlocked;
     * otherwise, all projects in database will be unlocked
     */
    private void unlockQuery(boolean useId) {
       
        String where = "";
        if (useId) {
            where = "where pp.id = " + planPropertiesId;
        }

        Query q = em
                .createQuery("update PlanProperties pp set pp.openHandle = 0, pp.openedByUser = ''"
                        + where);
        try {
            if (q.executeUpdate() < 1) {
                log.debug("Unlocking plan failed.");
            } else {
                log.debug("Unlocked plan");
            }
        } catch (Throwable e) {
            log.error("Unlocking plan failed:", e);
        }

        planPropertiesId = 0;
    }

    /**
     * Unlocks project with id {@link #planPropertiesId}.
     */
    public void unlockProject() {
        if (planPropertiesId != 0) {
            log.info("unlocking plan "+planPropertiesId);
            utilAction.unlockPlan(planPropertiesId);
        }
    }

    /**
     * Unlocks project depending on data model selection {@link #selection}
     */
    public String unlockselectedPlan() {
        if (selection != null) {
            planPropertiesId = selection.getId();
            unlockQuery(true);
        }
        return relist();
    }

    /**
     * Closes currently selected project {@link #selectedPlan}
     */
    public String closeProject() {
        if (selectedPlan != null) {
            unlockProject();
            selectedPlan = null;
        } else {
            log.debug("not unlocking any plan because none is open.");
        }
        return "success";
    }
}
TOP

Related Classes of eu.planets_project.pp.plato.action.project.LoadPlanAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.