]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
dbdf2483a961d65002041f8fc9b6b34396e7be5f
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.common.storage.jpa;
2
3 import javax.persistence.EntityManager;
4 import javax.persistence.EntityManagerFactory;
5 import javax.persistence.Query;
6 import javax.persistence.RollbackException;
7
8 import org.collectionspace.services.common.context.ServiceContext;
9 import org.collectionspace.services.common.document.InconsistentStateException;
10 import org.collectionspace.services.common.document.TransactionException;
11 import org.collectionspace.services.common.storage.TransactionContext;
12
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 @SuppressWarnings("rawtypes")
17 public class JPATransactionContext extends TransactionContext {
18     /** The logger. */
19     private final Logger logger = LoggerFactory.getLogger(TransactionContext.class);
20
21         private int transactionRefCount = 0;
22         private boolean aclTablesUpdatedFlag = false;
23         
24         EntityManagerFactory emf;
25         EntityManager em;
26         
27         public JPATransactionContext(ServiceContext ctx) {
28         emf = JpaStorageUtils.getEntityManagerFactory();            
29         em = emf.createEntityManager();
30         this.ctx = ctx;
31         }
32         
33         public JPATransactionContext() {
34         emf = JpaStorageUtils.getEntityManagerFactory();            
35         em = emf.createEntityManager();
36         }       
37
38         protected EntityManagerFactory getEntityManagerFactory() {
39                 return emf;
40         }
41         
42         protected EntityManager getEntityManager() {
43                 return em;
44         }
45                 
46         /**
47          * Set to 'true' if (and only if) a change has been made AND successfully committed to the Spring Security tables.
48          * 
49          * Since we can't include Spring Security table changes and JPA changes in a single transaction, we
50          * keep track of changes to the Spring Security tables here.  We'll use this flag to log a critical error if
51          * we think there is a chance the JPA tables and Spring Security tables get out of sync.
52          * 
53          * @param flag
54          */
55         public void setAclTablesUpdateFlag(boolean flag) {
56                 aclTablesUpdatedFlag = flag;
57         }
58         
59         protected boolean getAclTablesUpdateFlag() {
60                 return aclTablesUpdatedFlag;
61         }       
62         
63         @Override
64         public ServiceContext getServiceContext() {
65                 return ctx;
66         }
67         
68         @Override
69         public void markForRollback() {
70                 if (em.getTransaction().isActive() == true) {
71                         em.getTransaction().setRollbackOnly();
72                 } else {
73                         String msg = "Attemped to mark an inactive transaction for rollback.";
74                         logger.warn(msg);
75                 }
76         }
77         
78         @Override
79         public void close() throws TransactionException  {
80                 if (em.getTransaction().isActive() == true && em.getTransaction().getRollbackOnly() == true) {
81                         if (getAclTablesUpdateFlag() == false) {
82                                 //
83                                 // Since there were no changes committed to the Spring Security tables, we can just rollback and continue
84                                 //
85                                 em.getTransaction().rollback();
86                         } else {
87                                 String msg = handleInconsistentState();
88                                 throw new InconsistentStateException(msg);
89                         }
90         } else if (em.getTransaction().isActive() == true) {
91                 markForRollback();
92                 close(); // NOTE: Recursive call.
93                 throw new JPATransactionException("There was an active transaction.  You must commit the active transaction prior to calling this close method.");
94         }
95                 
96                 em.close();
97         JpaStorageUtils.releaseEntityManagerFactory(emf);               
98         }
99         
100         private String handleInconsistentState() throws InconsistentStateException {
101                 //
102                 // If we've modified the Spring Tables and need to rollback this JPA transaction, we now have a potentially critical inconsistent state in the system
103                 //
104                 String msg = "\n#\n# CRITICAL: The Spring Security tables just became inconsistent with CollectionSpace JPA AuthN and AuthZ tables.  Contact your CollectionSpace administrator immediately.\n#";
105
106                 //
107                 // Finish by rolling back the JPA transaction, closing the connection, and throwing an exception
108                 //
109                 logger.error(msg);
110                 em.getTransaction().rollback();
111                 em.close();
112         JpaStorageUtils.releaseEntityManagerFactory(emf);
113         
114         return msg;
115         }
116
117         @Override
118         synchronized public void beginTransaction() {
119                 if (transactionRefCount == 0) {
120                         em.getTransaction().begin();
121                 }
122         transactionRefCount++;
123         }
124         
125         @Override
126         public void persist(Object entity) {
127                 em.persist(entity);
128         }
129         
130         @Override
131         public Object merge(Object entity) {
132                 return em.merge(entity);
133         }
134         
135         @SuppressWarnings("unchecked")
136         @Override
137         public Object find(Class entityClass, Object primaryKey) {
138                 return em.find(entityClass, primaryKey);
139         }
140         
141         @SuppressWarnings("unchecked")
142         @Override
143         public Object find(Class entityClass, String id) {
144                 return em.find(entityClass, id);
145         }
146         
147         @Override
148         public Query createQuery(String qlString) {
149                 return em.createQuery(qlString);
150         }
151         
152         @Override
153     public void remove(Object entity) {
154                 em.remove(entity);
155         }
156         
157         @Override
158         public boolean isTransactionActive() {
159                 return em.getTransaction().isActive();
160         }
161         
162         @Override
163         public void flush() {
164                 em.flush();
165         }
166
167         @Override
168         public void commitTransaction() throws TransactionException {
169                 if (transactionRefCount == 0) {
170                 throw new JPATransactionException("There is no active transaction to commit.");
171                 }
172                 if (--transactionRefCount == 0) {
173                         em.getTransaction().commit();
174                 }
175         }
176 }