/** * 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; /** * Repr�sente une fa�ade permettant d'ex�cuter une t�che.<br> * Une t�che est responsable de la cr�ation et de la persistance de ses objets de r�sultats (impl�mentant l'interface * <code>MeasureBO</code>) ainsi que de ses erreurs (classe <code>ErrorBO</code>). <br /> <br /> Une t�che peut poss�der * : * <ul> * <li>une t�che parent : tant que la t�che parent n'est pas termin�e avec succ�s, celle-ci ne peut �tre lanc�e,</li> * <li>et/ou des t�ches enfants : lanc�es d�s la compl�tude avec succ�s de la t�che courante. * <li> * </ul> * <br /> Les attributs n�cessaires � une classe lui sont attribu�s via un pattern IOC. Une fois que la t�che a �t� * instanci�e, c'est son observateur (le Scheduler ou l'ex�cuteur d'analyse) qui lui transmet l'instance d'audit, de * projet, son statut, et ses t�ches enfants. Elle n'est responsable que de se nommer lors de son instanciation. Le * constructeur ne doit prendre aucun param�tre. <br /> <br /> Si la t�che �choue, elle doit passer en statut FAILED, et * g�n�rer des erreurs dans la base. Il est plus que vivement conseill� de ne pas utiliser les instance de projet et * d'audit lorsque les r�sultats sont persist�s, il faut utiliser des nouvelles instances directement � partir des DAO, * avec les id des instances offertes par l'observateur. <br /> <br /> Pour plus de d�tails sur la cr�ation d'une * nouvelle t�che, 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; /** * Pr�cise que l'ex�cution de la t�che s'est termin�e avec succ�s. */ public static final int TERMINATED = 0; /** * Pr�cise que l'ex�cution de la t�che a �chou�e. */ public static final int FAILED = 1; /** * Pr�cise que l'ex�cution de la t�che n'a pas �t� tent�e. */ public static final int NOT_ATTEMPTED = 2; /** * Pr�cise que l'ex�cution est en cours. */ public static final int RUNNING = 3; /** * Etat courant de la t�che */ protected int mStatus = NOT_ATTEMPTED; /** * Pr�cise que l'ex�cution de la t�che est suspendue en raison d'un manque de ressources. */ public static final int NO_RESOURCES = 4; /** * Pr�cise que l'ex�cution de la t�che est annul�e. */ public static final int CANCELLED = 5; /** * indique si la tache est obligatoire ou optionnelle obligatoire par d�faut */ protected boolean mMandatoryTask = true; /** * Projet attach� � la tache */ protected ProjectBO mProject = null; /** * Audit durant lequel est effectu�e la t�che. */ protected AuditBO mAudit = null; /** * Le nom de la t�che. */ protected String mName = null; /** * L'ensemble des param�tres temporaires d'une t�che */ 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 t�che */ protected Long mProjectId; /** l'id de l'audit auquel est rattach� la t�che */ protected Long mAuditId; /** les erreurs */ protected ArrayList mErrors; /** Param�tres de la t�che */ 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 d�finis */ 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 param�tres de la t�che (soit la forme de TaskParameterBO) */ public Collection getTaskParameters() { return mTaskParameters; } /** * @param pTaskParameters param�tres de la t�che */ 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 r�sultats dans la base de donn�es gr�ce � la session. * * @roseuid 42CD420D018C */ protected void persistResult() { } /** * Cr�e les erreurs et les persiste dans la base */ private void createErrors() { // la liste a �t� initialis�e � 0 �l�ments 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 pr�vient 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 ); } } } } /** * M�thode qui permet de cr�er 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 t�che s'est bien d�roul�e String[] tab = getName().split( "." ); // on ne devrait pas passer dans ce test si le nom de la tache // a �t� correctement d�fini if ( tab == null || tab.length == 0 ) { LOGGER.info( "la t�che " + mName + " � �t� ex�cut�e avec SUCCES " ); } else { // Prend juste le nom de la classe sans package LOGGER.info( "la t�che " + tab[tab.length - 1] + " � �t� ex�cut�e avec SUCCES " ); } } catch ( Exception e ) { LOGGER.error( e, e ); mStatus = FAILED; // une exception attrap�e ici est forc�ment une erreur critique // On r�cup�re le message de l'erreur String message = e.getMessage(); // Si le message est nul, on r�cup�re la description de l'erreur if ( null == message ) { message = e.toString(); } initError( message, ErrorBO.CRITICITY_FATAL ); } finally { // on cr�e 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; } } } /** * M�thode qui cr�e 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 d�fensif, 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 ); } } /** * M�thode qui effectue le traitement propre � chaque tache * * @throws TaskException car il y a plusieurs types d'exception suivant les t�ches * @throws JrafDaoException */ public abstract void execute() throws TaskException, JrafDaoException; /** * Cr�e une erreur avec un niveau de criticit� par d�faut * * @param pMessage le message */ public void initError( String pMessage ) { initError( pMessage, ErrorBO.CRITICITY_WARNING ); } /** * Cr�e une erreur avec un niveau de criticit� d�termin�e * * @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 d�passements de cha�ne // defa�on plus g�n�rique (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� provoqu�e // par un ProcessManager, on doit affecter le niveau de criticit� WARNING par d�faut 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 param�tre * @param pPersistent un bool�en indiquant si la taille max est conserv�e � la fin ou pas */ protected void affectFileSystemSize( Object pParam, boolean pPersistent ) { // Ca peut etre directement un r�pertoire if ( pParam instanceof File ) { mMaxFileSystemSize = calculateRecursiveSize( (File) pParam ); } else { // ou alors le nom du r�pertoire if ( pParam instanceof String ) { mMaxFileSystemSize = calculateRecursiveSize( new File( (String) pParam ) ); } else { // ou une liste de r�pertoires if ( pParam instanceof List ) { List list = (List) pParam; for ( int i = 0; i < list.size(); i++ ) { // et cumul sur chaque r�pertoire mMaxFileSystemSize += calculateRecursiveSize( new File( (String) list.get( i ) ) ); } } else { // ou un objet plus complexe de type parameter // un simpleStringParameterBO indiquant directement le r�pertoire if ( pParam instanceof StringParameterBO ) { // appel simple de la m�thode mMaxFileSystemSize = calculateRecursiveSize( new File( ( (StringParameterBO) pParam ).getValue() ) ); } else { // ou une liste de r�pertoires if ( pParam instanceof ListParameterBO ) { // r�cup�re la liste des r�pertoires List list = ( (ListParameterBO) pParam ).getParameters(); for ( int i = 0; i < list.size(); i++ ) { // et cumul sur chaque r�pertoire mMaxFileSystemSize += calculateRecursiveSize( new File( ( (StringParameterBO) ( list.get( i ) ) ).getValue() ) ); } } } } } } // Si c'est une tache qui conserve la place occup�e � la fin, on positionne la valeur if ( pPersistent ) { mPersistentFileSystemSize = mMaxFileSystemSize; } // sinon c'est 0 par d�faut } /** * 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 r�pertoire racine dont on veut la taille * @return la taille du fichier ou la taille de l'ensemble du r�pertoire si f est un r�pertoire */ 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 r�pertoire, appel r�cursif sur tous les sous-�l�ments 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 r�cup�re simplement la taille size += pFile.length(); } } return size; } /** * @return la taille du file syst�me � la fin de la tache */ public long getPersistentFileSystemSize() { return mPersistentFileSystemSize; } }