You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2012/05/30 01:40:13 UTC

svn commit: r1344049 - in /incubator/isis/trunk/framework: core/commons/src/main/java/org/apache/isis/core/commons/config/ runtimes/dflt/objectstores/jpa/jpa-openjpa/ runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dfl...

Author: danhaywood
Date: Tue May 29 23:40:12 2012
New Revision: 1344049

URL: http://svn.apache.org/viewvc?rev=1344049&view=rev
Log:
ISIS-48: more on the openjpa object store - resetting the hsqldb between tests

Modified:
    incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfiguration.java
    incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfigurationDefault.java
    incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/   (props changed)
    incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/pom.xml
    incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaObjectStore.java
    incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstaller.java
    incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/test/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstallerTest_openAndClose.java
    incubator/isis/trunk/framework/runtimes/dflt/testsupport/src/main/java/org/apache/isis/runtimes/dflt/testsupport/IsisSystemWithFixtures.java

Modified: incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfiguration.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfiguration.java?rev=1344049&r1=1344048&r2=1344049&view=diff
==============================================================================
--- incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfiguration.java (original)
+++ incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfiguration.java Tue May 29 23:40:12 2012
@@ -22,6 +22,7 @@ package org.apache.isis.core.commons.con
 import java.awt.Color;
 import java.awt.Font;
 import java.util.Iterator;
+import java.util.Map;
 
 import org.apache.isis.core.commons.components.Injectable;
 import org.apache.isis.core.commons.debug.DebuggableWithTitle;
@@ -183,4 +184,9 @@ public interface IsisConfiguration exten
      */
     ResourceStreamSource getResourceStreamSource();
 
+    /**
+     * A mutable copy of the current set of properties (name/values) held in this configuration.
+     */
+    Map<String, String> asMap();
+
 }

Modified: incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfigurationDefault.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfigurationDefault.java?rev=1344049&r1=1344048&r2=1344049&view=diff
==============================================================================
--- incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfigurationDefault.java (original)
+++ incubator/isis/trunk/framework/core/commons/src/main/java/org/apache/isis/core/commons/config/IsisConfigurationDefault.java Tue May 29 23:40:12 2012
@@ -21,11 +21,16 @@ package org.apache.isis.core.commons.con
 
 import java.awt.Color;
 import java.awt.Font;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Properties;
 import java.util.StringTokenizer;
 
+import com.google.common.collect.Maps;
+
 import org.apache.log4j.Logger;
 
 import org.apache.isis.core.commons.debug.DebugBuilder;
@@ -33,6 +38,7 @@ import org.apache.isis.core.commons.exce
 import org.apache.isis.core.commons.resource.ResourceStreamSource;
 
 public class IsisConfigurationDefault implements IsisConfiguration {
+    
     private static final Logger LOG = Logger.getLogger(IsisConfigurationDefault.class);
     private final Properties properties = new Properties();
     private final ResourceStreamSource resourceStreamSource;
@@ -378,4 +384,14 @@ public class IsisConfigurationDefault im
         }
     }
 
+    @Override
+    public Map<String,String> asMap() {
+        final Map<String, String> map = Maps.newHashMap();
+        for(String propertyName: this) {
+            final String propertyValue = this.getProperty(propertyName);
+            map.put(propertyName, propertyValue);
+        }
+        return map;
+    }
+
 }

Propchange: incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue May 29 23:40:12 2012
@@ -4,3 +4,4 @@ db
 .project
 target
 target-ide
+hsql-db

Modified: incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/pom.xml
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/pom.xml?rev=1344049&r1=1344048&r2=1344049&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/pom.xml (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/pom.xml Tue May 29 23:40:12 2012
@@ -74,9 +74,9 @@
         </dependency>
 
         <dependency>
-            <groupId>hsqldb</groupId>
+            <groupId>org.hsqldb</groupId>
             <artifactId>hsqldb</artifactId>
-            <version>1.8.0.10</version>
+            <version>2.2.8</version>
             <scope>test</scope>
         </dependency>
 

Modified: incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaObjectStore.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaObjectStore.java?rev=1344049&r1=1344048&r2=1344049&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaObjectStore.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaObjectStore.java Tue May 29 23:40:12 2012
@@ -6,6 +6,7 @@ import static org.apache.isis.core.commo
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 
+import java.sql.Connection;
 import java.text.MessageFormat;
 import java.util.List;
 import java.util.Map;
@@ -19,6 +20,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 import org.apache.log4j.Logger;
+import org.apache.openjpa.persistence.OpenJPAEntityManager;
 
 import org.apache.isis.core.commons.config.ConfigurationConstants;
 import org.apache.isis.core.commons.config.IsisConfiguration;
@@ -211,6 +213,14 @@ public class OpenJpaObjectStore implemen
         // does nothing.
     }
 
+    /**
+     * Non-API.
+     */
+    public Connection getConnection() {
+        OpenJPAEntityManager ojem = (OpenJPAEntityManager) entityManager;
+        return (Connection) ojem.getConnection();
+    }
+
     // ///////////////////////////////////////////////////////////////////////
     // TransactionMode (not API)
     // ///////////////////////////////////////////////////////////////////////
@@ -726,6 +736,7 @@ public class OpenJpaObjectStore implemen
 
 
 
+
 //    /**
 //     * @see #setHibernateApplicationComponents(HibernateMetaDataComponents)
 //     */

Modified: incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstaller.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstaller.java?rev=1344049&r1=1344048&r2=1344049&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstaller.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/main/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstaller.java Tue May 29 23:40:12 2012
@@ -9,6 +9,7 @@ import javax.persistence.EntityManagerFa
 
 import com.google.common.collect.Maps;
 
+import org.apache.isis.core.commons.components.Installer;
 import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterFactory;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -24,6 +25,26 @@ import org.apache.isis.runtimes.dflt.run
 import org.apache.isis.runtimes.dflt.runtime.system.persistence.AdapterManager;
 import org.apache.isis.runtimes.dflt.runtime.system.persistence.ObjectFactory;
 
+/**
+ * Configuration files are read in the usual fashion (as per {@link Installer#getConfigurationResources()}, ie will consult all of:
+ * <ul>
+ * <li><tt>persistor_openjpa.properties</tt>
+ * <li><tt>persistor.properties</tt>
+ * <li><tt>isis.properties</tt>
+ * </ul>
+ * 
+ * <p>
+ * With respect to configuration, all properties under <tt>isis.persistor.openjpa.impl.</tt> prefix are passed thru verbatim to the OpenJPA runtime.
+ * For example:
+ * <table>
+ * <tr><th>Isis Property</th><th>OpenJPA Property</th></tr>
+ * <tr><td><tt>isis.persistor.openjpa.impl.openjpa.ConnectionURL</tt></td><td><tt>openjpa.ConnectionURL</tt></td></tr>
+ * <tr><td><tt>isis.persistor.openjpa.impl.openjpa.ConnectionDriverName</tt></td><td><tt>openjpa.ConnectionDriverName</tt></td></tr>
+ * <tr><td><tt>isis.persistor.openjpa.impl.openjpa.ConnectionUserName</tt></td><td><tt>openjpa.ConnectionUserName</tt></td></tr>
+ * <tr><td><tt>isis.persistor.openjpa.impl.openjpa.ConnectionPassword</tt></td><td><tt>openjpa.ConnectionPassword</tt></td></tr>
+ * </table>
+ *
+ */
 public class OpenJpaPersistenceMechanismInstaller extends PersistenceMechanismInstallerAbstract {
 
     public static final String NAME = "openjpa";
@@ -38,16 +59,10 @@ public class OpenJpaPersistenceMechanism
     @Override
     protected ObjectStore createObjectStore(IsisConfiguration configuration, ObjectAdapterFactory adapterFactory, AdapterManager adapterManager) {
         if(entityManagerFactory == null) {
-            Map<String,String> props = Maps.newHashMap();
-
-            props.put("openjpa.jdbc.SynchronizeMappings", "buildSchema");
-            props.put("openjpa.ConnectionURL", "jdbc:hsqldb:db/test");
-            props.put("openjpa.ConnectionDriverName", "org.hsqldb.jdbcDriver");
-            props.put("openjpa.ConnectionUserName", "sa");
-            props.put("openjpa.ConnectionPassword", "");
-            props.put("openjpa.Log", "DefaultLevel=WARN, Tool=INFO");
-            props.put("openjpa.RuntimeUnenhancedClasses", "supported"); // in production, should always pre-enhance using the maven openjpa plugin
             
+            final IsisConfiguration openJpaConfig = configuration.createSubset("isis.persistor.openjpa.impl");
+            
+            final Map<String, String> props = openJpaConfig.asMap();
             final String typeList = entityTypeList();
             props.put("openjpa.MetaDataFactory", "org.apache.openjpa.persistence.jdbc.PersistenceMappingFactory(types=" + typeList + ")");
             

Modified: incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/test/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstallerTest_openAndClose.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/test/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstallerTest_openAndClose.java?rev=1344049&r1=1344048&r2=1344049&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/test/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstallerTest_openAndClose.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/jpa/jpa-openjpa/src/test/java/org/apache/isis/runtimes/dflt/objectstores/jpa/openjpa/OpenJpaPersistenceMechanismInstallerTest_openAndClose.java Tue May 29 23:40:12 2012
@@ -1,15 +1,23 @@
 package org.apache.isis.runtimes.dflt.objectstores.jpa.openjpa;
 
-import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertThat;
 
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.List;
+import java.util.Properties;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.commons.config.IsisConfigurationDefault;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOidDefault;
@@ -27,15 +35,41 @@ public class OpenJpaPersistenceMechanism
     
     @Rule
     public IsisSystemWithFixtures iswf = IsisSystemWithFixtures.builder()
+        .with(configuration())
         .with(new JpaProgrammingModelFacets())
         .with(new JpaMetaModelValidator())
         .with(new OpenJpaPersistenceMechanismInstaller())
         .withServices(repo)
-        .build();
+        .with(hsqldbListener())
+        .build()
+        ;
+
+    private static IsisSystemWithFixtures.Listener hsqldbListener() {
+        return new IsisSystemWithFixtures.ListenerAdapter(){
+
+            @Override
+            public void postSetupSystem(boolean firstTime) throws Exception {
+                final OpenJpaObjectStore objectStore = (OpenJpaObjectStore) IsisContext.getPersistenceSession().getObjectStore();
+                Connection connection = objectStore.getConnection();
+                Statement statement = connection.createStatement();
+                statement.executeUpdate("DELETE FROM JPAPRIMITIVEVALUEDENTITY");
+            }
+        };
+    }
 
-    @Before
-    public void setUp() throws Exception {
-        
+    private static IsisConfiguration configuration() {
+        final IsisConfigurationDefault configuration = new IsisConfigurationDefault();
+        Properties props = new Properties();
+        props.put("isis.persistor.openjpa.impl.openjpa.jdbc.SynchronizeMappings", "buildSchema");
+        props.put("isis.persistor.openjpa.impl.openjpa.ConnectionURL", "jdbc:hsqldb:mem:test");
+        props.put("isis.persistor.openjpa.impl.openjpa.ConnectionDriverName", "org.hsqldb.jdbcDriver");
+        props.put("isis.persistor.openjpa.impl.openjpa.ConnectionUserName", "sa");
+        props.put("isis.persistor.openjpa.impl.openjpa.ConnectionPassword", "");
+        props.put("isis.persistor.openjpa.impl.openjpa.Log", "DefaultLevel=ERROR, Tool=INFO");
+        props.put("isis.persistor.openjpa.impl.openjpa.RuntimeUnenhancedClasses", "supported"); // in production, should always pre-enhance using the maven openjpa plugin
+
+        configuration.add(props);
+        return configuration;
     }
 
     @Test

Modified: incubator/isis/trunk/framework/runtimes/dflt/testsupport/src/main/java/org/apache/isis/runtimes/dflt/testsupport/IsisSystemWithFixtures.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/testsupport/src/main/java/org/apache/isis/runtimes/dflt/testsupport/IsisSystemWithFixtures.java?rev=1344049&r1=1344048&r2=1344049&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/testsupport/src/main/java/org/apache/isis/runtimes/dflt/testsupport/IsisSystemWithFixtures.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/testsupport/src/main/java/org/apache/isis/runtimes/dflt/testsupport/IsisSystemWithFixtures.java Tue May 29 23:40:12 2012
@@ -71,32 +71,55 @@ public class IsisSystemWithFixtures impl
 
     public interface Listener {
 
-        void preSetupSystem(boolean firstTime);
-        void postSetupSystem();
+        void init(IsisConfiguration configuration) throws Exception;
         
-        void preTeardownSystem();
-        void postTeardownSystem();
+        void preSetupSystem(boolean firstTime) throws Exception;
+        void postSetupSystem(boolean firstTime) throws Exception;
+        
+        void preBounceSystem() throws Exception;
+        void postBounceSystem() throws Exception;
+
+        void preTeardownSystem() throws Exception;
+        void postTeardownSystem() throws Exception;
         
     }
     
     public static abstract class ListenerAdapter implements Listener {
+        
+        private IsisConfiguration configuration;
+
+        public void init(IsisConfiguration configuration) throws Exception {
+            this.configuration = configuration;
+        }
+        
+        protected IsisConfiguration getConfiguration() {
+            return configuration;
+        }
 
         @Override
-        public void preSetupSystem(boolean firstTime) {
+        public void preSetupSystem(boolean firstTime) throws Exception {
         }
 
         @Override
-        public void postSetupSystem() {
+        public void postSetupSystem(boolean firstTime) throws Exception {
         }
 
         @Override
-        public void preTeardownSystem() {
+        public void preBounceSystem() throws Exception {
         }
 
         @Override
-        public void postTeardownSystem() {
+        public void postBounceSystem() throws Exception {
         }
-        
+
+        @Override
+        public void preTeardownSystem() throws Exception {
+        }
+
+        @Override
+        public void postTeardownSystem() throws Exception {
+        }
+
     }
 
 
@@ -276,10 +299,16 @@ public class IsisSystemWithFixtures impl
      * Intended to be called from a test's {@link Before} method.
      */
     public void setUpSystem() throws Exception {
+        setUpSystem(FireListeners.FIRE);
+    }
+
+    private void setUpSystem(FireListeners fireListeners) throws Exception {
         Logger.getRootLogger().setLevel(Level.OFF);
 
         boolean firstTime = isisSystem == null;
-        firePreSetupSystem(firstTime);
+        if(fireListeners.shouldFire()) {
+            fireInitAndPreSetupSystem(firstTime);
+        }
         
         if(firstTime) {
             isisSystem = createIsisSystem(services);
@@ -295,10 +324,19 @@ public class IsisSystemWithFixtures impl
         if(firstTime && fixturesInitialization == Fixtures.Initialization.INIT) {
             fixtures.init(container);
         }
-        firePostSetupSystem(firstTime);
+        if(fireListeners.shouldFire()) {
+            firePostSetupSystem(firstTime);
+        }
     }
 
-
+    private enum FireListeners {
+        FIRE,
+        DONT_FIRE;
+        public boolean shouldFire() {
+            return this == FIRE;
+        }
+    }
+    
     private DomainObjectContainer getContainer() {
         return IsisContext.getPersistenceSession().getServicesInjector().getContainer();
     }
@@ -307,14 +345,24 @@ public class IsisSystemWithFixtures impl
      * Intended to be called from a test's {@link After} method.
      */
     public void tearDownSystem() throws Exception {
-        firePreTeardownSystem();
+        tearDownSystem(FireListeners.FIRE);
+    }
+
+    private void tearDownSystem(final FireListeners fireListeners) throws Exception {
+        if(fireListeners.shouldFire()) {
+            firePreTeardownSystem();
+        }
         IsisContext.closeSession();
-        firePostTeardownSystem();
+        if(fireListeners.shouldFire()) {
+            firePostTeardownSystem();
+        }
     }
 
     public void bounceSystem() throws Exception {
-        tearDownSystem();
-        setUpSystem();
+        firePreBounceSystem();
+        tearDownSystem(FireListeners.DONT_FIRE);
+        setUpSystem(FireListeners.DONT_FIRE);
+        firePostBounceSystem();
     }
 
 
@@ -360,30 +408,47 @@ public class IsisSystemWithFixtures impl
     // listeners
     ////////////////////////////////////////////////////////////
 
-    private void firePreSetupSystem(boolean firstTime) {
+    private void fireInitAndPreSetupSystem(boolean firstTime) throws Exception {
+        if(firstTime) {
+            for(Listener listener: listeners) {
+                listener.init(configuration);
+            }
+        }
         for(Listener listener: listeners) {
             listener.preSetupSystem(firstTime);
         }
     }
 
-    private void firePostSetupSystem(boolean firstTime) {
+    private void firePostSetupSystem(boolean firstTime) throws Exception {
         for(Listener listener: listeners) {
-            listener.preSetupSystem(firstTime);
+            listener.postSetupSystem(firstTime);
         }
     }
 
-    private void firePreTeardownSystem() {
+    private void firePreTeardownSystem() throws Exception {
         for(Listener listener: listeners) {
             listener.preTeardownSystem();
         }
     }
 
-    private void firePostTeardownSystem() {
+    private void firePostTeardownSystem() throws Exception {
         for(Listener listener: listeners) {
             listener.postTeardownSystem();
         }
     }
 
+    private void firePreBounceSystem() throws Exception {
+        for(Listener listener: listeners) {
+            listener.preBounceSystem();
+        }
+    }
+
+    private void firePostBounceSystem() throws Exception {
+        for(Listener listener: listeners) {
+            listener.postBounceSystem();
+        }
+    }
+
     
     ////////////////////////////////////////////////////////////
     // properties
@@ -493,8 +558,14 @@ public class IsisSystemWithFixtures impl
                 setUpSystem();
                 try {
                     base.evaluate();
-                } finally {
                     tearDownSystem();
+                } catch(Throwable ex) {
+                    try {
+                        tearDownSystem();
+                    } catch(Exception ex2) {
+                        // ignore, since already one pending
+                    }
+                    throw ex;
                 }
             }
         };