0001: /*
0002: * Copyright (c) 2004-2006, Jean-François Brazeau. All rights reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * 1. Redistributions of source code must retain the above copyright notice,
0008: * this list of conditions and the following disclaimer.
0009: *
0010: * 2. Redistributions in binary form must reproduce the above copyright
0011: * notice, this list of conditions and the following disclaimer in the
0012: * documentation and/or other materials provided with the distribution.
0013: *
0014: * 3. The name of the author may not be used to endorse or promote products
0015: * derived from this software without specific prior written permission.
0016: *
0017: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0018: * IMPLIEDWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0019: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0020: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0021: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
0022: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
0023: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0024: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
0025: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
0026: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0027: */
0028: package jfb.tools.activitymgr.core;
0029:
0030: import java.io.IOException;
0031: import java.io.InputStream;
0032: import java.io.LineNumberReader;
0033: import java.io.StringReader;
0034: import java.sql.Connection;
0035: import java.sql.PreparedStatement;
0036: import java.sql.ResultSet;
0037: import java.sql.SQLException;
0038: import java.sql.Statement;
0039: import java.text.SimpleDateFormat;
0040: import java.util.ArrayList;
0041: import java.util.Arrays;
0042: import java.util.Calendar;
0043: import java.util.Comparator;
0044:
0045: import jfb.tools.activitymgr.core.beans.Collaborator;
0046: import jfb.tools.activitymgr.core.beans.Contribution;
0047: import jfb.tools.activitymgr.core.beans.Duration;
0048: import jfb.tools.activitymgr.core.beans.Task;
0049: import jfb.tools.activitymgr.core.beans.TaskSearchFilter;
0050: import jfb.tools.activitymgr.core.beans.TaskSums;
0051: import jfb.tools.activitymgr.core.util.StringHelper;
0052:
0053: import org.apache.commons.dbcp.BasicDataSource;
0054: import org.apache.log4j.Logger;
0055:
0056: /**
0057: * Classe offrant les services de base de persistence de
0058: * l'application.
0059: */
0060: public class DbMgr {
0061:
0062: /** Logger */
0063: private static Logger log = Logger.getLogger(DbMgr.class);
0064:
0065: /** Formatteur de date */
0066: private static SimpleDateFormat sdf = new SimpleDateFormat(
0067: "yyyyMMdd");
0068:
0069: /** Datasource */
0070: private static BasicDataSource ds = null;
0071:
0072: /** Contexte de thread utilisé pour détecter les anomalies associées à la gestion de transaction */
0073: private static ThreadLocal threadLocal = new ThreadLocal();
0074:
0075: /**
0076: * Initialise la connexion à la base de données.
0077: * @param driverName le nom du driver JDBC.
0078: * @param url l'URL de connexion au serveur.
0079: * @param user l'identifiant de connexion/
0080: * @param password le mot de passe de connexion.
0081: * @throws DbException levé en cas d'incident technique d'accès à la base.
0082: */
0083: protected static void initDatabaseAccess(String driverName,
0084: String url, String user, String password)
0085: throws DbException {
0086: try {
0087: // Si la datasource existe on la ferme
0088: if (ds != null) {
0089: closeDatabaseAccess();
0090: }
0091: // Fermeture de la datasource
0092: BasicDataSource newDs = new BasicDataSource();
0093:
0094: // Initialisation de la Datasource
0095: newDs = new BasicDataSource();
0096: log.info("Connecting to '" + url + "'");
0097: newDs.setDriverClassName(driverName);
0098: newDs.setUrl(url);
0099: newDs.setUsername(user);
0100: newDs.setPassword(password);
0101: newDs.setDefaultAutoCommit(false);
0102:
0103: // Tentative de récupération d'une connexion
0104: // pour détecter les problèmes de connexion
0105: Connection con = newDs.getConnection();
0106: con.close();
0107:
0108: // Sauvegarde de la référence
0109: ds = newDs;
0110: } catch (SQLException e) {
0111: log.info("SQL Exception", e);
0112: throw new DbException("Couldn't get a SQL Connection", e);
0113: }
0114: }
0115:
0116: /**
0117: * Ferme la base de données.
0118: * @throws DbException levé en cas d'incident technique d'accès à la BDD.
0119: */
0120: protected static void closeDatabaseAccess() throws DbException {
0121: try {
0122: if (ds != null) {
0123: // Récupération de la connexion
0124: Connection con = ds.getConnection();
0125:
0126: // Cas d'une base HSQLDB embarquée
0127: if (isEmbeddedHSQLDB(con)) {
0128: // Extinction de la base de données
0129: con.createStatement().execute("shutdown");
0130: }
0131:
0132: // Fermeture de la datasource
0133: ds.close();
0134: ds = null;
0135: }
0136: } catch (SQLException e) {
0137: log.info("Incident SQL", e);
0138: throw new DbException(
0139: "Echec lors de la fermeture de la base de données",
0140: e);
0141: }
0142: }
0143:
0144: /**
0145: * Permet de commencer une transaction.
0146: *
0147: * <p>Une connexion à la base de données est établie. Celle ci
0148: * doit être validée par la couche appelante par une invocation
0149: * de <code>endTransaction</code>.</p>
0150: *
0151: * @return le contexte de transaction.
0152: * @throws DbException levé en cas d'incident technique d'accès à la base.
0153: */
0154: protected static DbTransaction beginTransaction()
0155: throws DbException {
0156: try {
0157: // Est-on connecté à la BDD ?
0158: if (ds == null)
0159: throw new DbException(
0160: "Database connection not established", null);
0161: // Obtention d'une connexion
0162: Connection con = ds.getConnection();
0163: if (threadLocal.get() != null)
0164: throw new Error("Conflicting transaction");
0165: threadLocal.set(con);
0166: //log.debug("Active : " + ds.getNumActive() + ", Idle : " + ds.getNumIdle() + ", Connexion : " + con);
0167: return new DbTransaction(con);
0168: } catch (SQLException e) {
0169: log.info("SQL Exception", e);
0170: throw new DbException("Couldn't get a SQL Connection", e);
0171: }
0172: }
0173:
0174: /**
0175: * Valide une transactrion.
0176: * @param tx contexte de transaction.
0177: * @throws DbException levé en cas d'incident technique d'accès à la base.
0178: */
0179: protected static void commitTransaction(DbTransaction tx)
0180: throws DbException {
0181: try {
0182: tx.getConnection().commit();
0183: } catch (SQLException e) {
0184: log.info("Incident SQL", e);
0185: throw new DbException("Echec du commit", e);
0186: }
0187: }
0188:
0189: /**
0190: * Vérifie si les tables existent dans le modèle.
0191: * @param tx le contexte de transaction.
0192: * @return un booléen indiquant si la table spécifiée existe dans le modèle.
0193: * @throws DbException levé en cas d'incident technique d'accès à la base.
0194: */
0195: protected static boolean tablesExist(DbTransaction tx)
0196: throws DbException {
0197: boolean tablesExist = true;
0198: tablesExist &= tableExists(tx, "COLLABORATOR");
0199: tablesExist &= tableExists(tx, "CONTRIBUTION");
0200: tablesExist &= tableExists(tx, "DURATION");
0201: tablesExist &= tableExists(tx, "TASK");
0202: return tablesExist;
0203: }
0204:
0205: /**
0206: * Vérifie si une table existe dans le modèle.
0207: * @param tx le contexte de transaction.
0208: * @param tableName le nom de la table.
0209: * @return un booléen indiquant si la table spécifiée existe dans le modèle.
0210: * @throws DbException levé en cas d'incident technique d'accès à la base.
0211: */
0212: private static boolean tableExists(DbTransaction tx,
0213: String tableName) throws DbException {
0214: PreparedStatement pStmt = null;
0215: try {
0216: // Récupération de la connexion
0217: Connection con = tx.getConnection();
0218:
0219: // Recherche de la table
0220: ResultSet rs = con.getMetaData().getTables(null, null,
0221: tableName, new String[] { "TABLE" });
0222:
0223: // Récupération du résultat
0224: boolean exists = rs.next();
0225:
0226: // Retour du résultat
0227: return exists;
0228: } catch (SQLException e) {
0229: log.info("Incident SQL", e);
0230: throw new DbException(
0231: "Echec lors du test d'existance de la table '"
0232: + tableName + "'", e);
0233: } finally {
0234: if (pStmt != null)
0235: try {
0236: pStmt.close();
0237: } catch (Throwable ignored) {
0238: }
0239: }
0240: }
0241:
0242: /**
0243: * Crée les tables du modèle de données.
0244: * @param tx contexte de transaction.
0245: * @throws DbException levé en cas d'incident technique d'accès à la base.
0246: */
0247: protected static void createTables(DbTransaction tx)
0248: throws DbException {
0249: Statement stmt = null;
0250: try {
0251: // Récupération de la connexion
0252: Connection con = tx.getConnection();
0253:
0254: // Lecture du fichier SQL de création de la BDD
0255: String batchName = "sql/"
0256: + (isHSQLDB(con) ? "hsqldb.sql" : "mysqldb.sql");
0257: InputStream in = DbMgr.class.getResourceAsStream(batchName);
0258: String batchContent = null;
0259: try {
0260: batchContent = StringHelper.fromInputStream(in);
0261: } catch (IOException e) {
0262: log
0263: .info(
0264: "I/O error while loading table creation SQL script.",
0265: e);
0266: throw new DbException(
0267: "I/O error while loading table creation SQL script.",
0268: null);
0269: }
0270:
0271: // Découpage et exécution du batch
0272: stmt = con.createStatement();
0273: // TODO Externaliser le découpage du script SQL
0274: LineNumberReader lnr = new LineNumberReader(
0275: new StringReader(batchContent));
0276: StringBuffer buf = new StringBuffer();
0277: boolean proceed = true;
0278: do {
0279: String line = null;
0280: // On ne lit dans le flux que si la ligne courante n'est pas
0281: // encore totalement traitée
0282: if (line == null) {
0283: try {
0284: line = lnr.readLine();
0285: } catch (IOException e) {
0286: log
0287: .info(
0288: "Unexpected I/O error while reading memory stream!",
0289: e);
0290: throw new DbException(
0291: "Unexpected I/O error while reading memory stream!",
0292: null);
0293: }
0294: log.debug("Line read : '" + line + "'");
0295: }
0296: // Si le flux est vide, on sort de la boucle
0297: if (line == null) {
0298: proceed = false;
0299: }
0300: // Sinon on traite la ligne
0301: else {
0302: line = line.trim();
0303: // Si la ligne est un commentaire on l'ignore
0304: if (line.startsWith("--")) {
0305: line = null;
0306: } else {
0307: // Sinon on regarde si la ligne possède
0308: // un point virgule
0309: int idx = line.indexOf(';');
0310: // Si c'est le cas, on découpe la chaîne et on
0311: // exécute la requête
0312: if (idx >= 0) {
0313: buf.append(line.subSequence(0, idx));
0314: line = line.substring(idx);
0315: String sql = buf.toString();
0316: buf.setLength(0);
0317: log.debug(" - sql='" + sql + "'");
0318: if (!"".equals(sql))
0319: stmt.executeUpdate(sql);
0320: }
0321: // sinon on ajoute la ligne au buffer de requeête
0322: else {
0323: buf.append(line);
0324: buf.append('\n');
0325: }
0326: }
0327: }
0328:
0329: } while (proceed);
0330:
0331: // Test de l'existence des tables
0332: if (!tablesExist(tx))
0333: throw new DbException(
0334: "Database table creation failure", null);
0335:
0336: // Fermeture du statement
0337: stmt.close();
0338: stmt = null;
0339: } catch (SQLException e) {
0340: log.info("Incident SQL", e);
0341: throw new DbException("Database table creation failure", e);
0342: } finally {
0343: if (stmt != null)
0344: try {
0345: stmt.close();
0346: } catch (Throwable ignored) {
0347: }
0348: }
0349: }
0350:
0351: /**
0352: * Crée un collaborateur.
0353: *
0354: * @param tx contexte de transaction.
0355: * @param newCollaborator le collaborateur à créer.
0356: * @return le collaborateur après création.
0357: * @throws DbException levé en cas d'incident technique d'accès à la base.
0358: */
0359: protected static Collaborator createCollaborator(DbTransaction tx,
0360: Collaborator newCollaborator) throws DbException {
0361: PreparedStatement pStmt = null;
0362: try {
0363: // Récupération de la connexion
0364: Connection con = tx.getConnection();
0365:
0366: // Préparation de la requête
0367: pStmt = con
0368: .prepareStatement("insert into collaborator (clb_login, clb_first_name, clb_last_name, clb_is_active) values (?, ?, ?, ?)");
0369: pStmt.setString(1, newCollaborator.getLogin());
0370: pStmt.setString(2, newCollaborator.getFirstName());
0371: pStmt.setString(3, newCollaborator.getLastName());
0372: pStmt.setBoolean(4, newCollaborator.getIsActive());
0373: pStmt.executeUpdate();
0374:
0375: // Récupération de l'identifiant généré
0376: long generatedId = getGeneratedId(pStmt);
0377: log.debug("Generated id=" + generatedId);
0378: newCollaborator.setId(generatedId);
0379:
0380: // Fermeture du statement
0381: pStmt.close();
0382: pStmt = null;
0383:
0384: // Retour du résultat
0385: return newCollaborator;
0386: } catch (SQLException e) {
0387: log.info("Incident SQL", e);
0388: throw new DbException(
0389: "Echec lors de la création du collaborateur '"
0390: + newCollaborator.getLogin() + "'", e);
0391: } finally {
0392: if (pStmt != null)
0393: try {
0394: pStmt.close();
0395: } catch (Throwable ignored) {
0396: }
0397: }
0398: }
0399:
0400: /**
0401: * Crée une contribution.
0402: *
0403: * @param tx contexte de transaction.
0404: * @param newContribution la nouvelle contribution.
0405: * @return la contribution après création.
0406: * @throws DbException levé en cas d'incident technique d'accès à la base.
0407: */
0408: protected static Contribution createContribution(DbTransaction tx,
0409: Contribution newContribution) throws DbException {
0410: PreparedStatement pStmt = null;
0411: try {
0412: // Récupération de la connexion
0413: Connection con = tx.getConnection();
0414:
0415: // Préparation de la requête
0416: pStmt = con
0417: .prepareStatement("insert into contribution (ctb_year, ctb_month, ctb_day, ctb_contributor, ctb_task, ctb_duration) values (?, ?, ?, ?, ?, ?)");
0418: pStmt.setInt(1, newContribution.getYear());
0419: pStmt.setInt(2, newContribution.getMonth());
0420: pStmt.setInt(3, newContribution.getDay());
0421: pStmt.setLong(4, newContribution.getContributorId());
0422: pStmt.setLong(5, newContribution.getTaskId());
0423: pStmt.setLong(6, newContribution.getDurationId());
0424: pStmt.executeUpdate();
0425:
0426: // Fermeture du statement
0427: pStmt.close();
0428: pStmt = null;
0429:
0430: // Retour du résultat
0431: return newContribution;
0432: } catch (SQLException e) {
0433: log.info("Incident SQL", e);
0434: throw new DbException(
0435: "Echec lors de la création d'une contribution", e);
0436: } finally {
0437: if (pStmt != null)
0438: try {
0439: pStmt.close();
0440: } catch (Throwable ignored) {
0441: }
0442: }
0443: }
0444:
0445: /**
0446: * Crée une contribution.
0447: *
0448: * @param tx contexte de transaction.
0449: * @param newDuration la nouvelle durée.
0450: * @return la durée après création.
0451: * @throws DbException levé en cas d'incident technique d'accès à la base.
0452: */
0453: protected static Duration createDuration(DbTransaction tx,
0454: Duration newDuration) throws DbException {
0455: PreparedStatement pStmt = null;
0456: try {
0457: // Récupération de la connexion
0458: Connection con = tx.getConnection();
0459:
0460: // Préparation de la requête
0461: pStmt = con
0462: .prepareStatement("insert into duration (dur_id, dur_is_active) values (?, ?)");
0463: pStmt.setLong(1, newDuration.getId());
0464: pStmt.setBoolean(2, newDuration.getIsActive());
0465: pStmt.executeUpdate();
0466:
0467: // Fermeture du statement
0468: pStmt.close();
0469: pStmt = null;
0470:
0471: // Retour du résultat
0472: return newDuration;
0473: } catch (SQLException e) {
0474: log.info("Incident SQL", e);
0475: throw new DbException(
0476: "Echec lors de la création de la durée : '"
0477: + newDuration + "'", e);
0478: } finally {
0479: if (pStmt != null)
0480: try {
0481: pStmt.close();
0482: } catch (Throwable ignored) {
0483: }
0484: }
0485: }
0486:
0487: /**
0488: * Crée une tache.
0489: *
0490: * <p>La tache parent peut être nulle pour indiquer que la nouvelle tache
0491: * est une tache racine.</p>
0492: *
0493: * @param tx le contexte de transaction.
0494: * @param parentTask la tache parent accueillant la nouvelle tache.
0495: * @param newTask la nouvelle tache.
0496: * @return la tache après création.
0497: * @throws DbException levé en cas d'incident technique d'accès à la base.
0498: */
0499: protected static Task createTask(DbTransaction tx, Task parentTask,
0500: Task newTask) throws DbException {
0501: PreparedStatement pStmt = null;
0502: try {
0503: // Récupération de la connexion
0504: Connection con = tx.getConnection();
0505:
0506: // Mise à jour du chemin de la tâche
0507: String parentPath = parentTask == null ? "" : parentTask
0508: .getFullPath();
0509: newTask.setPath(parentPath);
0510:
0511: // Génération du numéro de la tâche
0512: byte taskNumber = newTaskNumber(tx, parentPath);
0513: newTask.setNumber(taskNumber);
0514:
0515: // Préparation de la requête
0516: pStmt = con
0517: .prepareStatement("insert into task (tsk_path, tsk_number, tsk_code, tsk_name, tsk_budget, tsk_initial_cons, tsk_todo, tsk_comment) values (?, ?, ?, ?, ?, ?, ?, ?)");
0518: pStmt.setString(1, newTask.getPath());
0519: pStmt.setByte(2, newTask.getNumber());
0520: pStmt.setString(3, newTask.getCode());
0521: pStmt.setString(4, newTask.getName());
0522: pStmt.setLong(5, newTask.getBudget());
0523: pStmt.setLong(6, newTask.getInitiallyConsumed());
0524: pStmt.setLong(7, newTask.getTodo());
0525: pStmt.setString(8, newTask.getComment());
0526: pStmt.executeUpdate();
0527:
0528: // Récupération de l'identifiant généré
0529: long generatedId = getGeneratedId(pStmt);
0530: log.debug("Generated id=" + generatedId);
0531: newTask.setId(generatedId);
0532:
0533: // Fermeture du ResultSet
0534: pStmt.close();
0535: pStmt = null;
0536:
0537: // Retour du résultat
0538: return newTask;
0539: } catch (SQLException e) {
0540: log.info("Incident SQL", e);
0541: throw new DbException(
0542: "Echec lors de la création de la tache '"
0543: + newTask.getName() + "'", e);
0544: } finally {
0545: if (pStmt != null)
0546: try {
0547: pStmt.close();
0548: } catch (Throwable ignored) {
0549: }
0550: }
0551: }
0552:
0553: /**
0554: * Vérifie si la durée est utilisée en base.
0555: * @param tx le contexte de transaction.
0556: * @param duration la durée à vérifier.
0557: * @return un booléen indiquant si la durée est utilisée.
0558: * @throws DbException levé en cas d'incident technique d'accès à la base.
0559: */
0560: protected static boolean durationIsUsed(DbTransaction tx,
0561: Duration duration) throws DbException {
0562: PreparedStatement pStmt = null;
0563: ResultSet rs = null;
0564: try {
0565: // Récupération de la connexion
0566: Connection con = tx.getConnection();
0567:
0568: // Préparation de la requête
0569: pStmt = con
0570: .prepareStatement("select count(*) from contribution where ctb_duration=?");
0571: pStmt.setLong(1, duration.getId());
0572:
0573: // Exécution de la requête
0574: rs = pStmt.executeQuery();
0575:
0576: // Préparation du résultat
0577: if (!rs.next())
0578: throw new DbException("Nothing returned by the query",
0579: null);
0580: boolean durationIsUsed = rs.getInt(1) > 0;
0581:
0582: // Fermeture du statement
0583: pStmt.close();
0584: pStmt = null;
0585:
0586: // Retour du résultat
0587: return durationIsUsed;
0588: } catch (SQLException e) {
0589: log.info("Incident SQL", e);
0590: throw new DbException(
0591: "Echec lors de la vérification de l'utilisation de la durée '"
0592: + duration + "'", e);
0593: } finally {
0594: if (pStmt != null)
0595: try {
0596: pStmt.close();
0597: } catch (Throwable ignored) {
0598: }
0599: }
0600: }
0601:
0602: /**
0603: * Ferme une transactrion.
0604: * @param tx le contexte de transaction.
0605: * @throws DbException levé en cas d'incident technique d'accès à la base.
0606: */
0607: protected static void endTransaction(DbTransaction tx)
0608: throws DbException {
0609: try {
0610: tx.getConnection().close();
0611: } catch (SQLException e) {
0612: log.info("Incident SQL", e);
0613: throw new DbException(
0614: "Echec lors de la cloture de la connexion", e);
0615: }
0616: threadLocal.set(null);
0617: }
0618:
0619: /**
0620: * @param tx le contexte de transaction.
0621: * @param collaboratorId l'identifiant du collaborateur recherché.
0622: * @return le collaborateur dont l'identifiant est spécifié.
0623: * @throws DbException levé en cas d'incident technique d'accès à la base.
0624: */
0625: protected static Collaborator getCollaborator(DbTransaction tx,
0626: long collaboratorId) throws DbException {
0627: PreparedStatement pStmt = null;
0628: ResultSet rs = null;
0629: try {
0630: // Récupération de la connexion
0631: Connection con = tx.getConnection();
0632:
0633: // Préparation de la requête
0634: pStmt = con
0635: .prepareStatement("select clb_id, clb_login, clb_first_name, clb_last_name, clb_is_active from collaborator where clb_id=?");
0636: pStmt.setLong(1, collaboratorId);
0637:
0638: // Exécution de la requête
0639: rs = pStmt.executeQuery();
0640:
0641: // Préparation du résultat
0642: Collaborator collaborator = null;
0643: if (rs.next())
0644: collaborator = rsToCollaborator(rs);
0645:
0646: // Fermeture du statement
0647: pStmt.close();
0648: pStmt = null;
0649:
0650: // Retour du résultat
0651: return collaborator;
0652: } catch (SQLException e) {
0653: log.info("Incident SQL", e);
0654: throw new DbException(
0655: "Echec lors de la récupération du collaborateur d'identifiant '"
0656: + collaboratorId + "'", e);
0657: } finally {
0658: if (pStmt != null)
0659: try {
0660: pStmt.close();
0661: } catch (Throwable ignored) {
0662: }
0663: }
0664: }
0665:
0666: /**
0667: * Convertit le résultat d'une requête en collaborateur.
0668: * @param rs le result set.
0669: * @return le collaborateur.
0670: * @throws SQLException levé en cas de problème SQL.
0671: */
0672: private static Collaborator rsToCollaborator(ResultSet rs)
0673: throws SQLException {
0674: Collaborator collaborator = new Collaborator();
0675: collaborator.setId(rs.getLong(1));
0676: collaborator.setLogin(rs.getString(2));
0677: collaborator.setFirstName(rs.getString(3));
0678: collaborator.setLastName(rs.getString(4));
0679: collaborator.setIsActive(rs.getBoolean(5));
0680: return collaborator;
0681: }
0682:
0683: /**
0684: * @param tx le contexte de transaction.
0685: * @param login l'identifiant de connexion du collaborateur recherché.
0686: * @return le collaborateur dont l'identifiant de connexion est spécifié.
0687: * @throws DbException levé en cas d'incident technique d'accès à la base.
0688: */
0689: protected static Collaborator getCollaborator(DbTransaction tx,
0690: String login) throws DbException {
0691: PreparedStatement pStmt = null;
0692: ResultSet rs = null;
0693: try {
0694: // Récupération de la connexion
0695: Connection con = tx.getConnection();
0696:
0697: // Préparation de la requête
0698: pStmt = con
0699: .prepareStatement("select clb_id, clb_login, clb_first_name, clb_last_name, clb_is_active from collaborator where clb_login=?");
0700: pStmt.setString(1, login);
0701:
0702: // Exécution de la requête
0703: rs = pStmt.executeQuery();
0704:
0705: // Préparation du résultat
0706: Collaborator collaborator = null;
0707: if (rs.next())
0708: collaborator = rsToCollaborator(rs);
0709:
0710: // Fermeture du ResultSet
0711: pStmt.close();
0712: pStmt = null;
0713:
0714: // Retour du résultat
0715: return collaborator;
0716: } catch (SQLException e) {
0717: log.info("Incident SQL", e);
0718: throw new DbException(
0719: "Echec lors de la récupération ddu collaborateur de login '"
0720: + login + "'", e);
0721: } finally {
0722: if (pStmt != null)
0723: try {
0724: pStmt.close();
0725: } catch (Throwable ignored) {
0726: }
0727: }
0728: }
0729:
0730: /**
0731: * @param tx le contexte de transaction.
0732: * @param orderByClauseFieldIndex index de l'attribut utilisé pour le tri.
0733: * @param ascendantSort booléen indiquant si le tri doit être ascendant.
0734: * @param onlyActiveCollaborators booléen indiquant si l'on ne doit retourner que
0735: * les collaborateurs actifs.
0736: * @return la liste des collaborateurs.
0737: * @throws DbException levé en cas d'incident technique d'accès à la base.
0738: */
0739: protected static Collaborator[] getCollaborators(DbTransaction tx,
0740: int orderByClauseFieldIndex, boolean ascendantSort,
0741: boolean onlyActiveCollaborators) throws DbException {
0742: PreparedStatement pStmt = null;
0743: ResultSet rs = null;
0744: try {
0745: // Récupération de la connexion
0746: Connection con = tx.getConnection();
0747:
0748: // Préparation de la requête
0749: StringBuffer request = new StringBuffer(
0750: "select clb_id, clb_login, clb_first_name, clb_last_name, clb_is_active from collaborator ");
0751: if (onlyActiveCollaborators)
0752: request.append("where clb_is_active=?");
0753: request.append("order by ");
0754: switch (orderByClauseFieldIndex) {
0755: case Collaborator.ID_FIELD_IDX:
0756: request.append("clb_id");
0757: break;
0758: case Collaborator.LOGIN_FIELD_IDX:
0759: request.append("clb_login");
0760: break;
0761: case Collaborator.FIRST_NAME_FIELD_IDX:
0762: request.append("clb_first_name");
0763: break;
0764: case Collaborator.LAST_NAME_FIELD_IDX:
0765: request.append("clb_last_name");
0766: break;
0767: case Collaborator.IS_ACTIVE_FIELD_IDX:
0768: request.append("clb_is_active");
0769: break;
0770: default:
0771: throw new DbException("Unknown field index '"
0772: + orderByClauseFieldIndex + "'.", null);
0773: }
0774: request.append(ascendantSort ? " asc" : " desc");
0775: pStmt = con.prepareStatement(request.toString());
0776: if (onlyActiveCollaborators)
0777: pStmt.setBoolean(1, true);
0778:
0779: // Exécution de la requête
0780: rs = pStmt.executeQuery();
0781:
0782: // Recherche des sous-taches
0783: ArrayList list = new ArrayList();
0784: while (rs.next())
0785: list.add(rsToCollaborator(rs));
0786:
0787: // Fermeture du ResultSet
0788: pStmt.close();
0789: pStmt = null;
0790:
0791: // Retour du résultat
0792: log.debug(" => found " + list.size() + " entrie(s)");
0793: return (Collaborator[]) list.toArray(new Collaborator[list
0794: .size()]);
0795: } catch (SQLException e) {
0796: log.info("Incident SQL", e);
0797: throw new DbException(
0798: "Echec lors de la récupération des collaborateurs'",
0799: e);
0800: } finally {
0801: if (pStmt != null)
0802: try {
0803: pStmt.close();
0804: } catch (Throwable ignored) {
0805: }
0806: }
0807: }
0808:
0809: /**
0810: * @param tx le contexte de transaction.
0811: * @param contributor le collaborateur associé aux contributions.
0812: * @param task la tache associée aux contributions.
0813: * @param fromDate la date de départ.
0814: * @param toDate la date de fin.
0815: * @return la liste des contributions associées aux paramètres spécifiés.
0816: * @throws DbException levé en cas d'incident technique d'accès à la base.
0817: */
0818: protected static Contribution[] getContributions(DbTransaction tx,
0819: Collaborator contributor, Task task, Calendar fromDate,
0820: Calendar toDate) throws DbException {
0821: log.debug("getContributions(" + contributor + ", " + task
0822: + ", " + sdf.format(fromDate.getTime()) + ", "
0823: + sdf.format(toDate.getTime()) + ")");
0824: PreparedStatement pStmt = null;
0825: ResultSet rs = null;
0826: try {
0827: // Récupération de la connexion
0828: Connection con = tx.getConnection();
0829:
0830: // Préparation de la requête
0831: pStmt = con
0832: .prepareStatement("select ctb_year, ctb_month, ctb_day, ctb_contributor, ctb_task, ctb_duration from contribution where ctb_contributor=? and ctb_task=? and ctb_year*10000 + ( ctb_month*100 + ctb_day ) between ? and ?");
0833: pStmt.setLong(1, contributor.getId());
0834: pStmt.setLong(2, task.getId());
0835: pStmt.setString(3, sdf.format(fromDate.getTime()));
0836: pStmt.setString(4, sdf.format(toDate.getTime()));
0837:
0838: // Exécution de la requête
0839: rs = pStmt.executeQuery();
0840:
0841: // Extraction du résultat
0842: Contribution[] result = rsToContributions(rs);
0843:
0844: // Fermeture du ResultSet
0845: pStmt.close();
0846: pStmt = null;
0847:
0848: // Retour du résultat
0849: return result;
0850: } catch (SQLException e) {
0851: log.info("Incident SQL", e);
0852: throw new DbException(
0853: "Echec lors de la récupération des contributions",
0854: e);
0855: } finally {
0856: if (pStmt != null)
0857: try {
0858: pStmt.close();
0859: } catch (Throwable ignored) {
0860: }
0861: }
0862: }
0863:
0864: /**
0865: * Extrait les contributions du resultat de la requête SQL.
0866: * @param rs le résultat de la requête SQL.
0867: * @return les contributions extraites.
0868: * @throws SQLException levé en cas d'incident avec la base de données.
0869: */
0870: private static Contribution[] rsToContributions(ResultSet rs)
0871: throws SQLException {
0872: // Recherche des sous-taches
0873: ArrayList list = new ArrayList();
0874: while (rs.next()) {
0875: // Préparation du résultat
0876: Contribution contribution = new Contribution();
0877: contribution.setYear(rs.getInt(1));
0878: contribution.setMonth(rs.getInt(2));
0879: contribution.setDay(rs.getInt(3));
0880: contribution.setContributorId(rs.getInt(4));
0881: contribution.setTaskId(rs.getInt(5));
0882: contribution.setDurationId(rs.getLong(6));
0883: list.add(contribution);
0884: }
0885: log.debug(" => found " + list.size() + " entrie(s)");
0886: return (Contribution[]) list.toArray(new Contribution[list
0887: .size()]);
0888: }
0889:
0890: /**
0891: * Retourne les contributions associées aux paramètres spécifiés.
0892: *
0893: * <p>Tous les paramètres sont facultatifs. Chaque paramètre spécifié agît
0894: * comme un filtre sur le résultat. A l'inverse, l'omission d'un paramètre
0895: * provoque l'inclusion de toutes les contributions, quelque soit leurs
0896: * valeurs pour l'attribut considéré.</p>
0897: *
0898: * <p>La spécification des paramètres répond aux mêmes règles que pour la
0899: * méthode <code>getContributionsSum</code>.</p>
0900: *
0901: * @param tx le contexte de transaction.
0902: * @param task la tâche associée aux contributions (facultative).
0903: * @param contributor le collaborateur associé aux contributions (facultatif).
0904: * @param year l'année (facultative).
0905: * @param month le mois (facultatif).
0906: * @param day le jour (facultatif).
0907: * @return les contributions.
0908: * @throws DbException levé en cas d'incident technique d'accès à la base.
0909: *
0910: * @see jfb.tools.activitymgr.core.DbMgr#getContributionsSum(DbTransaction, Task, Collaborator, Integer, Integer, Integer)
0911: */
0912: protected static Contribution[] getContributions(DbTransaction tx,
0913: Task task, Collaborator contributor, Integer year,
0914: Integer month, Integer day) throws DbException {
0915: log.debug("getContributions(" + task + ", " + contributor
0916: + ", " + year + ", " + month + ", " + day + ")");
0917: PreparedStatement pStmt = null;
0918: ResultSet rs = null;
0919: try {
0920: // Récupération de la connexion
0921: Connection con = tx.getConnection();
0922:
0923: StringBuffer baseRequest = new StringBuffer(
0924: "select ctb_year, ctb_month, ctb_day, ctb_contributor, ctb_task, ctb_duration from contribution, task where ctb_task=tsk_id");
0925: String orderByClause = " order by ctb_year, ctb_month, ctb_day, tsk_path, tsk_number, ctb_contributor, ctb_duration";
0926: // Cas ou la tache n'est pas spécifiée
0927: if (task == null) {
0928: // Préparation de la requête
0929: completeContributionRequest(baseRequest, contributor,
0930: year, month, day);
0931: baseRequest.append(orderByClause);
0932: String request = baseRequest.toString();
0933: pStmt = con.prepareStatement(request);
0934: completeContributionReqParams(pStmt, 1, contributor,
0935: year, month, day);
0936: }
0937: // Si la tache n'admet pas de sous-taches, le cumul de
0938: // budget, de consommé initial, de reste à faire sont
0939: // égaux à ceux de la tache
0940: else if (task.getSubTasksCount() == 0) {
0941: // Préparation de la requête
0942: baseRequest.append(" and tsk_id=?");
0943: completeContributionRequest(baseRequest, contributor,
0944: year, month, day);
0945: baseRequest.append(orderByClause);
0946: String request = baseRequest.toString();
0947: pStmt = con.prepareStatement(request);
0948: pStmt.setLong(1, task.getId());
0949: log.debug(" taskId=" + task.getId());
0950: completeContributionReqParams(pStmt, 2, contributor,
0951: year, month, day);
0952: }
0953: // Sinon, il faut calculer
0954: else {
0955: // Paramètre pour la clause 'LIKE'
0956: String pathLike = task.getFullPath() + "%";
0957:
0958: // Préparation de la requête
0959: baseRequest.append(" and tsk_path like ?");
0960: completeContributionRequest(baseRequest, contributor,
0961: year, month, day);
0962: baseRequest.append(orderByClause);
0963: String request = baseRequest.toString();
0964: pStmt = con.prepareStatement(request);
0965: pStmt.setString(1, pathLike);
0966: completeContributionReqParams(pStmt, 2, contributor,
0967: year, month, day);
0968: }
0969:
0970: // Exécution de la requête
0971: log.debug("Request : " + baseRequest);
0972: rs = pStmt.executeQuery();
0973:
0974: // Extraction du résultat
0975: Contribution[] result = rsToContributions(rs);
0976:
0977: // Fermeture du statement
0978: pStmt.close();
0979: pStmt = null;
0980:
0981: // Retour du résultat
0982: return result;
0983: } catch (SQLException e) {
0984: log.info("Incident SQL", e);
0985: throw new DbException(
0986: "Echec lors de la récupération des contributions",
0987: e);
0988: } finally {
0989: try {
0990: if (pStmt != null)
0991: pStmt.close();
0992: } catch (Throwable ignored) {
0993: }
0994: }
0995: }
0996:
0997: /**
0998: * Calcule le nombre des contributions associée aux paramètres spécifiés.
0999: *
1000: * <p>Tous les paramètres sont facultatifs. Chaque paramètre spécifié agît
1001: * comme un filtre sur le résultat. A l'inverse, l'omission d'un paramètre
1002: * provoque l'inclusion de toutes les contributions, quelque soit leurs
1003: * valeurs pour l'attribut considéré.</p>
1004: *
1005: * <p>En spécifiant la tache X, on connaîtra la somme des contribution pour
1006: * la taches X. En ne spécifiant pas de tache, la somme sera effectuée quelque
1007: * soit les tâches.</p>
1008: *
1009: * @param tx le contexte de transaction.
1010: * @param task la tâche associée aux contributions (facultative).
1011: * @param contributor le collaborateur associé aux contributions (facultatif).
1012: * @param year l'année (facultative).
1013: * @param month le mois (facultatif).
1014: * @param day le jour (facultatif).
1015: * @return la seomme des contributions.
1016: * @throws DbException levé en cas d'incident technique d'accès à la base.
1017: */
1018: protected static long getContributionsNb(DbTransaction tx,
1019: Task task, Collaborator contributor, Integer year,
1020: Integer month, Integer day) throws DbException {
1021: log.debug("getContributionsSum(" + task + ", " + contributor
1022: + ", " + year + ", " + month + ", " + day + ")");
1023: return getContributionsAggregation(tx, "count(ctb_duration)",
1024: task, contributor, year, month, day);
1025: }
1026:
1027: /**
1028: * Calcule le cumuls des consommations associees aux contributions pour
1029: * les paramètres spécifiés.
1030: *
1031: * <p>Tous les paramètres sont facultatifs. Chaque paramètre spécifié agît
1032: * comme un filtre sur le résultat. A l'inverse, l'omission d'un paramètre
1033: * provoque l'inclusion de toutes les contributions, quelque soit leurs
1034: * valeurs pour l'attribut considéré.</p>
1035: *
1036: * <p>En spécifiant la tache X, on connaîtra la somme des contribution pour
1037: * la taches X. En ne spécifiant pas de tache, la somme sera effectuée quelque
1038: * soit les tâches.</p>
1039: *
1040: * @param tx le contexte de transaction.
1041: * @param task la tâche associée aux contributions (facultative).
1042: * @param contributor le collaborateur associé aux contributions (facultatif).
1043: * @param year l'année (facultative).
1044: * @param month le mois (facultatif).
1045: * @param day le jour (facultatif).
1046: * @return la seomme des contributions.
1047: * @throws DbException levé en cas d'incident technique d'accès à la base.
1048: */
1049: protected static long getContributionsSum(DbTransaction tx,
1050: Task task, Collaborator contributor, Integer year,
1051: Integer month, Integer day) throws DbException {
1052: log.debug("getContributionsSum(" + task + ", " + contributor
1053: + ", " + year + ", " + month + ", " + day + ")");
1054: return getContributionsAggregation(tx, "sum(ctb_duration)",
1055: task, contributor, year, month, day);
1056: }
1057:
1058: /**
1059: * Calcule une aggregation associee aux contributions pour les paramètres
1060: * spécifiés.
1061: *
1062: * <p>Tous les paramètres sont facultatifs. Chaque paramètre spécifié agît
1063: * comme un filtre sur le résultat. A l'inverse, l'omission d'un paramètre
1064: * provoque l'inclusion de toutes les contributions, quelque soit leurs
1065: * valeurs pour l'attribut considéré.</p>
1066: *
1067: * <p>En spécifiant la tache X, on connaîtra la somme des contribution pour
1068: * la taches X. En ne spécifiant pas de tache, la somme sera effectuée quelque
1069: * soit les tâches.</p>
1070: *
1071: * @param tx le contexte de transaction.
1072: * @param aggregation la chaîne représentant l'aggrégation (ex: <code>sum(ctb_contribution)</code>).
1073: * @param task la tâche associée aux contributions (facultative).
1074: * @param contributor le collaborateur associé aux contributions (facultatif).
1075: * @param year l'année (facultative).
1076: * @param month le mois (facultatif).
1077: * @param day le jour (facultatif).
1078: * @return la seomme des contributions.
1079: * @throws DbException levé en cas d'incident technique d'accès à la base.
1080: */
1081: private static long getContributionsAggregation(DbTransaction tx,
1082: String aggregation, Task task, Collaborator contributor,
1083: Integer year, Integer month, Integer day)
1084: throws DbException {
1085: log.debug("getContributionsSum(" + task + ", " + contributor
1086: + ", " + year + ", " + month + ", " + day + ")");
1087: PreparedStatement pStmt = null;
1088: ResultSet rs = null;
1089: try {
1090: // Récupération de la connexion
1091: Connection con = tx.getConnection();
1092:
1093: StringBuffer baseRequest = new StringBuffer("select ")
1094: .append(aggregation)
1095: .append(
1096: " from contribution, task where ctb_task=tsk_id");
1097: // Cas ou la tache n'est pas spécifiée
1098: if (task == null) {
1099: // Préparation de la requête
1100: completeContributionRequest(baseRequest, contributor,
1101: year, month, day);
1102: String request = baseRequest.toString();
1103: pStmt = con.prepareStatement(request);
1104: completeContributionReqParams(pStmt, 1, contributor,
1105: year, month, day);
1106: }
1107: // Si la tache n'admet pas de sous-taches, le cumul de
1108: // budget, de consommé initial, de reste à faire sont
1109: // égaux à ceux de la tache
1110: else if (task.getSubTasksCount() == 0) {
1111: // Préparation de la requête
1112: baseRequest.append(" and tsk_id=?");
1113: completeContributionRequest(baseRequest, contributor,
1114: year, month, day);
1115: String request = baseRequest.toString();
1116: pStmt = con.prepareStatement(request);
1117: pStmt.setLong(1, task.getId());
1118: log.debug(" taskId=" + task.getId());
1119: completeContributionReqParams(pStmt, 2, contributor,
1120: year, month, day);
1121: }
1122: // Sinon, il faut calculer
1123: else {
1124: // Paramètre pour la clause 'LIKE'
1125: String pathLike = task.getFullPath() + "%";
1126:
1127: // Préparation de la requête
1128: baseRequest.append(" and tsk_path like ?");
1129: completeContributionRequest(baseRequest, contributor,
1130: year, month, day);
1131: String request = baseRequest.toString();
1132: pStmt = con.prepareStatement(request);
1133: pStmt.setString(1, pathLike);
1134: completeContributionReqParams(pStmt, 2, contributor,
1135: year, month, day);
1136: }
1137:
1138: // Exécution de la requête
1139: log.debug("Request : " + baseRequest);
1140: rs = pStmt.executeQuery();
1141: if (!rs.next())
1142: throw new DbException(
1143: "Nothing returned from this query", null);
1144: long agregation = rs.getLong(1);
1145:
1146: // Fermeture du statement
1147: pStmt.close();
1148: pStmt = null;
1149:
1150: // Retour du résultat
1151: log.info("agregation=" + agregation);
1152: return agregation;
1153: } catch (SQLException e) {
1154: log.info("Incident SQL", e);
1155: throw new DbException(
1156: "Echec lors de la récupération des cumuls", e);
1157: } finally {
1158: try {
1159: if (pStmt != null)
1160: pStmt.close();
1161: } catch (Throwable ignored) {
1162: }
1163: }
1164: }
1165:
1166: /**
1167: * @param tx le contexte de transaction.
1168: * @param durationId l'identifiant de la durée.
1169: * @return la durée.
1170: * @throws DbException levé en cas d'incident technique d'accès à la base.
1171: */
1172: protected static Duration getDuration(DbTransaction tx,
1173: long durationId) throws DbException {
1174: PreparedStatement pStmt = null;
1175: ResultSet rs = null;
1176: try {
1177: // Récupération de la connexion
1178: Connection con = tx.getConnection();
1179:
1180: // Préparation de la requête
1181: pStmt = con
1182: .prepareStatement("select dur_id, dur_is_active from duration where dur_id=?");
1183: pStmt.setLong(1, durationId);
1184:
1185: // Exécution de la requête
1186: rs = pStmt.executeQuery();
1187:
1188: // Reécupération du résultat
1189: Duration duration = null;
1190: if (rs.next())
1191: duration = rsToDuration(rs);
1192:
1193: // Fermeture du ResultSet
1194: pStmt.close();
1195: pStmt = null;
1196:
1197: // Retour du résultat
1198: return duration;
1199: } catch (SQLException e) {
1200: log.info("Incident SQL", e);
1201: throw new DbException(
1202: "Echec lors de la récupération dde la durée '"
1203: + durationId + "'", e);
1204: } finally {
1205: if (pStmt != null)
1206: try {
1207: pStmt.close();
1208: } catch (Throwable ignored) {
1209: }
1210: }
1211: }
1212:
1213: /**
1214: * @param tx le contexte de transaction.
1215: * @param onlyActiveCollaborators booléen indiquant si l'on ne doit retourner que
1216: * les collaborateurs actifs.
1217: * @return la liste des durées.
1218: * @throws DbException levé en cas d'incident technique d'accès à la base.
1219: */
1220: protected static Duration[] getDurations(DbTransaction tx,
1221: boolean onlyActiveCollaborators) throws DbException {
1222: PreparedStatement pStmt = null;
1223: ResultSet rs = null;
1224: try {
1225: // Récupération de la connexion
1226: Connection con = tx.getConnection();
1227:
1228: // Préparation de la requête
1229: StringBuffer request = new StringBuffer(
1230: "select dur_id, dur_is_active from duration ");
1231: if (onlyActiveCollaborators)
1232: request.append("where dur_is_active=?");
1233: request.append("order by dur_id asc");
1234: pStmt = con.prepareStatement(request.toString());
1235: if (onlyActiveCollaborators)
1236: pStmt.setBoolean(1, true);
1237:
1238: // Exécution de la requête
1239: rs = pStmt.executeQuery();
1240:
1241: // Recherche des sous-taches
1242: ArrayList list = new ArrayList();
1243: while (rs.next())
1244: list.add(rsToDuration(rs));
1245:
1246: // Fermeture du ResultSet
1247: pStmt.close();
1248: pStmt = null;
1249:
1250: // Retour du résultat
1251: return (Duration[]) list.toArray(new Duration[list.size()]);
1252: } catch (SQLException e) {
1253: log.info("Incident SQL", e);
1254: throw new DbException(
1255: "Echec lors de la récupération des durées'", e);
1256: } finally {
1257: if (pStmt != null)
1258: try {
1259: pStmt.close();
1260: } catch (Throwable ignored) {
1261: }
1262: }
1263: }
1264:
1265: /**
1266: * Convertit le résultat d'une requête en durée.
1267: * @param rs le result set.
1268: * @return la durée.
1269: * @throws SQLException levé en cas de problème SQL.
1270: */
1271: private static Duration rsToDuration(ResultSet rs)
1272: throws SQLException {
1273: Duration duration = new Duration();
1274: duration.setId(rs.getLong(1));
1275: duration.setIsActive(rs.getBoolean(2));
1276: return duration;
1277: }
1278:
1279: /**
1280: * @param tx le contexte de transaction.
1281: * @param task la tache dont on veut connaitre la tache parent.
1282: * @return la tache parent d'une tache spécifiée.
1283: * @throws DbException levé en cas d'incident technique d'accès à la base.
1284: */
1285: protected static Task getParentTask(DbTransaction tx, Task task)
1286: throws DbException {
1287: Task parentTask = null;
1288: String parentTaskFullPath = task.getPath();
1289: // Si le chemin est vide, la tache parent est nulle (tache racine)
1290: if (parentTaskFullPath != null
1291: && !"".equals(parentTaskFullPath)) {
1292: // Extraction du chemin et du numéro de la tache recherchée
1293: log.debug("Fullpath='" + parentTaskFullPath + "'");
1294: String path = parentTaskFullPath.substring(0,
1295: parentTaskFullPath.length() - 2);
1296: byte number = StringHelper.toByte(parentTaskFullPath
1297: .substring(parentTaskFullPath.length() - 2));
1298: log.debug(" => path=" + path);
1299: log.debug(" => number=" + number);
1300:
1301: // Recherche de la tache
1302: parentTask = getTask(tx, path, number);
1303: }
1304: // Retour du résultat
1305: return parentTask;
1306: }
1307:
1308: /**
1309: * @param tx le contexte de transaction.
1310: * @param path le chemin dont on veut connaître les taches.
1311: * @return la liste des taches associées à un chemin donné.
1312: * @throws DbException levé en cas d'incident technique d'accès à la base.
1313: */
1314: protected static Task[] getTasks(DbTransaction tx, String path)
1315: throws DbException {
1316: PreparedStatement pStmt = null;
1317: ResultSet rs = null;
1318: try {
1319: // Récupération de la connexion
1320: Connection con = tx.getConnection();
1321:
1322: // Préparation de la requête
1323: pStmt = con
1324: .prepareStatement("select tsk_id from task where tsk_path=? order by tsk_number");
1325: pStmt.setString(1, path);
1326:
1327: // Exécution de la requête
1328: rs = pStmt.executeQuery();
1329:
1330: // Recherche des sous-taches
1331: ArrayList list = new ArrayList();
1332: while (rs.next()) {
1333: long taskId = rs.getLong(1);
1334: Task task = getTask(tx, taskId);
1335: list.add(task);
1336: }
1337:
1338: // Fermeture du ResultSet
1339: pStmt.close();
1340: pStmt = null;
1341:
1342: // Retour du résultat
1343: log.debug(" => found " + list.size() + " entrie(s)");
1344: return (Task[]) list.toArray(new Task[list.size()]);
1345: } catch (SQLException e) {
1346: log.info("Incident SQL", e);
1347: throw new DbException(
1348: "Echec lors de la récupération des sous taches de chemin '"
1349: + path + "'", e);
1350: } finally {
1351: if (pStmt != null)
1352: try {
1353: pStmt.close();
1354: } catch (Throwable ignored) {
1355: }
1356: }
1357: }
1358:
1359: /**
1360: * @param tx le contexte de transaction.
1361: * @param parentTask la tache parent dont on veut connaitre les sous-taches.
1362: * @return la liste des sous-taches.
1363: * @throws DbException levé en cas d'incident technique d'accès à la base.
1364: */
1365: protected static Task[] getSubtasks(DbTransaction tx,
1366: Task parentTask) throws DbException {
1367: // Récupération du chemin à partir de la tache parent
1368: String fullpath = parentTask == null ? "" : parentTask
1369: .getFullPath();
1370: log.debug("Looking for tasks with path='" + fullpath + "'");
1371: return getTasks(tx, fullpath);
1372: }
1373:
1374: /**
1375: * Retourn la liste des taches correspondant au filtre de recherche spécifié.
1376: * @param tx le contexte de transaction.
1377: * @param filter le filtre de recherche.
1378: * @return la liste des taches correspondant au filtre de recherche spécifié.
1379: * @throws DbException levé en cas d'incident technique d'accès à la base.
1380: */
1381: protected static Task[] getTasks(DbTransaction tx,
1382: TaskSearchFilter filter) throws DbException {
1383: PreparedStatement pStmt = null;
1384: ResultSet rs = null;
1385: try {
1386: // Récupération de la connexion
1387: Connection con = tx.getConnection();
1388:
1389: // Préparation de la requête
1390: StringBuffer request = new StringBuffer(
1391: "select tsk_id from task where ");
1392: // Ajout du nom de champ
1393: switch (filter.getFieldIndex()) {
1394: case TaskSearchFilter.TASK_NAME_FIELD_IDX:
1395: request.append("tsk_name");
1396: break;
1397: case TaskSearchFilter.TASK_CODE_FIELD_IDX:
1398: request.append("tsk_code");
1399: break;
1400: default:
1401: throw new DbException("Unknown field index '"
1402: + filter.getFieldIndex() + "'.", null);
1403: }
1404: // Ajout du critère de comparaison
1405: switch (filter.getCriteriaIndex()) {
1406: case TaskSearchFilter.IS_EQUAL_TO_CRITERIA_IDX:
1407: request.append("=?");
1408: break;
1409: case TaskSearchFilter.STARTS_WITH_CRITERIA_IDX:
1410: case TaskSearchFilter.ENDS_WITH_CRITERIA_IDX:
1411: case TaskSearchFilter.CONTAINS_WITH_CRITERIA_IDX:
1412: request.append(" like ?");
1413: break;
1414: default:
1415: throw new DbException("Unknown criteria index '"
1416: + filter.getCriteriaIndex() + "'.", null);
1417: }
1418: // Préparation de la requête
1419: log.debug("Search request : '" + request + "'");
1420: pStmt = con.prepareStatement(request.toString());
1421: String parameter = null;
1422: switch (filter.getCriteriaIndex()) {
1423: case TaskSearchFilter.IS_EQUAL_TO_CRITERIA_IDX:
1424: parameter = filter.getFieldValue();
1425: break;
1426: case TaskSearchFilter.STARTS_WITH_CRITERIA_IDX:
1427: parameter = filter.getFieldValue() + "%";
1428: break;
1429: case TaskSearchFilter.ENDS_WITH_CRITERIA_IDX:
1430: parameter = "%" + filter.getFieldValue();
1431: break;
1432: case TaskSearchFilter.CONTAINS_WITH_CRITERIA_IDX:
1433: parameter = "%" + filter.getFieldValue() + "%";
1434: break;
1435: default:
1436: throw new DbException("Unknown criteria index '"
1437: + filter.getCriteriaIndex() + "'.", null);
1438: }
1439: log.debug("Search parameter : '" + parameter + "'");
1440: pStmt.setString(1, parameter);
1441:
1442: // Exécution de la requête
1443: rs = pStmt.executeQuery();
1444:
1445: // Récupération du résultat
1446: ArrayList list = new ArrayList();
1447: while (rs.next()) {
1448: long taskId = rs.getLong(1);
1449: Task task = getTask(tx, taskId);
1450: list.add(task);
1451: }
1452:
1453: // Fermeture du ResultSet
1454: pStmt.close();
1455: pStmt = null;
1456:
1457: // Préparation du résultat
1458: Task[] tasks = (Task[]) list.toArray(new Task[list.size()]);
1459:
1460: // On trie les taches manuellement car le tri base de données
1461: // pose un problème dans la mesure ou la BDD considère le champ
1462: // tsk_path comme numérique pour le tri ce qui pose un pb
1463: // Ex :
1464: // ROOT (path : 01)
1465: // +- T1 (path : 0101)
1466: // | +- T11 (path : 010101)
1467: // | +- T12 (path : 010102)
1468: // +- T2 (path : 0102)
1469: // Si on ramène l'ensemble des sous taches de ROOT, on voudrait avoir
1470: // dans l'ordre T1, T11, T12, T2
1471: // Avec un tri base de donnée, on obtiendrait T1, T2, T11, T12 ; T2 ne se
1472: // trouve pas ou on l'attend, ceci en raison du fait qu'en comparaison
1473: // numérique 0102 est < à 010101 et à 010102. Par contre, en comparaison
1474: // de chaînes (en java), on a bien 0102 > 010101 et 010102.
1475: Arrays.sort(tasks, new Comparator() {
1476: public int compare(Object o1, Object o2) {
1477: Task t1 = (Task) o1;
1478: Task t2 = (Task) o2;
1479: return t1.getFullPath().compareTo(t2.getFullPath());
1480: }
1481:
1482: });
1483:
1484: // Retour du résultat
1485: return tasks;
1486: } catch (SQLException e) {
1487: log.info("Incident SQL", e);
1488: throw new DbException(
1489: "Unexpected error while searching tasks", e);
1490: } finally {
1491: if (pStmt != null)
1492: try {
1493: pStmt.close();
1494: } catch (Throwable ignored) {
1495: }
1496: }
1497: }
1498:
1499: /**
1500: * @param tx le contexte de transaction.
1501: * @param taskId l'identifiant de la tache recherchée.
1502: * @return la tache dont l'identifiant est spécifié.
1503: * @throws DbException levé en cas d'incident technique d'accès à la base.
1504: */
1505: protected static Task getTask(DbTransaction tx, long taskId)
1506: throws DbException {
1507: PreparedStatement pStmt = null;
1508: ResultSet rs = null;
1509: try {
1510: // Récupération de la connexion
1511: Connection con = tx.getConnection();
1512:
1513: // Préparation de la requête
1514: pStmt = con
1515: .prepareStatement("select tsk_path, tsk_number, tsk_code, tsk_name, tsk_budget, tsk_initial_cons, tsk_todo, tsk_comment from task where tsk_id=?");
1516: pStmt.setLong(1, taskId);
1517:
1518: // Exécution de la requête
1519: rs = pStmt.executeQuery();
1520:
1521: // Préparation du résultat
1522: Task task = null;
1523: if (rs.next()) {
1524: task = new Task();
1525: task.setId(taskId);
1526: task.setPath(rs.getString(1));
1527: task.setNumber(rs.getByte(2));
1528: task.setCode(rs.getString(3));
1529: task.setName(rs.getString(4));
1530: task.setBudget(rs.getLong(5));
1531: task.setInitiallyConsumed(rs.getLong(6));
1532: task.setTodo(rs.getLong(7));
1533: task.setComment(rs.getString(8));
1534: }
1535: // Fermeture du ResultSet
1536: pStmt.close();
1537: pStmt = null;
1538:
1539: // Si la tache existe bien
1540: if (task != null) {
1541: // Recherche du nombre de sous-taches
1542: String taskFullPath = task.getFullPath();
1543: pStmt = con
1544: .prepareStatement("select count(*) from task where tsk_path=?");
1545: pStmt.setString(1, taskFullPath);
1546:
1547: // Exécution de la requête
1548: rs = pStmt.executeQuery();
1549: if (rs.next()) {
1550: int subTasksCount = rs.getInt(1);
1551: task.setSubTasksCount(subTasksCount);
1552: }
1553: // Fermeture du ResultSet
1554: pStmt.close();
1555: pStmt = null;
1556: }
1557:
1558: // Retour du résultat
1559: return task;
1560: } catch (SQLException e) {
1561: log.info("Incident SQL", e);
1562: throw new DbException(
1563: "Echec lors de la récupération de la tache d'identifiant '"
1564: + taskId + "'", e);
1565: } finally {
1566: if (pStmt != null)
1567: try {
1568: pStmt.close();
1569: } catch (Throwable ignored) {
1570: }
1571: }
1572: }
1573:
1574: /**
1575: * @param tx le contexte de transaction.
1576: * @param taskPath le chemin de la tache recherchée.
1577: * @param taskNumber le numéro de la tache recherchée.
1578: * @return la tache dont le chemin et le numéro sont spécifiés.
1579: * @throws DbException levé en cas d'incident technique d'accès à la base.
1580: */
1581: protected static Task getTask(DbTransaction tx, String taskPath,
1582: byte taskNumber) throws DbException {
1583: log.debug("getTask(" + taskPath + ", " + taskNumber + ")");
1584: PreparedStatement pStmt = null;
1585: ResultSet rs = null;
1586: try {
1587: // Récupération de la connexion
1588: Connection con = tx.getConnection();
1589:
1590: // Préparation de la requête
1591: pStmt = con
1592: .prepareStatement("select tsk_id from task where tsk_path=? and tsk_number=?");
1593: pStmt.setString(1, taskPath);
1594: pStmt.setByte(2, taskNumber);
1595:
1596: // Exécution de la requête
1597: rs = pStmt.executeQuery();
1598:
1599: // Préparation du résultat
1600: Task task = null;
1601: if (rs.next()) {
1602: long taskId = rs.getLong(1);
1603: task = getTask(tx, taskId);
1604: }
1605: // Fermeture du ResultSet
1606: pStmt.close();
1607: pStmt = null;
1608:
1609: // Retour du résultat
1610: log.debug("task = " + task);
1611: return task;
1612: } catch (SQLException e) {
1613: log.info("Incident SQL", e);
1614: throw new DbException(
1615: "Echec lors de la récupération de la tache N° "
1616: + taskNumber + " du chemin '" + taskPath
1617: + "'", e);
1618: } finally {
1619: if (pStmt != null)
1620: try {
1621: pStmt.close();
1622: } catch (Throwable ignored) {
1623: }
1624: }
1625: }
1626:
1627: /**
1628: * @param tx le contexte de transaction.
1629: * @param taskPath le chemin de la tache recherchée.
1630: * @param taskCode le code de la tache recherchée.
1631: * @return la tache dont le code et la tache parent sont spécifiés.
1632: * @throws DbException levé en cas d'incident technique d'accès à la base.
1633: */
1634: protected static Task getTask(DbTransaction tx, String taskPath,
1635: String taskCode) throws DbException {
1636: PreparedStatement pStmt = null;
1637: ResultSet rs = null;
1638: try {
1639: // Récupération de la connexion
1640: Connection con = tx.getConnection();
1641:
1642: // Préparation de la requête
1643: pStmt = con
1644: .prepareStatement("select tsk_id from task where tsk_path=? and tsk_code=?");
1645: pStmt.setString(1, taskPath);
1646: pStmt.setString(2, taskCode);
1647:
1648: // Exécution de la requête
1649: rs = pStmt.executeQuery();
1650:
1651: // Préparation du résultat
1652: Task task = null;
1653: if (rs.next()) {
1654: long taskId = rs.getLong(1);
1655: task = getTask(tx, taskId);
1656: }
1657: // Fermeture du ResultSet
1658: pStmt.close();
1659: pStmt = null;
1660:
1661: // Retour du résultat
1662: return task;
1663: } catch (SQLException e) {
1664: log.info("Incident SQL", e);
1665: throw new DbException(
1666: "Echec lors de la récupération de la tache de code '"
1667: + taskCode + "'", e);
1668: } finally {
1669: if (pStmt != null)
1670: try {
1671: pStmt.close();
1672: } catch (Throwable ignored) {
1673: }
1674: }
1675: }
1676:
1677: /**
1678: * @param tx le contexte de transaction.
1679: * @param collaborator le collaborateur.
1680: * @param fromDate date de début.
1681: * @param toDate date de fin.
1682: * @return la liste de taches associées au collaborateur entre les 2 dates spécifiées.
1683: * @throws DbException levé en cas d'incident technique d'accès à la base.
1684: */
1685: protected static Task[] getTasks(DbTransaction tx,
1686: Collaborator collaborator, Calendar fromDate,
1687: Calendar toDate) throws DbException {
1688: log.debug("getTasks(" + collaborator + ", "
1689: + sdf.format(fromDate.getTime()) + ", "
1690: + sdf.format(toDate.getTime()) + ")");
1691: PreparedStatement pStmt = null;
1692: ResultSet rs = null;
1693: try {
1694: // Récupération de la connexion
1695: Connection con = tx.getConnection();
1696:
1697: // Préparation de la requête
1698: pStmt = con
1699: .prepareStatement("select distinct ctb_task, tsk_path, tsk_number from contribution, task where ctb_task=tsk_id and ctb_contributor=? and ctb_year*10000 + ( ctb_month*100 + ctb_day ) between ? and ? order by tsk_path, tsk_number");
1700: pStmt.setLong(1, collaborator.getId());
1701: pStmt.setString(2, sdf.format(fromDate.getTime()));
1702: pStmt.setString(3, sdf.format(toDate.getTime()));
1703:
1704: // Exécution de la requête
1705: rs = pStmt.executeQuery();
1706:
1707: // Recherche des sous-taches
1708: ArrayList list = new ArrayList();
1709: while (rs.next()) {
1710: long taskId = rs.getLong(1);
1711: Task task = getTask(tx, taskId);
1712: list.add(task);
1713: }
1714:
1715: // Fermeture du ResultSet
1716: pStmt.close();
1717: pStmt = null;
1718:
1719: // Retour du résultat
1720: log.debug(" => found " + list.size() + " entrie(s)");
1721: return (Task[]) list.toArray(new Task[list.size()]);
1722: } catch (SQLException e) {
1723: log.info("Incident SQL", e);
1724: throw new DbException(
1725: "Echec lors de la récupération des taches associées à un collaborateur",
1726: e);
1727: } finally {
1728: if (pStmt != null)
1729: try {
1730: pStmt.close();
1731: } catch (Throwable ignored) {
1732: }
1733: }
1734: }
1735:
1736: /**
1737: * @param tx le contexte de transaction.
1738: * @param task la tâche pour laquelle on souhaite connaître les totaux.
1739: * @return les totaux associés à une tache (consommé, etc.).
1740: * @throws DbException levé en cas d'incident technique d'accès à la base.
1741: */
1742: protected static TaskSums getTaskSums(DbTransaction tx, Task task)
1743: throws DbException {
1744: // TODO Factoriser cette méthose avec getContributionsSum
1745: PreparedStatement pStmt = null;
1746: ResultSet rs = null;
1747: try {
1748: // Récupération de la connexion
1749: Connection con = tx.getConnection();
1750:
1751: // Préparation du résultat
1752: TaskSums taskSums = new TaskSums();
1753:
1754: // Si la tache n'admet pas de sous-taches, le cumul de
1755: // budget, de consommé initial, de reste à faire sont
1756: // égaux à ceux de la tache
1757: if (task != null && task.getSubTasksCount() == 0) {
1758: taskSums.setBudgetSum(task.getBudget());
1759: taskSums.setInitiallyConsumedSum(task
1760: .getInitiallyConsumed());
1761: taskSums.setTodoSum(task.getTodo());
1762:
1763: // Calcul du consommé
1764: pStmt = con
1765: .prepareStatement("select sum(ctb_duration), count(ctb_duration) from contribution, task where ctb_task=tsk_id and tsk_id=?");
1766: pStmt.setLong(1, task.getId());
1767: rs = pStmt.executeQuery();
1768: if (!rs.next())
1769: throw new DbException(
1770: "Nothing returned from this query", null);
1771: taskSums.setConsumedSum(rs.getLong(1));
1772: taskSums.setContributionsNb(rs.getLong(2));
1773: pStmt.close();
1774: pStmt = null;
1775: }
1776: // Sinon, il faut calculer
1777: else {
1778: // Paramètre pour la clause 'LIKE'
1779: String pathLike = (task == null ? "" : task
1780: .getFullPath())
1781: + "%";
1782:
1783: // Calcul des cumuls
1784: pStmt = con
1785: .prepareStatement("select sum(tsk_budget), sum(tsk_initial_cons), sum(tsk_todo) from task where tsk_path like ?");
1786: pStmt.setString(1, pathLike);
1787: rs = pStmt.executeQuery();
1788: if (!rs.next())
1789: throw new DbException(
1790: "Nothing returned from this query", null);
1791: taskSums.setBudgetSum(rs.getLong(1));
1792: taskSums.setInitiallyConsumedSum(rs.getLong(2));
1793: taskSums.setTodoSum(rs.getLong(3));
1794: pStmt.close();
1795: pStmt = null;
1796:
1797: // Calcul du consommé
1798: pStmt = con
1799: .prepareStatement("select sum(ctb_duration), count(ctb_duration) from contribution, task where ctb_task=tsk_id and tsk_path like ?");
1800: pStmt.setString(1, pathLike);
1801: rs = pStmt.executeQuery();
1802: if (!rs.next())
1803: throw new DbException(
1804: "Nothing returned from this query", null);
1805: taskSums.setConsumedSum(rs.getLong(1));
1806: taskSums.setContributionsNb(rs.getLong(2));
1807: pStmt.close();
1808: pStmt = null;
1809:
1810: }
1811: // Retour du résultat
1812: return taskSums;
1813: } catch (SQLException e) {
1814: log.info("Incident SQL", e);
1815: throw new DbException(
1816: "Echec lors de la récupération des cumuls pour la tache d'identifiant '"
1817: + task.getId() + "'", e);
1818: } finally {
1819: try {
1820: if (pStmt != null)
1821: pStmt.close();
1822: } catch (Throwable ignored) {
1823: }
1824: }
1825: }
1826:
1827: /**
1828: * Supprime un collaborateur.
1829: * @param tx le contexte de transaction.
1830: * @param collaborator le collaborateur à supprimer.
1831: * @throws DbException levé en cas d'incident technique d'accès à la base.
1832: */
1833: protected static void removeCollaborator(DbTransaction tx,
1834: Collaborator collaborator) throws DbException {
1835: PreparedStatement pStmt = null;
1836: try {
1837: // Récupération de la connexion
1838: Connection con = tx.getConnection();
1839:
1840: // Préparation de la requête
1841: pStmt = con
1842: .prepareStatement("delete from collaborator where clb_id=?");
1843: pStmt.setLong(1, collaborator.getId());
1844:
1845: // Exécution de la requête
1846: int removed = pStmt.executeUpdate();
1847: if (removed != 1)
1848: throw new SQLException("No row was deleted");
1849:
1850: // Fermeture du statement
1851: pStmt.close();
1852: pStmt = null;
1853:
1854: } catch (SQLException e) {
1855: log.info("Incident SQL", e);
1856: throw new DbException(
1857: "Echec lors de la suppression du collaborateur '"
1858: + collaborator.getLogin() + "'", e);
1859: } finally {
1860: if (pStmt != null)
1861: try {
1862: pStmt.close();
1863: } catch (Throwable ignored) {
1864: }
1865: }
1866: }
1867:
1868: /**
1869: * Supprime une contribution.
1870: * @param tx le contexte de transaction.
1871: * @param contribution la contribution à supprimer.
1872: * @throws DbException levé en cas d'incident technique d'accès à la base.
1873: */
1874: protected static void removeContribution(DbTransaction tx,
1875: Contribution contribution) throws DbException {
1876: PreparedStatement pStmt = null;
1877: try {
1878: // Récupération de la connexion
1879: Connection con = tx.getConnection();
1880:
1881: // Préparation de la requête
1882: pStmt = con
1883: .prepareStatement("delete from contribution where ctb_year=? and ctb_month=? and ctb_day=? and ctb_contributor=? and ctb_task=?");
1884: pStmt.setInt(1, contribution.getYear());
1885: pStmt.setInt(2, contribution.getMonth());
1886: pStmt.setInt(3, contribution.getDay());
1887: pStmt.setLong(4, contribution.getContributorId());
1888: pStmt.setLong(5, contribution.getTaskId());
1889:
1890: // Exécution de la requête
1891: int removed = pStmt.executeUpdate();
1892: if (removed != 1)
1893: throw new SQLException("No row was deleted");
1894:
1895: // Fermeture du statement
1896: pStmt.close();
1897: pStmt = null;
1898: } catch (SQLException e) {
1899: log.info("Incident SQL", e);
1900: throw new DbException(
1901: "Echec lors de la suppression d'une contribution",
1902: e);
1903: } finally {
1904: if (pStmt != null)
1905: try {
1906: pStmt.close();
1907: } catch (Throwable ignored) {
1908: }
1909: }
1910: }
1911:
1912: /**
1913: * Supprime une durée du référentiel de durées.
1914: * @param tx le contexte de transaction.
1915: * @param duration la durée à supprimer.
1916: * @throws DbException levé en cas d'incident technique d'accès à la base.
1917: */
1918: protected static void removeDuration(DbTransaction tx,
1919: Duration duration) throws DbException {
1920: PreparedStatement pStmt = null;
1921: try {
1922: // Récupération de la connexion
1923: Connection con = tx.getConnection();
1924:
1925: // Préparation de la requête
1926: pStmt = con
1927: .prepareStatement("delete from duration where dur_id=?");
1928: pStmt.setLong(1, duration.getId());
1929:
1930: // Exécution de la requête
1931: int removed = pStmt.executeUpdate();
1932: if (removed != 1)
1933: throw new SQLException("No row was deleted");
1934:
1935: // Fermeture du statement
1936: pStmt.close();
1937: pStmt = null;
1938: } catch (SQLException e) {
1939: log.info("Incident SQL", e);
1940: throw new DbException(
1941: "Echec lors de la suppression de la durée '"
1942: + duration + "'", e);
1943: } finally {
1944: if (pStmt != null)
1945: try {
1946: pStmt.close();
1947: } catch (Throwable ignored) {
1948: }
1949: }
1950: }
1951:
1952: /**
1953: * Supprime une tache.
1954: * @param tx le contexte de transaction.
1955: * @param task la tache à supprimer.
1956: * @throws DbException levé en cas d'incident technique d'accès à la base.
1957: */
1958: protected static void removeTask(DbTransaction tx, Task task)
1959: throws DbException {
1960: PreparedStatement pStmt = null;
1961: try {
1962: // Récupération de la connexion
1963: Connection con = tx.getConnection();
1964:
1965: // Control sur les sous taches
1966: Task[] subTasks = DbMgr.getSubtasks(tx, task);
1967: for (int i = 0; i < subTasks.length; i++) {
1968: DbMgr.removeTask(tx, subTasks[i]);
1969: }
1970:
1971: // Préparation de la requête
1972: pStmt = con
1973: .prepareStatement("delete from task where tsk_id=?");
1974: pStmt.setLong(1, task.getId());
1975:
1976: // Exécution de la requête
1977: int removed = pStmt.executeUpdate();
1978: if (removed != 1)
1979: throw new SQLException("No row was deleted");
1980:
1981: // Fermeture du statement
1982: pStmt.close();
1983: pStmt = null;
1984: } catch (SQLException e) {
1985: log.info("Incident SQL", e);
1986: throw new DbException(
1987: "Echec lors de la suppression de la tache '" + task
1988: + "'", e);
1989: } finally {
1990: if (pStmt != null)
1991: try {
1992: pStmt.close();
1993: } catch (Throwable ignored) {
1994: }
1995: }
1996: }
1997:
1998: /**
1999: * Annule le modifications effectuées dans le cadre d'une transactrion.
2000: * @param tx contexte de transaction.
2001: * @throws DbException levé en cas d'incident technique d'accès à la base.
2002: */
2003: protected static void rollbackTransaction(DbTransaction tx)
2004: throws DbException {
2005: try {
2006: tx.getConnection().rollback();
2007: } catch (SQLException e) {
2008: log.info("Incident SQL", e);
2009: throw new DbException("Echec du rollback", e);
2010: }
2011: }
2012:
2013: /**
2014: * Modifie les attributs d'un collaborateur.
2015: * @param tx contexte de transaction.
2016: * @param collaborator le collaborateur à modifier.
2017: * @return le collaborateur modifié.
2018: * @throws DbException levé en cas d'incident technique d'accès à la base.
2019: */
2020: protected static Collaborator updateCollaborator(DbTransaction tx,
2021: Collaborator collaborator) throws DbException {
2022: PreparedStatement pStmt = null;
2023: try {
2024: // Récupération de la connexion
2025: Connection con = tx.getConnection();
2026:
2027: // Préparation de la requête
2028: pStmt = con
2029: .prepareStatement("update collaborator set clb_login=?, clb_first_name=?, clb_last_name=?, clb_is_active=? where clb_id=?");
2030: pStmt.setString(1, collaborator.getLogin());
2031: pStmt.setString(2, collaborator.getFirstName());
2032: pStmt.setString(3, collaborator.getLastName());
2033: pStmt.setBoolean(4, collaborator.getIsActive());
2034: pStmt.setLong(5, collaborator.getId());
2035:
2036: // Exécution de la requête
2037: int updated = pStmt.executeUpdate();
2038: if (updated != 1)
2039: throw new SQLException("No row was updated");
2040:
2041: // Fermeture du statement
2042: pStmt.close();
2043: pStmt = null;
2044:
2045: // Retour du résultat
2046: return collaborator;
2047: } catch (SQLException e) {
2048: log.info("Incident SQL", e);
2049: throw new DbException(
2050: "Echec lors de la mise à jour du collaborateur '"
2051: + collaborator.getLogin() + "'", e);
2052: } finally {
2053: if (pStmt != null)
2054: try {
2055: pStmt.close();
2056: } catch (Throwable ignored) {
2057: }
2058: }
2059: }
2060:
2061: /**
2062: * Modifie les attributs d'une contribution.
2063: * @param tx contexte de transaction.
2064: * @param contribution la contribution à modifier.
2065: * @return la contribution modifiée.
2066: * @throws DbException levé en cas d'incident technique d'accès à la base.
2067: */
2068: protected static Contribution updateContribution(DbTransaction tx,
2069: Contribution contribution) throws DbException {
2070: PreparedStatement pStmt = null;
2071: try {
2072: // Récupération de la connexion
2073: Connection con = tx.getConnection();
2074:
2075: // Préparation de la requête
2076: pStmt = con
2077: .prepareStatement("update contribution set ctb_duration=? where ctb_year=? and ctb_month=? and ctb_day=? and ctb_contributor=? and ctb_task=?");
2078: pStmt.setLong(1, contribution.getDurationId());
2079: pStmt.setInt(2, contribution.getYear());
2080: pStmt.setInt(3, contribution.getMonth());
2081: pStmt.setInt(4, contribution.getDay());
2082: pStmt.setLong(5, contribution.getContributorId());
2083: pStmt.setLong(6, contribution.getTaskId());
2084:
2085: // Exécution de la requête
2086: int updated = pStmt.executeUpdate();
2087: if (updated != 1)
2088: throw new SQLException("No row was updated");
2089:
2090: // Fermeture du statement
2091: pStmt.close();
2092: pStmt = null;
2093:
2094: // Retour du résultat
2095: return contribution;
2096: } catch (SQLException e) {
2097: log.info("Incident SQL", e);
2098: throw new DbException(
2099: "Echec lors de la mise à jour d'une contribution",
2100: e);
2101: } finally {
2102: if (pStmt != null)
2103: try {
2104: pStmt.close();
2105: } catch (Throwable ignored) {
2106: }
2107: }
2108: }
2109:
2110: /**
2111: * Met à jour une durée.
2112: * @param tx le contexte de transaction.
2113: * @param duration la durée à mettre à jour.
2114: * @return la durée mise à jour.
2115: * @throws DbException levé en cas d'incident technique d'accès à la base.
2116: */
2117: protected static Duration updateDuration(DbTransaction tx,
2118: Duration duration) throws DbException {
2119: PreparedStatement pStmt = null;
2120: try {
2121: // Récupération de la connexion
2122: Connection con = tx.getConnection();
2123:
2124: // Préparation de la requête
2125: pStmt = con
2126: .prepareStatement("update duration set dur_is_active=? where dur_id=?");
2127: pStmt.setBoolean(1, duration.getIsActive());
2128: pStmt.setLong(2, duration.getId());
2129:
2130: // Exécution de la requête
2131: int updated = pStmt.executeUpdate();
2132: if (updated != 1)
2133: throw new SQLException("No row was updated");
2134:
2135: // Fermeture du statement
2136: pStmt.close();
2137: pStmt = null;
2138:
2139: // Retour du résultat
2140: return duration;
2141: } catch (SQLException e) {
2142: log.info("Incident SQL", e);
2143: throw new DbException(
2144: "Echec lors de la mise à jour de la durée '"
2145: + duration.getId() + "'", e);
2146: } finally {
2147: if (pStmt != null)
2148: try {
2149: pStmt.close();
2150: } catch (Throwable ignored) {
2151: }
2152: }
2153: }
2154:
2155: /**
2156: * Change la tache d'une contribution.
2157: * @param tx contexte de transaction.
2158: * @param contribution la contribution.
2159: * @param newContributionTask la tache à affecter.
2160: * @return la contribution mise à jour.
2161: * @throws DbException levé en cas d'incident technique d'accès à la base.
2162: */
2163: protected static Contribution changeContributionTask(
2164: DbTransaction tx, Contribution contribution,
2165: Task newContributionTask) throws DbException {
2166: PreparedStatement pStmt = null;
2167: try {
2168: // Récupération de la connexion
2169: Connection con = tx.getConnection();
2170:
2171: // Préparation de la requête
2172: pStmt = con
2173: .prepareStatement("update contribution set ctb_task=? where ctb_year=? and ctb_month=? and ctb_day=? and ctb_contributor=? and ctb_task=?");
2174: pStmt.setLong(1, newContributionTask.getId());
2175: pStmt.setInt(2, contribution.getYear());
2176: pStmt.setInt(3, contribution.getMonth());
2177: pStmt.setInt(4, contribution.getDay());
2178: pStmt.setLong(5, contribution.getContributorId());
2179: pStmt.setLong(6, contribution.getTaskId());
2180:
2181: // Exécution de la requête
2182: int updated = pStmt.executeUpdate();
2183: if (updated != 1)
2184: throw new SQLException("No row was updated");
2185:
2186: // Mise à jour de la contribution
2187: contribution.setTaskId(newContributionTask.getId());
2188:
2189: // Fermeture du statement
2190: pStmt.close();
2191: pStmt = null;
2192:
2193: // Retour du résultat
2194: return contribution;
2195: } catch (SQLException e) {
2196: log.info("Incident SQL", e);
2197: throw new DbException(
2198: "Echec lors de la mise à jour d'une contribution",
2199: e);
2200: } finally {
2201: if (pStmt != null)
2202: try {
2203: pStmt.close();
2204: } catch (Throwable ignored) {
2205: }
2206: }
2207: }
2208:
2209: /**
2210: * Modifie les attributs d'une tache.
2211: * @param tx contexte de transaction.
2212: * @param task la tache à modifier.
2213: * @return la tache modifiée.
2214: * @throws DbException levé en cas d'incident technique d'accès à la base.
2215: */
2216: protected static Task updateTask(DbTransaction tx, Task task)
2217: throws DbException {
2218: PreparedStatement pStmt = null;
2219: try {
2220: // Récupération de la connexion
2221: Connection con = tx.getConnection();
2222:
2223: // Préparation de la requête
2224: pStmt = con
2225: .prepareStatement("update task set tsk_path=?, tsk_number=?, tsk_code=?, tsk_name=?, tsk_budget=?, tsk_initial_cons=?, tsk_todo=?, tsk_comment=? where tsk_id=?");
2226: pStmt.setString(1, task.getPath());
2227: pStmt.setByte(2, task.getNumber());
2228: pStmt.setString(3, task.getCode());
2229: pStmt.setString(4, task.getName());
2230: pStmt.setLong(5, task.getBudget());
2231: pStmt.setLong(6, task.getInitiallyConsumed());
2232: pStmt.setLong(7, task.getTodo());
2233: pStmt.setString(8, task.getComment());
2234: pStmt.setLong(9, task.getId());
2235:
2236: // Exécution de la requête
2237: int updated = pStmt.executeUpdate();
2238: if (updated != 1)
2239: throw new SQLException("No row was updated");
2240:
2241: // Fermeture du statement
2242: pStmt.close();
2243: pStmt = null;
2244:
2245: // Retour du résultat
2246: return task;
2247: } catch (SQLException e) {
2248: log.info("Incident SQL", e);
2249: throw new DbException(
2250: "Echec lors de la mise à jour de la tache '"
2251: + task.getName() + "'", e);
2252: } finally {
2253: if (pStmt != null)
2254: try {
2255: pStmt.close();
2256: } catch (Throwable ignored) {
2257: }
2258: }
2259: }
2260:
2261: /**
2262: * Complete la requete de calcul de la somme des contributions.
2263: * @param requestBase buffer utilisé pour la construction de la requête.
2264: * @param contributor le collaborateur ayant contribué à la tache (facultatif).
2265: * @param year l'année (facultative)
2266: * @param month le mois (facultatif)
2267: * @param day le jour (facultatif)
2268: */
2269: private static void completeContributionRequest(
2270: StringBuffer requestBase, Collaborator contributor,
2271: Integer year, Integer month, Integer day) {
2272: if (contributor != null)
2273: requestBase.append(" and ctb_contributor=?");
2274: if (year != null)
2275: requestBase.append(" and ctb_year=?");
2276: if (month != null)
2277: requestBase.append(" and ctb_month=?");
2278: if (day != null)
2279: requestBase.append(" and ctb_day=?");
2280: log.debug("built request : " + requestBase.toString());
2281: }
2282:
2283: /**
2284: * Complete les paramètres de la requete de calcul de la somme des contributions.
2285: * @param pStmt le statement.
2286: * @param startIndex
2287: * @param contributor le collaborateur ayant contribué à la tache (facultatif).
2288: * @param year l'année (facultative)
2289: * @param month le mois (facultatif)
2290: * @param day le jour (facultatif)
2291: * @throws SQLException levé en cas d'incident avec la base de données.
2292: */
2293: private static void completeContributionReqParams(
2294: PreparedStatement pStmt, int startIndex,
2295: Collaborator contributor, Integer year, Integer month,
2296: Integer day) throws SQLException {
2297: int idx = startIndex;
2298: log.debug("contributorId="
2299: + (contributor != null ? String.valueOf(contributor
2300: .getId()) : "null"));
2301: log.debug("year=" + year);
2302: log.debug("month=" + month);
2303: log.debug("day=" + day);
2304: if (contributor != null)
2305: pStmt.setLong(idx++, contributor.getId());
2306: if (year != null)
2307: pStmt.setInt(idx++, year.intValue());
2308: if (month != null)
2309: pStmt.setInt(idx++, month.intValue());
2310: if (day != null)
2311: pStmt.setInt(idx++, day.intValue());
2312: }
2313:
2314: /**
2315: * Génère un nouveau numéro de tache pour un chemin donné.
2316: * @param tx le contexte de transaction.
2317: * @param path le chemin considéré.
2318: * @return le numéro généré.
2319: * @throws DbException levé en cas d'incident technique d'accès à la base.
2320: */
2321: protected static byte newTaskNumber(DbTransaction tx, String path)
2322: throws DbException {
2323: PreparedStatement pStmt = null;
2324: ResultSet rs = null;
2325: try {
2326: // Récupération de la connexion
2327: Connection con = tx.getConnection();
2328:
2329: // Recherche du max
2330: pStmt = con
2331: .prepareStatement("select max(tsk_number) from task where tsk_path=?");
2332: pStmt.setString(1, path);
2333: rs = pStmt.executeQuery();
2334: if (!rs.next())
2335: throw new DbException(
2336: "Nothing returned from this query", null);
2337: byte max = rs.getByte(1);
2338: log.debug(" => max= : " + max);
2339:
2340: // Fermeture du statement
2341: pStmt.close();
2342: pStmt = null;
2343:
2344: // Retour du résultat
2345: return (byte) (max + 1);
2346: } catch (SQLException e) {
2347: log.info("Incident SQL", e);
2348: throw new DbException(
2349: "Echec lors de la génération d'un nouveau numéro de tache pour le chemin '"
2350: + path + "'", e);
2351: } finally {
2352: if (pStmt != null)
2353: try {
2354: pStmt.close();
2355: } catch (Throwable ignored) {
2356: }
2357: }
2358: }
2359:
2360: /**
2361: * Retourne l'identifiant généré automatiquement par la base de données.
2362: * @param pStmt le statement SQL.
2363: * @return l'identifiant généré.
2364: * @throws DbException levé en cas d'incident technique d'accès à la base.
2365: */
2366: private static long getGeneratedId(PreparedStatement pStmt)
2367: throws DbException {
2368: long generatedId = -1;
2369: PreparedStatement pStmt1 = null;
2370: try {
2371: // Récupération de la connexion
2372: Connection con = pStmt.getConnection();
2373: // Cas de HSQLDB
2374: if (isHSQLDB(con)) {
2375: log.debug("HSQL Database detected");
2376: pStmt1 = con.prepareStatement("call identity()");
2377: ResultSet rs = pStmt1.executeQuery();
2378: if (!rs.next())
2379: throw new DbException(
2380: "Nothing returned from this query", null);
2381: generatedId = rs.getLong(1);
2382:
2383: // Fermeture du statement
2384: pStmt1.close();
2385: pStmt1 = null;
2386: } else {
2387: log.debug("Generic Database detected");
2388: // Récupération de l'identifiant généré
2389: ResultSet rs = pStmt.getGeneratedKeys();
2390: if (!rs.next())
2391: throw new DbException(
2392: "Nothing returned from this query", null);
2393: generatedId = rs.getLong(1);
2394: }
2395: // Retour du résultat
2396: log.debug("Generated id=" + generatedId);
2397: return generatedId;
2398: } catch (SQLException e) {
2399: log.info("Incident SQL", e);
2400: throw new DbException(
2401: "Echec lors de la récupération de l'identifiant du nouvel objet",
2402: e);
2403: } finally {
2404: if (pStmt1 != null)
2405: try {
2406: pStmt1.close();
2407: } catch (Throwable ignored) {
2408: }
2409: }
2410: }
2411:
2412: /**
2413: * Indique si la BDD de données est une base HSQLDB.
2414: * @param con la connexion SQL.
2415: * @return un booléen indiquant si la BDD est de type HSQLDB.
2416: * @throws DbException levé en cas d'incident technique d'accès à la base.
2417: */
2418: private static boolean isHSQLDB(Connection con) throws DbException {
2419: try {
2420: // Récupération du nom de la base de données
2421: String dbName = con.getMetaData().getDatabaseProductName();
2422: log.debug("DbName=" + dbName);
2423: return "HSQL Database Engine".equals(dbName);
2424: } catch (SQLException e) {
2425: log.info("Incident SQL", e);
2426: throw new DbException(
2427: "Echec lors de la récupération du nom de la BDD", e);
2428: }
2429: }
2430:
2431: /**
2432: * Indique si la BDD de données est une base HSQLDB embarquée.
2433: * @param con la connexion SQL.
2434: * @return un booléen indiquant si la BDD est de type HSQLDB embarquée.
2435: * @throws DbException levé en cas d'incident technique d'accès à la base.
2436: */
2437: private static boolean isEmbeddedHSQLDB(Connection con)
2438: throws DbException {
2439: try {
2440: // Récupération du nom de la base de données
2441: String dbName = con.getMetaData().getDatabaseProductName();
2442: log.debug("DbName=" + dbName);
2443: return isHSQLDB(con)
2444: && ds.getUrl().startsWith("jdbc:hsqldb:file");
2445: } catch (SQLException e) {
2446: log.info("Incident SQL", e);
2447: throw new DbException(
2448: "Echec lors de la récupération du nom de la BDD", e);
2449: }
2450: }
2451:
2452: }
|