/* * codjo.net * * Common Apache License 2.0 */ package net.codjo.operation; import net.codjo.model.Period; import net.codjo.model.Table; import net.codjo.model.TableRecordingMode; import net.codjo.persistent.AbstractPersistent; import net.codjo.persistent.PersistenceException; import net.codjo.persistent.Reference; import net.codjo.utils.ConnectionManager; import java.sql.Connection; import java.sql.Statement; import java.util.Date; import java.util.List; import org.apache.log4j.Logger; /** * Classe g�n�rique pour tous les types d'op�ration. * * <p> La m�thode <code>proceed</code> permet d'executer l'op�ration. Cette m�thode d�l�gue le traitement � * son comportement. Le comportement d�fini donc l'action : import, traitement,... </p> * * @author $Author: marcona $ * @version $Revision: 1.17 $ * @see net.codjo.operation.OperationSettings */ public final class Operation extends AbstractPersistent { private static final Logger USER = Logger.getLogger("journal"); // Log private static final Logger APP = Logger.getLogger(Operation.class); private Reference operationSettingsRef; private OperationState operationState = new OperationState(); private Reference periodRef; private String portfolioGroupName; private String company; private List ptfRestrictionList; private AnomalyReport report; private static OperationSaveListener staticSaveListener; private OperationSaveListener saveListener; // private ArrayList whereClauseListUpdateWithPortfolio = new ArrayList(6); private SqlWhereClauseUtil sqlWhereClauseUtil = new SqlWhereClauseUtil(); /** * Constructor * * @param r Description of Parameter * * @throws IllegalArgumentException si l'un des arguments est invalide */ Operation(Reference selfRef, Reference period, String pfGrp, String company, Reference settings, AnomalyReport r) throws PersistenceException { super(selfRef); if (period == null || pfGrp == null || settings == null) { throw new IllegalArgumentException(); } portfolioGroupName = pfGrp; operationSettingsRef = settings; periodRef = period; operationSettingsRef.getObject(); periodRef.getObject(); this.report = r; this.company = company; } /** * Construction de la clause table pour une table donnee. Cette methode est utilise par deleteTable() et * markAnomalyField(). * * @param tableOfQuery Table sur laquelle vas porter la requete * * @return liste de table (ex: "AP_PORTFOLIO, BO_PORTFOLIO") */ public String buidTableClauseFor(Table tableOfQuery) { if (((getDestTable().getRecordingMode() == TableRecordingMode.BY_PERIOD_AND_PORTFOLIOGROUP) || (getDestTable().getRecordingMode() == TableRecordingMode.BY_PORTFOLIOGROUP)) && ((!("SANS".equals(getPortfolioGroupName()))) || (ptfRestrictionList != null))) { return tableOfQuery.getDBTableName() + ", BO_PORTFOLIO"; } else { return tableOfQuery.getDBTableName(); } } /** * Construction de la clause "where" pour une table donnee. Cette methode retourne la clause "where" * utilise par deleteTable() et markAnomalyField(). * * <p> ATTENTION : La methode buidTableClauseFor() doit etre utilise pour construire la clause de * selection des tables. </p> REMARQUE : l'objet whereClauseListUpdateWithPortfolio est utilis� � des fins * d'optimisation * * @param tableOfQuery Table sur laquelle vas porter la clause "where" * * @return Une clause where (ex: " where ...") ou null * * @throws IllegalArgumentException si le mode d'enregistrement est inconnu * @see #deleteTable(net.codjo.model.Table) * @see #markAnomalyField(boolean) * @see #buildWhereClauseFor(net.codjo.model.Table) */ public String buildWhereClauseFor(Table tableOfQuery) { String sourceSystem = getSourceTable().getSource(); String period = getPeriod().getPeriod(); // Initialisation de la liste des clauses where servant � l'update // whereClauseListUpdateWithPortfolio.add(0,""); // whereClauseListUpdateWithPortfolio.add(1,""); sqlWhereClauseUtil.init(); String whereClause = null; if (getDestTable().equals(tableOfQuery) || getSourceTable().equals(tableOfQuery)) { switch (getDestTable().getRecordingMode()) { case TableRecordingMode.NONE: whereClause = null; break; case TableRecordingMode.BY_PERIOD_AND_PORTFOLIOGROUP: if (!"SANS".equals(getPortfolioGroupName())) { whereClause = tableOfQuery.getDBTableName() + ".PORTFOLIO_CODE = BO_PORTFOLIO.PORTFOLIO_CODE" + " and PORTFOLIO_GROUP ='" + getPortfolioGroupName() + "'"; sqlWhereClauseUtil.dealWithPortfolioGroup(getPortfolioGroupName(), tableOfQuery.getDBTableName()); } case TableRecordingMode.BY_PERIOD: if (tableOfQuery.containsColumn("PERIOD")) { whereClause = "PERIOD='" + period + "'" + ((whereClause != null) ? (" and " + whereClause) : ""); sqlWhereClauseUtil.dealWithPeriod(period); } break; case TableRecordingMode.BY_PORTFOLIOGROUP: if (!"SANS".equals(getPortfolioGroupName())) { whereClause = tableOfQuery.getDBTableName() + ".PORTFOLIO_CODE = BO_PORTFOLIO.PORTFOLIO_CODE" + " and PORTFOLIO_GROUP ='" + getPortfolioGroupName() + "'"; sqlWhereClauseUtil.dealWithPortfolioGroup(getPortfolioGroupName(), tableOfQuery.getDBTableName()); } break; default: throw new IllegalArgumentException("Unknown Recording Mode :" + getDestTable().getRecordingMode()); } // Choix du Source System if (whereClause != null) { whereClause = " where " + whereClause; if (tableOfQuery.containsColumn("SOURCE_SYSTEM")) { if (!"MULTI_PTF".equals(sourceSystem)) { whereClause += " and " + tableOfQuery.getDBTableName() + ".SOURCE_SYSTEM = " + "'" + sourceSystem + "'"; sqlWhereClauseUtil.dealWithSourceSystem(sourceSystem, tableOfQuery.getDBTableName()); } } } } // Restriction portefeuilles if ((getDestTable().getRecordingMode() == TableRecordingMode.BY_PERIOD_AND_PORTFOLIOGROUP && ptfRestrictionList != null) || (getDestTable().getRecordingMode() == TableRecordingMode.BY_PORTFOLIOGROUP && ptfRestrictionList != null)) { whereClause = addPtfRestrictionList(whereClause); String str = addPtfRestrictionList(sqlWhereClauseUtil.getSelectTerm()); sqlWhereClauseUtil.addPtfRestrictionList(str); } // Crit�re de s�lection ou de delete if (getOperationSettings().getDestTable().equals(tableOfQuery)) { whereClause = addWhereCriteria(getOperationSettings().getDeleteCriteria(), whereClause); } else { whereClause = addWhereCriteria(getOperationSettings().getSelectCriteria(), whereClause); } String criteriaTemp = ""; criteriaTemp = addWhereCriteria((getOperationSettings().getDestTable().equals(tableOfQuery)) ? getOperationSettings().getDeleteCriteria() : getOperationSettings().getSelectCriteria(), criteriaTemp); // D�coupage du crit�re s�lection en 2 sous-crit�res (1 pour le select et un pour l'update) sqlWhereClauseUtil.buildCriteria(criteriaTemp, tableOfQuery); // Renseignement des champs p�riode avec la p�riode concern�e et la compagnie sqlWhereClauseUtil.fill(getPeriod().toString(), getPreviousPeriod(), getCompany()); return fillWhereClauseWithPeriod(whereClause); } /** * Remplissage de la whereClause pour prendre en compte le param�trage $CURRENT_PERIOD$ � remplacer * automatiquement par la p�riode courante $PREVIOUS_PERIOD$ � remplacer automatiquement par la p�riode * pr�c�dente * * @param initialWhereClause Description of the Parameter * * @return Description of the Return Value */ private String fillWhereClauseWithPeriod(String initialWhereClause) { if (initialWhereClause != null) { String clause = initialWhereClause; int idx = clause.indexOf("$CURRENT_PERIOD$"); if (idx >= 0) { StringBuilder criteria = new StringBuilder(clause); criteria.replace(idx, idx + 16, "'" + getPeriod() + "'"); clause = criteria.toString(); } int idxprev = clause.indexOf("$PREVIOUS_PERIOD$"); if (idxprev >= 0) { StringBuilder criteriaPrev = new StringBuilder(clause); criteriaPrev.replace(idxprev, idxprev + 17, "'" + getPreviousPeriod() + "'"); clause = criteriaPrev.toString(); } int idxCompany = clause.indexOf("$COMPANY$"); if (idxCompany >= 0) { StringBuilder criteriaPrev = new StringBuilder(clause); criteriaPrev.replace(idxCompany, idxCompany + 9, "'" + getCompany() + "'"); clause = criteriaPrev.toString(); } return clause; } return initialWhereClause; } /** * Determine la longueur de l'op�ration � effectuer (ex : Nb de lignes du fichier � importer). * * <p> <b>Attention</b> : Le comportement doit etre deja charge. </p> * * @throws OperationFailureException Si la determination echoue (L'etat de l'operation est mis en ECHEC) */ public void determineLengthOfTask() throws OperationFailureException { try { getLoadedBehavior().determineLengthOfTask(this); } catch (Exception ex) { manageOperationFailure(ex); } } /** * Retourne L'objet responsable de la gestion des anomaly pour cette operation. * * @return The AnomalyReport value */ public AnomalyReport getAnomalyReport() { return report; } /** * Retourne le comportement de l'op�ration. Si le comportement n'est pas d�j� charg�, alors la m�thode le * charge. * * @return le comportement. * * @throws PersistenceException - */ public Behavior getBehavior() throws PersistenceException { return getOperationSettings().getBehavior(); } /** * Gets the Commentry attribute of the ImportOperation object * * @return The OperationState value */ public String getCommentry() { return getOperationSettings().getCommentry(); } /** * R�cup�re la table destination de l'op�ration * * @return The Table value */ public Table getDestTable() { return getOperationSettings().getDestTable(); } /** * Retourne le comportement charge en memoire (sinon <code>null</code> ). * * @return le comportement (peut etre null). */ public Behavior getLoadedBehavior() { return getOperationSettings().getLoadedBehavior(); } /** * Gets the OperationSettings attribute of the Operation object * * @return The OperationSettings value */ public OperationSettings getOperationSettings() { return (OperationSettings)operationSettingsRef.getLoadedObject(); } /** * Gets the OperationState attribute of the ImportOperation object * * @return The OperationState value */ public OperationState getOperationState() { return operationState; } /** * Retourne le type de l'operation. * * @return le type de l'operation * * @see net.codjo.operation.OperationSettings#getOperationType */ public String getOperationType() { return getOperationSettings().getOperationType(); } /** * Gets the Period attribute of the ImportOperation object * * @return The Period value */ public Period getPeriod() { return (Period)periodRef.getLoadedObject(); } /** * Gets the PortfolioGroup attribute of the ImportOperation object * * @return The PortfolioGroup value */ public String getPortfolioGroupName() { return portfolioGroupName; } /** * Gets the Priority attribute of the ImportOperation object * * @return The Priority value */ public int getPriority() { return getOperationSettings().getPriority(); } /** * R�cup�re la table source de l'op�ration * * @return The Table value */ public Table getSourceTable() { return getOperationSettings().getSourceTable(); } /** * Gets the Automatic attribute of the ImportOperation object * * @return The Automatic value */ public boolean isAutomatic() { return getOperationSettings().isAutomatic(); } /** * Prepare l'execution de l'operation. * * @param firstLaunch Description of Parameter * * @throws OperationFailureException Description of Exception */ public void prepareProceed(boolean firstLaunch) throws OperationFailureException { try { getOperationSettings().lockUnloadBehavior(); getBehavior().prepareProceed(); if (firstLaunch || "Traitement".equals(getOperationType())) { deleteTable(getBehavior().getDestTable()); } if (getBehavior().getSourceTable() != null && getBehavior().getDestTable() != null) { markAnomalyField(firstLaunch); } } catch (Exception ex) { manageOperationFailure(ex); } } /** * Execute l'op�ration. Cette methode mets � jours automatiquement l'�tat de l'op�ration. Attention : Le * comportement doit etre prealablement charge. * * @throws IllegalArgumentException si la Behavior n'est pas charg�e */ public void proceed() throws OperationFailureException { if (getLoadedBehavior() == null) { throw new IllegalArgumentException("Behavior non charge"); } try { log(getPeriod() + " " + getOperationType() + " " + getSourceTable() + " -> " + getDestTable()); getLoadedBehavior().proceed(this); setOperationState(new OperationState(new Date(), OperationState.DONE)); } catch (Exception ex) { manageOperationFailure(ex); } finally { log("Fin op�ration : " + getOperationType()); } } /** * Sets the OperationState attribute of the ImportOperation object * * @param operationState The new OperationState value * * @throws IllegalArgumentException si l'un des arguments est invalide */ public void setOperationState(OperationState operationState) { if (operationState == null) { throw new IllegalArgumentException(); } this.operationState = operationState; setSynchronized(false); getOperationSettings().unlockUnloadBehavior(); } /** * Constructor for the setPortfolioGroupName object * * @param name Description of Parameter */ public void setPortfolioGroupName(String name) { portfolioGroupName = name; } /** * Fixe la restriction sur les codes portefeuilles * * @param ptfRestrictList La liste */ public void setPtfRestrictionList(List ptfRestrictList) { ptfRestrictionList = ptfRestrictList; } /** * Ajoute la liste des restriction / codes ptf � la clause where * * @param whereClause La clause Where avant ajout * * @return La clause where apr�s ajout */ private String addPtfRestrictionList(String whereClause) { if (!ptfRestrictionList.isEmpty()) { if (whereClause != null) { whereClause += " and BO_PORTFOLIO.PORTFOLIO_CODE in ("; } else { whereClause = " where BO_PORTFOLIO.PORTFOLIO_CODE in ("; } for (int i = 0; i < ptfRestrictionList.size(); i++) { whereClause += "'" + ptfRestrictionList.get(i) + "'"; if (i < ptfRestrictionList.size() - 1) { whereClause += ","; } } whereClause += ")"; } return whereClause; } /** * Ajoute le crit�re a la clause where. * * @param criteria Le critere * @param whereClause La clause where * * @return la nouvelle clause where */ private String addWhereCriteria(String criteria, String whereClause) { if (criteria != null && !"".equals(criteria)) { criteria = replaceVariable(criteria); if (whereClause != null) { whereClause += " and " + criteria; } else { whereClause = " where " + criteria; } } return whereClause; } /** * Efface le contenu de la table en fonction de son mode d'historisation. * * @param destTable Table de destination a effacer * * @throws Exception Description of the Exception * @see net.codjo.model.TableRecordingMode */ private void deleteTable(Table destTable) throws Exception { if (destTable == null) { return; } String whereClause = buildWhereClauseFor(destTable); String query = "set rowcount 1000 while exists (select 1 from " + buidTableClauseFor(destTable) + ((whereClause != null) ? whereClause : ("")) + ") begin begin tran delete " + destTable.getDBTableName() + " from " + buidTableClauseFor(destTable) + ((whereClause != null) ? whereClause : ("")) + " if @@error > 0" + " rollback else commit end set rowcount 0 "; ConnectionManager connectionManager = getLoadedBehavior().getConnectionManager(); Connection con = connectionManager.getConnection(); Statement stmt = null; try { APP.debug("Query delete = " + query); stmt = con.createStatement(); stmt.executeUpdate(query); } finally { connectionManager.releaseConnection(con, stmt); } } /** * DOCUMENT ME! */ private void error(String msg, Throwable e) { USER.error(msg, e); // APP.error(msg, e); } /** * Retourne la period Begin Of The Year. * * @return La valeur de boyPeriod */ private String getBoyPeriod() { String year = getPeriod().getPeriod().substring(0, 4); int y = Integer.parseInt(year) - 1; return y + "12"; } /** * Retourne la period N-1 * * @return P�riode N-1 */ public String getPreviousPeriod() { String year = getPeriod().getPeriod().substring(0, 4); String month = getPeriod().getPeriod().substring(4, 6); int y = Integer.parseInt(year) - 1; int m = Integer.parseInt(month) - 1; if (m == 0) { m = 12; year = String.valueOf(y); } String prevm = String.valueOf(m); if (prevm.length() <= 1) { prevm = "0" + prevm; } return year + prevm; } /** * DOCUMENT ME! */ private void log(String msg) { USER.info(msg); // APP.debug(msg); } /** * Gere l'echec de l'operation. * * @param ex L'exception ayant fait echouer l'operation */ private void manageOperationFailure(Exception ex) throws OperationFailureException { setOperationState(new OperationState(new Date(), OperationState.FAILED)); error("Erreur : ", ex); ex.printStackTrace(); if (ex instanceof OperationFailureException) { throw (OperationFailureException)ex; } else { throw new OperationFailureException(ex.getLocalizedMessage(), this); } } /** * Mets le champ ANOMALY � -1 pour les enregistrements qui doivent �tre trait�s. * * <p> Si le AnomalyReport ne fait pas d'update en source, cette methode ne fait rien. </p> * * <p> <b>ATTENTION</b> : Cette methode assume que le behavior est en memoire. </p> * * @param firstLaunch Traitement normal (ou reprise sur erreur) * * @throws Exception Description of the Exception */ private void markAnomalyField(boolean firstLaunch) throws Exception { if (!report.needsSourceUpdatable()) { return; } // Cr�ation la requete String query = buildUpdateQuery(firstLaunch); ConnectionManager connectionManager = getLoadedBehavior().getConnectionManager(); Connection con = connectionManager.getConnection(); // Connection con = getLoadedBehavior().getConnectionManager().getConnection(); Statement stmt = null; try { stmt = con.createStatement(); stmt.executeUpdate(query); } finally { // getLoadedBehavior().getConnectionManager().releaseConnection(con, stmt); connectionManager.releaseConnection(con, stmt); } } /** * Permet la cr�ation des requ�tes permettant un update optimis�. * * @param firstLaunch Traitement normal (ou reprise sur erreur) * * @throws Exception Description of the Exception */ private String buildUpdateQuery(boolean firstLaunch) throws Exception { Table srcTable = getLoadedBehavior().getSourceTable(); String srcTableName = srcTable.getDBTableName(); String query = ""; String whereClause = buildWhereClauseFor(srcTable); if (!firstLaunch) { if (whereClause != null) { whereClause += "and " + srcTableName + ".ANOMALY > 0"; } else { whereClause = " where " + srcTableName + ".ANOMALY > 0"; } } if (((getDestTable().getRecordingMode() == TableRecordingMode.BY_PERIOD_AND_PORTFOLIOGROUP) || (getDestTable().getRecordingMode() == TableRecordingMode.BY_PORTFOLIOGROUP)) && ((!"SANS".equals(getPortfolioGroupName())) || (ptfRestrictionList != null))) { // Cas d'un update (avec jointure) � partir la table source et BO_PORTFOLIO // Construction du select query = " select PORTFOLIO_CODE into #BO_PORTFOLIO_TMP from BO_PORTFOLIO "; query += sqlWhereClauseUtil.getSelectWhereClause(); // Cr�ation de l'index query += " create clustered index idx1 on #BO_PORTFOLIO_TMP(PORTFOLIO_CODE) "; // Cr�ation de l'update String udpateQuery = " update " + srcTableName + " set " + srcTableName + ".ANOMALY=-1," + srcTableName + ".ANOMALY_LOG=NULL" + " from " + srcTableName + ", BO_PORTFOLIO "; udpateQuery += sqlWhereClauseUtil.getUpdateWhereClause(); query += udpateQuery.replaceAll("BO_PORTFOLIO", "#BO_PORTFOLIO_TMP"); // drop de la table temporaire query += " drop table #BO_PORTFOLIO_TMP"; APP.debug("Update optimis�: " + query); } else { // Cas d'un update uniquement � partir de la table source query = "update " + srcTableName + " set " + srcTableName + ".ANOMALY=-1," + srcTableName + ".ANOMALY_LOG=NULL" + " from " + buidTableClauseFor(srcTable) + ((whereClause != null) ? whereClause : ""); APP.debug("Update non-optimis�: " + query); } return query; } /** * DOCUMENT ME! * * @param query Description of Parameter * * @return Description of the Returned Value */ private String replaceVariable(String query) { int idx = query.indexOf("##BOY##"); if (idx < 0) { return query; } StringBuffer builtQuery = new StringBuffer(query); builtQuery.replace(idx, idx + 7, getBoyPeriod()); return replaceVariable(builtQuery.toString()); } /** * <p>Appel la methode save du model.</p> * * <p>Appelle l'OperationSaveListener (static, ou d'instance) s'il existe, pour lui notifier * l'avant-sauvegarde et l'apr�s-sauvegarde.</p> * * @throws net.codjo.persistent.PersistenceException * - * @see net.codjo.persistent.Model#save */ @Override public void save() throws PersistenceException { if (saveListener != null) { saveListener.onBeforeSave(this); } else { if (staticSaveListener != null) { staticSaveListener.onBeforeSave(this); } } super.save(); if (saveListener != null) { saveListener.onAfterSave(this); } else { if (staticSaveListener != null) { staticSaveListener.onAfterSave(this); } } } public static OperationSaveListener getStaticSaveListener() { return staticSaveListener; } public static void setStaticSaveListener(OperationSaveListener staticSaveListener) { Operation.staticSaveListener = staticSaveListener; } public OperationSaveListener getSaveListener() { return saveListener; } public void setSaveListener(OperationSaveListener saveListener) { this.saveListener = saveListener; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } }