Java tutorial
/** * 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; } }