Package org.objectweb.speedo.j2eedo.bo

Source Code of org.objectweb.speedo.j2eedo.bo.DatabaseImpl

/*
* Speedo: an implementation of JDO compliant personality on top of JORM
* generic I/O sub-system. Copyright (C) 2001-2004 France Telecom R&D
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Release: 1.0
*
* Created on 1 mars 2004 @author fmillevi@yahoo.com
*
*/
package org.objectweb.speedo.j2eedo.bo;

import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.jdo.JDOException;
import javax.jdo.JDOFatalException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.objectweb.speedo.Alea;
import org.objectweb.speedo.j2eedo.common.PMHolder;
import org.objectweb.speedo.j2eedo.database.Address;
import org.objectweb.speedo.j2eedo.database.DatabaseObjectInterface;
import org.objectweb.speedo.j2eedo.database.Department;
import org.objectweb.speedo.j2eedo.database.Employee;
import org.objectweb.speedo.j2eedo.database.Project;
import org.objectweb.util.monolog.Monolog;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;

/**
* This class handle each request on the <b>J2EEDO</b> application.
* The doAction() method performs the current requested action.
* <p>
* It starts and commits a transaction if needed
* </p>
* <p>
* Call the asked action. When the action in the
* {@link DatabaseImpl#actionArray action list}, the 3 local static lists of
* id (department, employee and project) are redefined.
* </p>
*
* @author fmillevi@yahoo.com
*/
public class DatabaseImpl {
  /**
   * Defines the action <code>PARAMETER_PING</code><b> its value is ("ping")</b>
   * <p>
   * This action is use just to check if the application can be reached
   * </p>
   */
  final public static String PARAMETER_PING = "ping";
  /**
   * Defines the action <code>PARAMETER_NEW_DEPARTMENT</code><b> its value is
   * ("newDept")</b>
   * <p>
   * This action Creates a new department and some new employees (random
   * number defined between 10 and 70).
   * </p>
   *
   * @see DepartmentFactory#MIN_EMPLOYEE_PER_DEPARTMENT
   * @see DepartmentFactory#MAX_EMPLOYEE_PER_DEPARTMENT
   * @see DepartmentFactory#newDepartmentWithEmployees
   */
  final public static String PARAMETER_NEW_DEPARTMENT = "newDept";
  /**
   * Defines the action <code>PARAMETER_NEW_PROJECT</code><b> its value is
   * ("newProj")</b>
   * <p>
   * This action Creates a new project and affect few employees (random
   * number defined between 5 and 20).
   * </p>
   *
   * @see ProjectFactory#MIN_MEMBER_PER_PROJECT
   * @see ProjectFactory#MAX_MEMBER_PER_PROJECT
   * @see ProjectFactory#newProjectWithEmployees
   */
  final public static String PARAMETER_NEW_PROJECT = "newProj";
  /**
   * Defines the action <code>PARAMETER_NEW_EMPLOYEE</code><b> its value is
   * ("newEmp")</b>
   * <p>
   * Selects one of the known departments and creates a new employee.
   * </p>
   * @see EmployeeFactory#newEmployee
   */
  final public static String PARAMETER_NEW_EMPLOYEE = "newEmp";
  /**
   * Defines the action <code>PARAMETER_SET_BOSS</code><b> its value is
   * ("setDeptBoss")</b>
   * @see DepartmentFactory#setManagerForADepartment()
   */
  final public static String PARAMETER_SET_BOSS = "setDeptBoss";
  /**
   * Defines the action <code>PARAMETER_REM_EMPLOYEE</code><b> its value is
   * ("delEmployee")</b>
   * @see EmployeeFactory#deleteEmployee
   */
  final public static String PARAMETER_REM_EMPLOYEE = "delEmployee";
  /**
   * Defines the action <code>PARAMETER_REM_PROJECT</code><b> its value is
   * ("delProject")</b>
   * @see ProjectFactory#deleteProject
   */
  final public static String PARAMETER_REM_PROJECT = "delProject";
  /**
   * Defines the action <code>PARAMETER_SPLIT_PROJECT</code><b> its value is
   * ("splitProject")</b>
   * @see ProjectFactory#splitProject
   */
  final public static String PARAMETER_SPLIT_PROJECT = "splitProject";
  /**
   * Defines the action <code>PARAMETER_SPLIT_DEPARTMENT</code><b> its value is
   * ("splitDepartment")</b>
   * @see DepartmentFactory#splitDepartment
   */
  final public static String PARAMETER_SPLIT_DEPARTMENT = "splitDepartment";
  /**
   * Defines the action <code>PARAMETER_MERGE_DEPARTMENT</code><b> its value is
   * ("mergeDept")</b>
   * @see DepartmentFactory#mergeDepartment
   */
  final public static String PARAMETER_MERGE_DEPARTMENT = "mergeDept";
  /**
   * Defines the action <code>PARAMETER_INCREASE_SALARY</code><b> its value is
   * ("incSalary")</b> for good folsk only...
   * @see EmployeeFactory#increaseSalary()
   */
  final public static String PARAMETER_INCREASE_SALARY = "incSalary";
  /**
   * Defines the action <code>PARAMETER_GET_DEPARTMENT</code><b> its value is
   * ("getDepartment")</b>
   * @see DepartmentFactory#getDepartment()
   */
  final public static String PARAMETER_GET_DEPARTMENT = "getDepartment";
  /**
   * Defines the action <code>PARAMETER_GET_PROJECT</code><b> its value is
   * ("getProject")</b>
   * @see ProjectFactory#getProject()
   */
  final public static String PARAMETER_GET_PROJECT = "getProject";
  /**
   * Defines the action <code>PARAMETER_GET_EMPLOYEE</code><b> its value is
   * ("getEmployee")</b>
   * @see EmployeeFactory#getEmployees()
   */
  final public static String PARAMETER_GET_EMPLOYEE = "getEmployee";
  /**
   * Defines the action <code>PARAMETER_QUERY_PROJECTS</code><b> its value is
   * ("queryProjects")</b>
   * <p>
   * Performs one of the four queries:
   * <ul>
   * <li>Get employee by its id,</li>
   * <li>Get employees between min and max,</li>
   * <li>Get employees having the same manager,</li>
   * <li>Get employees member of a project.</li>
   * </ul>
   * </p>
   * @see EmployeeFactory#getEmployees()
   */
  final public static String PARAMETER_QUERY_PROJECTS = "queryProjects";
  /**
   * Defines the action <code>PARAMETER_QUERY_EMPLOYEES</code><b> its value is
   * ("queryEmployees")</b>
   * <p>
   * Performs one of the two queries:
   * <ul>
   * <li>Get project by its id,</li>
   * <li>Get projects by member.</li>
   * </ul>
   * </p>
   * @see ProjectFactory#getProjects()
   */
  final public static String PARAMETER_QUERY_EMPLOYEES = "queryEmployees";

  final public static String PARAMETER_EVICTALL = "evictall";
  /**
   * The String array <code>actionArray</code> gives the liste of actions
   * avalaibles
   */
  final public static String actionArray[] = {
      DatabaseImpl.PARAMETER_NEW_DEPARTMENT,
      DatabaseImpl.PARAMETER_NEW_PROJECT,
      DatabaseImpl.PARAMETER_NEW_EMPLOYEE,
      DatabaseImpl.PARAMETER_SET_BOSS,
      DatabaseImpl.PARAMETER_REM_EMPLOYEE,
      DatabaseImpl.PARAMETER_REM_PROJECT,
      DatabaseImpl.PARAMETER_SPLIT_PROJECT,
      DatabaseImpl.PARAMETER_SPLIT_DEPARTMENT,
      DatabaseImpl.PARAMETER_MERGE_DEPARTMENT,
      DatabaseImpl.PARAMETER_INCREASE_SALARY,
      DatabaseImpl.PARAMETER_GET_DEPARTMENT,
      DatabaseImpl.PARAMETER_GET_PROJECT,
      DatabaseImpl.PARAMETER_GET_EMPLOYEE,
      DatabaseImpl.PARAMETER_QUERY_PROJECTS,
      DatabaseImpl.PARAMETER_QUERY_EMPLOYEES,
      DatabaseImpl.PARAMETER_PING
    };
  final public static int READ = 1;
  final public static int WRITE = 0;
  /**
   * The double dimension array <code>actionWeightArray</code> gives for
   * each action the relative read and write weight
   *
   * @see #actionArray
   */
  final public static int actionWeightArray[][] = { //{write,read}
    { 4, 0 }, //DatabaseImpl.PARAMETER_NEW_DEPARTMENT,
    { 5, 3 }, //DatabaseImpl.PARAMETER_NEW_PROJECT,
    { 1, 1 }, //DatabaseImpl.PARAMETER_NEW_EMPLOYEE,
    { 4, 2 }, //DatabaseImpl.PARAMETER_SET_BOSS,
    { 1, 1 }, //DatabaseImpl.PARAMETER_REM_EMPLOYEE,
    { 4, 2 }, //DatabaseImpl.PARAMETER_REM_PROJECT,
    { 4, 3 }, //DatabaseImpl.PARAMETER_SPLIT_PROJECT,
    { 4, 4 }, //DatabaseImpl.PARAMETER_SPLIT_DEPARTMENT
    { 5, 2 }, //DatabaseImpl.PARAMETER_MERGE_DEPARTMENT,
    { 3, 2 }, //DatabaseImpl.PARAMETER_INCREASE_SALARY,
    { 0, 5 }, //DatabaseImpl.PARAMETER_GET_DEPARTMENT,
    { 0, 3 }, //DatabaseImpl.PARAMETER_GET_PROJECT,
    { 0, 1 }, //DatabaseImpl.PARAMETER_GET_EMPLOYEE,
    { 0, 3 }, //DatabaseImpl.PARAMETER_QUERY_PROJECT,
    { 0, 2 }, //DatabaseImpl.PARAMETER_QUERY_EMPLOYEE
    { 0, 0 } //DatabaseImpl.PARAMETER_PING
  };

  /**
   * The Vector <code>poolOfDepartmentId</code> is a static list of known
   * departmentId used to keep in mind the list of department without doing
   * any JDO request.
   * <p>
   * This is a local cache
   * </p>
   */
  public final static Vector poolOfDepartmentId = new Vector();
  /**
   * The Vector <code>poolOfProjectId</code> is a static list of known
   * projectId used to keep in mind the list of project without doing any JDO
   * request.
   * <p>
   * This is a local cache
   * </p>
   */
  public final static Vector poolOfProjectId = new Vector();
  /**
   * The Vector <code>poolOfEmployeeId</code> is a static list of known
   * employeeId used to keep in mind the list of employee without doing any
   * JDO request.
   * <p>
   * This is a local cache
   * </p>
   */
  public final static Vector poolOfEmployeeId = new Vector();

  private static boolean resetPools = true;

  static Logger logger = Monolog.initialize().getLogger(DatabaseImpl.class.getName());
   
    private static Hashtable needTransactionArray = new Hashtable();;

  static {
        // define the action needing transaction.
        int writeWeight;
        for (int i = 0; i < DatabaseImpl.actionWeightArray.length; i++) {
            writeWeight = DatabaseImpl.actionWeightArray[i][DatabaseImpl.WRITE];
            needTransactionArray.put(
                    DatabaseImpl.actionArray[i],
                    Boolean.valueOf(writeWeight != 0));
        }
  }

  private final static int PROJECT_INIT_SIZE = 100;
  private final static int DEPARTMENT_INIT_SIZE = 30;

    public final static DatabaseImpl instance = new DatabaseImpl();
   
    //private PMHolder persistenceManagerHolder;
    private DepartmentFactory departmentFactory = null;
    private EmployeeFactory employeeFactory = null;
    private ProjectFactory projectFactory = null;

    private DatabaseImpl() {
        this.departmentFactory = new DepartmentFactory();
        this.employeeFactory = new EmployeeFactory();
        this.projectFactory = new ProjectFactory();
    }

    /**
   * This method initialize the action to be performed, enables or disables
   * transaction management according the parameter withTransaction and calls
   * the private doAction() method.
   *
   * @param parameter
   *            is the action to be performed
   * @param withTransaction
   *            is a boolean use to enable or disable the use of transaction
   * @return threatment result as String
   * @throws JDOException
   * @throws Exception
   */
  public String doAction(String action, boolean performCommit, PMHolder pmHolder) {
        if (PARAMETER_PING.equalsIgnoreCase(action)) {
            return "Alive...";
        }
        PersistenceManager pm = pmHolder.getPersistenceManager();
        StringBuffer outStr = new StringBuffer();
    try {
            boolean demarcateJDOTx = (performCommit
                    || ((Boolean) needTransactionArray.get(action)).booleanValue())
                    && !pm.currentTransaction().isActive();
      if (PARAMETER_EVICTALL.equalsIgnoreCase(action)) {
          logger.log(BasicLevel.INFO, "Flushing cache ...");
          pm.evictAll();
        resetPools(pm, outStr);
          return "Cache flushed !";
      }
      initPools(pm);
            PollsSynchronizations poolsSync = new PollsSynchronizations();
            pm.setUserObject(poolsSync);
            pm.currentTransaction().setSynchronization(poolsSync);
      if (demarcateJDOTx) {
        logger.log(BasicLevel.INFO, "Begin JDO transaction.");
        pm.currentTransaction().begin();
      }
            StringTokenizer st = new StringTokenizer(action.trim(), ", ", false);
            while(st.hasMoreTokens()) {
                doAction(st.nextToken(), poolsSync, outStr, pm);
            }
      if (demarcateJDOTx && pm.currentTransaction().isActive()) {
                logger.log(BasicLevel.INFO, "Commit JDO transaction.");
        pm.currentTransaction().commit();
      }
    } catch (RuntimeException e) {
        logger.log(BasicLevel.WARN, "The action : '" + action
              + "' fails : Action canceled.", e);
      if (!pm.isClosed() && pm.currentTransaction().isActive()) {
        pm.currentTransaction().rollback();
            }
            if (!(e instanceof JDOFatalException)) {
                outStr.append("Action canceled").append(e.getMessage());
            } else {
                throw e;
            }
    } finally {
            pmHolder.closePersistenceManager();
    }
    return outStr.toString();
  }

  private void doAction(String action,
            PollsSynchronizations poolsSync,
            StringBuffer outStr,
            PersistenceManager pm) {
        logger.log(BasicLevel.DEBUG, "do action " + action);
        if (PARAMETER_NEW_DEPARTMENT.equalsIgnoreCase(action)) {
            departmentFactory.newDepartmentWithEmployees(poolsSync, outStr, pm);
        } else if (PARAMETER_NEW_PROJECT.equalsIgnoreCase(action)) {
            projectFactory.newProjectWithEmployees(poolsSync, outStr, pm);
        } else if (PARAMETER_SET_BOSS.equalsIgnoreCase(action)) {
            departmentFactory.setManagerForADepartment(outStr, pm);
        } else if (PARAMETER_NEW_EMPLOYEE.equalsIgnoreCase(action)) {
            employeeFactory.newEmployee(poolsSync, outStr, pm);
        } else if (PARAMETER_REM_EMPLOYEE.equalsIgnoreCase(action)) {
            employeeFactory.deleteEmployee(poolsSync, outStr, pm);
        } else if (PARAMETER_REM_PROJECT.equalsIgnoreCase(action)) {
            projectFactory.deleteProject(poolsSync, outStr, pm);
        } else if (PARAMETER_SPLIT_PROJECT.equalsIgnoreCase(action)) {
            projectFactory.splitProject(poolsSync, outStr, pm);
        } else if (PARAMETER_MERGE_DEPARTMENT.equalsIgnoreCase(action)) {
            departmentFactory.mergeDepartment(poolsSync, outStr, pm);
        } else if (PARAMETER_SPLIT_DEPARTMENT.equalsIgnoreCase(action)) {
            departmentFactory.splitDepartment(poolsSync, outStr, pm);
        } else if (PARAMETER_INCREASE_SALARY.equalsIgnoreCase(action)) {
            employeeFactory.increaseSalary(outStr, pm);
        } else if (PARAMETER_GET_DEPARTMENT.equalsIgnoreCase(action)) {
            departmentFactory.getDepartment(outStr, pm);
        } else if (PARAMETER_GET_PROJECT.equalsIgnoreCase(action)) {
            projectFactory.getProject(outStr, pm);
        } else if (PARAMETER_GET_EMPLOYEE.equalsIgnoreCase(action)) {
            employeeFactory.getEmployee(outStr, pm);
        } else if (PARAMETER_QUERY_PROJECTS.equalsIgnoreCase(action)) {
            projectFactory.getProjects(outStr, pm);
        } else if (PARAMETER_QUERY_EMPLOYEES.equalsIgnoreCase(action)) {
            employeeFactory.getEmployees(outStr, pm);
        } else {
            resetPools(pm, outStr);
        }
        logger.log(BasicLevel.DEBUG, "End of action : " + action);
    }
   
   
  private synchronized static void resetPools(
            PersistenceManager pm,
            StringBuffer outStr) {
        logger.log(BasicLevel.DEBUG, "Resets and shows pools");
    poolOfDepartmentId.clear();
    poolOfEmployeeId.clear();
    poolOfProjectId.clear();
    resetPools = true;
    initPools(pm);
    if (outStr != null) {
      outStr.append("\nDo nothing and dump static poll contents");
      outStr.append("\nDepartments:");
      outStr.append(DatabaseImpl.poolOfDepartmentId.toString());
      outStr.append("\nEmployees:");
      outStr.append(DatabaseImpl.poolOfEmployeeId.toString());
      outStr.append("\nProjects:");
      outStr.append(DatabaseImpl.poolOfProjectId.toString());
    }
  }
 
  private static synchronized void initPools(PersistenceManager pm) {
    if (!resetPools) {
      return;
        }
    try {
      if (poolOfDepartmentId.isEmpty()) {
                initPool(poolOfDepartmentId, Department.class, pm);
        logger.log(BasicLevel.DEBUG,
          "Initialize the static pool of Departments Id : "
            + poolOfDepartmentId);
      }
      if (poolOfProjectId.isEmpty()) {
                initPool(poolOfProjectId, Project.class, pm);
        logger.log(BasicLevel.DEBUG,
          "Initialize the static pool of Projects Id : "
            + poolOfProjectId);
      }
      if (poolOfEmployeeId.isEmpty()) {
                initPool(poolOfEmployeeId, Employee.class, pm);
        logger.log(BasicLevel.DEBUG,
          "Initialize the static pool of Employees Id : "
                        + poolOfEmployeeId);
      }
    } finally {
      DatabaseImpl.resetPools = false;
    }
  }

    /**
     * Initializes a pool of identifier
     * @param pool is the pool to fill
     * @param c is the persistent class
     * @param pm is the persistence manager to use
     */
  private static void initPool(Collection pool, Class c, PersistenceManager pm) {
    logger.log(BasicLevel.INFO, "(Re)Initialize static pool id for classe : "
                + c.getName());
        pm.getObjectIdClass(c);
        boolean hasMoreResult = true;
        int idx = 0;
        final int page_size = 1000;
        boolean hasTx = pm.currentTransaction().isActive();
        if (hasTx) {
            pm.currentTransaction().commit();
        }
        while(hasMoreResult) {
            pm.currentTransaction().begin();
            Query query = pm.newQuery(c);
            query.setRange(idx, idx + page_size);
            int nb = 0;
            try {
            Collection col = (Collection) query.execute();
            for(Iterator it = col.iterator(); it.hasNext();) {
                    nb ++;
              pool.add(new Long(((DatabaseObjectInterface) it.next()).getId()));
                }
        } finally {
            query.closeAll();
            }
            idx += page_size;
            hasMoreResult =  nb > 0;
            pm.currentTransaction().commit();
        }
  }

    /**
     * Gets an element from the pool.
     */
  private final static long getIdFromPool(Vector pool) {
    // Get an id from the pool.
    while (DatabaseImpl.resetPools) {
      try {
        logger.log(
          BasicLevel.DEBUG,
          "sleep until the end off static pool id reset...");
        Thread.sleep(10);
      } catch (InterruptedException e) {
      }
    }
    int alea = Alea.rand(0, Math.max(0, pool.size() -1));
        synchronized(pool) {
            return ((Long) pool.get(alea)).longValue();
        }
  }

  public static void initTestData(PMHolder pmHolder)
    throws JDOException, Exception {
    String str;
    PersistenceManager pm = pmHolder.getPersistenceManager();
    pm.evictAll();
    Iterator objIter = null;
    DatabaseImpl.poolOfDepartmentId.clear();
    DatabaseImpl.poolOfEmployeeId.clear();
    DatabaseImpl.poolOfProjectId.clear();
    // remove all employee
    Class[] classes = new Class[] {
            Employee.class,
            Address.class,
            Project.class,
            Department.class
    };
    pm.currentTransaction().begin();
    for (int i = 0; i < classes.length; i++) {
      logger.log(BasicLevel.DEBUG, "Removing " + classes[i].getName() + " ...");
      pm.deletePersistentAll((Collection) pm.newQuery(classes[i]).execute());
      logger.log(BasicLevel.INFO, "All " + classes[i].getName() + " have been removed.");
        }
    pm.currentTransaction().commit();

    pm.evictAll();

    pm.currentTransaction().begin();
    logger.log(BasicLevel.INFO, "Init departments and employees data.");
    for (int i = 0; i < DEPARTMENT_INIT_SIZE; i++) {
      str = DatabaseImpl.instance.doAction(
                    PARAMETER_NEW_DEPARTMENT, false, pmHolder);
      logger.log(BasicLevel.DEBUG, str);
    }
    DatabaseImpl.resetPools = true;
    logger.log(BasicLevel.INFO, "Init projects data.");
    for (int i = 0; i < PROJECT_INIT_SIZE; i++) {
            str = DatabaseImpl.instance.doAction(
                    PARAMETER_NEW_PROJECT, false, pmHolder);
      logger.log(BasicLevel.DEBUG, str);
    }
    DatabaseImpl.resetPools = true;
    pm.currentTransaction().commit();
    logger.log(BasicLevel.INFO, "Initial data set.");
    resetPools(pm, null);
    pm.evictAll();
    logger.log(BasicLevel.DEBUG, "Remove all cache entries.");
    pmHolder.closePersistenceManager();
    logger.log(BasicLevel.DEBUG, "Close the persistenceManager.");
  }

  /**
   * Returns one of the existing department id
   *
   * @return a department id
   */
  public static long getDepartmentIdFromPool() {
    return DatabaseImpl.getIdFromPool(DatabaseImpl.poolOfDepartmentId);
  }

  /**
   * Returns one of the existing employee id
   *
   * @return a employee id
   */
  public static long getEmployeeIdFromPool() {
    return DatabaseImpl.getIdFromPool(DatabaseImpl.poolOfEmployeeId);
  }

  /**
   * Returns one of the existing project id
   *
   * @return a project id
   */
  public static long getProjectIdFromPool() {
    return DatabaseImpl.getIdFromPool(DatabaseImpl.poolOfProjectId);
  }
}
TOP

Related Classes of org.objectweb.speedo.j2eedo.bo.DatabaseImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.