// $Id$\r
/**\r
* Copyright (C) 2007 EDIT\r
-* European Distributed Institute of Taxonomy \r
+* European Distributed Institute of Taxonomy\r
* http://www.e-taxonomy.eu\r
-* \r
+*\r
* The contents of this file are subject to the Mozilla Public License Version 1.1\r
* See LICENSE.TXT at the top of this package for the full license terms.\r
*/\r
\r
import java.util.ArrayList;\r
import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
import java.util.List;\r
import java.util.Map;\r
import java.util.Set;\r
import java.util.UUID;\r
\r
import org.apache.log4j.Logger;\r
+import org.hibernate.LockMode;\r
import org.hibernate.Session;\r
import org.springframework.context.ApplicationContext;\r
import org.springframework.context.ApplicationContextAware;\r
-import org.springframework.transaction.TransactionStatus;\r
import org.springframework.transaction.annotation.Transactional;\r
\r
+import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;\r
import eu.etaxonomy.cdm.api.service.pager.Pager;\r
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
import eu.etaxonomy.cdm.model.common.CdmBase;\r
import eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao;\r
+import eu.etaxonomy.cdm.persistence.query.Grouping;\r
import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
\r
-@Transactional(readOnly=true)\r
public abstract class ServiceBase<T extends CdmBase, DAO extends ICdmEntityDao<T>> implements IService<T>, ApplicationContextAware {\r
- private static final Logger logger = Logger.getLogger(ServiceBase.class);\r
- \r
- //flush after saving this number of objects\r
- int flushAfterNo = 2000;\r
- protected ApplicationContext appContext;\r
-\r
- protected DAO dao;\r
-\r
- protected abstract void setDao(DAO dao);\r
- \r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.Iyyy#setApplicationContext(org.springframework.context.ApplicationContext)\r
- */\r
- public void setApplicationContext(ApplicationContext appContext){\r
- this.appContext = appContext;\r
- }\r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * find\r
- * @param uuid\r
- * @return\r
- */\r
- public T getCdmObjectByUuid(UUID uuid) {\r
- return dao.findByUuid(uuid);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * the generic method arguments are a bit meaningless as \r
- * we're not typing the results. this should be changed to\r
- * public int count(Class<? extends T> clazz)\r
- * where clazz can be null, to count all instances of type T\r
- */\r
- public <TYPE extends T> int count(Class<TYPE> clazz) {\r
- return dao.count(clazz);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * merge with the above\r
- */\r
- public int count() {\r
- return dao.count();\r
- }\r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * saveOrUpdate\r
- * @param cdmObj\r
- * @return\r
- */\r
- @Transactional(readOnly = false)\r
- protected UUID saveCdmObject(T cdmObj){\r
- if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}\r
- return dao.saveOrUpdate(cdmObj);\r
- }\r
- \r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * @param cdmObj\r
- * @return\r
- */\r
- @Transactional(readOnly = false)\r
- protected UUID saveCdmObject(T cdmObj, TransactionStatus txStatus){\r
- // TODO: Implement with considering txStatus\r
- if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}\r
- return dao.saveOrUpdate(cdmObj);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * save(Set<T> ts)\r
- * @param <S>\r
- * @param cdmObjCollection\r
- * @return\r
- */\r
- @Transactional(readOnly = false)\r
- protected <S extends T> Map<UUID, S> saveCdmObjectAll(Collection<? extends S> cdmObjCollection){\r
- int types = cdmObjCollection.getClass().getTypeParameters().length;\r
- if (types > 0){\r
- if (logger.isDebugEnabled()){logger.debug("ClassType: + " + cdmObjCollection.getClass().getTypeParameters()[0]);}\r
- }\r
- \r
- Map<UUID, S> resultMap = new HashMap<UUID, S>();\r
- Iterator<? extends S> iterator = cdmObjCollection.iterator();\r
- int i = 0;\r
- while(iterator.hasNext()){\r
- if ( ( (i % 5000) == 0) && (i > 0) ){logger.debug("Saved " + i + " objects" );}\r
- S cdmObj = iterator.next();\r
- UUID uuid = saveCdmObject(cdmObj);\r
-// if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}\r
- resultMap.put(uuid, cdmObj);\r
- i++;\r
- if ( (i % flushAfterNo) == 0){\r
- try{\r
- logger.debug("no flush");\r
- //TODO fixme!!!\r
- dao.flush();\r
- }catch(Exception e){\r
- logger.error("UUUIIIII");\r
- \r
- }\r
- }\r
- }\r
-\r
- if ( logger.isInfoEnabled() ){logger.info("Saved " + i + " objects" );}\r
- logger.error("End of SaveCDMObject...Saved " + i + " objects" );\r
- return resultMap;\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public UUID delete(T persistentObject) {\r
- return dao.delete(persistentObject);\r
- }\r
-\r
- public boolean exists(UUID uuid) {\r
- return dao.exists(uuid);\r
- }\r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * rename find\r
- */\r
- public T findByUuid(UUID uuid) {\r
- return dao.findByUuid(uuid);\r
- }\r
- \r
- public List<T> findByUuid(Set<UUID> uuidSet) {\r
- return dao.findByUuid(uuidSet);\r
- }\r
- \r
- public T load(UUID uuid) {\r
- return dao.load(uuid);\r
- }\r
- \r
- public T load(UUID uuid, List<String> propertyPaths){\r
- return dao.load(uuid, propertyPaths);\r
- }\r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * should be single method\r
- * List<T> list(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths)\r
- */\r
- public <TYPE extends T> List<TYPE> list(Class<TYPE> type, int limit,int start) {\r
- return dao.list(type, limit, start);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * remove\r
- */\r
- public Pager<T> list(Integer pageSize, Integer pageNumber){\r
- return list(pageSize, pageNumber, null);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * should be single method\r
- * Pager<T> page(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths)\r
- */\r
- public Pager<T> list(Integer pageSize, Integer pageNumber, List<OrderHint> orderHints){\r
- return list(pageSize,pageNumber,orderHints,null);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * should be single method\r
- * Pager<T> page(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths)\r
- */\r
- public Pager<T> list(Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
- Integer numberOfResults = dao.count();\r
- List<T> results = new ArrayList<T>();\r
- pageNumber = pageNumber == null ? 0 : pageNumber;\r
- if(numberOfResults > 0) { // no point checking again\r
- Integer start = pageSize == null ? 0 : pageSize * (pageNumber - 1);\r
- results = dao.list(pageSize, start, orderHints,propertyPaths);\r
- }\r
- return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * should be single method\r
- * Pager<T> page(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths)\r
- */\r
- public <TYPE extends T> Pager<TYPE> list(Class<TYPE> type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
- Integer numberOfResults = dao.count(type);\r
- List<TYPE> results = new ArrayList<TYPE>();\r
- pageNumber = pageNumber == null ? 0 : pageNumber;\r
- if(numberOfResults > 0) { // no point checking again\r
- Integer start = pageSize == null ? 0 : pageSize * (pageNumber - 1);\r
- results = dao.list(type,pageSize, start, orderHints,propertyPaths);\r
- }\r
- return new DefaultPagerImpl<TYPE>(pageNumber, numberOfResults, pageSize, results);\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public UUID save(T newInstance) {\r
- return dao.save(newInstance);\r
- }\r
- \r
- @Transactional(readOnly = false)\r
- public UUID merge(T newInstance) {\r
- return dao.merge(newInstance);\r
- }\r
- \r
-// @Transactional(readOnly = false)\r
- public void clear() {\r
- dao.clear();\r
- }\r
- \r
- public Session getSession() {\r
- return dao.getSession();\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * rename -> save\r
- */\r
- @Transactional(readOnly = false)\r
- public Map<UUID, T> saveAll(Collection<T> newInstances) {\r
- return dao.saveAll(newInstances);\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public UUID saveOrUpdate(T transientObject) {\r
- return dao.saveOrUpdate(transientObject);\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public UUID update(T transientObject) {\r
- return dao.update(transientObject);\r
- }\r
-\r
- public UUID refresh(T persistentObject) {\r
- return dao.refresh(persistentObject);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * delete\r
- * @param cdmObj\r
- * @return\r
- */\r
- @Transactional(readOnly = false)\r
- protected UUID removeCdmObject(T cdmObj){\r
- if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}\r
- return dao.delete(cdmObj);\r
- }\r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * should be single method\r
- * List<T> list(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths)\r
- */\r
- public List<T> list(int limit, int start) {\r
- return dao.list(limit, start);\r
- }\r
-\r
- /**\r
- * FIXME Candidate for harmonization\r
- * is this method used, and if so, should it be exposed in the service layer?\r
- * it seems a bit incongruous that we use an ORM to hide the fact that there is a \r
- * database, then expose a method that talks about "rows" . . .\r
- */\r
- public List<T> rows(String tableName, int limit, int start) {\r
- return dao.rows(tableName, limit, start);\r
- }\r
+ @SuppressWarnings("unused")\r
+ private static final Logger logger = Logger.getLogger(ServiceBase.class);\r
+\r
+ //flush after saving this number of objects\r
+ int flushAfterNo = 2000;\r
+ protected ApplicationContext appContext;\r
+\r
+ protected DAO dao;\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public void lock(T t, LockMode lockMode) {\r
+ dao.lock(t, lockMode);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public void refresh(T t, LockMode lockMode, List<String> propertyPaths) {\r
+ dao.refresh(t, lockMode, propertyPaths);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = false)\r
+ public void clear() {\r
+ dao.clear();\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public int count(Class<? extends T> clazz) {\r
+ return dao.count(clazz);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = false)\r
+ public String delete(T persistentObject) {\r
+ return dao.delete(persistentObject).toString();\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public boolean exists(UUID uuid) {\r
+ return dao.exists(uuid);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public List<T> find(Set<UUID> uuidSet) {\r
+ return dao.list(uuidSet, null, null, null, null);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public List<T> findById(Set<Integer> idSet) { //can't be called find(Set<Integer>) as this conflicts with find(Set<UUID)\r
+ return dao.listByIds(idSet, null, null, null, null);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public T find(UUID uuid) {\r
+ return dao.findByUuid(uuid);\r
+ }\r
+ \r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public T findWithoutFlush(UUID uuid) {\r
+ return dao.findByUuidWithoutFlush(uuid);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public T find(int id) {\r
+ return dao.findById(id);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public Session getSession() {\r
+ return dao.getSession();\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths) {\r
+ return dao.group(clazz, limit, start, groups, propertyPaths);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths){\r
+ return dao.list(type,limit, start, orderHints,propertyPaths);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public T load(UUID uuid) {\r
+ return dao.load(uuid);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public T load(UUID uuid, List<String> propertyPaths){\r
+ return dao.load(uuid, propertyPaths);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = false)\r
+ public T merge(T newInstance) {\r
+ return dao.merge(newInstance);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public <S extends T> Pager<S> page(Class<S> type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
+ Integer numberOfResults = dao.count(type);\r
+ List<S> results = new ArrayList<S>();\r
+ pageNumber = pageNumber == null ? 0 : pageNumber;\r
+ if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)\r
+ Integer start = pageSize == null ? 0 : pageSize * pageNumber;\r
+ results = dao.list(type, pageSize, start, orderHints,propertyPaths);\r
+ }\r
+ return new DefaultPagerImpl<S>(pageNumber, numberOfResults, pageSize, results);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public UUID refresh(T persistentObject) {\r
+ return dao.refresh(persistentObject);\r
+ }\r
+\r
+ /**\r
+ * FIXME Candidate for harmonization\r
+ * is this method used, and if so, should it be exposed in the service layer?\r
+ * it seems a bit incongruous that we use an ORM to hide the fact that there is a\r
+ * database, then expose a method that talks about "rows" . . .\r
+ */\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public List<T> rows(String tableName, int limit, int start) {\r
+ return dao.rows(tableName, limit, start);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = false)\r
+ public Map<UUID, T> save(Collection<T> newInstances) {\r
+ return dao.saveAll(newInstances);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = false)\r
+ public UUID save(T newInstance) {\r
+ return dao.save(newInstance);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = false)\r
+ public UUID saveOrUpdate(T transientObject) {\r
+ return dao.saveOrUpdate(transientObject);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = false)\r
+ public Map<UUID, T> saveOrUpdate(Collection<T> transientInstances) {\r
+ return dao.saveOrUpdateAll(transientInstances);\r
+ }\r
+\r
+ @Override\r
+ public void setApplicationContext(ApplicationContext appContext){\r
+ this.appContext = appContext;\r
+ }\r
+\r
+\r
+ protected abstract void setDao(DAO dao);\r
+\r
+ @Override\r
+ @Transactional(readOnly = false)\r
+ public UUID update(T transientObject) {\r
+ return dao.update(transientObject);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public List<T> list(T example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+ return dao.list(example, includeProperties, limit, start, orderHints, propertyPaths);\r
+ }\r
+ \r
+ \r
+\r
}\r