/* =========================================================== * TradeManager : An application to trade strategies for the Java(tm) platform * =========================================================== * * (C) Copyright 2011-2011, by Simon Allen and Contributors. * * Project Info: org.trade * * 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Java is a trademark or registered trademark of Oracle, Inc. * in the United States and other countries.] * * (C) Copyright 2011-2011, by Simon Allen and Contributors. * * Original Author: Simon Allen; * Contributor(s): -; * * Changes * ------- * */ package org.trade.core.lookup; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Vector; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import org.trade.core.dao.EntityManagerHelper; import org.trade.core.properties.ConfigProperties; import org.trade.core.util.Reflector; import org.trade.core.valuetype.Decode; /** * Implementation of the LookupServiceProvider interface that uses the * devtool.properties.ConfigProperties object for obtaining Lookup information. * * @author Simon Allen */ public class DBTableLookupServiceProvider implements LookupServiceProvider { /* * This will be a hashtable of hashtables of Lookup objects. The first key * is the lookup name and the second key is the LookupQualifier. */ private static Hashtable<String, Hashtable<String, Lookup>> _lookups = new Hashtable<String, Hashtable<String, Lookup>>(); /** * Default Constructor */ public DBTableLookupServiceProvider() { } public static void clearLookup() { _lookups.clear(); } /** * Method getLookup. * * @param lookupName * String * @param qualifier * LookupQualifier * * @param optional * boolean * @return Lookup * @throws LookupException * @see org.trade.core.lookup.LookupServiceProvider#getLookup(String, * LookupQualifier) */ public synchronized Lookup getLookup(String lookupName, LookupQualifier qualifier, boolean optional) throws LookupException { Lookup lookup = getCachedLookup(lookupName, qualifier); if (null == lookup) { try { Vector<Vector<Object>> rows = new Vector<Vector<Object>>(); Vector<String> colNames = new Vector<String>(); Enumeration<?> en = ConfigProperties.getPropAsEnumeration(lookupName + "_DBTable"); while (en.hasMoreElements()) { colNames.addElement((String) en.nextElement()); } // Have all of the columns - want to get a vector for each // column value Vector<Enumeration<?>> colRows = new Vector<Enumeration<?>>(); int i; int colNamesSize = colNames.size(); for (i = 0; i < colNamesSize; i++) { colRows.addElement(ConfigProperties.getPropAsEnumeration(colNames.elementAt(i))); } // Now construct a Vector Vector - representing the table of // data boolean exit = false; do { Vector<Object> row = new Vector<Object>(); boolean foundOne = false; boolean addIt = true; int colRowsSize = colRows.size(); for (i = 0; i < colRowsSize; i++) { Object value = null; en = colRows.elementAt(i); if (en.hasMoreElements()) { foundOne = true; value = en.nextElement(); row.addElement(value); } else { // Represent an empty value row.addElement(""); } // Check to see if the returned lookup is to be // constrained if (foundOne && (qualifier != null)) { Object qualVal = qualifier.getValue("" + colNames.elementAt(i)); if (null != qualVal) { if (!qualVal.equals(value)) { addIt = false; } } } } if (foundOne) { if (addIt) { rows.addElement(row); } } else { exit = true; } } while (!exit); // There should be only one row per table that // contains the DAO name and method name for the display name String dao = null; String type = null; String methodName = null; int rowsSize = rows.size(); for (i = 0; i < rowsSize; i++) { Vector<Object> row = rows.elementAt(i); int rowSize = row.size(); for (int y = 0; y < rowSize; y++) { if ("DAO_DECODE_TYPE".equals(colNames.elementAt(y))) { type = (String) row.elementAt(y); } else if ("DAO_DECODE_CODE".equals(colNames.elementAt(y))) { dao = (String) row.elementAt(y); } else if ("DAO_DECODE_DISPLAY_NAME".equals(colNames.elementAt(y))) { methodName = (String) row.elementAt(y); } } // Clear the first row and add the objects and display name // from the DB rows.clear(); /* * Add the None selected row. */ if (optional) { Vector<Object> newRowNone = new Vector<Object>(); Class<?> clazz = Class.forName(dao); Object daoObjectNone = clazz.newInstance(); newRowNone.add(type); newRowNone.add(daoObjectNone); newRowNone.add(Decode.NONE); rows.add(newRowNone); } List<?> codes = getCodes(dao); for (Object daoObject : codes) { Method method = Reflector.findMethod(daoObject.getClass(), methodName, null); if (null != method) { Object[] o = new Object[0]; Object displayNameValue = method.invoke(daoObject, o); if (null != displayNameValue) { Vector<Object> newRow = new Vector<Object>(); newRow.add(type); newRow.add(daoObject); newRow.add(displayNameValue); rows.add(newRow); } } } } // If rows where found then I managed to provide the lookup if (rows.size() > 0) { lookup = new PropertiesLookup(colNames, rows); } } catch (Throwable t) { // If this occurs means this provider is unable to provide // the lookup ignore the exception. } if (null != lookup) { addLookupToCache(lookupName, qualifier, lookup); } } return lookup; } /** * Returns null if the lookup is not in the cache. * * @param lookupName * String * @param qualifier * LookupQualifier * @return Lookup */ private Lookup getCachedLookup(String lookupName, LookupQualifier qualifier) { Lookup lookup = null; Hashtable<?, ?> lookupsByQualifier = _lookups.get(lookupName); if (null != lookupsByQualifier) { lookup = (Lookup) lookupsByQualifier.get(qualifier.toString()); } /* * Need to clone the object otherwise changes in position in the object * returned would effect everyone using the object. */ if (null != lookup) { lookup = (Lookup) lookup.clone(); } return (lookup); } /** * Method addLookupToCache. * * @param lookupName * String * @param qualifier * LookupQualifier * @param lookup * Lookup */ private synchronized void addLookupToCache(String lookupName, LookupQualifier qualifier, Lookup lookup) { Hashtable<String, Lookup> lookupsByQualifier = _lookups.get(lookupName); if (null == lookupsByQualifier) { lookupsByQualifier = new Hashtable<String, Lookup>(); _lookups.put(lookupName, lookupsByQualifier); } lookupsByQualifier.put(qualifier.toString(), lookup); } /** * Method getCodes. * * @param className * String * @return List<?> * @throws ClassNotFoundException */ private synchronized List<?> getCodes(String className) throws ClassNotFoundException { try { EntityManager entityManager = EntityManagerHelper.getEntityManager(); entityManager.getTransaction().begin(); Class<?> c = Class.forName(className); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery(); Root<?> from = criteriaQuery.from(c); CriteriaQuery<Object> select = criteriaQuery.select(from); TypedQuery<Object> typedQuery = entityManager.createQuery(select); List<Object> items = typedQuery.getResultList(); entityManager.getTransaction().commit(); if (items.size() > 0) { return items; } } catch (Exception re) { EntityManagerHelper.rollback(); throw re; } finally { EntityManagerHelper.close(); } return new ArrayList<Object>(0); } }