Author: norman
Date: Fri Apr 30 13:36:21 2010
New Revision: 939668

URL: http://svn.apache.org/viewvc?rev=939668&view=rev
Log:
Fix duplicated primary key problem on heavy load and add a unit test case 
(IMAP-137)

Added:
    
james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAStressTest.java
Removed:
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/MailboxSessionEntityManagerFactory.java
    james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/openjpa/
Modified:
    
james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAHostSystem.java
    james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailbox.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxManager.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPASubscriptionManager.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPATransactionalMapper.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMailboxMapper.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMessageMapper.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMailbox.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailbox.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailboxManager.java
    
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/user/JPASubscriptionMapper.java

Modified: 
james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAHostSystem.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAHostSystem.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAHostSystem.java
 (original)
+++ 
james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAHostSystem.java
 Fri Apr 30 13:36:21 2010
@@ -30,7 +30,6 @@ import org.apache.james.imap.encode.main
 import org.apache.james.imap.functional.ImapHostSystem;
 import org.apache.james.imap.functional.InMemoryUserManager;
 import org.apache.james.imap.jpa.JPASubscriptionManager;
-import org.apache.james.imap.jpa.MailboxSessionEntityManagerFactory;
 import org.apache.james.imap.jpa.openjpa.OpenJPAMailboxManager;
 import org.apache.james.imap.mailbox.MailboxSession;
 import org.apache.james.imap.main.DefaultImapDecoderFactory;
@@ -66,15 +65,9 @@ public class JPAHostSystem extends ImapH
                 "org.apache.james.imap.jpa.mail.model.JPAMessage;" +
                 "org.apache.james.imap.jpa.mail.model.JPAProperty;" +
                 "org.apache.james.imap.jpa.user.model.JPASubscription)");
-        // persimistic locking..
-        properties.put("openjpa.LockManager", "pessimistic");
-        properties.put("openjpa.ReadLockLevel", "read");
-        properties.put("openjpa.WriteLockLevel", "write");
-        properties.put("openjpa.jdbc.TransactionIsolation", "repeatable-read");
         userManager = new InMemoryUserManager();
         entityManagerFactory = 
OpenJPAPersistence.getEntityManagerFactory(properties);
-        MailboxSessionEntityManagerFactory factory = new 
MailboxSessionEntityManagerFactory(entityManagerFactory);
-        mailboxManager = new OpenJPAMailboxManager(userManager, new 
JPASubscriptionManager(factory), factory);
+        mailboxManager = new OpenJPAMailboxManager(userManager, new 
JPASubscriptionManager(entityManagerFactory), entityManagerFactory);
         
         final DefaultImapProcessorFactory defaultImapProcessorFactory = new 
DefaultImapProcessorFactory();
         resetUserMetaData();

Added: 
james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAStressTest.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAStressTest.java?rev=939668&view=auto
==============================================================================
--- 
james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAStressTest.java
 (added)
+++ 
james/imap/trunk/deployment/src/test/java/org/apache/james/imap/functional/jpa/JPAStressTest.java
 Fri Apr 30 13:36:21 2010
@@ -0,0 +1,144 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.imap.functional.jpa;
+
+import java.io.ByteArrayInputStream;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.mail.Flags;
+import javax.persistence.EntityManagerFactory;
+
+import org.apache.commons.logging.impl.SimpleLog;
+import org.apache.james.imap.jpa.JPASubscriptionManager;
+import org.apache.james.imap.jpa.openjpa.OpenJPAMailboxManager;
+import org.apache.james.imap.mailbox.Mailbox;
+import org.apache.james.imap.mailbox.MailboxException;
+import org.apache.james.imap.mailbox.MailboxSession;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JPAStressTest {
+
+    
+    private OpenJPAMailboxManager mailboxManager;
+
+    
+    @Before
+    public void setUp() {
+        HashMap<String, String> properties = new HashMap<String, String>();
+        properties.put("openjpa.ConnectionDriverName", "org.h2.Driver");
+        properties.put("openjpa.ConnectionURL", 
"jdbc:h2:mem:imap;DB_CLOSE_DELAY=-1");
+        properties.put("openjpa.Log", "JDBC=WARN, SQL=WARN, Runtime=WARN");
+        properties.put("openjpa.ConnectionFactoryProperties", 
"PrettyPrint=true, PrettyPrintLineLength=72");
+        properties.put("openjpa.jdbc.SynchronizeMappings", 
"buildSchema(ForeignKeys=true)");
+        properties.put("openjpa.MetaDataFactory", 
"jpa(Types=org.apache.james.imap.jpa.mail.model.JPAHeader;" +
+                "org.apache.james.imap.jpa.mail.model.JPAMailbox;" +
+                
"org.apache.james.imap.jpa.mail.model.AbstractJPAMailboxMembership;" +
+                "org.apache.james.imap.jpa.mail.model.JPAMailboxMembership;" +
+                "org.apache.james.imap.jpa.mail.model.AbstractJPAMessage;" +
+                "org.apache.james.imap.jpa.mail.model.JPAMessage;" +
+                "org.apache.james.imap.jpa.mail.model.JPAProperty;" +
+                "org.apache.james.imap.jpa.user.model.JPASubscription)");
+        // persimistic locking..
+        properties.put("openjpa.LockManager", "pessimistic");
+        properties.put("openjpa.ReadLockLevel", "read");
+        properties.put("openjpa.WriteLockLevel", "write");
+        properties.put("openjpa.jdbc.TransactionIsolation", "repeatable-read");
+        EntityManagerFactory entityManagerFactory = 
OpenJPAPersistence.getEntityManagerFactory(properties);
+        //MailboxSessionEntityManagerFactory factory = new 
MailboxSessionEntityManagerFactory(entityManagerFactory);
+        
+        mailboxManager = new OpenJPAMailboxManager(null, new 
JPASubscriptionManager(entityManagerFactory), entityManagerFactory);
+    }
+    
+    @After
+    public void tearDown() {
+        MailboxSession session = mailboxManager.createSystemSession("test", 
new SimpleLog("Test"));
+        try {
+            mailboxManager.deleteEverything(session);
+        } catch (MailboxException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        session.close();
+    }
+    /**
+     * Proof of bug https://issues.apache.org/jira/browse/IMAP-137
+     *
+     * @throws InterruptedException
+     * @throws MailboxException
+     */
+    @Test
+    public void testStessTest() throws InterruptedException, MailboxException {
+       
+        final CountDownLatch latch = new CountDownLatch(1000);
+        final ExecutorService pool = Executors.newFixedThreadPool(500);
+        
+        MailboxSession session = mailboxManager.createSystemSession("test", 
new SimpleLog("Test"));
+        mailboxManager.startProcessingRequest(session);
+        
mailboxManager.createMailbox(OpenJPAMailboxManager.USER_NAMESPACE_PREFIX 
+".INBOX", session);
+        mailboxManager.endProcessingRequest(session);
+        mailboxManager.logout(session, false);
+        final AtomicBoolean fail = new AtomicBoolean(false);
+        
+        // fire of 1000 append operations
+        for (int i = 0 ; i < 1000; i++) {
+            pool.execute(new Runnable() {
+                
+                public void run() {
+                    if (fail.get()){
+                        latch.countDown();
+                        return;
+                    }
+                    
+                    MailboxSession session = 
mailboxManager.createSystemSession("test", new SimpleLog("Test"));
+
+                    try {
+                        mailboxManager.startProcessingRequest(session);
+                        Mailbox m = 
mailboxManager.getMailbox(OpenJPAMailboxManager.USER_NAMESPACE_PREFIX 
+".INBOX", session);
+                        
+                        System.out.println("uid=" + m.appendMessage(new 
ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), 
session, false, new Flags()));
+                        mailboxManager.endProcessingRequest(session);
+                        mailboxManager.logout(session,false);
+                    } catch (MailboxException e) {
+                        e.printStackTrace();
+                        fail.set(true);
+                    } finally {
+                        latch.countDown();
+                    }
+                    
+                    
+                }
+            });
+        }
+        
+        latch.await();
+        
+        org.junit.Assert.assertFalse("Unable to append all 
messages",fail.get());
+        pool.shutdown();
+
+        
+    }
+}

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailbox.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailbox.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailbox.java 
(original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailbox.java 
Fri Apr 30 13:36:21 2010
@@ -24,9 +24,7 @@ import java.util.Date;
 import java.util.List;
 
 import javax.mail.Flags;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityTransaction;
-import javax.persistence.Query;
+import javax.persistence.EntityManagerFactory;
 
 import org.apache.james.imap.jpa.mail.JPAMailboxMapper;
 import org.apache.james.imap.jpa.mail.JPAMessageMapper;
@@ -51,9 +49,9 @@ import org.apache.james.imap.store.mail.
  */
 public abstract class JPAMailbox extends StoreMailbox<Long> {
 
-    protected final MailboxSessionEntityManagerFactory entityManagerFactory;
+    protected final EntityManagerFactory entityManagerFactory;
     
-    public JPAMailbox(final MailboxEventDispatcher dispatcher, final 
Mailbox<Long> mailbox, final MailboxSessionEntityManagerFactory 
entityManagerfactory) {
+    public JPAMailbox(final MailboxEventDispatcher dispatcher, final 
Mailbox<Long> mailbox, final EntityManagerFactory entityManagerfactory) {
         super(dispatcher, mailbox);
         this.entityManagerFactory = entityManagerfactory;        
     }  
@@ -73,10 +71,8 @@ public abstract class JPAMailbox extends
 
     
     @Override
-    protected MessageMapper<Long> createMessageMapper(MailboxSession session) {
-        EntityManager manager = entityManagerFactory.getEntityManager(session);
-                
-        JPAMessageMapper mapper = new JPAMessageMapper(manager, 
getMailboxId());
+    protected MessageMapper<Long> createMessageMapper(MailboxSession session) 
{                
+        JPAMessageMapper mapper = new JPAMessageMapper(entityManagerFactory, 
getMailboxId());
        
         return mapper;
     }
@@ -105,21 +101,4 @@ public abstract class JPAMailbox extends
         final Header header = new JPAHeader(lineNumber, name, value);
         return header;
     }
-
-    /**
-     * Reserve next Uid in mailbox and return the mailbox. We use a 
transaction here to be sure we don't get any duplicates
-     * 
-     */
-    protected Mailbox<Long> reserveNextUid(MailboxSession session) throws 
MailboxException {
-        EntityManager entityManager = 
entityManagerFactory.getEntityManager(session);
-
-        EntityTransaction transaction = entityManager.getTransaction();
-        transaction.begin();
-        Query query = 
entityManager.createNamedQuery("findMailboxById").setParameter("idParam", 
getMailboxId());
-        org.apache.james.imap.jpa.mail.model.JPAMailbox mailbox = 
(org.apache.james.imap.jpa.mail.model.JPAMailbox) query.getSingleResult();
-        mailbox.consumeUid();
-        entityManager.persist(mailbox);
-        transaction.commit();
-        return mailbox;
-    }
 }

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxManager.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxManager.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxManager.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPAMailboxManager.java
 Fri Apr 30 13:36:21 2010
@@ -19,7 +19,7 @@
 package org.apache.james.imap.jpa;
 
 
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 
 import org.apache.james.imap.jpa.mail.JPAMailboxMapper;
 import org.apache.james.imap.mailbox.MailboxException;
@@ -39,9 +39,9 @@ import org.apache.james.imap.store.trans
  */
 public abstract class JPAMailboxManager extends StoreMailboxManager<Long> {
 
-    protected final MailboxSessionEntityManagerFactory entityManagerFactory;
+    protected final EntityManagerFactory entityManagerFactory;
     public JPAMailboxManager(final Authenticator authenticator, final 
Subscriber subscriber, 
-            final MailboxSessionEntityManagerFactory entityManagerFactory) {
+            final EntityManagerFactory entityManagerFactory) {
         super(authenticator, subscriber);
         this.entityManagerFactory = entityManagerFactory;
     }
@@ -60,6 +60,12 @@ public abstract class JPAMailboxManager 
         });
     }
 
+    /**
+     * Delete all mailboxes 
+     * 
+     * @param maibloxSession
+     * @throws MailboxException
+     */
     public void deleteEverything(MailboxSession maibloxSession) throws 
MailboxException {
         final MailboxMapper<Long> mapper = createMailboxMapper(maibloxSession);
         mapper.execute(new TransactionalMapper.Transaction() {
@@ -72,17 +78,10 @@ public abstract class JPAMailboxManager 
     }
 
     
-    @Override
-    public void endProcessingRequest(MailboxSession session) {
-        // close the entityManager after each request so we are sure 
everything is flushed
-        entityManagerFactory.closeEntityManager(session);
-       
-    }
     
     @Override
     protected MailboxMapper<Long> createMailboxMapper(MailboxSession session) {
-        EntityManager manager = entityManagerFactory.getEntityManager(session);
-        return new JPAMailboxMapper(manager);
+        return new JPAMailboxMapper(entityManagerFactory);
     }
 
     

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPASubscriptionManager.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPASubscriptionManager.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPASubscriptionManager.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPASubscriptionManager.java
 Fri Apr 30 13:36:21 2010
@@ -18,7 +18,7 @@
  ****************************************************************/
 package org.apache.james.imap.jpa;
 
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 
 import org.apache.james.imap.jpa.user.JPASubscriptionMapper;
 import org.apache.james.imap.jpa.user.model.JPASubscription;
@@ -33,9 +33,9 @@ import org.apache.james.imap.store.user.
  *
  */
 public class JPASubscriptionManager extends StoreSubscriptionManager {
-    private final MailboxSessionEntityManagerFactory factory;
+    private final EntityManagerFactory factory;
     
-    public JPASubscriptionManager(final MailboxSessionEntityManagerFactory 
factory) {
+    public JPASubscriptionManager(final EntityManagerFactory factory) {
         super();
         this.factory = factory;
     }
@@ -44,10 +44,8 @@ public class JPASubscriptionManager exte
      * (non-Javadoc)
      * @see 
org.apache.james.imap.store.StoreSubscriptionManager#createMapper(org.apache.james.imap.mailbox.MailboxSession)
      */
-    protected SubscriptionMapper createMapper(MailboxSession session) {
-        EntityManager manager = factory.getEntityManager(session);
-                
-        JPASubscriptionMapper  mapper = new JPASubscriptionMapper(manager);
+    protected SubscriptionMapper createMapper(MailboxSession session) {        
        
+        JPASubscriptionMapper  mapper = new JPASubscriptionMapper(factory);
         
         return mapper;
     }

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPATransactionalMapper.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPATransactionalMapper.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPATransactionalMapper.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/JPATransactionalMapper.java
 Fri Apr 30 13:36:21 2010
@@ -19,6 +19,7 @@
 package org.apache.james.imap.jpa;
 
 import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 import javax.persistence.EntityTransaction;
 import javax.persistence.PersistenceException;
 
@@ -28,17 +29,29 @@ import org.apache.james.imap.mailbox.Sto
 import org.apache.james.imap.store.transaction.AbstractTransactionalMapper;
 
 /**
- * JPA implementation of TransactionMapper  
+ * JPA implementation of TransactionMapper. This class is not thread-safe!
  *
  */
 public class JPATransactionalMapper extends AbstractTransactionalMapper {
 
-    protected final EntityManager entityManager;
+    private final EntityManagerFactory factory;
+    private EntityManager entityManager;
     
-    public JPATransactionalMapper(final EntityManager entityManager) {
-        this.entityManager = entityManager;
+    public JPATransactionalMapper(final EntityManagerFactory factory) {
+        this.factory = factory;
     }
 
+    /**
+     * Return the currently used {...@link EntityManager}. If the currently 
used {...@link EntityManager} is null or is closed a new will get obtained from 
the {...@link EntityManagerFactory}
+     * 
+     * @return entitymanger
+     */
+    protected EntityManager getManager() {
+        if (entityManager == null || entityManager.isOpen() == false) {
+            entityManager = factory.createEntityManager();
+        }
+        return entityManager;
+    }
 
     /*
      * (non-Javadoc)
@@ -46,20 +59,20 @@ public class JPATransactionalMapper exte
      */
     protected void begin() throws MailboxException {
         try {
-            entityManager.getTransaction().begin();
+            getManager().getTransaction().begin();
         } catch (PersistenceException e) {
             throw new 
StorageException(HumanReadableText.START_TRANSACTION_FAILED, e);
         }
     }
     
 
-    /*
-     * (non-Javadoc)
-     * @see 
org.apache.james.imap.store.transaction.AbstractTransactionalMapper#commit()
+    /**
+     * Commit the Transaction and close the EntityManager
      */
     protected void commit() throws MailboxException {
         try {
-            entityManager.getTransaction().commit();
+            getManager().getTransaction().commit();
+            getManager().close();
         } catch (PersistenceException e) {
             throw new 
StorageException(HumanReadableText.COMMIT_TRANSACTION_FAILED, e);
         }
@@ -73,7 +86,7 @@ public class JPATransactionalMapper exte
         EntityTransaction transaction = entityManager.getTransaction();
         // check if we have a transaction to rollback
         if (transaction.isActive()) {
-            entityManager.getTransaction().rollback();
+            getManager().getTransaction().rollback();
         }
     }
 

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMailboxMapper.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMailboxMapper.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMailboxMapper.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMailboxMapper.java
 Fri Apr 30 13:36:21 2010
@@ -21,7 +21,7 @@ package org.apache.james.imap.jpa.mail;
 
 import java.util.List;
 
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 import javax.persistence.NoResultException;
 import javax.persistence.PersistenceException;
 
@@ -40,8 +40,8 @@ public class JPAMailboxMapper extends JP
 
     private static final char SQL_WILDCARD_CHAR = '%';
     
-    public JPAMailboxMapper(EntityManager entityManager) {
-        super(entityManager);
+    public JPAMailboxMapper(EntityManagerFactory factory) {
+        super(factory);
     }
 
     /**
@@ -50,7 +50,7 @@ public class JPAMailboxMapper extends JP
     public boolean existsMailboxStartingWith(String mailboxName) throws 
StorageException {
         
         final String name = mailboxName + SQL_WILDCARD_CHAR; 
-        final Long numberOfChildMailboxes = (Long) 
entityManager.createNamedQuery("countMailboxesWithNameLike").setParameter("nameParam",
 name).getSingleResult();
+        final Long numberOfChildMailboxes = (Long) 
getManager().createNamedQuery("countMailboxesWithNameLike").setParameter("nameParam",
 name).getSingleResult();
         return numberOfChildMailboxes != null && numberOfChildMailboxes > 0;
     }
 
@@ -61,7 +61,7 @@ public class JPAMailboxMapper extends JP
      */
     public void save(Mailbox<Long> mailbox) throws StorageException {
         try {
-            entityManager.persist(mailbox);
+            getManager().persist(mailbox);
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SAVE_FAILED, e);
         } 
@@ -72,7 +72,7 @@ public class JPAMailboxMapper extends JP
      */
     public Mailbox<Long> findMailboxByName(String name) throws 
StorageException, MailboxNotFoundException {
         try {
-            return (JPAMailbox) 
entityManager.createNamedQuery("findMailboxByName").setParameter("nameParam", 
name).getSingleResult();
+            return (JPAMailbox) 
getManager().createNamedQuery("findMailboxByName").setParameter("nameParam", 
name).getSingleResult();
         } catch (NoResultException e) {
             throw new MailboxNotFoundException(name);
             
@@ -86,7 +86,7 @@ public class JPAMailboxMapper extends JP
      */
     public void delete(Mailbox<Long> mailbox) throws StorageException {
         try {  
-            entityManager.remove(mailbox);
+            getManager().remove(mailbox);
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.DELETED_FAILED, e);
         } 
@@ -98,7 +98,7 @@ public class JPAMailboxMapper extends JP
     @SuppressWarnings("unchecked")
     public List<Mailbox<Long>> findMailboxWithNameLike(String name) throws 
StorageException {
         try {
-            return 
entityManager.createNamedQuery("findMailboxWithNameLike").setParameter("nameParam",
 SQL_WILDCARD_CHAR + name + SQL_WILDCARD_CHAR).getResultList();
+            return 
getManager().createNamedQuery("findMailboxWithNameLike").setParameter("nameParam",
 SQL_WILDCARD_CHAR + name + SQL_WILDCARD_CHAR).getResultList();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         } 
@@ -109,7 +109,7 @@ public class JPAMailboxMapper extends JP
      */
     public void deleteAll() throws StorageException {
         try {
-            entityManager.createNamedQuery("deleteAll").executeUpdate();
+            getManager().createNamedQuery("deleteAll").executeUpdate();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.DELETED_FAILED, e);
         } 
@@ -120,7 +120,7 @@ public class JPAMailboxMapper extends JP
      */
     public long countMailboxesWithName(String name) throws StorageException {
         try {
-            return (Long) 
entityManager.createNamedQuery("countMailboxesWithName").setParameter("nameParam",
 name).getSingleResult();
+            return (Long) 
getManager().createNamedQuery("countMailboxesWithName").setParameter("nameParam",
 name).getSingleResult();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.COUNT_FAILED, e);
         } 
@@ -131,7 +131,7 @@ public class JPAMailboxMapper extends JP
      */
     public Mailbox<Long> findMailboxById(Long mailboxId) throws 
StorageException, MailboxNotFoundException  {
         try {
-            return (JPAMailbox) 
entityManager.createNamedQuery("findMailboxById").setParameter("idParam", 
mailboxId).getSingleResult();
+            return (JPAMailbox) 
getManager().createNamedQuery("findMailboxById").setParameter("idParam", 
mailboxId).getSingleResult();
         } catch (NoResultException e) {
             throw new MailboxNotFoundException(mailboxId);   
         } catch (PersistenceException e) {

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMessageMapper.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMessageMapper.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMessageMapper.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/JPAMessageMapper.java
 Fri Apr 30 13:36:21 2010
@@ -20,7 +20,7 @@ package org.apache.james.imap.jpa.mail;
 
 import java.util.List;
 
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 import javax.persistence.PersistenceException;
 
 import org.apache.james.imap.api.display.HumanReadableText;
@@ -34,12 +34,17 @@ import org.apache.james.imap.mailbox.Sea
 import org.apache.james.imap.store.mail.MessageMapper;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
 
+
+/**
+ * JPA implementation of a {...@link MessageMapper}. This class is not 
thread-safe!
+ *
+ */
 public class JPAMessageMapper extends JPATransactionalMapper implements 
MessageMapper<Long> {
 
     private final long mailboxId;
     
-    public JPAMessageMapper(final EntityManager entityManager, final long 
mailboxId) {
-        super(entityManager);
+    public JPAMessageMapper(final EntityManagerFactory factory, final long 
mailboxId) {
+        super(factory);
         this.mailboxId = mailboxId;
     }
 
@@ -75,21 +80,21 @@ public class JPAMessageMapper extends JP
 
     @SuppressWarnings("unchecked")
     private List<MailboxMembership<Long>> findMessagesInMailboxAfterUID(long 
mailboxId, long uid) {
-        return entityManager.createNamedQuery("findMessagesInMailboxAfterUID")
+        return getManager().createNamedQuery("findMessagesInMailboxAfterUID")
         .setParameter("idParam", mailboxId)
         .setParameter("uidParam", uid).getResultList();
     }
 
     @SuppressWarnings("unchecked")
     private List<MailboxMembership<Long>> findMessagesInMailboxWithUID(long 
mailboxId, long uid) {
-        return entityManager.createNamedQuery("findMessagesInMailboxWithUID")
+        return getManager().createNamedQuery("findMessagesInMailboxWithUID")
         .setParameter("idParam", mailboxId)
         .setParameter("uidParam", uid).getResultList();
     }
 
     @SuppressWarnings("unchecked")
     private List<MailboxMembership<Long>> 
findMessagesInMailboxBetweenUIDs(long mailboxId, long from, long to) {
-        return 
entityManager.createNamedQuery("findMessagesInMailboxBetweenUIDs")
+        return 
getManager().createNamedQuery("findMessagesInMailboxBetweenUIDs")
         .setParameter("idParam", mailboxId)
         .setParameter("fromParam", from)
         .setParameter("toParam", to).getResultList();
@@ -97,7 +102,7 @@ public class JPAMessageMapper extends JP
 
     @SuppressWarnings("unchecked")
     private List<MailboxMembership<Long>> findMessagesInMailbox(long 
mailboxId) {
-        return 
entityManager.createNamedQuery("findMessagesInMailbox").setParameter("idParam", 
mailboxId).getResultList();
+        return 
getManager().createNamedQuery("findMessagesInMailbox").setParameter("idParam", 
mailboxId).getResultList();
     }
 
     /**
@@ -131,26 +136,26 @@ public class JPAMessageMapper extends JP
 
     @SuppressWarnings("unchecked")
     private List<MailboxMembership<Long>> findDeletedMessagesInMailbox(long 
mailboxId) {
-        return 
entityManager.createNamedQuery("findDeletedMessagesInMailbox").setParameter("idParam",
 mailboxId).getResultList();
+        return 
getManager().createNamedQuery("findDeletedMessagesInMailbox").setParameter("idParam",
 mailboxId).getResultList();
     }
 
     @SuppressWarnings("unchecked")
     private List<MailboxMembership<Long>> 
findDeletedMessagesInMailboxAfterUID(long mailboxId, long uid) {
-        return 
entityManager.createNamedQuery("findDeletedMessagesInMailboxAfterUID")
+        return 
getManager().createNamedQuery("findDeletedMessagesInMailboxAfterUID")
         .setParameter("idParam", mailboxId)
         .setParameter("uidParam", uid).getResultList();
     }
 
     @SuppressWarnings("unchecked")
     private List<MailboxMembership<Long>> 
findDeletedMessagesInMailboxWithUID(long mailboxId, long uid) {
-        return 
entityManager.createNamedQuery("findDeletedMessagesInMailboxWithUID")
+        return 
getManager().createNamedQuery("findDeletedMessagesInMailboxWithUID")
         .setParameter("idParam", mailboxId)
         .setParameter("uidParam", uid).getResultList();
     }
 
     @SuppressWarnings("unchecked")
     private List<MailboxMembership<Long>> 
findDeletedMessagesInMailboxBetweenUIDs(long mailboxId, long from, long to) {
-        return 
entityManager.createNamedQuery("findDeletedMessagesInMailboxBetweenUIDs")
+        return 
getManager().createNamedQuery("findDeletedMessagesInMailboxBetweenUIDs")
         .setParameter("idParam", mailboxId)
         .setParameter("fromParam", from)
         .setParameter("toParam", to).getResultList();
@@ -161,7 +166,7 @@ public class JPAMessageMapper extends JP
      */
     public long countMessagesInMailbox() throws StorageException {
         try {
-            return (Long) 
entityManager.createNamedQuery("countMessagesInMailbox").setParameter("idParam",
 mailboxId).getSingleResult();
+            return (Long) 
getManager().createNamedQuery("countMessagesInMailbox").setParameter("idParam", 
mailboxId).getSingleResult();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.COUNT_FAILED, e);
         }
@@ -172,7 +177,7 @@ public class JPAMessageMapper extends JP
      */
     public long countUnseenMessagesInMailbox() throws StorageException {
         try {
-            return (Long) 
entityManager.createNamedQuery("countUnseenMessagesInMailbox").setParameter("idParam",
 mailboxId).getSingleResult();
+            return (Long) 
getManager().createNamedQuery("countUnseenMessagesInMailbox").setParameter("idParam",
 mailboxId).getSingleResult();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.COUNT_FAILED, e);
         }
@@ -185,7 +190,7 @@ public class JPAMessageMapper extends JP
     public List<MailboxMembership<Long>> searchMailbox(SearchQuery query) 
throws StorageException {
         try {
             final String jql = formulateJQL(mailboxId, query);
-            return entityManager.createQuery(jql).getResultList();
+            return getManager().createQuery(jql).getResultList();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         }
@@ -223,7 +228,7 @@ public class JPAMessageMapper extends JP
      */
     public void delete(MailboxMembership<Long> message) throws 
StorageException {
         try {
-            entityManager.remove(message);
+            getManager().remove(message);
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.DELETED_FAILED, e);
         }
@@ -236,7 +241,7 @@ public class JPAMessageMapper extends JP
     @SuppressWarnings("unchecked")
     public List<MailboxMembership<Long>> findUnseenMessagesInMailbox()  throws 
StorageException {
         try {
-            return 
entityManager.createNamedQuery("findUnseenMessagesInMailboxOrderByUid").setParameter("idParam",
 mailboxId).getResultList();
+            return 
getManager().createNamedQuery("findUnseenMessagesInMailboxOrderByUid").setParameter("idParam",
 mailboxId).getResultList();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         }
@@ -248,7 +253,7 @@ public class JPAMessageMapper extends JP
     @SuppressWarnings("unchecked")
     public List<MailboxMembership<Long>> findRecentMessagesInMailbox() throws 
StorageException {
         try {
-            return 
entityManager.createNamedQuery("findRecentMessagesInMailbox").setParameter("idParam",
 mailboxId).getResultList();
+            return 
getManager().createNamedQuery("findRecentMessagesInMailbox").setParameter("idParam",
 mailboxId).getResultList();
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SEARCH_FAILED, e);
         }
@@ -259,7 +264,7 @@ public class JPAMessageMapper extends JP
      */
     public void save(MailboxMembership<Long> message) throws StorageException {
         try {
-            entityManager.persist(message);
+            getManager().persist(message);
         } catch (PersistenceException e) {
             throw new StorageException(HumanReadableText.SAVE_FAILED, e);
         }

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMailbox.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMailbox.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMailbox.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/mail/model/JPAMailbox.java
 Fri Apr 30 13:36:21 2010
@@ -66,7 +66,7 @@ public class JPAMailbox implements Mailb
     
     /** The value for the size field */
     @Basic(optional=false) private long size = 0;
-
+    
     /**
      * JPA only
      */

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailbox.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailbox.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailbox.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailbox.java
 Fri Apr 30 13:36:21 2010
@@ -25,10 +25,11 @@ import java.util.Date;
 import java.util.List;
 
 import javax.mail.Flags;
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Query;
 
 import org.apache.james.imap.jpa.JPAMailbox;
-import org.apache.james.imap.jpa.MailboxSessionEntityManagerFactory;
 import org.apache.james.imap.jpa.mail.JPAMailboxMapper;
 import org.apache.james.imap.jpa.mail.model.AbstractJPAMailboxMembership;
 import org.apache.james.imap.jpa.mail.model.JPAHeader;
@@ -40,6 +41,8 @@ import org.apache.james.imap.store.mail.
 import org.apache.james.imap.store.mail.model.Mailbox;
 import org.apache.james.imap.store.mail.model.MailboxMembership;
 import org.apache.james.imap.store.mail.model.PropertyBuilder;
+import org.apache.openjpa.persistence.OpenJPAEntityManager;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
 
 /**
  * OpenJPA implementation of Mailbox
@@ -48,11 +51,11 @@ import org.apache.james.imap.store.mail.
 public class OpenJPAMailbox extends JPAMailbox{
 
     private final boolean useStreaming;
-    public OpenJPAMailbox(MailboxEventDispatcher dispatcher, Mailbox<Long> 
mailbox,  MailboxSessionEntityManagerFactory entityManagerfactory) {
+    public OpenJPAMailbox(MailboxEventDispatcher dispatcher, Mailbox<Long> 
mailbox,  EntityManagerFactory entityManagerfactory) {
                this(dispatcher, mailbox, entityManagerfactory, false);
        }
 
-    public OpenJPAMailbox(MailboxEventDispatcher dispatcher, Mailbox<Long> 
mailbox, MailboxSessionEntityManagerFactory entityManagerfactory, final boolean 
useStreaming) {
+    public OpenJPAMailbox(MailboxEventDispatcher dispatcher, Mailbox<Long> 
mailbox, EntityManagerFactory entityManagerfactory, final boolean useStreaming) 
{
         super(dispatcher, mailbox, entityManagerfactory);
         this.useStreaming = useStreaming;
     }
@@ -61,10 +64,8 @@ public class OpenJPAMailbox extends JPAM
      * (non-Javadoc)
      * @see 
org.apache.james.imap.jpa.JPAMailbox#createMailboxMapper(org.apache.james.imap.mailbox.MailboxSession)
      */
-       protected JPAMailboxMapper createMailboxMapper(MailboxSession session) {
-           EntityManager manager = 
entityManagerFactory.getEntityManager(session);
-                   
-        JPAMailboxMapper mapper = new JPAMailboxMapper(manager);
+       protected JPAMailboxMapper createMailboxMapper(MailboxSession session) 
{                    
+        JPAMailboxMapper mapper = new JPAMailboxMapper(entityManagerFactory);
 
         return mapper;
     }
@@ -90,5 +91,30 @@ public class OpenJPAMailbox extends JPAM
             return super.createMessage(internalDate, uid, size, 
bodyStartOctet, document, flags, headers, propertyBuilder);
         }
     }
+    
+    /**
+     * Reserve next Uid in mailbox and return the mailbox. We use a 
transaction here to be sure we don't get any duplicates
+     * 
+     */
+    protected Mailbox<Long> reserveNextUid(MailboxSession session) throws 
MailboxException {
+        OpenJPAEntityManager oem = 
OpenJPAPersistence.cast(entityManagerFactory.createEntityManager());
+        boolean optimistic = oem.getOptimistic();
+        try {
+
+            oem.setOptimistic(false);
+            EntityTransaction transaction = oem.getTransaction();
+            transaction.begin();
+            Query query = 
oem.createNamedQuery("findMailboxById").setParameter("idParam", getMailboxId());
+            org.apache.james.imap.jpa.mail.model.JPAMailbox mailbox = 
(org.apache.james.imap.jpa.mail.model.JPAMailbox) query.getSingleResult();
+            //entityManager.lock(mailbox, LockModeType.READ);
+            mailbox.consumeUid();
+            oem.persist(mailbox);
+            oem.flush();
+            transaction.commit();
+            return mailbox;
+        } finally {
+            oem.setOptimistic(optimistic);
+        }
+    }
 
 }

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailboxManager.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailboxManager.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailboxManager.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/openjpa/OpenJPAMailboxManager.java
 Fri Apr 30 13:36:21 2010
@@ -19,8 +19,9 @@
 
 package org.apache.james.imap.jpa.openjpa;
 
+import javax.persistence.EntityManagerFactory;
+
 import org.apache.james.imap.jpa.JPAMailboxManager;
-import org.apache.james.imap.jpa.MailboxSessionEntityManagerFactory;
 import org.apache.james.imap.mailbox.util.MailboxEventDispatcher;
 import org.apache.james.imap.store.Authenticator;
 import org.apache.james.imap.store.StoreMailbox;
@@ -35,12 +36,12 @@ public class OpenJPAMailboxManager exten
 
     private boolean useStreaming;
 
-    public OpenJPAMailboxManager(Authenticator authenticator, Subscriber 
subscriber, MailboxSessionEntityManagerFactory entityManagerFactory, boolean 
useStreaming) {
+    public OpenJPAMailboxManager(Authenticator authenticator, Subscriber 
subscriber, EntityManagerFactory entityManagerFactory, boolean useStreaming) {
         super(authenticator, subscriber, entityManagerFactory);
         this.useStreaming = useStreaming;
     }
 
-    public OpenJPAMailboxManager(Authenticator authenticator, Subscriber 
subscriber, MailboxSessionEntityManagerFactory entityManagerFactory) {
+    public OpenJPAMailboxManager(Authenticator authenticator, Subscriber 
subscriber, EntityManagerFactory entityManagerFactory) {
         this(authenticator, subscriber, entityManagerFactory, false);
     }
 

Modified: 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/user/JPASubscriptionMapper.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/user/JPASubscriptionMapper.java?rev=939668&r1=939667&r2=939668&view=diff
==============================================================================
--- 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/user/JPASubscriptionMapper.java
 (original)
+++ 
james/imap/trunk/jpa/src/main/java/org/apache/james/imap/jpa/user/JPASubscriptionMapper.java
 Fri Apr 30 13:36:21 2010
@@ -20,7 +20,7 @@ package org.apache.james.imap.jpa.user;
 
 import java.util.List;
 
-import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
 import javax.persistence.NoResultException;
 import javax.persistence.PersistenceException;
 
@@ -31,12 +31,12 @@ import org.apache.james.imap.store.user.
 import org.apache.james.imap.store.user.model.Subscription;
 
 /**
- * Maps data access logic to JPA operations.
+ * JPA implementation of a {...@link SubscriptionMapper}. This class is not 
thread-safe!
  */
 public class JPASubscriptionMapper extends JPATransactionalMapper implements 
SubscriptionMapper {
 
-    public JPASubscriptionMapper(final EntityManager entityManager) {
-        super(entityManager);
+    public JPASubscriptionMapper(final EntityManagerFactory factory) {
+        super(factory);
     }
 
 
@@ -46,7 +46,7 @@ public class JPASubscriptionMapper exten
      */
     public Subscription findFindMailboxSubscriptionForUser(final String user, 
final String mailbox) throws SubscriptionException {
         try {
-            return (Subscription) 
entityManager.createNamedQuery("findFindMailboxSubscriptionForUser")
+            return (Subscription) 
getManager().createNamedQuery("findFindMailboxSubscriptionForUser")
             .setParameter("userParam", user).setParameter("mailboxParam", 
mailbox).getSingleResult();
         } catch (NoResultException e) {
             return null;
@@ -61,7 +61,7 @@ public class JPASubscriptionMapper exten
      */
     public void save(Subscription subscription) throws SubscriptionException {
         try {
-            entityManager.persist(subscription);
+            getManager().persist(subscription);
         } catch (PersistenceException e) {
             throw new SubscriptionException(HumanReadableText.SAVE_FAILED, e);
         }
@@ -74,7 +74,7 @@ public class JPASubscriptionMapper exten
     @SuppressWarnings("unchecked")
     public List<Subscription> findSubscriptionsForUser(String user) throws 
SubscriptionException {
         try {
-            return (List<Subscription>) 
entityManager.createNamedQuery("findSubscriptionsForUser").setParameter("userParam",
 user).getResultList();
+            return (List<Subscription>) 
getManager().createNamedQuery("findSubscriptionsForUser").setParameter("userParam",
 user).getResultList();
         } catch (PersistenceException e) {
             throw new SubscriptionException(HumanReadableText.SEARCH_FAILED, 
e);
         }
@@ -86,7 +86,7 @@ public class JPASubscriptionMapper exten
      */
     public void delete(Subscription subscription) throws SubscriptionException 
{
         try {
-            entityManager.remove(subscription);
+            getManager().remove(subscription);
         } catch (PersistenceException e) {
             throw new SubscriptionException(HumanReadableText.DELETED_FAILED, 
e);
         }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to