eu.planets_project.pp.plato.application.AdminAction.java Source code

Java tutorial

Introduction

Here is the source code for eu.planets_project.pp.plato.application.AdminAction.java

Source

/*******************************************************************************
 * 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.application;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.dom4j.Document;
import org.dom4j.io.XMLWriter;
import org.jboss.annotation.ejb.cache.Cache;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.faces.FacesMessages;
import org.junit.runner.Computer;

import eu.planets_project.pp.plato.action.IProjectCleaner;
import eu.planets_project.pp.plato.action.IProjectExport;
import eu.planets_project.pp.plato.action.interfaces.IAdmin;
import eu.planets_project.pp.plato.action.interfaces.IMessages;
import eu.planets_project.pp.plato.action.project.LoadPlanAction;
import eu.planets_project.pp.plato.model.Alternative;
import eu.planets_project.pp.plato.model.Plan;
import eu.planets_project.pp.plato.model.PlanProperties;
import eu.planets_project.pp.plato.model.Values;
import eu.planets_project.pp.plato.model.tree.Leaf;
import eu.planets_project.pp.plato.model.tree.TemplateTree;
import eu.planets_project.pp.plato.model.values.Value;
import eu.planets_project.pp.plato.util.MemoryTest;
import eu.planets_project.pp.plato.util.PlatoLogger;
import eu.planets_project.pp.plato.xml.ProjectExporter;

/**
 * Performs several admin actions such as removing all projects from database or exporting/importing
 * all projects. Most actions require input of admin passcode.
 *
 * @author Hannes Kulovits
 */
@Stateful
@Scope(ScopeType.APPLICATION)
@Name("admin")
@Cache(org.jboss.ejb3.cache.NoPassivationCache.class)
public class AdminAction implements IAdmin, Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 8226431137018309922L;

    private static final Log log = PlatoLogger.getLogger(AdminAction.class);

    @PersistenceContext
    EntityManager em;

    /**
     * List of messages displayed to the Plato users.
     */
    @In(required = false, create = true)
    @Out
    IMessages allmessages;

    @In(create = true)
    private LoadPlanAction loadPlan;

    /**
     * News message entered by the user
     */
    @In(required = false)
    @Out
    private String news = "";

    /**
     * Name of the author who entered the news text
     */
    @In(required = false)
    @Out
    private String author = "";

    /**
     * Importance level of entered message (hard coded to 'Info')
     */
    private String importance = "Info";

    /**
     * Switch for turning on/off news.
     */
    @Out
    boolean showNews = true;

    @Out(required = false)
    private String exportDir = "";

    private MemoryTest memTest = new MemoryTest();

    private ProjectExporter exporter = new ProjectExporter();

    public void throwException() {
        throw new RuntimeException("Test Exception");
    }

    /**
     * Password enterd by the user.
     */
    @In(required = false)
    String password;

    /**
     * Predefined hash coded passcode computed by SHA-1
     */
    private String code = "d1f686a6914ac3925ba26732abc96d8878465746";

    /**
     * Checks if entered passcode equals the predefined administration password.
     * Administration password stored in @see {@link #code}.
     * @return true if the entered password equals the administration passcode.
     */
    public boolean check() {
        log.info(computeSHA(password));
        boolean allow = (password != null && (computeSHA(password).equals(code)));
        if (!allow) {
            FacesMessages.instance().add(FacesMessage.SEVERITY_INFO, "Sorry, wrong passcode.");
        }
        return allow;
    }

    private static String convertToHex(byte[] data) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < data.length; i++) {
            int halfbyte = (data[i] >>> 4) & 0x0F;
            int two_halfs = 0;
            do {
                if ((0 <= halfbyte) && (halfbyte <= 9))
                    buf.append((char) ('0' + halfbyte));
                else
                    buf.append((char) ('a' + (halfbyte - 10)));
                halfbyte = data[i] & 0x0F;
            } while (two_halfs++ < 1);
        }
        return buf.toString();
    }

    private static String computeSHA(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(input.getBytes("UTF-8"));
            byte[] code = md.digest();
            return convertToHex(code);
        } catch (NoSuchAlgorithmException e) {
            log.error("Algorithm SHA-1 not found!", e);
            e.printStackTrace();
            return null;
        } catch (UnsupportedEncodingException e) {
            log.error("Encoding problem: UTF-8 not supported!", e);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Unlocks all projects. The user must provide the correct administration passcode.
     * @see eu.planets_project.pp.plato.action.project.LoadPlanAction#unlockAll()
     * @return always null to user stays on same screen after action
     */
    public String unlockAll() {
        if (check()) {
            loadPlan.unlockAll();
        }
        return null;
    }

    /**
     * Unlocks project with provided projectID.
     * @see #projectID
     */
    public String unlockUsingProjectID() {
        Query q = em.createQuery("update PlanProperties pp set pp.openHandle = 0 where pp.id = " + projectID);
        if (q.executeUpdate() < 1) {
            FacesMessages.instance().add(FacesMessage.SEVERITY_ERROR,
                    "Unlocking project " + projectID + " failed.");
            log.info("Unlocking project " + projectID + " failed.");
        } else
            FacesMessages.instance().add(FacesMessage.SEVERITY_ERROR, "Unlocked project " + this.projectID);
        log.info("Unlocked project " + projectID);
        return null;
    }

    /**
     * Adds a news entry to list of messages displayed to user.
     * @see #allmessages
     */
    public void addNews() {
        if (check()) {
            allmessages.addNewsMessage(new NewsClass(news, importance, author));
            news = "";
        }
        System.gc();
    }

    /**
     * Clears list containing exception messages occured during Plato runtime.
     */
    public void clearErrors() {
        if (check()) {
            allmessages.clearErrors();
        }
        return;
    }

    /**
     * Clears list of news entered by the administrator.
     */
    public void clearNews() {
        if (check()) {
            allmessages.clearNews();
        }

    }

    @Remove
    @Destroy
    public void destroy() {
    }

    @In(create = true)
    IProjectExport projectExport;

    @In(create = true)
    IProjectCleaner projectCleaner;

    public String cleanupValues() {
        List<PlanProperties> ppList = em.createQuery("select p from PlanProperties p").getResultList();
        int total = 0;
        int i = 0;
        for (PlanProperties pp : ppList) {
            int number = projectCleaner.cleanupProject(pp.getId());
            FacesMessages.instance().add(FacesMessage.SEVERITY_INFO,
                    "Plan " + pp.getName() + ": removed " + number + " values.");
            total += number;
            i++;
            if ((i % 5) == 0) {
                System.gc();
            }
        }
        FacesMessages.instance().add(FacesMessage.SEVERITY_INFO,
                "All projects cleaned up, removed " + total + " Values objects in total");
        return null;
    }

    /**
     * Clears all projects in database.
     * @return null Stay on same screen after action performed.
     */
    public String clearData() {
        if (check()) {
            List<Plan> projectList = em.createQuery("select p from Plan p").getResultList();
            for (Plan p : projectList) {
                log.info("deleting plan " + p.getPlanProperties().getName());
                log.debug("removing value scale linkage...");
                for (Leaf l : p.getTree().getRoot().getAllLeaves()) {
                    for (Alternative a : p.getAlternativesDefinition().getAlternatives()) {
                        Values values = l.getValues(a.getName());
                        if (values != null) {
                            for (Value v : values.getList()) {
                                if (v != null) {
                                    v.setScale(null);
                                }
                            }
                        }
                    }
                }
                log.debug("removing entity... ");
                em.remove(p);
                log.debug("plan removed");
            }
            em.flush();
            FacesMessages.instance().add(FacesMessage.SEVERITY_INFO, "All projects deleted!");
        }
        return null;
    }

    /**
     * Plan ID entered by the user
     */
    @In(required = false)
    private String projectID;

    /**
     * Removes a project matching project ID entered by user.
     * @see #projectID
     */
    public String clearDataUsingProjectID() {
        if (check()) {
            List<Plan> projectList = em
                    .createQuery("select p from Plan p where p.planProperties.id = " + this.projectID)
                    .getResultList();

            if (!projectList.isEmpty()) {
                Plan p = projectList.get(0);
                log.info("Deleting project " + p.getPlanProperties().getId());
                em.remove(p);
                em.flush();
                FacesMessages.instance().add(FacesMessage.SEVERITY_INFO, "Plan " + this.projectID + " deleted!");
            } else {
                FacesMessages.instance().add(FacesMessage.SEVERITY_INFO, "Plan " + this.projectID + " not found!");
            }
        }
        return null;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    /**
     *
     * @return null Always returns null, so user stays on same screen after action performed
     */
    public String clearAllData() {
        if (check()) {
            this.clearData();
            this.resetPublicLibraries();
            this.deleteUserLibraries();
        }
        return null;
    }

    /**
    *
    * @return null Always returns null, so user stays on same screen after action performed
    */
    public String clearKB() {
        if (check()) {
            this.resetPublicLibraries();
            this.deleteUserLibraries();
        }
        return null;
    }

    /**
     * Exports all projects into a single xml file. Projects are exported using {@link eu.planets_project.pp.plato.xml.ProjectExporter#exportToXml(Plan)}
     * @return null Always returns null, so user stays on same screen after action performed
     */
    public String exportAllProjectsToZip() {
        if (check()) {
            return projectExport.exportAllProjectsToZip();
        }
        return null;
    }

    /**
     * Exports private templates stored in database to xml
     * Templates are exported using {@link eu.planets_project.pp.plato.xml.ProjectExporter#exportTemplates(java.util.List)}
     */
    public String exportPrivateTemplates() {
        if (check()) {
            List<TemplateTree> templates = em.createQuery("select n from TemplateTree n where owner is not null")
                    .getResultList();
            if (!templates.isEmpty()) {
                this.returnXMLExport(exporter.exportTemplates(templates));
            } else
                FacesMessages.instance().add(FacesMessage.SEVERITY_ERROR, "No Templates found!");
        }
        return null;
    }

    /**
     * Renders the given exported XML-Document as HTTP response
     */
    private String returnXMLExport(Document doc) {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_kkmmss");
        String timestamp = format.format(new Date(System.currentTimeMillis()));

        String filename = "export_" + timestamp + ".xml";
        HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext()
                .getResponse();
        response.setContentType("application/x-download");
        response.setHeader("Content-Disposition", "attachement; filename=\"" + filename + "\"");
        //response.setContentLength(xml.length());
        try {
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            XMLWriter writer = new XMLWriter(out, ProjectExporter.prettyFormat);
            writer.write(doc);
            writer.flush();
            writer.close();
            out.flush();
            out.close();
        } catch (IOException e) {
            FacesMessages.instance().add(FacesMessage.SEVERITY_ERROR,
                    "An error occured while generating the export file.");
            log.error("Could not open response-outputstream: ", e);
        }
        FacesContext.getCurrentInstance().responseComplete();
        return null;
    }

    /**
     * Exports all templates stored in database to xml
     * Templates are exported using {@link eu.planets_project.pp.plato.xml.ProjectExporter#exportTemplates(java.util.List)}
     */
    public String exportAllTemplates() {
        if (check()) {
            List<TemplateTree> templates = em.createQuery("select n from TemplateTree n").getResultList();

            if (!templates.isEmpty()) {
                this.returnXMLExport(exporter.exportTemplates(templates));
            } else
                FacesMessages.instance().add(FacesMessage.SEVERITY_ERROR, "No Templates found!");
        }
        return null;
    }

    /**
     * removes all public templates from database
     * @return null Always returns null so user stays on same screen after action performed.
     */
    public String resetPublicLibraries() {
        if (check()) {
            List<TemplateTree> templates = em.createQuery("select n from TemplateTree n where owner is null")
                    .getResultList();
            for (TemplateTree t : templates) {
                log.info("Deleting Template Tree " + t.getName());
                em.remove(t);
            }
            em.flush();

            FacesMessages.instance().add(FacesMessage.SEVERITY_INFO, "Public Templates removed!");
        }
        return null;
    }

    /**
     * Removes all templates created by arbitrary user.
     * @return null Always returns null.
     */
    // TODO add per-user option for removing templates of a certain user
    public String deleteUserLibraries() {
        if (check()) {
            List<TemplateTree> templates = em.createQuery("select n from TemplateTree n where owner is not null")
                    .getResultList();
            for (TemplateTree t : templates) {
                log.info("Deleting Template Tree " + t.getName() + " of user " + t.getOwner());
                em.remove(t);
            }
            em.flush();

            FacesMessages.instance().add(FacesMessage.SEVERITY_INFO, "Private Templates removed!");
        }
        return null;
    }

    public String refresh() {
        if (exportDir == null)
            return exportDir;
        else
            return null;
    }

    public void munchMem(int mb) {
        log.info("Munching " + mb + " MB");
        memTest.munchMem(mb);
        FacesMessages.instance().add(FacesMessage.SEVERITY_INFO, "Munched " + mb + " MB");
    }

    public void releaseMem() {
        log.info("Releasing memory...");
        memTest.releaseMem();
    }

    /**
     * prints a hashcode for a provided String (arg[0]) using SHA-1 encryption
     * Use this as a quick way of computing a password hash and pasting
     * the code that you get into the variable {@link #code}
     * @param args one: args[0] must be the passcode for which you want to compute the hash
     */
    public static void main(String[] args) {
        System.out.println(computeSHA(args[0]));
    }

}