cleanup
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / service / CdmStore.java
index a348874747b36733d95c575d351c9b858c994e70..06e2e2cc896ddbdd07dece5758e2afcfda37fbb4 100644 (file)
@@ -8,20 +8,30 @@
 */
 package eu.etaxonomy.cdm.service;
 
-import org.apache.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.hibernate.Session;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.transaction.TransactionStatus;
-import org.springframework.transaction.support.DefaultTransactionDefinition;
 
+import com.vaadin.spring.annotation.SpringComponent;
+import com.vaadin.spring.annotation.ViewScope;
 import com.vaadin.ui.Notification;
 import com.vaadin.ui.UI;
 
 import eu.etaxonomy.cdm.api.application.CdmRepository;
 import eu.etaxonomy.cdm.api.service.DeleteResult;
 import eu.etaxonomy.cdm.api.service.IService;
+import eu.etaxonomy.cdm.model.agent.AgentBase;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
+import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
+import eu.etaxonomy.cdm.model.name.Registration;
+import eu.etaxonomy.cdm.model.name.TaxonName;
+import eu.etaxonomy.cdm.model.occurrence.Collection;
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
+import eu.etaxonomy.cdm.model.reference.Reference;
 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent.Type;
 import eu.etaxonomy.vaadin.mvp.AbstractView;
@@ -33,143 +43,16 @@ import eu.etaxonomy.vaadin.mvp.AbstractView;
  * TODO better naming of this class, ServiceWrapper, ServiceOperator, ...?
  *
  */
-public class CdmStore<T extends CdmBase, S extends IService<T>> {
+@SpringComponent
+@ViewScope
+public class CdmStore {
 
-    private static final Logger logger = Logger.getLogger(CdmStore.class);
+    private static final Logger logger = LogManager.getLogger();
 
+    @Autowired
+    @Qualifier("cdmRepository")
     private CdmRepository repo;
 
-    private S service;
-
-    TransactionStatus txStatus = null;
-
-//    ConversationHolder conversationHolder = null;
-//
-//    /**
-//     * @return the conversationHolder
-//     */
-//    public ConversationHolder getConversationHolder() {
-//        return conversationHolder;
-//    }
-
-    protected DefaultTransactionDefinition txDefinition = null;
-
-    /**
-     *
-     * @param repo
-     * @param service
-     *            may be <code>null</code>, but delete operations will fail with
-     *            a NullPointerException in this case.
-     */
-    public CdmStore(CdmRepository repo, S service) {
-
-        this.repo = repo;
-        this.service = service;
-
-    }
-
-//    /**
-//     * constructor which takes a ConversationHolder. The supplying class of the conversationHolder needs
-//     * to care for <code>bind()</code>, <code>unbind()</code> and <code>close()</code> since the store is
-//     * only responsible for starting and committing of transactions.
-//     *
-//     * @param repo
-//     * @param service
-//     * @param conversationHolder
-//     */
-//    public CdmStore(CdmRepository repo, S service, ConversationHolder conversationHolder) {
-//
-//        this.repo = repo;
-//        this.service = service;
-//        this.conversationHolder = conversationHolder;
-//
-//    }
-
-    /**
-     * @return
-     *
-     */
-    public TransactionStatus startTransaction() {
-//        if(conversationHolder != null && !conversationHolder.isTransactionActive()){
-//            //conversationHolder.setDefinition(getTransactionDefinition());
-//            return conversationHolder.startTransaction();
-//        } else {
-            checkExistingTransaction();
-            txStatus = repo.startTransaction();
-            return txStatus;
-//        }
-    }
-
-    /**
-     *
-     */
-    protected void checkExistingTransaction() {
-        if (txStatus != null) {
-            // @formatter:off
-            // holding the TransactionStatus as state is not good design. we
-            // should change the save operation
-            // in the EditorView so that the presenter can process the save in
-            // one method call.
-            // Problems:
-            // 1. the fieldGroup needs a open session and read transaction
-            // during the validation, otherwise
-            // LazyInitialisationExceptions occur.
-            // 2. passing the TransactionState to the view also doesn't seem
-            // like a good idea.
-            // @formatter:on
-            throw new RuntimeException("Opening a second transaction in the same" + this.getClass().getSimpleName() + " is not supported");
-        }
-    }
-
-    /**
-     * If the bean is contained in the session it is being updated by doing an
-     * evict and merge. The fieldGroup is updated with the merged bean.
-     *
-     *
-     * @param bean
-     * @return The bean merged to the session or original bean in case a merge
-     *         was not necessary.
-     */
-    public T mergedBean(T bean) {
-
-        Session session = getSession();
-
-        // session.clear();
-        if (session.contains(bean)) {
-            // evict bean before merge to avoid duplicate beans in same session
-            logger.trace(this._toString() + ".mergedBean() - evict " + bean.toString());
-            session.evict(bean);
-        }
-
-        logger.trace(this._toString() + ".mergedBean() - doing merge of" + bean.toString());
-        // to avoid merge problems as described in
-        // https://dev.e-taxonomy.eu/redmine/issues/6687
-        // we are set the hibernate property
-        // hibernate.event.merge.entity_copy_observer=allow
-        @SuppressWarnings("unchecked")
-        T mergedBean = (T) session.merge(bean);
-        logger.trace(this._toString() + ".mergedBean() - bean after merge " + bean.toString());
-        return mergedBean;
-
-    }
-
-    /**
-     * @return
-     */
-    private Session getSession() {
-
-        Session session;
-//        if(conversationHolder != null){
-//            session = conversationHolder.getSession();
-//        } else {
-            session = repo.getSession();
-//        }
-        logger.trace(this._toString() + ".getSession() - session:" + session.hashCode() + ", persistenceContext: "
-                + ((SessionImplementor) session).getPersistenceContext() + " - " + session.toString());
-
-        return session;
-    }
-
     protected String _toString() {
         return this.getClass().getSimpleName() + "@" + this.hashCode();
     }
@@ -181,36 +64,49 @@ public class CdmStore<T extends CdmBase, S extends IService<T>> {
      * @return the merged bean, this bean is <b>not reloaded</b> from the
      *         persistent storage.
      */
-    public EntityChangeEvent saveBean(T bean, AbstractView view) {
+    public <T extends CdmBase> EntityChangeEvent saveBean(T bean, AbstractView view) {
 
         Type changeEventType;
-        if(bean.getId() > 1){
+        if(bean.isPersited()){
             changeEventType = Type.MODIFIED;
         } else {
             changeEventType = Type.CREATED;
         }
 
-        Session session = getSession();
-        logger.trace(this._toString() + ".onEditorSaveEvent - session: " + session.hashCode());
-
-        if(txStatus == null
-//                || (conversationHolder != null && !conversationHolder.isTransactionActive())
-                ){
-            // no running transaction, start one ...
-            startTransaction();
+        try{
+            TransactionStatus txStatus = repo.startTransaction();
+            Session session = repo.getSession();
+            try {
+                logger.trace(this._toString() + ".onEditorSaveEvent - merging bean into session");
+                // merge the changes into the session, ...
+                if (session.contains(bean)) {
+                    // evict bean before merge to avoid duplicate beans in same session
+                    logger.trace(this._toString() + ".mergedBean() - evict " + bean.toString());
+                    session.evict(bean);
+                }
+                logger.trace(this._toString() + ".mergedBean() - doing merge of" + bean.toString());
+                @SuppressWarnings("unchecked")
+                T mergedBean = (T) session.merge(bean);
+                repo.commitTransaction(txStatus);
+                return new EntityChangeEvent(mergedBean, changeEventType, view);
+            } catch(Exception e){
+                transactionRollbackIfNotCompleted(txStatus);
+                throw e;
+            }
+        } finally {
+            repo.clearSession(); // #7559
         }
 
-        logger.trace(this._toString() + ".onEditorSaveEvent - merging bean into session");
-        // merge the changes into the session, ...
-
-        T mergedBean = mergedBean(bean);
+    }
 
-        // NOTE: saveOrUpdate is really needed here even if we to a merge before
-        // repo.getCommonService().saveOrUpdate(mergedBean);
-        session.flush();
-        commitTransction();
 
-        return new EntityChangeEvent(mergedBean, changeEventType, view);
+    /**
+     * @param txStatus
+     */
+    public void transactionRollbackIfNotCompleted(TransactionStatus txStatus) {
+        if(!txStatus.isCompleted()){
+            repo.getTransactionManager().rollback(txStatus);
+        }
     }
 
     /**
@@ -218,22 +114,22 @@ public class CdmStore<T extends CdmBase, S extends IService<T>> {
      * @param bean
      * @return a EntityChangeEvent in case the deletion was successful otherwise <code>null</code>.
      */
-    public final EntityChangeEvent deleteBean(T bean, AbstractView view) {
-
-        logger.trace(this._toString() + ".onEditorPreSaveEvent - starting transaction");
-
-        startTransaction();
-        logger.trace(this._toString() + ".deleteBean - deleting" + bean.toString());
-        DeleteResult result = service.delete(bean);
-        if (result.isOk()) {
-            getSession().flush();
-            commitTransction();
-            logger.trace(this._toString() + ".deleteBean - transaction comitted");
-            return new EntityChangeEvent(bean, Type.REMOVED, view);
-        } else {
-            handleDeleteresultInError(result);
-            txStatus = null;
+    public final <T extends CdmBase> EntityChangeEvent deleteBean(T bean, AbstractView view) {
+
+        IService<T> typeSpecificService = serviceFor(bean);
+
+        try{
+            logger.trace(this._toString() + ".deleteBean - deleting" + bean.toString());
+            DeleteResult result = typeSpecificService.delete(bean);
+            if (result.isOk()) {
+                return new EntityChangeEvent(bean, Type.REMOVED, view);
+            } else {
+                handleDeleteresultInError(result);
+            }
+        } finally {
+            repo.clearSession(); // #7559
         }
+
         return null;
     }
 
@@ -272,28 +168,29 @@ public class CdmStore<T extends CdmBase, S extends IService<T>> {
         notification.show(UI.getCurrent().getPage());
     }
 
-
-    protected void commitTransction() {
-
-//        if(conversationHolder != null){
-//            conversationHolder.commit();
-//        } else {
-            repo.commitTransaction(txStatus);
-            txStatus = null;
-//        }
+    @SuppressWarnings("unchecked")
+    protected <T extends CdmBase> IService<T> serviceFor(T bean){
+         Class<? extends CdmBase> cdmType = bean.getClass();
+
+         if(Registration.class.isAssignableFrom(cdmType)){
+             return (IService<T>) repo.getRegistrationService();
+         } else if(TaxonName.class.isAssignableFrom(cdmType)){
+             return (IService<T>) repo.getNameService();
+         } else if(Reference.class.isAssignableFrom(cdmType)){
+             return (IService<T>) repo.getReferenceService();
+         } else if (NameTypeDesignation.class.isAssignableFrom(cdmType)){
+             throw new RuntimeException("no generic sercvice for NameTypeDesignation, use dedicated methods of NameService");
+         } else if (SpecimenOrObservationBase.class.isAssignableFrom(cdmType)){
+             return (IService<T>) repo.getOccurrenceService();
+         } else if (AgentBase.class.isAssignableFrom(cdmType)){
+             return (IService<T>) repo.getAgentService();
+         } else if (Collection.class.isAssignableFrom(cdmType)){
+             return (IService<T>) repo.getCollectionService();
+         } else if (Collection.class.isAssignableFrom(cdmType)){
+             return (IService<T>) repo.getCollectionService();
+         } else {
+             throw new RuntimeException("Implementation to find service for " + cdmType + " still missing.");
+         }
     }
 
-    /**
-     * @param entityId
-     */
-    public T loadBean(int entityId) {
-//        conversationHolder.startTransaction();
-        return service.find(entityId);
-    }
-
-    public S getService() {
-        return service;
-    }
-
-
 }