org.squale.squalix.core.AbstractTask.java Source code

Java tutorial

Introduction

Here is the source code for org.squale.squalix.core.AbstractTask.java

Source

/**
 * Copyright (C) 2008-2010, Squale Project - http://www.squale.org
 *
 * This file is part of Squale.
 *
 * Squale is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or any later version.
 *
 * Squale 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 Lesser General Public License
 * along with Squale.  If not, see <http://www.gnu.org/licenses/>.
 */
//Source file: D:\\cc_views\\squale_v0_0_act\\squale\\src\\squalix\\src\\org\\squale\\squalix\\core\\Task.java
package org.squale.squalix.core;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.squale.jraf.commons.exception.JrafDaoException;
import org.squale.jraf.commons.exception.JrafPersistenceException;
import org.squale.jraf.helper.PersistenceHelper;
import org.squale.jraf.spi.persistence.IPersistenceProvider;
import org.squale.jraf.spi.persistence.ISession;
import org.squale.squalecommon.daolayer.component.ApplicationDAOImpl;
import org.squale.squalecommon.daolayer.component.AuditDAOImpl;
import org.squale.squalecommon.daolayer.component.ProjectDAOImpl;
import org.squale.squalecommon.daolayer.result.ErrorDAOImpl;
import org.squale.squalecommon.enterpriselayer.businessobject.component.ApplicationBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.AuditBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.ProjectBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.ListParameterBO;
import org.squale.squalecommon.enterpriselayer.businessobject.component.parameters.StringParameterBO;
import org.squale.squalecommon.enterpriselayer.businessobject.result.ErrorBO;
import org.squale.squalecommon.util.SqualeCommonConstants;
import org.squale.squalecommon.util.SqualeCommonUtils;
import org.squale.squalecommon.util.mail.IMailerProvider;
import org.squale.squalecommon.util.mail.MailerHelper;
import org.squale.squalix.messages.MessageMailManager;
import org.squale.squalix.messages.Messages;

/**
 * Reprsente une faade permettant d'excuter une tche.<br>
 * Une tche est responsable de la cration et de la persistance de ses objets de rsultats (implmentant l'interface
 * <code>MeasureBO</code>) ainsi que de ses erreurs (classe <code>ErrorBO</code>). <br /> <br /> Une tche peut possder
 * :
 * <ul>
 * <li>une tche parent : tant que la tche parent n'est pas termine avec succs, celle-ci ne peut tre lance,</li>
 * <li>et/ou des tches enfants : lances ds la compltude avec succs de la tche courante.
 * <li>
 * </ul>
 * <br /> Les attributs ncessaires  une classe lui sont attribus via un pattern IOC. Une fois que la tche a t
 * instancie, c'est son observateur (le Scheduler ou l'excuteur d'analyse) qui lui transmet l'instance d'audit, de
 * projet, son statut, et ses tches enfants. Elle n'est responsable que de se nommer lors de son instanciation. Le
 * constructeur ne doit prendre aucun paramtre. <br /> <br /> Si la tche choue, elle doit passer en statut FAILED, et
 * gnrer des erreurs dans la base. Il est plus que vivement conseill de ne pas utiliser les instance de projet et
 * d'audit lorsque les rsultats sont persists, il faut utiliser des nouvelles instances directement  partir des DAO,
 * avec les id des instances offertes par l'observateur. <br /> <br /> Pour plus de dtails sur la cration d'une
 * nouvelle tche, reportez-vous au P720U associ.
 * 
 * @author m400842
 * @version 1.0
 */
public abstract class AbstractTask implements Runnable {

    /**
     * L'application
     */
    protected ApplicationBO mApplication;

    /**
     * Provider de persistence
     */
    private IPersistenceProvider mPersistenceProvider;

    /**
     * Session hibernate
     */
    private ISession mSession;

    /**
     * Prcise que l'excution de la tche s'est termine avec succs.
     */
    public static final int TERMINATED = 0;

    /**
     * Prcise que l'excution de la tche a choue.
     */
    public static final int FAILED = 1;

    /**
     * Prcise que l'excution de la tche n'a pas t tente.
     */
    public static final int NOT_ATTEMPTED = 2;

    /**
     * Prcise que l'excution est en cours.
     */
    public static final int RUNNING = 3;

    /**
     * Etat courant de la tche
     */
    protected int mStatus = NOT_ATTEMPTED;

    /**
     * Prcise que l'excution de la tche est suspendue en raison d'un manque de ressources.
     */
    public static final int NO_RESOURCES = 4;

    /**
     * Prcise que l'excution de la tche est annule.
     */
    public static final int CANCELLED = 5;

    /**
     * indique si la tache est obligatoire ou optionnelle obligatoire par dfaut
     */
    protected boolean mMandatoryTask = true;

    /**
     * Projet attach  la tache
     */
    protected ProjectBO mProject = null;

    /**
     * Audit durant lequel est effectue la tche.
     */
    protected AuditBO mAudit = null;

    /**
     * Le nom de la tche.
     */
    protected String mName = null;

    /**
     * L'ensemble des paramtres temporaires d'une tche
     */
    protected TaskData mData = null;

    /** l'id de l'application auquelle est rattach le projet */
    protected Long mApplicationId;

    /** l'id du projet auquel est rattach la tche */
    protected Long mProjectId;

    /** l'id de l'audit auquel est rattach la tche */
    protected Long mAuditId;

    /** les erreurs */
    protected ArrayList mErrors;

    /** Paramtres de la tche */
    private Collection mTaskParameters = new ArrayList();

    /** Taille max du file system au cours de la tache */
    protected long mMaxFileSystemSize = 0;

    /** Taille du file system  la fin de la tache */
    protected long mPersistentFileSystemSize = 0;

    /**
     * Logger
     */
    private static final Log LOGGER = LogFactory.getLog(AbstractTask.class);

    /**
     * Access method for the mStatus property.
     * 
     * @return the current value of the mStatus property
     * @roseuid 42CD420D01DA
     */
    public int getStatus() {
        return mStatus;
    }

    /**
     * Access method for the mProject property.
     * 
     * @return the current value of the mProject property
     * @roseuid 42CD420D0209
     */
    public ProjectBO getProject() {
        return mProject;
    }

    /**
     * Access method for the mAudit property.
     * 
     * @return the current value of the mAudit property
     * @roseuid 42CD420D0238
     */
    public AuditBO getAudit() {
        return mAudit;
    }

    /**
     * Sets the value of the mStatus property.
     * 
     * @param pStatus the new value of the mStatus property
     * @roseuid 42D22A170000
     */
    public void setStatus(int pStatus) {
        mStatus = pStatus;
    }

    /**
     * @return le nom de la tache
     */
    public String getName() {
        return mName;
    }

    /**
     * @return l'objet contenant l'ensemble des parametres temporaires dfinis
     */
    public TaskData getData() {
        return mData;
    }

    /**
     * @param pData le nouvel ensemble de parametres temporaires
     */
    public void setData(TaskData pData) {
        mData = pData;
    }

    /**
     * @return l'id de l'application
     */
    public Long getApplicationId() {
        return mApplicationId;
    }

    /**
     * @return l'id du projet
     */
    public Long getProjectId() {
        return mProjectId;
    }

    /**
     * @return la session
     */
    public ISession getSession() {
        return mSession;
    }

    /**
     * @param pLong le nouvel id de l'application
     */
    public void setApplicationId(Long pLong) {
        mApplicationId = pLong;
    }

    /**
     * @param pLong le nouvel id du projet
     */
    public void setProjectId(Long pLong) {
        mProjectId = pLong;
    }

    /**
     * @return l'id de l'audit
     */
    public Long getAuditId() {
        return mAuditId;
    }

    /**
     * @param pLong le nouvel id de l'audit
     */
    public void setAuditId(Long pLong) {
        mAuditId = pLong;
    }

    /**
     * @return la liste des errors
     */
    public ArrayList getErrors() {
        return mErrors;
    }

    /**
     * @param pList la nouvelle liste d'erreurs
     */
    public void setErrors(ArrayList pList) {
        mErrors = pList;
    }

    /**
     * @return paramtres de la tche (soit la forme de TaskParameterBO)
     */
    public Collection getTaskParameters() {
        return mTaskParameters;
    }

    /**
     * @param pTaskParameters paramtres de la tche
     */
    public void setTaskParameters(Collection pTaskParameters) {
        mTaskParameters = pTaskParameters;
    }

    /**
     * @return true si la tache est obligatoire
     */
    public boolean isMandatoryTask() {
        return mMandatoryTask;
    }

    /**
     * @param pCategory la nouvelle valeur
     */
    public void setMandatoryTask(boolean pCategory) {
        mMandatoryTask = pCategory;
    }

    /**
     * Persiste les objets rsultats dans la base de donnes grce  la session.
     * 
     * @roseuid 42CD420D018C
     */
    protected void persistResult() {
    }

    /**
     * Cre les erreurs et les persiste dans la base
     */
    private void createErrors() {
        // la liste a t initialise  0 lments
        if (mErrors.size() > 0) {
            boolean hasFatalError = false;
            Iterator it = mErrors.iterator();
            while (it.hasNext()) {
                ErrorBO error = (ErrorBO) it.next();
                // le seul champ  remplir
                if (null == error.getTaskName()) {
                    error.setTaskName(mName);
                }
                // si la tache n'est pas failed(peut arriver si la tache n'a pas lev d'exception)
                // et qu'une erreur est fatale on met le status  Failed
                // on met le status de la tache au status maximum des erreurs
                if (mStatus != FAILED && error.getLevel() == ErrorBO.CRITICITY_FATAL) {
                    mStatus = FAILED;
                    hasFatalError = true;
                }
                if (!it.hasNext() && mStatus == FAILED) {
                    // If task has failed, we set the last error in fatal criticity
                    // if task doesn't already contain one.
                    if (!hasFatalError) {
                        error.setLevel(ErrorBO.CRITICITY_FATAL);
                    }
                    // Dans le cas d'une erreur fatale, on prvient les admins
                    // que la tache a chou
                    Date current = Calendar.getInstance().getTime();
                    DateFormat formatter = new SimpleDateFormat("d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
                    formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
                    String hour = formatter.format(current);
                    String[] infos = new String[] { mName, mApplication.getName(),
                            mApplication.getServeurBO().getName(), mProject.getName(), "" + mAudit.getId(), hour };

                    String object = Messages.getString("mail.sender.squalix.task",
                            new String[] { mApplication.getName() })
                            + Messages.getString("mail.task.failed.object", infos);

                    MessageMailManager mail = new MessageMailManager();
                    mail.addContent("mail.header", null);
                    mail.addContent("mail.task.failed.content", infos);
                    String content = mail.getContent();
                    String dest = SqualeCommonConstants.ONLY_ADMINS;
                    IMailerProvider mailer = MailerHelper.getMailerProvider();
                    SqualeCommonUtils.notifyByEmail(mailer, null, dest, null, object, content, false);
                }
                // Pas de conversion InitialMessage -> Message
                try {
                    // On attribue les bonnes valeurs aux erreurs
                    error.setProject(mProject);
                    error.setAudit(mAudit);
                    // enregistrement en base
                    ErrorDAOImpl.getInstance().create(mSession, error);
                    mSession.closeSession();
                } catch (JrafDaoException e) {
                    LOGGER.error(e, e);
                }
            }
        }
    }

    /**
     * Mthode qui permet de crer une session, qui effectue le travail propre  la tache et ferme la session
     */
    public final void run() {
        if (mStatus == NOT_ATTEMPTED) {
            try {
                mStatus = RUNNING;
                // initialisation
                init();
                // code propre  la tache
                execute();
                // signale que la tche s'est bien droule
                String[] tab = getName().split(".");
                // on ne devrait pas passer dans ce test si le nom de la tache
                // a t correctement dfini
                if (tab == null || tab.length == 0) {
                    LOGGER.info("la tche " + mName + "  t excute avec SUCCES ");
                } else { // Prend juste le nom de la classe sans package
                    LOGGER.info("la tche " + tab[tab.length - 1] + "  t excute avec SUCCES ");
                }
            } catch (Exception e) {
                LOGGER.error(e, e);
                mStatus = FAILED;
                // une exception attrape ici est forcment une erreur critique
                // On rcupre le message de l'erreur
                String message = e.getMessage();
                // Si le message est nul, on rcupre la description de l'erreur
                if (null == message) {
                    message = e.toString();
                }
                initError(message, ErrorBO.CRITICITY_FATAL);
            } finally { // on cre les erreurs
                createErrors();
                try {
                    mSession.commitTransaction();
                } catch (JrafPersistenceException jpe) {
                    LOGGER.error(jpe, jpe);
                }
            }
            // Changement d'tat si une erreur n'est pas survenue
            if (mStatus == AbstractTask.RUNNING) {
                mStatus = TERMINATED;
            }
        }
    }

    /**
     * Mthode qui cre la session
     * 
     * @throws JrafDaoException en cas d'chec
     */
    private final void init() throws JrafDaoException {
        mErrors = new ArrayList(0);
        mPersistenceProvider = PersistenceHelper.getPersistenceProvider();
        mSession = mPersistenceProvider.getSession();
        mSession.beginTransaction();
        mAudit = (AuditBO) AuditDAOImpl.getInstance().get(mSession, mAuditId);
        mApplication = (ApplicationBO) ApplicationDAOImpl.getInstance().get(mSession, mApplicationId);
        // Ce n'est pas vraiment du code dfensif, mais c'est plutot d'ordre logique:
        // Pour les taches de niveau application on ne recharge pas le projet
        if (null != mProjectId) {
            mProject = (ProjectBO) ProjectDAOImpl.getInstance().get(mSession, mProjectId);
        }
    }

    /**
     * Mthode qui effectue le traitement propre  chaque tache
     * 
     * @throws TaskException car il y a plusieurs types d'exception suivant les tches
     * @throws JrafDaoException
     */
    public abstract void execute() throws TaskException, JrafDaoException;

    /**
     * Cre une erreur avec un niveau de criticit par dfaut
     * 
     * @param pMessage le message
     */
    public void initError(String pMessage) {
        initError(pMessage, ErrorBO.CRITICITY_WARNING);
    }

    /**
     * Cre une erreur avec un niveau de criticit dtermine
     * 
     * @param pMessage le message
     * @param pCriticyLevel le niveau de criticit de l'erreur
     */
    public void initError(String pMessage, String pCriticyLevel) {
        // cas particulier, petit filtrage
        if (pMessage.indexOf("see the compiler error output") == -1) {
            // Prise en compte de la limite de taille des messages
            // TODO voir comment on peut traiter ces dpassements de chane
            // defaon plus gnrique (via Hibernate ?)
            final int maxLength = 2000;
            String newMessage = pMessage;
            if (newMessage.length() > maxLength) {
                newMessage = newMessage.substring(0, maxLength);
            }
            // on est sur une erreur qui a t provoque
            // par un ProcessManager, on doit affecter le niveau de criticit WARNING par dfaut
            ErrorBO error = new ErrorBO(newMessage, newMessage, pCriticyLevel, mName, mAudit, mProject);
            mErrors.add(error);
        }
    }

    /**
     * @return la taille max du file system
     */
    protected long getMaxFileSystemSize() {
        return mMaxFileSystemSize;
    }

    /**
     * Positionne la taille max et la taille  la fin du file system pour cette tache
     * 
     * @param pParam le paramtre
     * @param pPersistent un boolen indiquant si la taille max est conserve  la fin ou pas
     */
    protected void affectFileSystemSize(Object pParam, boolean pPersistent) {
        // Ca peut etre directement un rpertoire
        if (pParam instanceof File) {
            mMaxFileSystemSize = calculateRecursiveSize((File) pParam);
        } else {
            // ou alors le nom du rpertoire
            if (pParam instanceof String) {
                mMaxFileSystemSize = calculateRecursiveSize(new File((String) pParam));
            } else {
                // ou une liste de rpertoires
                if (pParam instanceof List) {
                    List list = (List) pParam;
                    for (int i = 0; i < list.size(); i++) {
                        // et cumul sur chaque rpertoire
                        mMaxFileSystemSize += calculateRecursiveSize(new File((String) list.get(i)));
                    }
                } else {
                    // ou un objet plus complexe de type parameter
                    // un simpleStringParameterBO indiquant directement le rpertoire
                    if (pParam instanceof StringParameterBO) {
                        // appel simple de la mthode
                        mMaxFileSystemSize = calculateRecursiveSize(
                                new File(((StringParameterBO) pParam).getValue()));
                    } else {
                        // ou une liste de rpertoires
                        if (pParam instanceof ListParameterBO) {
                            // rcupre la liste des rpertoires
                            List list = ((ListParameterBO) pParam).getParameters();
                            for (int i = 0; i < list.size(); i++) {
                                // et cumul sur chaque rpertoire
                                mMaxFileSystemSize += calculateRecursiveSize(
                                        new File(((StringParameterBO) (list.get(i))).getValue()));
                            }
                        }
                    }
                }
            }
        }
        // Si c'est une tache qui conserve la place occupe  la fin, on positionne la valeur
        if (pPersistent) {

            mPersistentFileSystemSize = mMaxFileSystemSize;
        } // sinon c'est 0 par dfaut
    }

    /**
     * Set the size of temporary and persistent data when there many file/directory
     * each element of pParam is an Array. Each array conatins two information.
     * In first position the file/directory location. 
     * In second position a Boolean which indicate if this elementy is persistent.    
     * 
     * @param pParam List of Array which contains the directory place and 
     */
    protected void affectFileSystemSize(List<Object[]> pParam) {
        long size = 0;
        long sizePersistent = 0;
        for (int index = 0; index < pParam.size(); index++) {
            Object[] elt = pParam.get(index);
            boolean persistent = ((Boolean) elt[1]).booleanValue();
            affectFileSystemSize(elt[0], persistent);
            size = size + mMaxFileSystemSize;
            if (persistent) {
                sizePersistent = sizePersistent + mPersistentFileSystemSize;
            }
        }
        mMaxFileSystemSize = size;
        mPersistentFileSystemSize = sizePersistent;
    }

    /**
     * @param pFile le rpertoire racine dont on veut la taille
     * @return la taille du fichier ou la taille de l'ensemble du rpertoire si f est un rpertoire
     */
    private int calculateRecursiveSize(File pFile) {
        int size = 0;
        // si le fichier existe, on le traite, sinon on renvoie 0
        if (pFile.exists()) {
            // Si c'est un rpertoire, appel rcursif sur tous les sous-lments
            if (pFile.isDirectory()) {
                File[] tab = pFile.listFiles();
                for (int i = 0; i < tab.length; i++) {
                    size += calculateRecursiveSize(tab[i]);
                }
            } else {
                // on est sur un fichier, on rcupre simplement la taille
                size += pFile.length();
            }
        }
        return size;
    }

    /**
     * @return la taille du file systme  la fin de la tache
     */
    public long getPersistentFileSystemSize() {
        return mPersistentFileSystemSize;
    }
}