onami-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sclas...@apache.org
Subject svn commit: r1542116 [2/3] - in /onami/sandbox/persist: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/onami/ src/main/java/org/apache/onami/persist/ src/test/ src/test/java/ src/test/java/org/ sr...
Date Thu, 14 Nov 2013 23:19:37 GMT
Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceModule.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceModule.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceModule.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceModule.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,264 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import com.google.inject.AbstractModule;
+import com.google.inject.matcher.Matcher;
+import com.google.inject.matcher.Matchers;
+import org.aopalliance.intercept.MethodInterceptor;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.transaction.UserTransaction;
+import java.lang.reflect.AnnotatedElement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.apache.onami.persist.Preconditions.checkNotNull;
+import static com.google.inject.matcher.Matchers.any;
+
+/**
+ * Main module of the jpa-persistence guice extension.
+ * <p/>
+ * Add either a {@link ApplicationManagedPersistenceUnitModule} or a
+ * {@link ContainerManagedPersistenceUnitModule} per persistence unit using the methods
+ * <ul>
+ * <li>{@link #add(ApplicationManagedPersistenceUnitModule)}</li>
+ * <li>{@link #addApplicationManagedPersistenceUnit(String)}</li>
+ * <li>{@link #addApplicationManagedPersistenceUnit(String, Properties)}</li>
+ * <li>{@link #add(ContainerManagedPersistenceUnitModule)}</li>
+ * <li>{@link #addContainerManagedPersistenceUnit(String)}</li>
+ * <li>{@link #addContainerManagedPersistenceUnit(String, Properties)}</li>
+ * </ul>
+ * <p/>
+ * If container managed persistence units have been added and JTA transactions are supported.
+ * Use {@link #setUserTransactionJndiName(String)} to define the JNDI name of the
+ * {@link UserTransaction} provided by the container.
+ */
+public final class PersistenceModule
+    extends AbstractModule
+{
+
+    // ---- Members
+
+    /**
+     * List of all module builders.
+     */
+    private final List<PersistenceUnitBuilder> moduleBuilders = new ArrayList<PersistenceUnitBuilder>();
+
+    /**
+     * List of all persistence unit modules.
+     * If this list is empty it means that configure has not yet been called
+     */
+    private final List<AbstractPersistenceUnitModule> modules = new ArrayList<AbstractPersistenceUnitModule>();
+
+    /**
+     * Container for holding all registered persistence units.
+     */
+    private final PersistenceUnitContainer puContainer = new PersistenceUnitContainer();
+
+    /**
+     * The JNDI name to lookup the {@link UserTransaction}.
+     */
+    private String utJndiName;
+
+    /**
+     * The {@link UserTransactionFacade}.
+     */
+    private UserTransactionFacade utFacade = null;
+
+    // ---- Methods
+
+    /**
+     * Adds an application managed persistence unit.
+     *
+     * @param puName the name of the persistence unit as specified in the persistence.xml. Must not be {@code null}.
+     * @return a builder to further configure the persistence unit.
+     */
+    public PersistenceUnitBuilder addApplicationManagedPersistenceUnit( String puName )
+    {
+        checkNotNull( puName );
+        return add( new ApplicationManagedPersistenceUnitModule( puName ) );
+    }
+
+    /**
+     * Adds an application managed persistence unit.
+     *
+     * @param puName     the name of the persistence unit as specified in the persistence.xml. Must not be {@code null}.
+     * @param properties the properties to pass to the {@link EntityManagerFactory}. Must not be {@code null}.
+     * @return a builder to further configure the persistence unit.
+     */
+    public PersistenceUnitBuilder addApplicationManagedPersistenceUnit( String puName, Properties properties )
+    {
+        checkNotNull( puName );
+        checkNotNull( properties );
+        return add( new ApplicationManagedPersistenceUnitModule( puName, properties ) );
+    }
+
+    /**
+     * Adds an application managed persistence unit.
+     *
+     * @param module the module of the persistence unit. Must not be {@code null}.
+     * @return a builder to further configure the persistence unit.
+     */
+    public PersistenceUnitBuilder add( ApplicationManagedPersistenceUnitModule module )
+    {
+        ensureConfigurHasNotYetBeenExecuted();
+        checkNotNull( module );
+        final PersistenceUnitBuilder builder = new PersistenceUnitBuilder( module );
+        moduleBuilders.add( builder );
+        return builder;
+    }
+
+    /**
+     * Adds an container managed persistence unit.
+     *
+     * @param emfJndiName the JNDI name of the {@link EntityManagerFactory}. Must not be {@code null}.
+     * @return a builder to further configure the persistence unit.
+     */
+    public PersistenceUnitBuilder addContainerManagedPersistenceUnit( String emfJndiName )
+    {
+        checkNotNull( emfJndiName );
+        return add( new ContainerManagedPersistenceUnitModule( emfJndiName ) );
+    }
+
+    /**
+     * Adds an container managed persistence unit.
+     *
+     * @param emfJndiName the JNDI name of the {@link EntityManagerFactory}. Must not be {@code null}.
+     * @param properties  the properties to pass to the {@link EntityManager}. Must not be {@code null}.
+     * @return a builder to further configure the persistence unit.
+     */
+    public PersistenceUnitBuilder addContainerManagedPersistenceUnit( String emfJndiName, Properties properties )
+    {
+        checkNotNull( emfJndiName );
+        checkNotNull( properties );
+        return add( new ContainerManagedPersistenceUnitModule( emfJndiName, properties ) );
+    }
+
+    /**
+     * Adds an container managed persistence unit.
+     *
+     * @param module the module of the persistence unit. Must not be {@code null}.
+     * @return a builder to further configure the persistence unit.
+     */
+    public PersistenceUnitBuilder add( ContainerManagedPersistenceUnitModule module )
+    {
+        ensureConfigurHasNotYetBeenExecuted();
+        checkNotNull( module );
+        final PersistenceUnitBuilder builder = new PersistenceUnitBuilder( module );
+        moduleBuilders.add( builder );
+        return builder;
+    }
+
+    /**
+     * Setter for defining the JNDI name of the container managed {@link UserTransaction}.
+     *
+     * @param utJndiName the JNDI name of the container managed {@link UserTransaction}.
+     */
+    public void setUserTransactionJndiName( String utJndiName )
+    {
+        ensureConfigurHasNotYetBeenExecuted();
+        this.utJndiName = utJndiName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void configure()
+    {
+        if ( configureHasNotBeenExecutedYet() )
+        {
+            if ( 0 == moduleBuilders.size() )
+            {
+                addError( "no persistence units defined. At least one persistence unit is required." );
+                return;
+            }
+            initUserTransactionFacade();
+            for ( PersistenceUnitBuilder builder : moduleBuilders )
+            {
+                final AbstractPersistenceUnitModule module = builder.build();
+                puContainer.add( module.getPersistenceService(), module.getUnitOfWork() );
+                modules.add( module );
+            }
+        }
+
+        for ( AbstractPersistenceUnitModule module : modules )
+        {
+            install( module );
+
+            final Matcher<AnnotatedElement> matcher = Matchers.annotatedWith( Transactional.class );
+            final MethodInterceptor transactionInterceptor = module.getTransactionInterceptor( utFacade );
+
+            bindInterceptor( matcher, any(), transactionInterceptor );
+            bindInterceptor( any(), matcher, transactionInterceptor );
+        }
+
+        bind( PersistenceService.class ).annotatedWith( AllPersistenceUnits.class ).toInstance( puContainer );
+        bind( UnitOfWork.class ).annotatedWith( AllPersistenceUnits.class ).toInstance( puContainer );
+        bind( PersistenceFilter.class ).toInstance( new PersistenceFilter( puContainer ) );
+    }
+
+    /**
+     * @return {@code true} if {@link #configure()} has not yet been invoked.
+     */
+    private boolean configureHasNotBeenExecutedYet()
+    {
+        return modules.size() == 0;
+    }
+
+    /**
+     * Make sure that the {@link #configure()} method has not been executed yet.
+     */
+    private void ensureConfigurHasNotYetBeenExecuted()
+    {
+        if ( configureHasNotBeenExecutedYet() )
+        {
+            return;
+        }
+        throw new IllegalStateException( "cannot change a module after creating the injector." );
+    }
+
+    /**
+     * Initializes the field {@link #utFacade} with the {@link UserTransaction} obtained by a
+     * JNDI lookup.
+     */
+    private void initUserTransactionFacade()
+    {
+        if ( null != utJndiName )
+        {
+            try
+            {
+                final InitialContext ctx = new InitialContext();
+                final UserTransaction txn = (UserTransaction) ctx.lookup( utJndiName );
+                utFacade = new UserTransactionFacade( txn );
+            }
+            catch ( NamingException e )
+            {
+                addError( "lookup for UserTransaction with JNDI name '%s' failed", utJndiName );
+            }
+        }
+    }
+
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceModule.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceModule.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceModule.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceService.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceService.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceService.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceService.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,56 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is the main control to the entire persistence engine. Before calling any other method
+ * of either {@link UnitOfWork}, {@link EntityManagerProvider}, or any method annotated with
+ * @{@link Transactional} the persistence service must be started.
+ */
+public interface PersistenceService
+{
+
+    /**
+     * Starts the underlying persistence engine and makes jpa-persist ready for use.
+     * This method must be called by your code prior to using any other jpa-persist artifacts.
+     * If you are using jpa-persist in a web container {@link PersistenceFilter} will call this
+     * method upon initialization of the web application.
+     *
+     * @throws IllegalArgumentException if the service is already running.
+     */
+    void start()
+        throws IllegalArgumentException;
+
+    /**
+     * @return {@code true} if the underlying persistence engine is running.
+     *         {@code false} otherwise.
+     */
+    boolean isRunning();
+
+    /**
+     * Stops the underlying persistence engine.
+     * <ul>
+     * <li>If already stopped, calling this method does nothing.</li>
+     * <li>If not yet started, it also does nothing.</li>
+     * </ul>
+     */
+    void stop();
+
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceService.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceService.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitBuilder.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitBuilder.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitBuilder.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitBuilder.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,102 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import java.lang.annotation.Annotation;
+
+import static org.apache.onami.persist.Preconditions.checkNotNull;
+
+/**
+ * Builder class for configurating a guice-jpa persistence unit.
+ */
+public final class PersistenceUnitBuilder
+{
+
+    // ---- Members
+
+    /**
+     * The module which is built by this instance.
+     */
+    private AbstractPersistenceUnitModule module;
+
+    // ---- Constructors
+
+    /**
+     * Constructor.
+     *
+     * @param module the module which is built by this instance.
+     */
+    PersistenceUnitBuilder( AbstractPersistenceUnitModule module )
+    {
+        this.module = module;
+    }
+
+    // ---- Methods
+
+    /**
+     * Add an annotation to the module. The annotation is used to bind the {@link UnitOfWork} and
+     * the {@link EntityManagerProvider} in guice.
+     *
+     * @param annotation the annotation. May be {@code null}.
+     * @return the builder for method chaining.
+     */
+    public PersistenceUnitBuilder annotatedWith( Class<? extends Annotation> annotation )
+    {
+        checkNotNull( module, "cannot change a module after creating the injector." );
+        module.annotatedWith( annotation );
+        return this;
+    }
+
+    /**
+     * Configure the persistence unit to use local transactions. This means even if the data source
+     * is managed by the container its transaction will not participate in a global container managed
+     * transaction (CMT).
+     */
+    public void useResourceLocalTransaction()
+    {
+        checkNotNull( module, "cannot change a module after creating the injector." );
+        module.setTransactionType( TransactionType.RESOURCE_LOCAL );
+    }
+
+    /**
+     * Configure the persistence unit to use global transactions. This means all transactions on this
+     * data source will participate in a global container managed transaction (CMT)
+     */
+    public void useJtaTransaction()
+    {
+        checkNotNull( module, "cannot change a module after creating the injector." );
+        module.setTransactionType( TransactionType.JTA );
+    }
+
+    /**
+     * Builds the module and also changes the state of the builder.
+     * After calling this method all calls to the builder will result in an exception.
+     *
+     * @return the persistence module.
+     */
+    AbstractPersistenceUnitModule build()
+    {
+        checkNotNull( module, "build() can only be called once." );
+        final AbstractPersistenceUnitModule m = module;
+        module = null;
+        return m;
+    }
+
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitBuilder.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitBuilder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitContainer.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitContainer.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitContainer.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitContainer.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,145 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.apache.onami.persist.Preconditions.checkNotNull;
+
+/**
+ * Container of persistence units. This is a convenience wrapper for multiple
+ * persistence units. calling any method of either {@link PersistenceService} or
+ * {@link UnitOfWork} will propagate this call to all added persistence units.
+ */
+class PersistenceUnitContainer
+    implements PersistenceService, UnitOfWork
+{
+
+    // ---- Members
+
+    /**
+     * Collection of all known persistence services.
+     */
+    private final Set<PersistenceService> persistenceServices = new HashSet<PersistenceService>();
+
+    /**
+     * Collection of all known units of work.
+     */
+    private final Set<UnitOfWork> unitsOfWork = new HashSet<UnitOfWork>();
+
+    // ---- Methods
+
+    /**
+     * Adds a persistence service and a unit of work to this container.
+     *
+     * @param ps  the persistence service to add. Must not be {@code null}.
+     * @param uow the unit of work to add. Must not be {@code null}.
+     */
+    void add( PersistenceService ps, UnitOfWork uow )
+    {
+        checkNotNull( ps );
+        checkNotNull( uow );
+        persistenceServices.add( ps );
+        unitsOfWork.add( uow );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public synchronized void start()
+    {
+        for ( PersistenceService ps : persistenceServices )
+        {
+            ps.start();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public synchronized boolean isRunning()
+    {
+        for ( PersistenceService ps : persistenceServices )
+        {
+            if ( !ps.isRunning() )
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public synchronized void stop()
+    {
+        for ( PersistenceService ps : persistenceServices )
+        {
+            ps.stop();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public void begin()
+    {
+        for ( UnitOfWork unitOfWork : unitsOfWork )
+        {
+            unitOfWork.begin();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public boolean isActive()
+    {
+        for ( UnitOfWork unitOfWork : unitsOfWork )
+        {
+            if ( !unitOfWork.isActive() )
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    // @Override
+    public void end()
+    {
+        for ( UnitOfWork unitOfWork : unitsOfWork )
+        {
+            unitOfWork.end();
+        }
+
+    }
+
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitContainer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitContainer.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/PersistenceUnitContainer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/Preconditions.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/Preconditions.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/Preconditions.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/Preconditions.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,58 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+/**
+ * Checks to ensure arguments are in a valid state.
+ */
+class Preconditions
+{
+
+    /**
+     * Check that a reference is not null.
+     *
+     * @param <T> the type of the reference
+     * @param reference the reference to check.
+     * @return the reference itself.
+     * @throws NullPointerException if the reference is null.
+     */
+    static <T> T checkNotNull(T reference) {
+        if (reference == null) {
+            throw new NullPointerException(  );
+        }
+        return reference;
+    }
+
+    /**
+     * Check that a reference is not null.
+     *
+     * @param <T> the type of the reference
+     * @param reference the reference to check.
+     * @param message the message of the NullPointerException if one is thrown.
+     * @return the reference itself.
+     * @throws NullPointerException if the reference is null.
+     */
+    static <T> T checkNotNull(T reference, String message) {
+        if (reference == null) {
+            throw new NullPointerException( message );
+        }
+        return reference;
+    }
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/Preconditions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/Preconditions.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/Preconditions.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/ResourceLocalTxnInterceptor.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/ResourceLocalTxnInterceptor.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/ResourceLocalTxnInterceptor.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/ResourceLocalTxnInterceptor.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,166 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import org.aopalliance.intercept.MethodInterceptor;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import java.lang.annotation.Annotation;
+
+import static org.apache.onami.persist.Preconditions.checkNotNull;
+
+/**
+ * {@link MethodInterceptor} for intercepting methods of persistence units of type RESOURCE_LOCAL.
+ */
+class ResourceLocalTxnInterceptor
+    extends AbstractTxnInterceptor
+{
+
+    // ---- Constructor
+
+    /**
+     * Constructor.
+     *
+     * @param emProvider   the provider for {@link EntityManager}. Must not be {@code null}.
+     * @param puAnntoation the annotation of the persistence unit this interceptor belongs to.
+     */
+    public ResourceLocalTxnInterceptor( EntityManagerProviderImpl emProvider, Class<? extends Annotation> puAnntoation )
+    {
+        super( emProvider, emProvider, puAnntoation );
+        checkNotNull( emProvider );
+    }
+
+    // ---- Methods
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected TransactionFacade getTransactionFacade( final EntityManager em )
+    {
+        final EntityTransaction txn = em.getTransaction();
+        if ( txn.isActive() )
+        {
+            return new InnerTransaction( txn );
+        }
+        return new OuterTransaction( txn );
+    }
+
+    // ---- Inner Classes
+
+    /**
+     * TransactionFacade representing an inner (nested) transaction.
+     * Starting and committing a transaction has no effect.
+     * This Facade will set the rollbackOnly flag in case of a roll back.
+     */
+    private static class InnerTransaction
+        implements TransactionFacade
+    {
+        private final EntityTransaction txn;
+
+        InnerTransaction( EntityTransaction txn )
+        {
+            this.txn = txn;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        // @Override
+        public void begin()
+        {
+            // Do nothing
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        // @Override
+        public void commit()
+        {
+            // Do nothing
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        // @Override
+        public void rollback()
+        {
+            txn.setRollbackOnly();
+        }
+    }
+
+    /**
+     * TransactionFacade representing an outer transaction.
+     * This Facade starts and ends the transaction.
+     * If an inner transaction has set the rollbackOnly flag the transaction will be rolled back
+     * in any case.
+     */
+    private static class OuterTransaction
+        implements TransactionFacade
+    {
+        private final EntityTransaction txn;
+
+        /**
+         * {@inheritDoc}
+         */
+        OuterTransaction( EntityTransaction txn )
+        {
+            this.txn = txn;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        // @Override
+        public void begin()
+        {
+            txn.begin();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        // @Override
+        public void commit()
+        {
+            if ( txn.getRollbackOnly() )
+            {
+                txn.rollback();
+            }
+            else
+            {
+                txn.commit();
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        // @Override
+        public void rollback()
+        {
+            txn.rollback();
+        }
+    }
+
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/ResourceLocalTxnInterceptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/ResourceLocalTxnInterceptor.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/ResourceLocalTxnInterceptor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionFacade.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionFacade.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionFacade.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionFacade.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,57 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import javax.persistence.EntityTransaction;
+import javax.transaction.UserTransaction;
+
+/**
+ * Interface which hides away the details of inner (nested) and outer transactions as well
+ * as the details between {@link EntityTransaction} and {@link UserTransaction}.
+ */
+interface TransactionFacade
+{
+
+    /**
+     * Starts a transaction.
+     * <p/>
+     * The first call to begin will start the actual transaction. Subsequent calls will start a
+     * 'nested' transaction.
+     */
+    void begin();
+
+    /**
+     * Commits a transaction.
+     * <p/>
+     * Only the actual transaction can be committed. Calls to commit on nested transactions have
+     * no effect.
+     */
+    void commit();
+
+    /**
+     * Rolls a transaction back.
+     * <p/>
+     * Only the actual transaction can be rolled back. Calls to rollback on nested transactions will
+     * set the onlyRollBack flag on the actual transaction. Setting this flag wil cause an actual
+     * transaction to be rolled back in any case.
+     */
+    void rollback();
+
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionFacade.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionFacade.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionFacade.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionType.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionType.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionType.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionType.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,37 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+/**
+ * Type of a transaction.
+ */
+enum TransactionType
+{
+
+    /**
+     * A transaction which is local to the application and is not managed by a container.
+     */
+    RESOURCE_LOCAL,
+
+    /**
+     * A transaction which is global and is managed by a container.
+     */
+    JTA
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionType.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionType.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/Transactional.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/Transactional.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/Transactional.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/Transactional.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,76 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a method or class to be executed within a transaction.
+ * <p/>
+ * This will span a new transaction around the method unless there is already a running transaction.
+ * In the case that there is a running transaction no new transaction is started.
+ * If a rollback happens for a method which did not start the transaction the already existing
+ * transaction will be marked as rollbackOnly.
+ * <p/>
+ * Guice uses AOP to enhance a method annotated with @{@link Transactional} with a wrapper.
+ * This means the @{@link Transactional} only works as expected when:
+ * <ul>
+ * <li>
+ * The object on which the method is called has been created by guice.
+ * This can be achieved by having it (or a {@link Provider}) injected into your class
+ * or by calling {@link Injector#getInstance(Class)} or {@link Injector#getInstance(Key)}.
+ * </li>
+ * <li>
+ * The method which should be run transactional is not private and not final
+ * </li>
+ * </ul>
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface Transactional
+{
+
+    /**
+     * A List of annotations for persistence units on which to start a transaction.
+     * Default is on all persistence units.
+     */
+    Class<? extends Annotation>[] onUnits() default { };
+
+    /**
+     * A list of exceptions to rollback on. Default is {@link RuntimeException}.
+     */
+    Class<? extends Exception>[] rollbackOn() default RuntimeException.class;
+
+    /**
+     * A list of exceptions to <b>not<b> rollback on. Use this to exclude one ore more subclasses of
+     * the exceptions defined in rollbackOn(). Default is none.
+     */
+    Class<? extends Exception>[] ignore() default { };
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/Transactional.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/Transactional.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/Transactional.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionalAnnotationReader.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionalAnnotationReader.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionalAnnotationReader.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionalAnnotationReader.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,96 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.reflect.Method;
+
+/**
+ * Reader which obtains the concrete @{@link Transactional} annotation on a method. The reader may use some sort of
+ * caching.
+ */
+class TransactionalAnnotationReader
+{
+    private static final Transactional DEFAULT_TRANSACTIONAL = DefaultTransactional.class.getAnnotation( Transactional.class );
+
+    /**
+     * cache for {@link Transactional} annotations per method.
+     */
+    final TransactionalCache transactionalCache = new TransactionalCache();
+
+
+    /**
+     * Reads the @{@link Transactional} of a given method invocation.
+     *
+     * @param methodInvocation the method invocation for which to obtain the @{@link Transactional}.
+     * @return the @{@link Transactional} of the given method invocation. Never {@code null}.
+     */
+    Transactional readAnnotationFrom( MethodInvocation methodInvocation )
+    {
+        final Method method = methodInvocation.getMethod();
+        Transactional result;
+
+        result = transactionalCache.get( method );
+        if ( null == result )
+        {
+            result = getTransactional( methodInvocation, method );
+            transactionalCache.put( method, result );
+        }
+        return result;
+    }
+
+    private Transactional getTransactional( MethodInvocation methodInvocation, Method method )
+    {
+        Transactional result;
+        result = method.getAnnotation( Transactional.class );
+        if ( null == result )
+        {
+            final Class<?> targetClass = methodInvocation.getThis().getClass();
+            result = targetClass.getAnnotation( Transactional.class );
+        }
+        if ( null == result )
+        {
+            result = DEFAULT_TRANSACTIONAL;
+        }
+        return result;
+    }
+
+    /**
+     * Helper class for obtaining the default of @{@link Transactional}.
+     */
+    @Transactional
+    private static class DefaultTransactional
+    {
+    }
+
+    private static class TransactionalCache
+    {
+        Transactional get( Method method )
+        {
+            return null;
+        }
+
+        void put( Method method, Transactional annotation )
+        {
+            // nop
+        }
+    }
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionalAnnotationReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionalAnnotationReader.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/TransactionalAnnotationReader.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/UnitOfWork.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/UnitOfWork.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/UnitOfWork.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/UnitOfWork.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,84 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import javax.persistence.EntityManager;
+
+/**
+ * The Unit of work correlates with the life cycle of the {@link EntityManager}.
+ * According to JPA every thread should use its own {@link EntityManager}. Therefore the unit of
+ * work will control the life cycle of the {@link EntityManager} on a per thread basis. This means
+ * the UnitOfWork is thread safe.
+ * <p/>
+ * Most of the time it is not recommended to manual control the unit of work.
+ * <p/>
+ * For applications running in a container the {@link PersistenceFilter} is recommended.
+ * It will start a unit of work for every incoming request and properly close it at the end.
+ * <p/>
+ * For stand alone application it is recommended to relay on the @{@link Transactional} annotation.
+ * The transaction handler will automatically span a unit of work around a transaction.
+ * <p/>
+ * The most likely scenario in which one would want to take manual control over the unit of work
+ * is in a background thread within a container (i.e. timer triggered jobs).
+ * <p/>
+ * Recommended pattern:
+ * <pre>
+ * public void someMethod() {
+ *   final boolean unitOfWorkWasInactive = ! unitOfWork.isActive();
+ *   if (unitOfWorkWasInactive) {
+ *     unitOfWork.begin();
+ *   }
+ *   try {
+ *     // do work
+ *   }
+ *   finally {
+ *     if (unitOfWorkWasInactive) {
+ *       unitOfWork.end();
+ *     }
+ *   }
+ * }
+ * </pre>
+ */
+public interface UnitOfWork
+{
+
+    /**
+     * Starts the unit of work.
+     * When the unit of work has already been started for the current thread an
+     * {@link IllegalStateException} is thrown.
+     *
+     * @throws IllegalStateException if the unit of work is already running for this thread.
+     */
+    void begin()
+        throws IllegalStateException;
+
+    /**
+     * @return {@code true} if the unit of work is already running for this thread
+     *         {@code false} otherwise.
+     */
+    boolean isActive();
+
+    /**
+     * Stops the unit of work.
+     * When the unit of work is not active this method will do nothing.
+     */
+    void end();
+
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/UnitOfWork.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/UnitOfWork.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/UnitOfWork.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/main/java/org/apache/onami/persist/UserTransactionFacade.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/main/java/org/apache/onami/persist/UserTransactionFacade.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/main/java/org/apache/onami/persist/UserTransactionFacade.java (added)
+++ onami/sandbox/persist/src/main/java/org/apache/onami/persist/UserTransactionFacade.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,195 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.UserTransaction;
+
+import static org.apache.onami.persist.Preconditions.checkNotNull;
+
+/**
+ * Facade to the {@link UserTransaction} which wraps all checked exception into runtime exceptions.
+ */
+class UserTransactionFacade
+{
+
+    // ---- Members
+
+    private final UserTransaction txn;
+
+    // ---- Constructor
+
+    /**
+     * Constructor.
+     *
+     * @param txn the actual user transaction to facade. Must not be {@code null}.
+     */
+    UserTransactionFacade( UserTransaction txn )
+    {
+        checkNotNull( txn );
+        this.txn = txn;
+    }
+
+    // ---- Methods
+
+    /**
+     * @see {@link UserTransaction#begin()}.
+     */
+    void begin()
+    {
+        try
+        {
+            txn.begin();
+        }
+        catch ( NotSupportedException e )
+        {
+            throw new RuntimeException( "nested transactions are not supported by the user transaction " + txn, e );
+        }
+        catch ( SystemException e )
+        {
+            throw new RuntimeException( "unexpected error occured", e );
+        }
+    }
+
+    /**
+     * @see {@link UserTransaction#commit()}.
+     */
+    void commit()
+    {
+        try
+        {
+            txn.commit();
+        }
+        catch ( SecurityException e )
+        {
+            throw new RuntimeException( "not allowed to commit the transaction", e );
+        }
+        catch ( IllegalStateException e )
+        {
+            throw new RuntimeException( "no transaction associated with userTransaction", e );
+        }
+        catch ( RollbackException e )
+        {
+            throw new RuntimeException( "rollback during commit", e );
+        }
+        catch ( HeuristicMixedException e )
+        {
+            throw new RuntimeException( "heuristic partial rollback during commit", e );
+        }
+        catch ( HeuristicRollbackException e )
+        {
+            throw new RuntimeException( "heuristic rollback during commit", e );
+        }
+        catch ( SystemException e )
+        {
+            throw new RuntimeException( "unexpected error occured", e );
+        }
+    }
+
+    /**
+     * @see {@link UserTransaction#rollback()}.
+     */
+    void rollback()
+    {
+        try
+        {
+            txn.rollback();
+        }
+        catch ( IllegalStateException e )
+        {
+            throw new RuntimeException( "no transaction associated with userTransaction", e );
+        }
+        catch ( SecurityException e )
+        {
+            throw new RuntimeException( "not allowed to rollback the transaction", e );
+        }
+        catch ( SystemException e )
+        {
+            throw new RuntimeException( "unexpected error occured", e );
+        }
+    }
+
+    /**
+     * @see {@link UserTransaction#setRollbackOnly()}.
+     */
+    void setRollbackOnly()
+    {
+        try
+        {
+            txn.setRollbackOnly();
+        }
+        catch ( IllegalStateException e )
+        {
+            throw new RuntimeException( "no transaction associated with userTransaction", e );
+        }
+        catch ( SystemException e )
+        {
+            throw new RuntimeException( "unexpected error occured", e );
+        }
+    }
+
+    /**
+     * @see {@link UserTransaction#getStatus()}.
+     */
+    int getStatus()
+    {
+        try
+        {
+            int status = txn.getStatus();
+            for ( int i = 0; Status.STATUS_UNKNOWN == status && i < 5; i++ )
+            {
+                try
+                {
+                    Thread.sleep( 30L );
+                }
+                catch ( InterruptedException e )
+                {
+                    // do nothing
+                }
+                status = txn.getStatus();
+            }
+            return status;
+        }
+        catch ( SystemException e )
+        {
+            throw new RuntimeException( "unexpected error occured", e );
+        }
+    }
+
+    /**
+     * @see {@link UserTransaction#setTransactionTimeout(int)}.
+     */
+    void setTransactionTimeout( int seconds )
+    {
+        try
+        {
+            txn.setTransactionTimeout( seconds );
+        }
+        catch ( SystemException e )
+        {
+            throw new RuntimeException( "unexpected error occured", e );
+        }
+    }
+}

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/UserTransactionFacade.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/UserTransactionFacade.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/main/java/org/apache/onami/persist/UserTransactionFacade.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/NestedTransactionTest.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/NestedTransactionTest.java?rev=1542116&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/NestedTransactionTest.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/NestedTransactionTest.java Thu Nov 14 23:19:36 2013
@@ -0,0 +1,432 @@
+package org.apache.onami.persist;
+
+/*
+ * 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.
+ */
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import junit.framework.TestCase;
+import org.apache.onami.persist.testframework.TransactionalTask;
+import org.apache.onami.persist.testframework.TransactionalWorker;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnAnyThrowingNone;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnAnyThrowingRuntimeTestException;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnAnyThrowingTestException;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnNoneThrowingNone;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnNoneThrowingRuntimeTestException;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnNoneThrowingTestException;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingNone;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingTestException;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnTestExceptionThrowingNone;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnTestExceptionThrowingRuntimeTestException;
+import org.apache.onami.persist.testframework.tasks.TaskRollingBackOnTestExceptionThrowingTestException;
+
+/**
+ * Tests running nested transactions.
+ * The test make us of the testframework.
+ * Since the test is running a loop only the injector is created directly in the test to ensure
+ * that for every {@link TestVector} a new injector instance is used.
+ */
+public class NestedTransactionTest
+    extends TestCase
+{
+
+    /**
+     * All possible combination of {@link TransactionalTask}s
+     * and if they should have been rolled back.
+     */
+    private static final TestVector[] TEST_VECTORS =
+        { new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnAnyThrowingTestException.class,
+                            true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnNoneThrowingTestException.class,
+                            true ), new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                                                    TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnTestExceptionThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                                                     TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                                                     true ), new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                                                                             TaskRollingBackOnTestExceptionThrowingTestException.class,
+                                                                             true ),
+
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class, TaskRollingBackOnAnyThrowingNone.class,
+                            true ), new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                                                    TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class, TaskRollingBackOnNoneThrowingNone.class,
+                            true ), new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                                                    TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnAnyThrowingTestException.class,
+                            true ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnNoneThrowingTestException.class,
+                            false ), new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                                                     TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnTestExceptionThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                                                     TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                                                     false ), new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                                                                              TaskRollingBackOnTestExceptionThrowingTestException.class,
+                                                                              true ),
+
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class, TaskRollingBackOnAnyThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                                                     TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class, TaskRollingBackOnNoneThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                                                     TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class, TaskRollingBackOnAnyThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                                                     TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class, TaskRollingBackOnNoneThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                                                     TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ), };
+
+    /**
+     * Test which iterates over ALL possible combinations of inner and outer tasks.
+     */
+    public void testNestedTransactions()
+    {
+        final StringBuilder msg = new StringBuilder();
+        for ( TestVector v : TEST_VECTORS )
+        {
+            try
+            {
+                doTestNestedTransaction( v );
+            }
+            catch ( AssertionError e )
+            {
+                msg.append( "\n" );
+                msg.append( e.getMessage() );
+            }
+        }
+        if ( msg.length() > 0 )
+        {
+            fail( msg.toString() );
+        }
+    }
+
+    private void doTestNestedTransaction( TestVector testVector )
+    {
+        final PersistenceModule pm = new PersistenceModule();
+        pm.addApplicationManagedPersistenceUnit( "testUnit" );
+        final Injector injector = Guice.createInjector( pm );
+        final PersistenceService persistService = injector.getInstance( PersistenceService.class );
+        persistService.start();
+        try
+        {
+            // given
+            final TransactionalWorker worker = injector.getInstance( TransactionalWorker.class );
+            worker.scheduleTask( testVector.getOuterTask() );
+            worker.scheduleTask( testVector.getInnerTask() );
+
+            // when
+            worker.doTasks();
+
+            // then
+            if ( testVector.shouldRollBack() )
+            {
+                worker.assertNoEntityHasBeenPersisted();
+            }
+            else
+            {
+                worker.assertAllEntitesHaveBeenPersisted();
+            }
+        }
+        finally
+        {
+            persistService.stop();
+        }
+
+    }
+
+    private static class TestVector
+    {
+        private final Class<? extends TransactionalTask> outerTask;
+
+        private final Class<? extends TransactionalTask> innerTask;
+
+        private final boolean shouldRollBack;
+
+        public TestVector( Class<? extends TransactionalTask> outerTask, Class<? extends TransactionalTask> innerTask,
+                           boolean shouldRollBack )
+        {
+            this.outerTask = outerTask;
+            this.innerTask = innerTask;
+            this.shouldRollBack = shouldRollBack;
+        }
+
+        public Class<? extends TransactionalTask> getOuterTask()
+        {
+            return outerTask;
+        }
+
+        public Class<? extends TransactionalTask> getInnerTask()
+        {
+            return innerTask;
+        }
+
+        public boolean shouldRollBack()
+        {
+            return shouldRollBack;
+        }
+    }
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/NestedTransactionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/NestedTransactionTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/NestedTransactionTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message