/* * Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The * University of Hong Kong (HKU). All Rights Reserved. * * This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1] * * [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */ package hk.hku.cecid.piazza.commons.dao; import hk.hku.cecid.piazza.commons.module.Component; import hk.hku.cecid.piazza.commons.util.Instance; import hk.hku.cecid.piazza.commons.util.PropertyTree; import hk.hku.cecid.piazza.commons.util.StringUtilities; import java.net.URL; import java.util.Properties; /** * The DAO pattern can be made highly flexible by adopting the Abstract Factory * and the Factory Method Patterns. * <p> * The Factory Method pattern can be used to produce a number of DAOs needed by * the application when the underlying storage is not subject to change from one * implementation to another. When it is subject to change, the Abstract Factory * pattern can in turn build on and use the Factory Method Implementation. In * this case, it provides an abstract DAO factory object that can construct * various types of concrete DAO factories, each factory supporting a different * type of persistent storage implementation. Once you obtain the concrete DAO * factory for a specific implementation, you use it to produce DAOs supported * and implemented in that implementation. * * @author Hugo Y. K. Lam * */ public abstract class DAOFactory extends Component { private PropertyTree daoprops = new PropertyTree(); /** * Creates a new instance of DAOFactory. */ protected DAOFactory() { } /** * Initializes the DAO Factory. * * @throws DAOException when there is any error in the initialization. * @see #initFactory() */ protected void init() throws DAOException { String[] daoDescriptors = StringUtilities.tokenize( getParameter("config"), ",\t\r\n"); for (int i = 0; i < daoDescriptors.length; i++) { String daoDescriptor = daoDescriptors[i].trim(); if (!"".equals(daoDescriptor)) { URL daoResourceURL = getModule().getResource(daoDescriptor); if (daoResourceURL != null) { try { if (!daoprops.append(new PropertyTree(daoResourceURL))) { throw new DAOException("Invalid DAO descriptor"); } else { getModule().getLogger().debug( "DAO descriptor '" + daoDescriptor + "' loaded successfully"); } } catch (Exception e) { throw new DAOException( "Unable to load dao descriptor from URL '" + daoResourceURL + "'", e); } } else { throw new DAOException("DAO descriptor '" + daoDescriptor + "' not found"); } } } initFactory(); } /** * Creates a new DAO. * * @param inf the DAO interface class. * @throws DAOException if there is any problem in looking up the DAO with * the interface specified. * @return the DAO retrieved by the interface specified. */ public DAO createDAO(Class inf) throws DAOException { if (inf == null) { throw new DAOException("DAO interface class cannot be null"); } else return createDAO(inf.getName()); } /** * Creates a new DAO. * * @param daoname the DAO name. * @throws DAOException if there is any problem in looking up the DAO with * the name specified. * @return the DAO retrieved by the name specified. * @see #initDAO(DAO) */ public DAO createDAO(String daoname) throws DAOException { try { if (daoname == null) { throw new DAOException("DAO name cannot be null"); } String propKey = "/dao-config/dao[@name='" + daoname + "']/"; String daoImpl = daoprops.getProperty(propKey + "class"); if (daoImpl == null) { throw new DAOException("No implementation specified"); } Instance daoInstance = new Instance(daoImpl, getModule() .getClassLoader()); DAO dao = (DAO) daoInstance.getObject(); Properties params = daoprops .createProperties(propKey + "parameter"); Properties daoParams = dao.getParameters(); if (daoParams != null) { daoParams.putAll(params); } initDAO(dao); dao.daoCreated(); return dao; } catch (Exception e) { throw new DAOException("Error in creating DAO for '" + daoname + "'", e); } } /** * Invoked by the init() method for initializing the implementing factory. * * @throws DAOException if unable to initialize the factory. * @see #init() */ protected abstract void initFactory() throws DAOException; /** * Invoked by the createDAO() method for initializing the given DAO. * * @param dao the DAO. * @throws DAOException if unable to initialize the DAO. * @see #createDAO(Class) * @see #createDAO(String) */ protected abstract void initDAO(DAO dao) throws DAOException; /** * Creates a new transaction. * * @return a new transaction. * @throws DAOException if unable to create a new transaction. */ public Transaction createTransaction() throws DAOException { throw new DAOException("Transaction not supported"); } /** * Gets a parameter from the parameters of this DAOFactory. * * @param key the parameter key. * @return the parameter value associated with the specified key. * @throws DAOException if there is no parameter matching the specified key. */ protected String getParameter(String key) throws DAOException { if (getParameters() == null) { throw new DAOException("No parameters found"); } String param = getParameters().getProperty(key); if (param == null) { throw new DAOException("Parameter '" + key + "' missing"); } else { return param; } } /** * Gets a parameter from the parameters of this DAOFactory. * * @param key the parameter key. * @param def the default value. * @return the parameter value associated with the specified key. The * default value will be returned if there is no parameter matching * the specified key. */ protected String getParameter(String key, String def) { try { return getParameter(key); } catch (DAOException e) { return def; } } /** * Creates a DAO Factory. * * @param name the DAO Factory name. * @param provider the provider of the DAO Factory. * @param params the parameters for creating the DAO Factory. * @param loader the class loader for loading the factory class. * @throws DAOException if there is any error when creating the DAO Factory * using the specified parameters. * @return the DAO Factory created by the parameters specified. */ public static DAOFactory createDAOFactory(String name, String provider, Properties params, ClassLoader loader) throws DAOException { try { if (provider == null) { throw new DAOException("No provider specified"); } Class factory = Class.forName(provider, true, loader); DAOFactory daoFactory = (DAOFactory) factory.newInstance(); daoFactory.setName(name); daoFactory.setParameters(params); daoFactory.init(); return daoFactory; } catch (Exception e) { throw new DAOException( "Error in creating and initializing DAO Factory", e); } } }