Persistence/OrderSystemExample/AbstractPersistenceTeam

Team AbstractPersistenceTeam of the OT/JPA example "Order-System".

Note, that lazy loading is currently disabled here.

package org.objectteams.samples.ordersystem.persistence;

import java.util.Collection;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.RollbackException;
import javax.persistence.spi.PersistenceUnitInfo;

import org.objectteams.Team;
import org.objectteams.eclipselink.adaptation.ObjectTeamsSemanticsAdapter;
import org.objectteams.eclipselink.adaptation.ObjectTeamsStructureAdapter;
import org.objectteams.jpa.lazyloading.lifting.PersistenceUnitInfoSource;
import org.objectteams.jpa.lazyloading.lifting.RoleCreationInterceptor;
import org.objectteams.jpa.lazyloading.lifting.RoleCreationInterceptorFactory;
import org.objectteams.jpa.lazyloading.lifting.RoleCreationInterceptorHolder;
import org.objectteams.jpa.lazyloading.lifting.RoleQueryingRoleCreationInterceptor;

import base org.eclipse.persistence.internal.jpa.deployment.JPAInitializer;

/**
 * <p>
 * This generic team provides some methods for performing database operations
 * in a transaction.
 * </p><p> 
 * Its roles are responsible for initializing and closing the persistence framework
 * at corresponding points in the application.
 * </p>
 * 
 * @author stephan
 */
public abstract team class AbstractPersistenceTeam 
{
        private EntityManagerFactory _emf;
        private EntityManager _em;
        private EntityTransaction currentTxn = null;
        
        /** Use this field for invoking {@link LifeCycle#closePersistenceContext()}. */
        protected LifeCycle lifeCycle;

        public AbstractPersistenceTeam() {
            this.lifeCycle = new LifeCycle();
            within (this)
                this.lifeCycle.startAdaptation();
        }

        /** Specifies the simple name of the persistence unit to use. */
        abstract protected String getPersistenceUnitName();

        /** Perform the given operation in a transaction, re-using an existing transaction, if any. */
        protected void inTransactionDo(Runnable r) {
                boolean owningTxn = false;
                try {
                if (this.currentTxn == null) {
                        this.currentTxn = this._em.getTransaction();
                        this.currentTxn.begin();
                        owningTxn = true;
                }
                try {
                        r.run();
                } catch (PersistenceException pe) {
                        pe.printStackTrace();
                        throw pe;
                }
                this._em.flush();
                } finally {
                        if (owningTxn) {
                                if (this.currentTxn.isActive())
                                        try {
                                                this.currentTxn.commit();
                                        } catch (RollbackException re) {
                                                System.err.println(re.getCause());
                                                throw re;
                                        }
                                this.currentTxn = null;
                        }
                }
        }

        /** Persist (initial) or merge (update) the given object within a transaction. */
        protected void persistInTransaction(final Object entity) {
                inTransactionDo(new Runnable() { public void run() {
                        if (!_em.contains(entity))
                                _em.persist(entity);
                        else
                                _em.merge(entity);
                }});
        }

        /** Remove the given entity within a transaction. */
        protected void removeInTransaction(final Object entity) {
                inTransactionDo(new Runnable() { public void run() {
                        _em.remove(entity);
                }});
        }

        /** Find all entities from the given table (assumed to have type <code>&lt;E&gt;</code>). */
        @SuppressWarnings("unchecked")
        public <E> Collection<E> findAllEntities(String tableName) {
                Query query = this._em.createQuery("SELECT e FROM "+tableName+" e");
                return (Collection<E>) query.getResultList();
        }
        
        /** Log a msg to console. */
        public void simpleLog(String msg) {
                System.out.println(msg);
        }

        /** 
         * Unbound role to handle start and stop of an OT-adapted JPA context.
         * Method {@link #startAdaptation} is called explicitly, 
         * whereas {@link #closePersistenceContext()} is intended to be triggered from a callin hooking into the application.
         */
        protected class LifeCycle
        {
            private ObjectTeamsStructureAdapter _structureAdapter;
            private Team _semanticsAdapter;
            // used to communicate the persistence unit from preDeploy to the RoleQueryingRoleCreationInterceptor (lazy loading):
            protected PersistenceUnitInfo _puInfo;

            protected void startAdaptation() {
                simpleLog("starting JPA");
                        
                // activate objectteams-jpa teams:
                _structureAdapter = new ObjectTeamsStructureAdapter();
                _semanticsAdapter = new ObjectTeamsSemanticsAdapter();
                _structureAdapter.activate(Team.ALL_THREADS);
                _semanticsAdapter.activate(Team.ALL_THREADS);
                
                // connect to the entity manager:
                simpleLog("creating entity manager factory");
                AbstractPersistenceTeam.this._emf = Persistence.createEntityManagerFactory(getPersistenceUnitName());
                simpleLog("creating entity manager");
                AbstractPersistenceTeam.this._em = AbstractPersistenceTeam.this._emf.createEntityManager();

                //simpleLog("initializing lazy loading");
                //configureLazyLoading();
                        
                simpleLog("starting JPA: done.");
            }
                
            private void configureLazyLoading() {
                RoleCreationInterceptorHolder holder = new RoleCreationInterceptorHolder();
                final RoleQueryingRoleCreationInterceptor roleQueryingIterceptor = new RoleQueryingRoleCreationInterceptor();
                roleQueryingIterceptor.setEntityManager(AbstractPersistenceTeam.this._em);
                roleQueryingIterceptor.setPersistenceUnitInfoSource(new PersistenceUnitInfoSource() {
                    public PersistenceUnitInfo getPersistenceUnitInfo() {
                        return LifeCycle.this._puInfo;
                    }
                });
                holder.setRoleCreationInterceptorFactory(new RoleCreationInterceptorFactory() {
                    public RoleCreationInterceptor create() {
                        return roleQueryingIterceptor;
                    }
                });
            }

            protected void closePersistenceContext() {
                AbstractPersistenceTeam.this._em.close();
                AbstractPersistenceTeam.this._emf.close();
                
                _structureAdapter.deactivate();
                        _semanticsAdapter.deactivate();
            }

        }
        protected class InitHook playedBy JPAInitializer {

                fetchPersistentUnit <- after callPredeploy;

                void fetchPersistentUnit(PersistenceUnitInfo persistenceUnitInfo) {
                        if (getPersistenceUnitName().equals(persistenceUnitInfo.getPersistenceUnitName()))
                                AbstractPersistenceTeam.this.lifeCycle._puInfo = persistenceUnitInfo;
                }
        }
}