polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nic...@apache.org
Subject [42/81] [abbrv] [partial] zest-java git commit: First round of changes to move to org.apache.zest namespace.
Date Fri, 31 Jul 2015 02:59:22 GMT
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWork.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWork.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWork.java
new file mode 100644
index 0000000..47fa360
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWork.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2007-2011, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2007-2012, Niclas Hedhman. All Rights Reserved.
+ * Copyright (c) 2013-2015, Paul Merlin. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.api.unitofwork;
+
+import java.util.Map;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.composite.AmbiguousTypeException;
+import org.apache.zest.api.entity.EntityBuilder;
+import org.apache.zest.api.entity.EntityReference;
+import org.apache.zest.api.entity.Identity;
+import org.apache.zest.api.entity.LifecycleException;
+import org.apache.zest.api.property.PropertyDescriptor;
+import org.apache.zest.api.query.Query;
+import org.apache.zest.api.query.QueryBuilder;
+import org.apache.zest.api.structure.MetaInfoHolder;
+import org.apache.zest.api.usecase.Usecase;
+import org.apache.zest.functional.Function;
+
+/**
+ * All operations on entities goes through an UnitOfWork.
+ * <p>
+ * A UnitOfWork allows you to access
+ * Entities and work with them. All modifications to Entities are recorded by the UnitOfWork,
+ * and at the end they may be sent to the underlying EntityStore by calling complete(). If the
+ * UoW was read-only you may instead simply discard() it.
+ * </p>
+ * <p>
+ * A UoW differs from a traditional Transaction in the sense that it is not tied at all to the underlying
+ * storage resource. Because of this there is no timeout on a UoW. It can be very short or very long.
+ * Another difference is that if a call to complete() fails, and the cause is validation errors in the
+ * Entities of the UoW, then these can be corrected and the UoW retried. By contrast, when a Transaction
+ * commit fails, then the whole transaction has to be done from the beginning again.
+ * </p>
+ * <p>
+ * A UoW can be associated with a Usecase. A Usecase describes the metainformation about the process
+ * to be performed by the UoW.
+ * </p>
+ * <p>
+ * If a code block that uses a UoW throws an exception you need to ensure that this is handled properly,
+ * and that the UoW is closed before returning. Because discard() is a no-op if the UoW is closed, we therefore
+ * recommend the following template to be used:
+ * </p>
+ * <pre>
+ *     UnitOfWork uow = module.newUnitOfWork();
+ *     try
+ *     {
+ *         ...
+ *         uow.complete();
+ *     }
+ *     finally
+ *     {
+ *         uow.discard();
+ *     }
+ * </pre>
+ * <p>
+ * This ensures that in the happy case the UoW is completed, and if any exception is thrown the UoW is discarded. After
+ * the UoW has completed the discard() method doesn't do anything, and so has no effect. You can choose to either add
+ * catch blocks for any exceptions, including exceptions from complete(), or skip them.
+ * </p>
+ * <p>
+ * Since 2.1 you can leverage Java 7 Automatic Resource Management (ie. Try With Resources) and use the following
+ * template instead:
+ * </p>
+ * <pre>
+ *     try( UnitOfWork uow = module.newUnitOfWork() )
+ *     {
+ *         ...
+ *         uow.complete();
+ *     }
+ * </pre>
+ * <p>
+ * It has the very same effect than the template above but is shorter.</p>
+ */
+public interface UnitOfWork extends MetaInfoHolder, AutoCloseable
+{
+
+    /**
+     * Get the UnitOfWorkFactory that this UnitOfWork was created from.
+     *
+     * @return The UnitOfWorkFactory instance that was used to create this UnitOfWork.
+     */
+    UnitOfWorkFactory unitOfWorkFactory();
+
+    long currentTime();
+
+    /**
+     * Get the Usecase for this UnitOfWork
+     *
+     * @return the Usecase
+     */
+    Usecase usecase();
+
+    void setMetaInfo( Object metaInfo );
+
+    <T> Query<T> newQuery( QueryBuilder<T> queryBuilder );
+
+//    DataSet newDataSetBuilder(Specification<?>... constraints);
+
+    /**
+     * Create a new Entity which implements the given mixin type.
+     * <p>
+     * An EntityComposite
+     * will be chosen according to what has been registered and the visibility rules
+     * for Modules and Layers will be considered. If several
+     * EntityComposites implement the type then an AmbiguousTypeException will be thrown.
+     * </p>
+     * <p>
+     * The identity of the Entity will be generated by the IdentityGenerator of the Module of the EntityComposite.
+     * </p>
+     *
+     * @param type the mixin type that the EntityComposite must implement
+     *
+     * @return a new Entity
+     *
+     * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered
+     * @throws AmbiguousTypeException      If several mixins implement the given type
+     * @throws LifecycleException          if the entity cannot be created
+     */
+    <T> T newEntity( Class<T> type )
+        throws EntityTypeNotFoundException, AmbiguousTypeException, LifecycleException;
+
+    /**
+     * Create a new Entity which implements the given mixin type. An EntityComposite
+     * will be chosen according to what has been registered and the visibility rules
+     * for Modules and Layers will be considered. If several
+     * EntityComposites implement the type then an AmbiguousTypeException will be thrown.
+     *
+     * @param type     the mixin type that the EntityComposite must implement
+     * @param identity the identity of the new Entity
+     *
+     * @return a new Entity
+     *
+     * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered
+     * @throws AmbiguousTypeException      If several mixins implement the given type
+     * @throws LifecycleException          if the entity cannot be created
+     */
+    <T> T newEntity( Class<T> type, String identity )
+        throws EntityTypeNotFoundException, AmbiguousTypeException, LifecycleException;
+
+    /**
+     * Create a new EntityBuilder for an EntityComposite which implements the given mixin type. An EntityComposite
+     * will be chosen according to what has been registered and the visibility rules
+     * for Modules and Layers will be considered. If several
+     * EntityComposites implement the type then an AmbiguousTypeException will be thrown.
+     *
+     * @param type the mixin type that the EntityComposite must implement
+     *
+     * @return a new EntityBuilder
+     *
+     * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered
+     * @throws AmbiguousTypeException      If several mixins implement the given type
+     */
+    <T> EntityBuilder<T> newEntityBuilder( Class<T> type )
+        throws EntityTypeNotFoundException, AmbiguousTypeException;
+
+    /**
+     * Create a new EntityBuilder for an EntityComposite which implements the given mixin type. An EntityComposite
+     * will be chosen according to what has been registered and the visibility rules
+     * for Modules and Layers will be considered. If several
+     * mixins implement the type then an AmbiguousTypeException will be thrown.
+     *
+     * @param type     the mixin type that the EntityComposite must implement
+     * @param identity the identity of the new Entity
+     *
+     * @return a new EntityBuilder
+     *
+     * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered
+     * @throws AmbiguousTypeException      If several mixins implement the given type
+     */
+    <T> EntityBuilder<T> newEntityBuilder( Class<T> type, String identity )
+        throws EntityTypeNotFoundException, AmbiguousTypeException;
+
+    /**
+     * Create a new EntityBuilder for an EntityComposite wich implements the given mixin type starting with the given
+     * state.
+     * <p>
+     * An EntityComposite will be chosen according to what has been registered and the visibility rules for Modules and
+     * Layers will be considered.
+     *
+     * @param <T>                      Entity type
+     * @param type                     Entity type
+     * @param propertyFunction         a function providing the state of properties
+     * @param associationFunction      a function providing the state of associations
+     * @param manyAssociationFunction  a function providing the state of many associations
+     * @param namedAssociationFunction a function providing the state of named associations
+     *
+     * @return a new EntityBuilder starting with the given state
+     *
+     * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered
+     * @throws AmbiguousTypeException      If several mixins implement the given type
+     */
+    <T> EntityBuilder<T> newEntityBuilderWithState( Class<T> type,
+                                                    Function<PropertyDescriptor, Object> propertyFunction,
+                                                    Function<AssociationDescriptor, EntityReference> associationFunction,
+                                                    Function<AssociationDescriptor, Iterable<EntityReference>> manyAssociationFunction,
+                                                    Function<AssociationDescriptor, Map<String, EntityReference>> namedAssociationFunction )
+        throws EntityTypeNotFoundException, AmbiguousTypeException;
+
+    /**
+     * Create a new EntityBuilder for an EntityComposite wich implements the given mixin type starting with the given
+     * state.
+     * <p>
+     * An EntityComposite will be chosen according to what has been registered and the visibility rules for Modules and
+     * Layers will be considered.
+     *
+     * @param <T>                      Entity type
+     * @param type                     Entity type
+     * @param identity                 the identity of the new Entity
+     * @param propertyFunction         a function providing the state of properties
+     * @param associationFunction      a function providing the state of associations
+     * @param manyAssociationFunction  a function providing the state of many associations
+     * @param namedAssociationFunction a function providing the state of named associations
+     *
+     * @return a new EntityBuilder starting with the given state
+     *
+     * @throws EntityTypeNotFoundException If no mixins implements the given type
+     * @throws AmbiguousTypeException      If several mixins implement the given type
+     */
+    <T> EntityBuilder<T> newEntityBuilderWithState( Class<T> type, String identity,
+                                                    Function<PropertyDescriptor, Object> propertyFunction,
+                                                    Function<AssociationDescriptor, EntityReference> associationFunction,
+                                                    Function<AssociationDescriptor, Iterable<EntityReference>> manyAssociationFunction,
+                                                    Function<AssociationDescriptor, Map<String, EntityReference>> namedAssociationFunction )
+        throws EntityTypeNotFoundException, AmbiguousTypeException;
+
+    /**
+     * Find an Entity of the given mixin type with the give identity. This
+     * method verifies that it exists by asking the underlying EntityStore.
+     *
+     * @param type     of the entity
+     * @param identity of the entity
+     *
+     * @return the entity
+     *
+     * @throws EntityTypeNotFoundException if no entity type could be found
+     * @throws NoSuchEntityException       if the entity could not be found
+     */
+    <T> T get( Class<T> type, String identity )
+        throws EntityTypeNotFoundException, NoSuchEntityException;
+
+    /**
+     * If you have a reference to an Entity from another
+     * UnitOfWork and want to create a reference to it in this
+     * UnitOfWork, then call this method.
+     *
+     * @param entity the Entity to be dereferenced
+     *
+     * @return an Entity from this UnitOfWork
+     *
+     * @throws EntityTypeNotFoundException if no entity type could be found
+     */
+    <T> T get( T entity )
+        throws EntityTypeNotFoundException;
+
+    /**
+     * Remove the given Entity.
+     *
+     * @param entity the Entity to be removed.
+     *
+     * @throws LifecycleException if the entity could not be removed
+     */
+    void remove( Object entity )
+        throws LifecycleException;
+
+    /**
+     * Complete this UnitOfWork. This will send all the changes down to the underlying
+     * EntityStore's.
+     *
+     * @throws UnitOfWorkCompletionException         if the UnitOfWork could not be completed
+     * @throws ConcurrentEntityModificationException if entities have been modified by others
+     */
+    void complete()
+        throws UnitOfWorkCompletionException, ConcurrentEntityModificationException;
+
+    /**
+     * Discard this UnitOfWork. Use this if a failure occurs that you cannot handle,
+     * or if the usecase was of a read-only character. This is a no-op of the UnitOfWork
+     * is already closed.
+     */
+    void discard();
+
+    /**
+     * Discard this UnitOfWork. Use this if a failure occurs that you cannot handle,
+     * or if the usecase was of a read-only character. This is a no-op of the UnitOfWork
+     * is already closed. This simply call the {@link #discard()} method and is an
+     * implementation of the {@link AutoCloseable} interface providing Try With Resources
+     * support for UnitOfWork.
+     */
+    @Override
+    public void close();
+
+    /**
+     * Check if the UnitOfWork is open. It is closed after either complete() or discard()
+     * methods have been called successfully.
+     *
+     * @return true if the UnitOfWork is open.
+     */
+    boolean isOpen();
+
+    /**
+     * Check if the UnitOfWork is paused. It is not paused after it has been create through the
+     * UnitOfWorkFactory, and it can be paused by calling {@link #pause()} and then resumed by calling
+     * {@link #resume()}.
+     *
+     * @return true if this UnitOfWork has been paused.
+     */
+    boolean isPaused();
+
+    /**
+     * Pauses this UnitOfWork.
+     * <p>
+     * Calling this method will cause the underlying UnitOfWork to become the current UnitOfWork until the
+     * the resume() method is called. It is the client's responsibility not to drop the reference to this
+     * UnitOfWork while being paused.
+     * </p>
+     */
+    void pause();
+
+    /**
+     * Resumes this UnitOfWork to again become the current UnitOfWork.
+     */
+    void resume();
+
+    /**
+     * Register a callback. Callbacks are invoked when the UnitOfWork
+     * is completed or discarded.
+     *
+     * @param callback a callback to be registered with this UnitOfWork
+     */
+    void addUnitOfWorkCallback( UnitOfWorkCallback callback );
+
+    /**
+     * Unregister a callback. Callbacks are invoked when the UnitOfWork
+     * is completed or discarded.
+     *
+     * @param callback a callback to be unregistered with this UnitOfWork
+     */
+    void removeUnitOfWorkCallback( UnitOfWorkCallback callback );
+
+    /**
+     * Converts the provided Entity to a Value of the same type.
+     * This is a convenience method to convert an EntityComposite to a ValueComposite.
+     * <p>
+     * All Property values are transferred across as-is, and the Association, ManyAssociation
+     * and NamedAssociatino values are kept in the ValueComposite as EntityReferences
+     * until they are dereferenced (get() and other methods), and IF a UnitOfWork is
+     * present at dereferencing the corresponding EntityCompoiste is retrieved from the
+     * EntityStore. If there is not an UnitOfWork present, an exception is thrown.
+     * </p>
+     * <p>
+     * For this to work, the Composites (both Entity and Value) must not declare the
+     * EntityComposite and ValueComposite super types, but rely on the declaration in
+     * the assembly, and also extend the Identity supertype.
+     * </p>
+     * Example;
+     * <pre><code>
+     *     public interface Person extends Identity { ... };
+     *     public class MyAssembler
+     *     {
+     *         public void assemble( ModuleAssembly module )
+     *         {
+     *             module.values( Person.class );
+     *             module.entities( Person.class );
+     *         }
+     *     }
+     * </code></pre>
+     *
+     * @param primaryType The shared type for which the properties and associations will
+     *                    be converted. Properties outside this type will be ignored.
+     * @param entityComposite The entity to be convered.
+     */
+    <T extends Identity> T toValue( Class<T> primaryType, T entityComposite );
+
+    /**
+     * Converts the provided Value to an Entity of the same type.
+     * This is a convenience method to convert a ValueComposite to an EntityComposite.
+     * <p>
+     * All Property values are transferred across as-is (no deep copy in case mutable
+     * types (DISCOURAGED!) are used), and the Association, ManyAssociation
+     * and NamedAssociatino that were in the ValueComposite as EntityReferences are
+     * transferred into the EntityComposite correctly, and can be dereferenced.
+     * </p>
+     * <p>
+     * This method MUST be called within a UnitOfWork.
+     * </p>
+     * <p>
+     * If an Entity with the Identity in the ValueComposite already exists, then that
+     * Entity is updated with the values from the ValueComposite. If an Entity of
+     * that Identity doesn't exist and new one is created.
+     * </p>
+     * <p>
+     * For this to work, the Composites (both Entity and Value) must not declare the
+     * EntityComposite and ValueComposite super types, but rely on the declaration in
+     * the assembly, and also extend the Identity supertype.
+     * </p>
+     * Example;
+     * <pre><code>
+     *     public interface Person extends Identity { ... };
+     *     public class MyAssembler
+     *     {
+     *         public void assemble( ModuleAssembly module )
+     *         {
+     *             module.values( Person.class );
+     *             module.entities( Person.class );
+     *         }
+     *     }
+     * </code></pre>
+     *
+     * @param primaryType The shared type for which the properties and associations will
+     *                    be converted. Properties outside this type will be ignored.
+     * @param valueComposite The Value to be convered into an Entity.
+     */
+    <T extends Identity> T toEntity( Class<T> primaryType, T valueComposite );
+
+
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkCallback.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkCallback.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkCallback.java
new file mode 100644
index 0000000..af0f987
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkCallback.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.api.unitofwork;
+
+/**
+ * Callback interface for UnitOfWork completion or discard. Implementations
+ * of this interface can be registered through {@link UnitOfWork#addUnitOfWorkCallback(UnitOfWorkCallback)}.
+ *
+ * If Entities implement this interface they will also receive invocations of this callback interface.
+ */
+public interface UnitOfWorkCallback
+{
+    /**
+     * This is called before the completion of the UnitOfWork.
+     * The callback may do any validation checks and throw
+     * UnitOfWorkCompletionException if there is any reason
+     * why the UnitOfWork is not in a valid state to be completed.
+     *
+     * @throws UnitOfWorkCompletionException
+     */
+    void beforeCompletion()
+        throws UnitOfWorkCompletionException;
+
+    /**
+     * This is called after the completion or discarding
+     * of the UnitOfWork. The callback may do any cleanup
+     * necessary related to the UnitOfWork. Note that the
+     * UnitOfWork is no longer active when this method is
+     * called, so no methods on it may be invoked.
+     *
+     * @param status
+     */
+    void afterCompletion( UnitOfWorkStatus status );
+
+    enum UnitOfWorkStatus
+    {
+        COMPLETED, DISCARDED
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkCompletionException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkCompletionException.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkCompletionException.java
new file mode 100644
index 0000000..092fc62
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkCompletionException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.api.unitofwork;
+
+/**
+ * When an attempt to {@link UnitOfWork#complete()} an UnitOfWork
+ * fails, this exception will be thrown.
+ */
+public class UnitOfWorkCompletionException
+    extends Exception
+{
+    private static final long serialVersionUID = 6531642131384516904L;
+
+    public UnitOfWorkCompletionException()
+    {
+    }
+
+    public UnitOfWorkCompletionException( String string )
+    {
+        super( string );
+    }
+
+    public UnitOfWorkCompletionException( String string, Throwable throwable )
+    {
+        super( string, throwable );
+    }
+
+    public UnitOfWorkCompletionException( Throwable throwable )
+    {
+        super( throwable );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkException.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkException.java
new file mode 100644
index 0000000..4cc5c9f
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkException.java
@@ -0,0 +1,45 @@
+/*  Copyright 2007 Niclas Hedhman.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.unitofwork;
+
+/**
+ * Base Exception for UnitOfWork related concerns.
+ */
+public class UnitOfWorkException
+    extends RuntimeException
+{
+    private static final long serialVersionUID = -8544178439804058558L;
+
+    public UnitOfWorkException()
+    {
+    }
+
+    public UnitOfWorkException( String message )
+    {
+        super( message );
+    }
+
+    public UnitOfWorkException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+    public UnitOfWorkException( Throwable cause )
+    {
+        super( cause );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkFactory.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkFactory.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkFactory.java
new file mode 100644
index 0000000..0f3bcb4
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkFactory.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2007, Niclas Hedhman. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.api.unitofwork;
+
+import org.apache.zest.api.entity.EntityComposite;
+import org.apache.zest.api.usecase.Usecase;
+
+/**
+ * Factory for UnitOfWork.
+ */
+public interface UnitOfWorkFactory
+{
+    /**
+     * Create a new UnitOfWork and associate it with the current thread.
+     * <p>
+     * The UnitOfWork will use the default Usecase settings.
+     * </p>
+     * <p>
+     * Current time will be set to System.currentTimeMillis();
+     * </p>
+     * @return a new UnitOfWork
+     */
+    UnitOfWork newUnitOfWork();
+
+    /**
+     * Create a new UnitOfWork and associate it with the current thread.
+     * <p>
+     * The UnitOfWork will use the default Usecase settings.
+     * </p>
+     * @return a new UnitOfWork
+     */
+    UnitOfWork newUnitOfWork( long currentTime );
+
+    /**
+     * Create a new UnitOfWork for the given Usecase and associate it with the current thread.
+     * <p>
+     * Current time will be set to System.currentTimeMillis();
+     * </p>
+     * @param usecase the Usecase for this UnitOfWork
+     *
+     * @return a new UnitOfWork
+     */
+    UnitOfWork newUnitOfWork( Usecase usecase );
+
+    /**
+     * Create a new UnitOfWork for the given Usecase and associate it with the current thread.
+     *
+     * @param usecase the Usecase for this UnitOfWork
+     *
+     * @return a new UnitOfWork
+     */
+    UnitOfWork newUnitOfWork( Usecase usecase, long currentTime );
+
+    /**
+     * @return true if there is an active UnitOfWork associated with the executing thread
+     */
+    boolean isUnitOfWorkActive();
+
+    /**
+     * Returns the UnitOfWork that is currently associated with the executing thread.
+     *
+     * @return The current UnitOfWork associated with the executing thread
+     *
+     * @throws IllegalStateException if no current UnitOfWork is active
+     */
+    UnitOfWork currentUnitOfWork()
+        throws IllegalStateException;
+
+    /**
+     * Returns the UnitOfWork that the EntityComposite is bound to.
+     *
+     * @param entity the entity to be checked.
+     *
+     * @return The UnitOfWork instance that the Entity is bound to, or null if the entity is not associated with
+     *         any UnitOfWork.
+     */
+    UnitOfWork getUnitOfWork( EntityComposite entity );
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkOptions.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkOptions.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkOptions.java
new file mode 100644
index 0000000..176d9a0
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkOptions.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.zest.api.unitofwork;
+
+/**
+ * Set instances of this in MetaInfo on UnitOfWork or the associated Usecase.
+ *  <p>
+ * Options:
+ *  </p>
+ * <p>
+ * "pruneOnPause": if true, then clear out all instances that have been loaded in the UoW but not modified
+ * </p>
+ */
+public class UnitOfWorkOptions
+{
+    private boolean pruneOnPause = false;
+
+    public UnitOfWorkOptions( boolean pruneOnPause )
+    {
+        this.pruneOnPause = pruneOnPause;
+    }
+
+    public boolean isPruneOnPause()
+    {
+        return pruneOnPause;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkTemplate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkTemplate.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkTemplate.java
new file mode 100644
index 0000000..cd91cb9
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/UnitOfWorkTemplate.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.zest.api.unitofwork;
+
+import org.apache.zest.api.structure.Module;
+import org.apache.zest.api.usecase.Usecase;
+
+/**
+ * UnitOfWork Template.
+ */
+public abstract class UnitOfWorkTemplate<RESULT, ThrowableType extends Throwable>
+{
+    private Usecase usecase = Usecase.DEFAULT;
+    private int retries = 10;
+    private boolean complete = true;
+
+    protected UnitOfWorkTemplate()
+    {
+    }
+
+    protected UnitOfWorkTemplate( int retries, boolean complete )
+    {
+        this.retries = retries;
+        this.complete = complete;
+    }
+
+    protected UnitOfWorkTemplate( Usecase usecase, int retries, boolean complete )
+    {
+        this.usecase = usecase;
+        this.retries = retries;
+        this.complete = complete;
+    }
+
+    protected abstract RESULT withUnitOfWork( UnitOfWork uow )
+        throws ThrowableType;
+
+    @SuppressWarnings( "unchecked" )
+    public RESULT withModule( Module module )
+        throws ThrowableType, UnitOfWorkCompletionException
+    {
+        int loop = 0;
+        ThrowableType ex = null;
+        do
+        {
+            UnitOfWork uow = module.newUnitOfWork( usecase );
+
+            try
+            {
+                RESULT result = withUnitOfWork( uow );
+                if( complete )
+                {
+                    try
+                    {
+                        uow.complete();
+                        return result;
+                    }
+                    catch( ConcurrentEntityModificationException e )
+                    {
+                        // Retry?
+                        ex = (ThrowableType) e;
+                    }
+                }
+            }
+            catch( Throwable e )
+            {
+                ex = (ThrowableType) e;
+            }
+            finally
+            {
+                uow.discard();
+            }
+        }
+        while( loop++ < retries );
+
+        throw ex;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java
new file mode 100644
index 0000000..9891b36
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java
@@ -0,0 +1,181 @@
+/*  Copyright 2008 Edward Yakop.
+ *  Copyright 2009 Niclas Hedhman.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.unitofwork.concern;
+
+import java.lang.reflect.Method;
+import org.apache.zest.api.common.AppliesTo;
+import org.apache.zest.api.concern.GenericConcern;
+import org.apache.zest.api.injection.scope.Invocation;
+import org.apache.zest.api.injection.scope.Structure;
+import org.apache.zest.api.structure.Module;
+import org.apache.zest.api.unitofwork.ConcurrentEntityModificationException;
+import org.apache.zest.api.unitofwork.UnitOfWork;
+import org.apache.zest.api.usecase.Usecase;
+import org.apache.zest.api.usecase.UsecaseBuilder;
+
+/**
+ * {@code UnitOfWorkConcern} manages the unit of work complete, discard and retry policy.
+ *
+ * @see UnitOfWorkPropagation
+ * @see UnitOfWorkDiscardOn
+ */
+@AppliesTo( UnitOfWorkPropagation.class )
+public class UnitOfWorkConcern
+    extends GenericConcern
+{
+    private static final Class<?>[] DEFAULT_DISCARD_CLASSES = new Class[]{ Throwable.class };
+
+    @Structure
+    Module module;
+
+    @Invocation
+    UnitOfWorkPropagation propagation;
+
+    /**
+     * Handles method with {@code UnitOfWorkPropagation} annotation.
+     *
+     * @param proxy  The object.
+     * @param method The invoked method.
+     * @param args   The method arguments.
+     *
+     * @return The returned value of method invocation.
+     *
+     * @throws Throwable Thrown if the method invocation throw exception.
+     */
+    @Override
+    public Object invoke( Object proxy, Method method, Object[] args )
+        throws Throwable
+    {
+        UnitOfWorkPropagation.Propagation propagationPolicy = propagation.value();
+        if( propagationPolicy == UnitOfWorkPropagation.Propagation.REQUIRED )
+        {
+            if( module.isUnitOfWorkActive() )
+            {
+                return next.invoke( proxy, method, args );
+            }
+            else
+            {
+                Usecase usecase = usecase();
+                return invokeWithCommit( proxy, method, args, module.newUnitOfWork( usecase ) );
+            }
+        }
+        else if( propagationPolicy == UnitOfWorkPropagation.Propagation.MANDATORY )
+        {
+            if( !module.isUnitOfWorkActive() )
+            {
+                throw new IllegalStateException( "UnitOfWork was required but there is no available unit of work." );
+            }
+        }
+        else if( propagationPolicy == UnitOfWorkPropagation.Propagation.REQUIRES_NEW )
+        {
+            Usecase usecase = usecase();
+            return invokeWithCommit( proxy, method, args, module.newUnitOfWork( usecase ) );
+        }
+        return next.invoke( proxy, method, args );
+    }
+
+    private Usecase usecase()
+    {
+        String usecaseName = propagation.usecase();
+        Usecase usecase;
+        if( usecaseName == null )
+        {
+            usecase = Usecase.DEFAULT;
+        }
+        else
+        {
+            usecase = UsecaseBuilder.newUsecase( usecaseName );
+        }
+        return usecase;
+    }
+
+    protected Object invokeWithCommit( Object proxy, Method method, Object[] args, UnitOfWork currentUnitOfWork )
+        throws Throwable
+    {
+        try
+        {
+            UnitOfWorkRetry retryAnnot = method.getAnnotation( UnitOfWorkRetry.class );
+            int maxTries = 0;
+            long delayFactor = 0;
+            long initialDelay = 0;
+            if( retryAnnot != null )
+            {
+                maxTries = retryAnnot.retries();
+                initialDelay = retryAnnot.initialDelay();
+                delayFactor = retryAnnot.delayFactory();
+            }
+            int retry = 0;
+            while( true )
+            {
+                Object result = next.invoke( proxy, method, args );
+                try
+                {
+                    currentUnitOfWork.complete();
+                    return result;
+                }
+                catch( ConcurrentEntityModificationException e )
+                {
+                    if( retry >= maxTries )
+                    {
+                        throw e;
+                    }
+                    module.currentUnitOfWork().discard();
+                    Thread.sleep( initialDelay + retry * delayFactor );
+                    retry++;
+                    currentUnitOfWork = module.newUnitOfWork( usecase() );
+                }
+            }
+        }
+        catch( Throwable throwable )
+        {
+            // Discard only if this concern create a unit of work
+            discardIfRequired( method, currentUnitOfWork, throwable );
+            throw throwable;
+        }
+    }
+
+    /**
+     * Discard unit of work if the discard policy match.
+     *
+     * @param aMethod     The invoked method. This argument must not be {@code null}.
+     * @param aUnitOfWork The current unit of work. This argument must not be {@code null}.
+     * @param aThrowable  The exception thrown. This argument must not be {@code null}.
+     */
+    protected void discardIfRequired( Method aMethod, UnitOfWork aUnitOfWork, Throwable aThrowable )
+    {
+        UnitOfWorkDiscardOn discardPolicy = aMethod.getAnnotation( UnitOfWorkDiscardOn.class );
+        Class<?>[] discardClasses;
+        if( discardPolicy != null )
+        {
+            discardClasses = discardPolicy.value();
+        }
+        else
+        {
+            discardClasses = DEFAULT_DISCARD_CLASSES;
+        }
+
+        Class<? extends Throwable> aThrowableClass = aThrowable.getClass();
+        for( Class<?> discardClass : discardClasses )
+        {
+            if( discardClass.isAssignableFrom( aThrowableClass ) )
+            {
+                aUnitOfWork.discard();
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkDiscardOn.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkDiscardOn.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkDiscardOn.java
new file mode 100644
index 0000000..566ddef
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkDiscardOn.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2008, Edward Yakop. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.api.unitofwork.concern;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation to denote the unit of work discard policy.
+ * <p>
+ * By default, discard is applied on any method that has {@link UnitOfWorkPropagation} and any exception is thrown.
+ * </p>
+ * <p>
+ * Apply {@code UnitOfWorkDiscardOn} to override the default settings.
+ * </p>
+ * <p>
+ * Usage example:
+ * </p>
+ * <pre>
+ * <code>
+ *
+ * &#64;Concerns( UnitOfWorkConcern.class )
+ * public class MyBusinessServiceMixin implements BusinessService
+ * {
+ *   &#64;Structure UnitOfWorkFactory uowf;
+ *
+ *   &#64;UnitOfWorkDiscardOn( MyBusinessException.class )
+ *   public void myBusinessMethod()
+ *   {
+ *     // Must invoke current unit of work.
+ *     UnitOfWork uow = uowf.currentUnitOfWork();
+ *
+ *     // Perform business logic
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * <p>
+ * The unit of work will be discarded iff {@code MyBusinessException} exceptions or its subclass is thrown from within
+ * {@code myBusinessMethod} method.
+ * </p>
+ */
+@Retention( RUNTIME )
+@Target( METHOD )
+@Inherited
+@Documented
+public @interface UnitOfWorkDiscardOn
+{
+    Class<? extends Throwable>[] value() default { Throwable.class };
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkPropagation.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkPropagation.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkPropagation.java
new file mode 100644
index 0000000..3c0f23e
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkPropagation.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2008, Edward Yakop. All Rights Reserved.
+ * Copyright (c) 2009, Niclas Hedhman. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.api.unitofwork.concern;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation to denote the unit of work propagation.
+ * <p>
+ * Usage example:
+ * </p>
+ * <pre>
+ * <code>
+ *
+ * &#64;Concerns( UnitOfWorkConcern.class )
+ * public class MyBusinessServiceMixin implements BusinessService
+ * {
+ *   &#64;Structure UnitOfWorkFactory uowf;
+ *
+ *   &#64;UnitOfWorkPropagation
+ *   public void myBusinessMethod()
+ *   {
+ *     // Must invoke current unit of work.
+ *     UnitOfWork uow = uowf.currentUnitOfWork();
+ *
+ *     // Perform business logic
+ *   }
+ * }
+ * </code>
+ * </pre>
+ */
+@Retention( RUNTIME )
+@Target( METHOD )
+@Inherited
+@Documented
+public @interface UnitOfWorkPropagation
+{
+    Propagation value() default Propagation.REQUIRED;
+
+    String usecase() default "";
+
+    /**
+     * Propagation behaviors.
+     */
+    enum Propagation
+    {
+        /**
+         * Default propagation behavior.
+         * Behavior: <br>
+         * If no current transaction: creates a new UnitOfWork <br>
+         * If there is a current UnitOfWork: use the current UnitOfWork.
+         */
+        REQUIRED,
+
+        /**
+         * Behavior: <br>
+         * If no current UnitOfWork: throw an exception <br>
+         * If there is a current UnitOfWork: use the current UnitOfWork.
+         */
+        MANDATORY,
+
+        /**
+         * Behavior: <br>
+         * If no current UnitOfWork: creates a new UnitOfWork <br>
+         * If there is a current UnitOfWork: suspend the current UnitOfWork and create a new UnitOfWork.
+         */
+        REQUIRES_NEW
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkRetry.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkRetry.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkRetry.java
new file mode 100644
index 0000000..490cc49
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkRetry.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.zest.api.unitofwork.concern;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * This annotation describes the retries that should occur in case of {@link org.apache.zest.api.unitofwork.ConcurrentEntityModificationException}
+ * occurs.
+ */
+@Retention( RUNTIME )
+@Target( METHOD )
+@Inherited
+@Documented
+public @interface UnitOfWorkRetry
+{
+    int retries() default 1;
+
+    long initialDelay() default 0;
+
+    long delayFactory() default 10;
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/package.html
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/package.html b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/package.html
new file mode 100644
index 0000000..68cbe0e
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/package.html
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<html>
+    <body>
+        <h2>UnitOfWork Concerns.</h2>
+        <p>
+            UnitOfWork Concerns allow declarative UnitOfWork propagation, discard wrt. exceptions and automatic retry.
+        </p>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/unitofwork/package.html
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/package.html b/core/api/src/main/java/org/apache/zest/api/unitofwork/package.html
new file mode 100644
index 0000000..1bc08fa
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/package.html
@@ -0,0 +1,21 @@
+<!--
+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.
+-->
+<html>
+    <body>
+        <h2>UnitOfWork API.</h2>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/usecase/Usecase.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/usecase/Usecase.java b/core/api/src/main/java/org/apache/zest/api/usecase/Usecase.java
new file mode 100644
index 0000000..f5bd66b
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/usecase/Usecase.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.api.usecase;
+
+import java.io.Serializable;
+import org.apache.zest.api.common.MetaInfo;
+import org.apache.zest.api.structure.MetaInfoHolder;
+
+/**
+ * A Usecase. A Usecase is used as a model for UnitOfWork, and helps
+ * implementations decide what to do in certain circumstances.
+ */
+public final class Usecase
+    implements Serializable, MetaInfoHolder
+{
+    public static final Usecase DEFAULT = new Usecase( "Default", new MetaInfo() );
+
+    private static final long serialVersionUID = 1L;
+    private final String name;
+    private final MetaInfo metaInfo;
+
+    Usecase( String name, MetaInfo metaInfo )
+    {
+        this.name = name;
+        this.metaInfo = metaInfo;
+    }
+
+    /**
+     * Name of the usecase.
+     *
+     * @return the name
+     */
+    public String name()
+    {
+        return name;
+    }
+
+    /**
+     * Meta-info for the usecase. This can be of any type, and is typically set when creating the usecase
+     * and read during the execution of the usecase.
+     *
+     * @param infoType the MetaInfo type to retrieve.
+     *
+     * @return the previously stored metaInfo of the given type for the usecase.
+     */
+    @Override
+    public <T> T metaInfo( Class<T> infoType )
+    {
+        return metaInfo.get( infoType );
+    }
+
+    @Override
+    public String toString()
+    {
+        return name + ", meta info:" + metaInfo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/usecase/UsecaseBuilder.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/usecase/UsecaseBuilder.java b/core/api/src/main/java/org/apache/zest/api/usecase/UsecaseBuilder.java
new file mode 100644
index 0000000..3bbbd93
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/usecase/UsecaseBuilder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.api.usecase;
+
+import org.apache.zest.api.common.MetaInfo;
+
+/**
+ * Builder for Usecases.
+ */
+public final class UsecaseBuilder
+{
+    public static UsecaseBuilder buildUsecase( String aName )
+    {
+        return new UsecaseBuilder( aName );
+    }
+
+    public static Usecase newUsecase( String aName )
+    {
+        return new UsecaseBuilder( aName ).newUsecase();
+    }
+
+    private MetaInfo metaInfo = new MetaInfo();
+
+    private String name;
+
+    private UsecaseBuilder( String name )
+    {
+        this.name = name;
+    }
+
+    public UsecaseBuilder withMetaInfo( Object metaInfo )
+    {
+        this.metaInfo.set( metaInfo );
+        return this;
+    }
+
+    public Usecase newUsecase()
+    {
+        return new Usecase( name, metaInfo );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/usecase/package.html
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/usecase/package.html b/core/api/src/main/java/org/apache/zest/api/usecase/package.html
new file mode 100644
index 0000000..71c696a
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/usecase/package.html
@@ -0,0 +1,21 @@
+<!--
+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.
+-->
+<html>
+    <body>
+        <h2>Usecase API.</h2>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/util/Annotations.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/util/Annotations.java b/core/api/src/main/java/org/apache/zest/api/util/Annotations.java
new file mode 100644
index 0000000..553e6c1
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/util/Annotations.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.api.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+import org.apache.zest.functional.Function;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.functional.Specification;
+
+import static org.apache.zest.api.util.Classes.interfacesOf;
+import static org.apache.zest.api.util.Classes.typeOf;
+import static org.apache.zest.functional.Iterables.flatten;
+import static org.apache.zest.functional.Iterables.flattenIterables;
+import static org.apache.zest.functional.Iterables.iterable;
+import static org.apache.zest.functional.Iterables.map;
+
+/**
+ * Useful methods for handling Annotations.
+ */
+public final class Annotations
+{
+    public static Function<Type, Iterable<Annotation>> ANNOTATIONS_OF = Classes.forTypes( new Function<Type, Iterable<Annotation>>()
+    {
+        @Override
+        public Iterable<Annotation> map( Type type )
+        {
+            return Iterables.iterable( Classes.RAW_CLASS.map( type ).getAnnotations() );
+        }
+    } );
+
+    public static Specification<AnnotatedElement> hasAnnotation( final Class<? extends Annotation> annotationType )
+    {
+        return new Specification<AnnotatedElement>()
+        {
+            @Override
+            public boolean satisfiedBy( AnnotatedElement element )
+            {
+                return element.getAnnotation( annotationType ) != null;
+            }
+        };
+    }
+
+    public static Function<Annotation, Class<? extends Annotation>> type()
+    {
+        return new Function<Annotation, Class<? extends Annotation>>()
+        {
+            @Override
+            public Class<? extends Annotation> map( Annotation annotation )
+            {
+                return annotation.annotationType();
+            }
+        };
+    }
+
+    public static Specification<Annotation> isType( final Class<? extends Annotation> annotationType )
+    {
+        return new Specification<Annotation>()
+        {
+            @Override
+            public boolean satisfiedBy( Annotation annotation )
+            {
+                return annotation.annotationType().equals( annotationType );
+            }
+        };
+    }
+
+    public static <T extends Annotation> T annotationOn( Type type, Class<T> annotationType )
+    {
+        return annotationType.cast( Classes.RAW_CLASS.map( type ).getAnnotation( annotationType ) );
+    }
+
+    public static Iterable<Annotation> findAccessorAndTypeAnnotationsIn( AccessibleObject accessor )
+    {
+        return flatten( iterable( accessor.getAnnotations() ),
+                        flattenIterables( map( Annotations.ANNOTATIONS_OF, interfacesOf( typeOf( accessor ) ) ) ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/util/Base64Encoder.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/util/Base64Encoder.java b/core/api/src/main/java/org/apache/zest/api/util/Base64Encoder.java
new file mode 100644
index 0000000..2779d6e
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/util/Base64Encoder.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2009 Alin Dreghiciu.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.util;
+
+/**
+ * Base64Encoder.
+ */
+public final class Base64Encoder
+{
+
+    /**
+     * Utility class. ment to be used via static methods.
+     */
+    private Base64Encoder()
+    {
+        // utility class
+    }
+
+    /**
+     * Encodes a String into a base 64 String. The resulting encoding is chunked at 76 bytes.
+     *
+     * @param s String to encode.
+     *
+     * @return encoded string.
+     */
+    public static String encode( String s, boolean includePadding )
+    {
+        byte[] sBytes = s.getBytes();
+        sBytes = encode( sBytes, includePadding );
+        s = new String( sBytes );
+        return s;
+    }
+
+    /**
+     * Decodes a base 64 String into a String.
+     *
+     * @param s String to decode.
+     *
+     * @return encoded string.
+     *
+     * @throws java.lang.IllegalArgumentException
+     *          _ If the given byte array was not valid base64 encoding.
+     */
+    public static String decode( String s )
+        throws IllegalArgumentException
+    {
+        s = s.replaceAll( "\n", "" );
+        s = s.replaceAll( "\r", "" );
+        byte[] sBytes = s.getBytes();
+        sBytes = decode( sBytes );
+        s = new String( sBytes );
+        return s;
+    }
+
+    private static final byte[] ALPHASET =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".getBytes();
+
+    private static final int I6O2 = 255 - 3;
+    private static final int O6I2 = 3;
+    private static final int I4O4 = 255 - 15;
+    private static final int O4I4 = 15;
+    private static final int I2O6 = 255 - 63;
+    private static final int O2I6 = 63;
+
+    /**
+     * Encodes a byte array into a base 64 byte array.
+     *
+     * @param dData byte array to encode.
+     *
+     * @return encoded byte array.
+     */
+    public static byte[] encode( byte[] dData, boolean includePadding )
+    {
+        if( dData == null )
+        {
+            throw new IllegalArgumentException( "Cannot encode null" );
+        }
+        byte[] eData = new byte[ ( ( dData.length + 2 ) / 3 ) * 4 ];
+
+        int eIndex = 0;
+        for( int i = 0; i < dData.length; i += 3 )
+        {
+            int d1;
+            int d2 = 0;
+            int d3 = 0;
+            int e1;
+            int e2;
+            int e3;
+            int e4;
+            int pad = 0;
+
+            d1 = dData[ i ];
+            if( ( i + 1 ) < dData.length )
+            {
+                d2 = dData[ i + 1 ];
+                if( ( i + 2 ) < dData.length )
+                {
+                    d3 = dData[ i + 2 ];
+                }
+                else
+                {
+                    pad = 1;
+                }
+            }
+            else
+            {
+                pad = 2;
+            }
+
+            e1 = ALPHASET[ ( d1 & I6O2 ) >> 2 ];
+            e2 = ALPHASET[ ( d1 & O6I2 ) << 4 | ( d2 & I4O4 ) >> 4 ];
+            e3 = ALPHASET[ ( d2 & O4I4 ) << 2 | ( d3 & I2O6 ) >> 6 ];
+            e4 = ALPHASET[ ( d3 & O2I6 ) ];
+
+            eData[ eIndex++ ] = (byte) e1;
+            eData[ eIndex++ ] = (byte) e2;
+            eData[ eIndex++ ] = ( pad < 2 ) ? (byte) e3 : (byte) '=';
+            eData[ eIndex++ ] = ( pad < 1 ) ? (byte) e4 : (byte) '=';
+
+            if( pad > 0 && !includePadding )
+            {
+                byte[] neweData = new byte[ eData.length - pad ];
+                System.arraycopy( eData, 0, neweData, 0, eIndex - pad );
+                eData = neweData;
+            }
+        }
+
+        return eData;
+    }
+
+    private final static int[] CODES = new int[ 256 ];
+
+    static
+    {
+        for( int i = 0; i < CODES.length; i++ )
+        {
+            CODES[ i ] = 64;
+        }
+        for( int i = 0; i < ALPHASET.length; i++ )
+        {
+            CODES[ ALPHASET[ i ] ] = i;
+        }
+    }
+
+    /**
+     * Decodes a base64 byte array into a byte array.
+     * <p>
+     *
+     * @param eData byte array to decode.
+     *
+     * @return decoded byte array.
+     *
+     * @throws java.lang.IllegalArgumentException
+     *          thrown if the given byte array was not valid com.sun.syndication.io.impl.Base64 encoding.
+     */
+    public static byte[] decode( byte[] eData )
+    {
+        if( eData == null )
+        {
+            throw new IllegalArgumentException( "Cannot decode null" );
+        }
+        byte[] cleanEData = eData.clone();
+        int cleanELength = 0;
+        for( byte anEData : eData )
+        {
+            if( anEData < 256 && CODES[ anEData ] < 64 )
+            {
+                cleanEData[ cleanELength++ ] = anEData;
+            }
+        }
+
+        int dLength = ( cleanELength / 4 ) * 3;
+        switch( cleanELength % 4 )
+        {
+        case 3:
+            dLength += 2;
+            break;
+        case 2:
+            dLength++;
+            break;
+        }
+
+        byte[] dData = new byte[ dLength ];
+        int dIndex = 0;
+        for( int i = 0; i < eData.length; i += 4 )
+        {
+            if( ( i + 3 ) > eData.length )
+            {
+                throw new IllegalArgumentException(
+                    "byte array is not a valid base64 encoding"
+                );
+            }
+            int e1 = CODES[ cleanEData[ i ] ];
+            int e2 = CODES[ cleanEData[ i + 1 ] ];
+            int e3 = CODES[ cleanEData[ i + 2 ] ];
+            int e4 = CODES[ cleanEData[ i + 3 ] ];
+            dData[ dIndex++ ] = (byte) ( ( e1 << 2 ) | ( e2 >> 4 ) );
+            if( dIndex < dData.length )
+            {
+                dData[ dIndex++ ] = (byte) ( ( e2 << 4 ) | ( e3 >> 2 ) );
+            }
+            if( dIndex < dData.length )
+            {
+                dData[ dIndex++ ] = (byte) ( ( e3 << 6 ) | ( e4 ) );
+            }
+        }
+        return dData;
+    }
+}


Mime
View raw message