Java tutorial
/* ************************************************************************* * The contents of this file are subject to the Openbravo Public License * Version 1.1 (the "License"), being the Mozilla Public License * Version 1.1 with a permitted attribution clause; you may not use this * file except in compliance with the License. You may obtain a copy of * the License at http://www.openbravo.com/legal/license.html * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU * All portions are Copyright (C) 2008-2011 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************ */ package org.openbravo.service.dataset; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.hibernate.criterion.Restrictions; import org.openbravo.base.exception.OBException; import org.openbravo.base.model.Entity; import org.openbravo.base.model.ModelProvider; import org.openbravo.base.model.Property; import org.openbravo.base.provider.OBProvider; import org.openbravo.base.provider.OBSingleton; import org.openbravo.base.structure.BaseOBObject; import org.openbravo.base.util.Check; import org.openbravo.dal.core.OBContext; import org.openbravo.dal.service.OBCriteria; import org.openbravo.dal.service.OBDal; import org.openbravo.dal.service.OBQuery; import org.openbravo.model.ad.module.Module; import org.openbravo.model.ad.utility.DataSet; import org.openbravo.model.ad.utility.DataSetColumn; import org.openbravo.model.ad.utility.DataSetTable; import org.openbravo.model.common.enterprise.Organization; /** * Offers services around datasets. The main function is to retrieve DataSets and to determine which * Properties of an Entity can be exported and which objects can be exported. * * @author Martin Taal */ public class DataSetService implements OBSingleton { private static final Logger log = Logger.getLogger(DataSetService.class); private static DataSetService instance; public static synchronized DataSetService getInstance() { if (instance == null) { instance = OBProvider.getInstance().get(DataSetService.class); } return instance; } public static synchronized void setInstance(DataSetService instance) { DataSetService.instance = instance; } /** * Returns true if the {@link DataSet} has data. Note that the client/organization of the current * user are used for querying * * @param dataSet * the data set to check for content * @return true if there are objects in the data set, false other wise * @see DataSet#getDataSetTableList() * @see DataSetTable */ public boolean hasData(DataSet dataSet) { long totalCnt = 0; for (DataSetTable dataSetTable : dataSet.getDataSetTableList()) { final Entity entity = ModelProvider.getInstance() .getEntityByTableName(dataSetTable.getTable().getDBTableName()); final OBCriteria<BaseOBObject> obc = OBDal.getInstance().createCriteria(entity.getName()); totalCnt += obc.count(); if (totalCnt > 0) { return true; } } return totalCnt > 0; } /** * Checks if objects of a {@link DataSetTable} of the {@link DataSet} have changed since a * specific date. Note that this method does not use whereclauses or other filters defined in the * dataSetTable. It checks all instances of the table of the DataSetTable. * * @param dataSet * the DataSetTables of this dataSet are checked. * @param afterDate * the time limit * @return true if there is at least one object which has changed since afterDate, false * afterwards */ public <T extends BaseOBObject> boolean hasChanged(DataSet dataSet, Date afterDate) { for (DataSetTable dataSetTable : dataSet.getDataSetTableList()) { final Entity entity = ModelProvider.getInstance() .getEntityByTableName(dataSetTable.getTable().getDBTableName()); final OBCriteria<T> obc = OBDal.getInstance().createCriteria(entity.getName()); obc.add(Restrictions.gt(Organization.PROPERTY_UPDATED, afterDate)); // todo: count is slower than exists, is exists possible? List<?> list = obc.list(); if (obc.count() < 20 && obc.count() > 0) { log.warn("The following rows were changed after your last update.database or export.database:"); for (Object obj : list) { log.warn(" -" + obj); } } else if (obc.count() > 20) { log.warn("Rows inside the table " + ((BaseOBObject) list.get(0)).getEntity().getTableName() + " were changed after your last update.database or export.database:"); } if (obc.count() > 0) { return true; } } return false; } /** * Retrieves a dataset using the value and module of the dataset * * @param value * the value used to find the dataset in the database * @param moduleId * the id of the module used to find the dataset in the database * @return the found DataSet */ public DataSet getDataSetByValueModule(String value, String moduleId) { final Module module = OBDal.getInstance().get(Module.class, moduleId); final OBCriteria<DataSet> obc = OBDal.getInstance().createCriteria(DataSet.class); obc.add(Restrictions.eq(DataSet.PROPERTY_MODULE, module)); obc.add(Restrictions.eq(DataSet.PROPERTY_SEARCHKEY, value)); final List<?> list = obc.list(); Check.isTrue(list.size() <= 1, "There is more than one dataset available when searching using the name/id " + value + "/" + moduleId); if (list.size() == 0) { return null; } return (DataSet) list.get(0); } /** * Finds datasets belonging to the Module with a specific moduleId. * * @param moduleId * the moduleId of the module to use for searching datasets * @return the list of found datasets */ public List<DataSet> getDataSetsByModuleID(String moduleId) { final Module module = OBDal.getInstance().get(Module.class, moduleId); final OBCriteria<DataSet> obc = OBDal.getInstance().createCriteria(DataSet.class); obc.add(Restrictions.eq(DataSet.PROPERTY_MODULE, module)); return obc.list(); } /** * Finds a dataset solely on the basis of its value * * @param value * the value to search for * @return the found DataSet */ public DataSet getDataSetByValue(String value) { final OBCriteria<DataSet> obc = OBDal.getInstance().createCriteria(DataSet.class); obc.add(Restrictions.eq(DataSet.PROPERTY_SEARCHKEY, value)); final List<DataSet> ds = obc.list(); // Check.isTrue(ds.size() > 0, "There is no DataSet with name " + value); if (ds.size() == 0) { // TODO: throw an exception? return null; } Check.isTrue(ds.size() == 1, "There is more than one DataSet with the name " + value + ". The number of found DataSets is " + ds.size()); return ds.get(0); } /** * Returns a list of DataSet tables instances on the basis of the DataSet * * @param dataSet * the DataSet for which the list of tables is required * @return the DataSetTables of the DataSet * @deprecated use dataSet.getDataSetTableList() */ @Deprecated public List<DataSetTable> getDataSetTables(DataSet dataSet) { return dataSet.getDataSetTableList(); } /** * Return the list of DataSet columns for a table * * @param dataSetTable * the dataSetTable for which the columns need to be found * @return the list of DataSetColumns of the dataSetTable * @deprecated use dataSetTable.getDataSetColumnList() */ @Deprecated public List<DataSetColumn> getDataSetColumns(DataSetTable dataSetTable) { return dataSetTable.getDataSetColumnList(); } /** * Determines which objects are exportable using the DataSetTable whereClause. * * @param dataSetTable * the dataSetTable defines the Entity and the whereClause to use * @param moduleId * the moduleId is a parameter in the whereClause * @return the list of exportable business objects */ public List<BaseOBObject> getExportableObjects(DataSetTable dataSetTable, String moduleId) { return getExportableObjects(dataSetTable, moduleId, new HashMap<String, Object>()); } /** * Determines which objects are exportable using the DataSetTable whereClause. * * @param dataSetTable * the dataSetTable defines the Entity and the whereClause to use * @param moduleId * the moduleId is a parameter in the whereClause * @param parameters * a collection of named parameters which are used in the whereClause of the dataSetTable * @return the list of exportable business objects */ @SuppressWarnings("unchecked") public List<BaseOBObject> getExportableObjects(DataSetTable dataSetTable, String moduleId, Map<String, Object> parameters) { // do the part which can be done as super user separately from the // actual read of the db OBContext.setAdminMode(); try { final String entityName = dataSetTable.getTable().getName(); final Entity entity = ModelProvider.getInstance().getEntity(entityName); if (entity == null) { log.error("Entity not found using table name " + entityName); return new ArrayList<BaseOBObject>(); } String whereClause = dataSetTable.getSQLWhereClause(); final Map<String, Object> existingParams = new HashMap<String, Object>(); if (whereClause != null) { if (parameters != null) { for (final String name : parameters.keySet()) { if (whereClause.indexOf(":" + name) != -1) { final Object value = parameters.get(name); existingParams.put(name, "null".equals(value) ? null : value); } } } } if (moduleId != null && whereClause != null) { while (whereClause.indexOf("@moduleid@") != -1) { whereClause = whereClause.replace("@moduleid@", "'" + moduleId + "'"); } if (whereClause.indexOf(":moduleid") != -1 && parameters.get("moduleid") == null) { existingParams.put("moduleid", moduleId); } } final OBQuery<BaseOBObject> oq = OBDal.getInstance().createQuery(entity.getName(), whereClause); oq.setFilterOnActive(false); oq.setNamedParameters(existingParams); if (OBContext.getOBContext().getRole().getId().equals("0") && OBContext.getOBContext().getCurrentClient().getId().equals("0")) { oq.setFilterOnReadableOrganization(false); oq.setFilterOnReadableClients(false); } final List<?> list = oq.list(); Collections.sort(list, new BaseOBIDHexComparator()); return (List<BaseOBObject>) list; } finally { OBContext.restorePreviousMode(); } } /** * Determines which objects are exportable using the DataSetTable whereClause. Returns an iterator * over these objects. The returned objects are sorted by id. * * @param dataSetTable * the dataSetTable defines the Entity and the whereClause to use * @param moduleId * the moduleId is a parameter in the whereClause * @param parameters * a collection of named parameters which are used in the whereClause of the dataSetTable * @return iterator over the exportable objects */ public Iterator<BaseOBObject> getExportableObjectsIterator(DataSetTable dataSetTable, String moduleId, Map<String, Object> parameters) { final String entityName = dataSetTable.getTable().getName(); final Entity entity = ModelProvider.getInstance().getEntity(entityName); if (entity == null) { log.error("Entity not found using table name " + entityName); return new ArrayList<BaseOBObject>().iterator(); } String whereClause = dataSetTable.getSQLWhereClause(); final Map<String, Object> existingParams = new HashMap<String, Object>(); for (final String name : parameters.keySet()) { if (whereClause.indexOf(":" + name) != -1) { final Object value = parameters.get(name); existingParams.put(name, "null".equals(value) ? null : value); } } if (moduleId != null && whereClause != null) { while (whereClause.indexOf("@moduleid@") != -1) { whereClause = whereClause.replace("@moduleid@", "'" + moduleId + "'"); } if (whereClause.indexOf(":moduleid") != -1 && parameters.get("moduleid") == null) { existingParams.put("moduleid", moduleId); } } // set the order by, first detect if there is an alias String alias = ""; // this is a space on purpose if (whereClause != null && whereClause.toLowerCase().trim().startsWith("as")) { // strip the as final String strippedWhereClause = whereClause.toLowerCase().trim().substring(2).trim(); // get the next space final int index = strippedWhereClause.indexOf(" "); alias = strippedWhereClause.substring(0, index); alias += "."; } final OBQuery<BaseOBObject> oq = OBDal.getInstance().createQuery(entity.getName(), (whereClause != null ? whereClause : "") + " order by " + alias + "id"); oq.setFilterOnActive(false); oq.setNamedParameters(existingParams); if (OBContext.getOBContext().getRole().getId().equals("0") && OBContext.getOBContext().getCurrentClient().getId().equals("0")) { oq.setFilterOnReadableOrganization(false); oq.setFilterOnReadableClients(false); } try { return oq.iterate(); } catch (final Exception e) { throw new OBException(e); } } /** * This method will return the properties as defined by the DataSetcolumns definition. It will * return transient properties but not the audit-info properties if so excluded by the DataSet * definition. * * @param bob * the business object to export * @param dataSetTable * the dataSetTable to export * @param dataSetColumns * the list of potential columns to export * @return the list of properties which are exportable */ public List<Property> getEntityProperties(BaseOBObject bob, DataSetTable dataSetTable, List<DataSetColumn> dataSetColumns) { return getExportableProperties(bob, dataSetTable, dataSetColumns, true); } /** * This method will return the properties as defined by the DataSetcolumns definition. It will * <b>not</b> return transient properties and neither the audit-info properties if so excluded by * the DataSet definition. * * @param bob * the business object to export * @param dataSetTable * the dataSetTable to export * @param dataSetColumns * the list of potential columns to export * @return the list of properties which are exportable */ public List<Property> getExportableProperties(BaseOBObject bob, DataSetTable dataSetTable, List<DataSetColumn> dataSetColumns) { return getExportableProperties(bob, dataSetTable, dataSetColumns, false); } /** * This method will return the properties which are exportable as defined by the DataSetcolumns * definition. It will include transient properties depending on the parameter. Audit-info * properties are never exported * * @param bob * the business object to export * @param dataSetTable * the dataSetTable to export * @param dataSetColumns * the list of potential columns to export * @param exportTransients * if true then transient properties are also exportable * @return the list of properties which are exportable */ public List<Property> getExportableProperties(BaseOBObject bob, DataSetTable dataSetTable, List<DataSetColumn> dataSetColumns, boolean exportTransients) { final Entity entity = bob.getEntity(); final List<Property> exportables; // check if all are included, except the excluded if (dataSetTable.isIncludeAllColumns()) { exportables = new ArrayList<Property>(entity.getProperties()); // now remove the excluded for (final DataSetColumn dsc : dataSetColumns) { if (dsc.isExcluded()) { exportables.remove(entity.getPropertyByColumnName(dsc.getColumn().getDBColumnName())); } } } else { // not all included, go through the DataSetcolumns // and add the not excluded exportables = new ArrayList<Property>(); for (final DataSetColumn dsc : dataSetColumns) { if (!dsc.isExcluded()) { exportables.add(entity.getPropertyByColumnName(dsc.getColumn().getDBColumnName())); } } } // remove the transients if (!exportTransients) { final List<Property> toRemove = new ArrayList<Property>(); for (final Property p : exportables) { if (p.isTransient(bob)) { toRemove.add(p); } } exportables.removeAll(toRemove); } // Remove the auditinfo if (dataSetTable.isExcludeAuditInfo()) { removeAuditInfo(exportables); } return exportables; } public void removeAuditInfo(List<Property> properties) { final List<Property> toRemove = new ArrayList<Property>(); for (final Property p : properties) { if (p.isAuditInfo()) { toRemove.add(p); } } properties.removeAll(toRemove); } // compares the content of a list by converting the id to a hex public static class BaseOBIDHexComparator implements Comparator<Object> { public int compare(Object o1, Object o2) { if (!(o1 instanceof BaseOBObject) || !(o2 instanceof BaseOBObject)) { return 0; } final BaseOBObject bob1 = (BaseOBObject) o1; final BaseOBObject bob2 = (BaseOBObject) o2; if (!(bob1.getId() instanceof String) || !(bob2.getId() instanceof String)) { return 0; } try { final BigInteger bd1 = new BigInteger(bob1.getId().toString(), 32); final BigInteger bd2 = new BigInteger(bob2.getId().toString(), 32); return bd1.compareTo(bd2); } catch (final NumberFormatException n) { // ignoring exception on purpose, some id's can't be compared numerically return 0; } } } public static class BaseStringComparator implements Comparator<Object> { public int compare(Object o1, Object o2) { if (!(o1 instanceof BaseOBObject) || !(o2 instanceof BaseOBObject)) { return 0; } final BaseOBObject bob1 = (BaseOBObject) o1; final BaseOBObject bob2 = (BaseOBObject) o2; final String bd1 = bob1.getId().toString(); final String bd2 = bob2.getId().toString(); return bd1.compareTo(bd2); } } }