JAMES-1738 Import Onami lifeCycle and its tests

Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/c1f94a46
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/c1f94a46
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/c1f94a46

Branch: refs/heads/master
Commit: c1f94a46d5fcd5e63c6eac8f64997b7ee371f4da
Parents: 91d3ebf
Author: Benoit Tellier <[email protected]>
Authored: Wed Oct 5 11:16:46 2016 +0200
Committer: Benoit Tellier <[email protected]>
Committed: Wed Oct 5 14:48:52 2016 +0200

----------------------------------------------------------------------
 server/container/guice/onami/pom.xml            | 198 +++++++++++++++++
 .../onami/lifecycle/AbstractBasicStageable.java |  50 +++++
 .../lifecycle/AbstractMethodTypeListener.java   | 112 ++++++++++
 .../onami/lifecycle/AbstractStageable.java      |  60 +++++
 .../james/onami/lifecycle/DefaultStager.java    | 218 +++++++++++++++++++
 .../james/onami/lifecycle/DisposingStager.java  |  50 +++++
 .../james/onami/lifecycle/LifeCycleModule.java  | 117 ++++++++++
 .../onami/lifecycle/LifeCycleStageModule.java   | 200 +++++++++++++++++
 .../james/onami/lifecycle/NoOpStageHandler.java |  47 ++++
 .../lifecycle/NoOpStageableTypeMapper.java      |  34 +++
 .../james/onami/lifecycle/PreDestroyModule.java |  52 +++++
 .../james/onami/lifecycle/StageHandler.java     |  43 ++++
 .../apache/james/onami/lifecycle/Stageable.java |  41 ++++
 .../james/onami/lifecycle/StageableMethod.java  |  86 ++++++++
 .../onami/lifecycle/StageableTypeMapper.java    |  39 ++++
 .../apache/james/onami/lifecycle/Stager.java    |  64 ++++++
 .../onami/lifecycle/DefaultStagerTestCase.java  | 105 +++++++++
 .../onami/lifecycle/MultiLifeCycleObject.java   |  76 +++++++
 .../onami/lifecycle/MultiLifeCycleTestCase.java | 144 ++++++++++++
 .../james/onami/lifecycle/StageObject1.java     |  45 ++++
 .../james/onami/lifecycle/StageObject2.java     |  45 ++++
 .../onami/lifecycle/StagingOrderTestCase.java   |  85 ++++++++
 .../james/onami/lifecycle/TestAnnotationA.java  |  33 +++
 .../james/onami/lifecycle/TestAnnotationB.java  |  33 +++
 .../james/onami/lifecycle/TestAnnotationC.java  |  33 +++
 server/container/guice/pom.xml                  |   1 +
 26 files changed, 2011 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/onami/pom.xml 
b/server/container/guice/onami/pom.xml
new file mode 100644
index 0000000..d7433d6
--- /dev/null
+++ b/server/container/guice/onami/pom.xml
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>james-server-guice</artifactId>
+        <groupId>org.apache.james</groupId>
+        <version>3.0.0-beta5-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>james-server-onami</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Apache James :: Server :: Onami</name>
+    <description>Guice tooling from Onami project</description>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>disable-build-for-older-jdk</id>
+            <activation>
+                <jdk>(,1.8)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-jar-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>jar</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>test-jar</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-compile</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testCompile</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-test</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-install-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-install</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-resources-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-resources</id>
+                                <phase>none</phase>
+                            </execution>
+                            <execution>
+                                <id>default-testResources</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <artifactId>maven-site-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-descriptor</id>
+                                <phase>none</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>build-for-jdk-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <source>1.8</source>
+                            <target>1.8</target>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build><dependencies>
+            <dependency>
+                <groupId>com.google.inject</groupId>
+                <artifactId>guice</artifactId>
+            </dependency>
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <scope>test</scope>
+            </dependency>
+        </dependencies>
+        </profile>
+        <profile>
+            <id>animal-sniffer-java-8</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>animal-sniffer-maven-plugin</artifactId>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java18</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>check_java_8</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractBasicStageable.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractBasicStageable.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractBasicStageable.java
new file mode 100644
index 0000000..a065a55
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractBasicStageable.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+/**
+ * Base implementation for stageables.
+ *
+ * @author Mikhail Mazursky
+ */
+public abstract class AbstractBasicStageable<S>
+    implements Stageable
+{
+
+    /**
+     * Object to stage.
+     */
+    protected final S object;
+
+    protected AbstractBasicStageable( S object )
+    {
+        this.object = object;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final String toString()
+    {
+        return object.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractMethodTypeListener.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractMethodTypeListener.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractMethodTypeListener.java
new file mode 100644
index 0000000..6ae63c5
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractMethodTypeListener.java
@@ -0,0 +1,112 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.TypeEncounter;
+import com.google.inject.spi.TypeListener;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * A Guice {@code TypeListener} to hear annotated methods with lifecycle 
annotations.
+ */
+abstract class AbstractMethodTypeListener
+    implements TypeListener
+{
+
+    /**
+     * The {@code java} package constants.
+     */
+    private static final String JAVA_PACKAGE = "java";
+
+    /**
+     * The lifecycle annotations to search on methods in the order to be 
searched.
+     */
+    protected final List<? extends Class<? extends Annotation>> 
annotationTypes;
+
+    /**
+     * Creates a new methods listener instance.
+     *
+     * @param annotationTypes the lifecycle annotations to search on methods 
in the order to be searched.
+     */
+    public AbstractMethodTypeListener( List<? extends Class<? extends 
Annotation>> annotationTypes )
+    {
+        this.annotationTypes = annotationTypes;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final <I> void hear( TypeLiteral<I> type, TypeEncounter<I> 
encounter )
+    {
+        hear( type, type.getRawType(), encounter );
+    }
+
+    /**
+     * Allows traverse the input klass hierarchy.
+     *
+     * @param parentType the owning type being heard
+     * @param klass      encountered by Guice.
+     * @param encounter  the injection context.
+     */
+    private <I> void hear( final TypeLiteral<I> parentType, Class<? super I> 
klass, TypeEncounter<I> encounter )
+    {
+        Package pkg;
+        if ( klass == null || ( ( pkg = klass.getPackage() ) != null && 
pkg.getName().startsWith( JAVA_PACKAGE ) ) )
+        {
+            return;
+        }
+
+        for ( Class<? extends Annotation> annotationType : annotationTypes )
+        {
+            for ( Method method : klass.getDeclaredMethods() )
+            {
+                if ( method.isAnnotationPresent( annotationType ) )
+                {
+                    if ( method.getParameterTypes().length != 0 )
+                    {
+                        encounter.addError( "Annotated methods with @%s must 
not accept any argument, found %s",
+                                            annotationType.getName(), method );
+                    }
+
+                    hear( method, parentType, encounter, annotationType );
+                }
+            }
+        }
+
+        hear( parentType, klass.getSuperclass(), encounter );
+    }
+
+    /**
+     * Allows implementations to define the behavior when lifecycle annotation 
is found on the method.
+     *
+     * @param method         encountered by this type handler.
+     * @param parentType     the owning type being heard
+     * @param encounter      the injection context.
+     * @param annotationType the annotation type that was specified.
+     */
+    protected abstract <I> void hear( Method method, TypeLiteral<I> 
parentType, TypeEncounter<I> encounter,
+                                      Class<? extends Annotation> 
annotationType );
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractStageable.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractStageable.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractStageable.java
new file mode 100644
index 0000000..07cbc84
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/AbstractStageable.java
@@ -0,0 +1,60 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+/**
+ * Base implementation for stageables.
+ *
+ * @author Mikhail Mazursky
+ */
+public abstract class AbstractStageable<S>
+    extends AbstractBasicStageable<S>
+{
+
+    protected AbstractStageable( S object )
+    {
+        super( object );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final void stage( StageHandler stageHandler )
+    {
+        try
+        {
+            doStage();
+        }
+        catch ( Throwable e )
+        {
+            stageHandler.onError( object, e );
+            return;
+        }
+        stageHandler.onSuccess( object );
+    }
+
+    /**
+     * Does actual object staging.
+     *
+     * @throws Exception
+     */
+    protected abstract void doStage() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/DefaultStager.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/DefaultStager.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/DefaultStager.java
new file mode 100644
index 0000000..96cf2a2
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/DefaultStager.java
@@ -0,0 +1,218 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import java.io.Closeable;
+import java.lang.annotation.Annotation;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Queue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Default {@link Stager} implementation.
+ */
+public class DefaultStager<A extends Annotation>
+    implements DisposingStager<A>
+{
+    private final Class<A> stage;
+
+    /**
+     * Stack of elements have to be disposed.
+     */
+    private final Queue<Stageable> stageables;
+
+    /**
+     * @param stage the annotation that specifies this stage
+     */
+    public DefaultStager( Class<A> stage )
+    {
+        this( stage, Order.FIRST_IN_FIRST_OUT );
+    }
+
+       /**
+     * @param stage the annotation that specifies this stage
+     * @param mode  execution order
+     */
+    public DefaultStager( Class<A> stage, Order mode )
+    {
+        this.stage = stage;
+
+        Queue<Stageable> localStageables;
+        switch ( mode )
+        {
+            case FIRST_IN_FIRST_OUT:
+            {
+                localStageables = new ArrayDeque<Stageable>();
+                break;
+            }
+
+            case FIRST_IN_LAST_OUT:
+            {
+                localStageables = Collections.asLifoQueue( new 
ArrayDeque<Stageable>() );
+                break;
+            }
+
+            default:
+            {
+                throw new IllegalArgumentException( "Unknown mode: " + mode );
+            }
+        }
+        stageables = localStageables;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void register( Stageable stageable )
+    {
+        synchronized ( stageables )
+        {
+            stageables.add( stageable );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T extends ExecutorService> T register( T executorService )
+    {
+        register( new ExecutorServiceStageable( executorService ) );
+        return executorService;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T extends Closeable> T register( T closeable )
+    {
+        register( new CloseableStageable( closeable ) );
+        return closeable;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void stage()
+    {
+        stage( null );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void stage( StageHandler stageHandler )
+    {
+        if ( stageHandler == null )
+        {
+            stageHandler = new NoOpStageHandler();
+        }
+
+        while ( true )
+        {
+            Stageable stageable;
+            synchronized ( stageables )
+            {
+                stageable = stageables.poll();
+            }
+            if ( stageable == null )
+            {
+                break;
+            }
+            stageable.stage( stageHandler );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Class<A> getStage()
+    {
+        return stage;
+    }
+
+    /**
+     * specifies ordering for a {@link DefaultStager}
+     */
+    public static enum Order
+    {
+        /**
+         * FIFO
+         */
+        FIRST_IN_FIRST_OUT,
+
+        /**
+         * FILO/LIFO
+         */
+        FIRST_IN_LAST_OUT
+    }
+
+    private static class CloseableStageable extends 
AbstractStageable<Closeable>
+    {
+
+        public CloseableStageable( Closeable closeable )
+        {
+            super( closeable );
+        }
+
+        @Override
+        protected void doStage() throws Exception
+        {
+            object.close();
+        }
+
+    }
+
+    private static class ExecutorServiceStageable extends 
AbstractStageable<ExecutorService>
+    {
+
+        public ExecutorServiceStageable( ExecutorService executor )
+        {
+            super( executor );
+        }
+
+        @Override
+        protected void doStage() throws Exception
+        {
+            object.shutdown();
+            try
+            {
+                if ( !object.awaitTermination( 1, TimeUnit.MINUTES ) )
+                {
+                    object.shutdownNow();
+                }
+            }
+            catch ( InterruptedException e )
+            {
+                object.shutdownNow();
+                Thread.currentThread().interrupt();
+            }
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/DisposingStager.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/DisposingStager.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/DisposingStager.java
new file mode 100644
index 0000000..87bec80
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/DisposingStager.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import java.io.Closeable;
+import java.lang.annotation.Annotation;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * {@link org.apache.onami.lifecycle.core.Stager} that disposes resources.
+ *
+ * @author Mikhail Mazursky
+ */
+public interface DisposingStager<A extends Annotation> extends Stager<A>
+{
+
+    /**
+     * Register an {@link java.util.concurrent.ExecutorService} to be staged.
+     *
+     * @param executorService object to be staged to dispose resources.
+     * @return Staged object
+     */
+    <T extends ExecutorService> T register( T executorService );
+
+    /**
+     * Register a {@link java.io.Closeable} to be staged.
+     *
+     * @param closeable object to be staged to dispose resources.
+     * @return Staged object
+     */
+    <T extends Closeable> T register( T closeable );
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/LifeCycleModule.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/LifeCycleModule.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/LifeCycleModule.java
new file mode 100644
index 0000000..1827e38
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/LifeCycleModule.java
@@ -0,0 +1,117 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.ProvisionException;
+import com.google.inject.TypeLiteral;
+import com.google.inject.matcher.Matcher;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.TypeEncounter;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static com.google.inject.matcher.Matchers.any;
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+
+/**
+ * Guice module to register methods to be invoked after injection is complete.
+ */
+public abstract class LifeCycleModule
+    extends AbstractModule
+{
+
+    /**
+     * Binds lifecycle listener.
+     *
+     * @param annotation the lifecycle annotation to be searched.
+     */
+    protected final void bindLifeCycle( Class<? extends Annotation> annotation 
)
+    {
+        bindLifeCycle( annotation, any() );
+    }
+
+    /**
+     * Binds lifecycle listener.
+     *
+     * @param annotation  the lifecycle annotation to be searched.
+     * @param typeMatcher the filter for injectee types.
+     */
+    protected final void bindLifeCycle( Class<? extends Annotation> 
annotation, Matcher<? super TypeLiteral<?>> typeMatcher )
+    {
+        bindLifeCycle( asList( annotation ), typeMatcher );
+    }
+
+    /**
+     * Binds lifecycle listener.
+     *
+     * @param annotations  the lifecycle annotations to be searched in the 
order to be searched.
+     * @param typeMatcher the filter for injectee types.
+     */
+    protected final void bindLifeCycle( List<? extends Class<? extends 
Annotation>> annotations, Matcher<? super TypeLiteral<?>> typeMatcher )
+    {
+        bindListener( typeMatcher, new AbstractMethodTypeListener( annotations 
)
+        {
+
+            @Override
+            protected <I> void hear( final Method method, TypeLiteral<I> 
parentType, TypeEncounter<I> encounter,
+                                     final Class<? extends Annotation> 
annotationType )
+            {
+                encounter.register( new InjectionListener<I>()
+                {
+
+                    @Override
+                    public void afterInjection( I injectee )
+                    {
+                        try
+                        {
+                            method.invoke( injectee );
+                        }
+                        catch ( IllegalArgumentException e )
+                        {
+                            // should not happen, anyway...
+                            throw new ProvisionException(
+                                format( "Method @%s %s requires arguments", 
annotationType.getName(), method ), e );
+                        }
+                        catch ( IllegalAccessException e )
+                        {
+                            throw new ProvisionException(
+                                format( "Impossible to access to @%s %s on 
%s", annotationType.getName(), method,
+                                        injectee ), e );
+                        }
+                        catch ( InvocationTargetException e )
+                        {
+                            throw new ProvisionException(
+                                format( "An error occurred while invoking @%s 
%s on %s", annotationType.getName(),
+                                        method, injectee ), e.getCause() );
+                        }
+                    }
+
+                } );
+            }
+
+        } );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/LifeCycleStageModule.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/LifeCycleStageModule.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/LifeCycleStageModule.java
new file mode 100644
index 0000000..8698df1
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/LifeCycleStageModule.java
@@ -0,0 +1,200 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.matcher.Matcher;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.TypeEncounter;
+import com.google.inject.util.Types;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.inject.matcher.Matchers.any;
+import static java.util.Arrays.asList;
+
+/**
+ * Guice module to register methods to be invoked when {@link Stager#stage()} 
is invoked.
+ * <p/>
+ * Module instance have has so it must not be used to construct more than one 
{@link com.google.inject.Injector}.
+ */
+public abstract class LifeCycleStageModule
+    extends LifeCycleModule
+{
+
+    private List<BindingBuilder<?>> bindings;
+
+    /**
+     * Convenience to generate the correct key for retrieving stagers from an 
injector.
+     * E.g.
+     * <p/>
+     * <code><pre>
+     * Stager&lt;MyAnnotation&gt; stager = injector.getInstance( 
LifeCycleStageModule.key( MyAnnotation.class ) );
+     * </pre></code>
+     *
+     * @param stage the annotation that represents this stage and the methods 
with this annotation
+     * @param <A>   the Annotation type
+     * @return the Guice key to use for accessing the stager for the input 
stage
+     */
+    public static <A extends Annotation> Key<Stager<A>> key( Class<A> stage )
+    {
+        return Key.get( type( stage ) );
+    }
+
+    private static <A extends Annotation> TypeLiteral<Stager<A>> type( 
Class<A> stage )
+    {
+        ParameterizedType parameterizedType = 
Types.newParameterizedTypeWithOwner( null, Stager.class, stage );
+        //noinspection unchecked
+        @SuppressWarnings( "unchecked" ) // TODO
+        TypeLiteral<Stager<A>> stagerType = (TypeLiteral<Stager<A>>) 
TypeLiteral.get( parameterizedType );
+        return stagerType;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected final void configure()
+    {
+        if ( bindings != null )
+        {
+            throw new IllegalStateException( "Re-entry is not allowed" );
+        }
+        bindings = new ArrayList<BindingBuilder<?>>();
+        try
+        {
+            configureBindings();
+            for ( BindingBuilder<?> binding : bindings )
+            {
+                bind( binding );
+            }
+        }
+        finally
+        {
+            bindings = null;
+        }
+    }
+
+    private <A extends Annotation> void bind( BindingBuilder<A> binding )
+    {
+        final Stager<A> stager = binding.stager;
+        final StageableTypeMapper typeMapper = binding.typeMapper;
+        bind( type( stager.getStage() ) ).toInstance( stager );
+
+        bindListener( binding.typeMatcher, new AbstractMethodTypeListener( 
asList( stager.getStage() ) )
+        {
+
+            @Override
+            protected <I> void hear( final Method stageMethod, final 
TypeLiteral<I> parentType,
+                                     final TypeEncounter<I> encounter,
+                                     final Class<? extends Annotation> 
annotationType )
+            {
+                encounter.register( new InjectionListener<I>()
+                {
+
+                    @Override
+                    public void afterInjection( I injectee )
+                    {
+                        Stageable stageable = new StageableMethod( 
stageMethod, injectee );
+                        stager.register( stageable );
+                        typeMapper.registerType( stageable, parentType );
+                    }
+
+                } );
+            }
+
+        } );
+    }
+
+    protected abstract void configureBindings();
+
+    protected final <A extends Annotation> MapperBinding bindStager( Stager<A> 
stager )
+    {
+        BindingBuilder<A> builder = new BindingBuilder<A>( checkNotNull( 
stager, "Argument 'stager' must be not null" ) );
+        bindings.add( builder );
+        return builder;
+    }
+
+    protected interface MatcherBinding
+    {
+        /**
+         * Sets the filter for injectee types.
+         *
+         * @param typeMatcher the filter for injectee types.
+         */
+        void matching( Matcher<? super TypeLiteral<?>> typeMatcher );
+    }
+
+    protected interface MapperBinding extends MatcherBinding
+    {
+        /**
+         * Sets the container to register mappings from {@link Stageable}s to 
the types that created them.
+         *
+         * @param typeMapper container to map {@link Stageable}s to types.
+         */
+        MatcherBinding mappingWith( StageableTypeMapper typeMapper );
+    }
+
+    /**
+     * Builder pattern helper.
+     */
+    private static class BindingBuilder<A extends Annotation> implements 
MapperBinding
+    {
+
+        private Matcher<? super TypeLiteral<?>> typeMatcher = any();
+
+        private final Stager<A> stager;
+
+        private StageableTypeMapper typeMapper = new NoOpStageableTypeMapper();
+
+        public BindingBuilder( Stager<A> stager )
+        {
+            this.stager = stager;
+        }
+
+        @Override
+        public MatcherBinding mappingWith( StageableTypeMapper typeMapper )
+        {
+            this.typeMapper = checkNotNull( typeMapper, "Argument 'typeMapper' 
must be not null." );
+            return this;
+        }
+
+        @Override
+        public void matching( Matcher<? super TypeLiteral<?>> typeMatcher )
+        {
+            this.typeMatcher = checkNotNull( typeMatcher, "Argument 
'typeMatcher' must be not null" );
+        }
+
+    }
+
+    private static <T> T checkNotNull( T object, String message )
+    {
+        if ( object == null )
+        {
+            throw new IllegalArgumentException( message );
+        }
+        return object;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/NoOpStageHandler.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/NoOpStageHandler.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/NoOpStageHandler.java
new file mode 100644
index 0000000..b543857
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/NoOpStageHandler.java
@@ -0,0 +1,47 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+/**
+ * NOP {@code StageHandler} implementation.
+ */
+public final class NoOpStageHandler
+    implements StageHandler
+{
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <I, E extends Throwable> void onError( I injectee, E error )
+    {
+        // do nothing
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <I> void onSuccess( I injectee )
+    {
+        // do nothing
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/NoOpStageableTypeMapper.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/NoOpStageableTypeMapper.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/NoOpStageableTypeMapper.java
new file mode 100644
index 0000000..f273b6f
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/NoOpStageableTypeMapper.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import com.google.inject.TypeLiteral;
+
+class NoOpStageableTypeMapper
+    implements StageableTypeMapper
+{
+
+    @Override
+    public <I> void registerType( Stageable stageable, TypeLiteral<I> 
parentType )
+    {
+        // NOP
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/PreDestroyModule.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/PreDestroyModule.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/PreDestroyModule.java
new file mode 100644
index 0000000..e28060b
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/PreDestroyModule.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import com.google.inject.TypeLiteral;
+
+import javax.annotation.PreDestroy;
+
+/**
+ * Guice module to register methods to be invoked when {@link 
org.apache.onami.lifecycle.core.Stager#stage()} is invoked.
+ * <p/>
+ * Module instance have state so it must not be used to construct more than 
one {@link com.google.inject.Injector}.
+ *
+ * @author Mikhail Mazursky
+ */
+public class PreDestroyModule
+    extends LifeCycleStageModule
+{
+
+    private final DisposingStager<PreDestroy> stager = new 
DefaultStager<PreDestroy>(
+        PreDestroy.class, DefaultStager.Order.FIRST_IN_LAST_OUT );
+
+    @Override
+    protected void configureBindings()
+    {
+        bindStager( stager );
+        bind( new TypeLiteral<DisposingStager<PreDestroy>>() {} ).toInstance( 
stager );
+    }
+
+    public DisposingStager<PreDestroy> getStager()
+    {
+        return stager;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageHandler.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageHandler.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageHandler.java
new file mode 100644
index 0000000..fa2a576
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageHandler.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.james.onami.lifecycle;
+
+/**
+ * A {@link StageHandler} instance is used to track staging progresses.
+ */
+public interface StageHandler
+{
+
+    /**
+     * Tracks the input injectee successfully staged the resources.
+     *
+     * @param injectee the injectee to be staged
+     */
+    <I> void onSuccess( I injectee );
+
+    /**
+     * Tracks an error occurred while the input injectee staged the resources.
+     *
+     * @param injectee the injectee to be staged
+     * @param error    the exception occurred
+     */
+    <I, E extends Throwable> void onError( I injectee, E error );
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/Stageable.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/Stageable.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/Stageable.java
new file mode 100644
index 0000000..8865cca
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/Stageable.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+/**
+ * Object that knows how to stage some resources.
+ */
+public interface Stageable
+{
+
+    /**
+     * Stage allocated resources, tracking progresses in the
+     * input {@code StageHandler}.
+     *
+     * @param stageHandler the handler to track progresses.
+     */
+    void stage( StageHandler stageHandler );
+
+    /**
+     * @return Description of a stageable resource.
+     */
+    @Override
+    String toString();
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageableMethod.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageableMethod.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageableMethod.java
new file mode 100644
index 0000000..b10315a
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageableMethod.java
@@ -0,0 +1,86 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * A {@link StageableMethod} is a reference to a stageable injectee
+ * and related method to release resources.
+ */
+final class StageableMethod
+    extends AbstractBasicStageable<Object>
+{
+
+    /**
+     * The method to be invoked to stage resources.
+     */
+    private final Method stageMethod;
+
+    /**
+     * Creates a new {@link StageableMethod} reference.
+     *
+     * @param stageMethod the method to be invoked to stage resources.
+     * @param injectee    the target injectee has to stage the resources.
+     */
+    StageableMethod( Method stageMethod, Object injectee )
+    {
+        super( injectee );
+        this.stageMethod = stageMethod;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final void stage( StageHandler stageHandler )
+    {
+        try
+        {
+            AccessController.doPrivileged( new PrivilegedAction<Void>()
+            {
+
+                @Override
+                public Void run()
+                {
+                    stageMethod.setAccessible( true );
+                    return null;
+                }
+
+            } );
+            stageMethod.invoke( object );
+        }
+        catch ( InvocationTargetException e )
+        {
+            stageHandler.onError( object, e.getCause() );
+            return;
+        }
+        catch ( Throwable e )
+        {
+            stageHandler.onError( object, e );
+            return;
+        }
+        stageHandler.onSuccess( object );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageableTypeMapper.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageableTypeMapper.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageableTypeMapper.java
new file mode 100644
index 0000000..e799373
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/StageableTypeMapper.java
@@ -0,0 +1,39 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import com.google.inject.TypeLiteral;
+
+/**
+ * Container for mapping a {@link Stageable} to the parent type
+ * that created it. Useful in specialty Stage containers.
+ */
+public interface StageableTypeMapper
+{
+
+    /**
+     * Register a new {@link Stageable} with the type that created it
+     *
+     * @param stageable stageable
+     * @param parentType     the owning type being heard
+     */
+    <I> void registerType( Stageable stageable, TypeLiteral<I> parentType );
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/Stager.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/Stager.java
 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/Stager.java
new file mode 100644
index 0000000..a6a63c0
--- /dev/null
+++ 
b/server/container/guice/onami/src/main/java/org/apache/james/onami/lifecycle/Stager.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A Stager is a mini-container that stages resources
+ * invoking {@link Stageable#stage(StageHandler)}.
+ * <p/>
+ * Order of disposal is specified by the concrete implementation of this
+ * interface via {@link org.apache.onami.lifecycle.core.DefaultStager.Order}.
+ * <p/>
+ * Implementations must be thread-safe because registration can be done from
+ * any thread.
+ */
+public interface Stager<A extends Annotation>
+{
+
+    /**
+     * Register a {@link Stageable} to stage resources.
+     *
+     * @param stageable object to be invoked to stage resources.
+     */
+    void register( Stageable stageable );
+
+    /**
+     * Stages resources invoking {@link Stageable#stage(StageHandler)}.
+     */
+    void stage();
+
+    /**
+     * Stages resources invoking {@link Stageable#stage(StageHandler)}.
+     *
+     * @param stageHandler the {@link StageHandler} instance that tracks 
progresses.
+     * @since 0.2.0
+     */
+    void stage( StageHandler stageHandler );
+
+    /**
+     * Returns the annotation that represents this stage.
+     *
+     * @return stage annotation.
+     */
+    Class<A> getStage();
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/DefaultStagerTestCase.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/DefaultStagerTestCase.java
 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/DefaultStagerTestCase.java
new file mode 100644
index 0000000..03c9ee6
--- /dev/null
+++ 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/DefaultStagerTestCase.java
@@ -0,0 +1,105 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class DefaultStagerTestCase
+{
+
+    @Test
+    public void stagerShouldStageObjectsRegisteredWhileStaging()
+    {
+        final Stager<TestAnnotationA> stager =
+                new DefaultStager<TestAnnotationA>( TestAnnotationA.class );
+        final AtomicBoolean staged = new AtomicBoolean();
+        stager.register( new Stageable()
+        {
+            @Override
+            public void stage( StageHandler stageHandler )
+            {
+                stager.register( new Stageable()
+                {
+                    @Override
+                    public void stage( StageHandler stageHandler )
+                    {
+                        staged.set( true );
+                    }
+                } );
+            }
+        } );
+
+        stager.stage();
+
+        Assert.assertTrue( staged.get() );
+    }
+
+    /*
+     * Deadlock scenario:
+     * 1. DefaultStager holds lock while calling Stageable.stage();
+     * 2. Stageable.stage() blocks on some thread
+     * 3. the thread blocks on the lock in DefaultStager.register()
+     */
+    @Test
+    public void stagerShouldNotDeadlockWhileStagingObjectChains()
+    {
+        final AtomicBoolean staged = new AtomicBoolean();
+        final Stager<TestAnnotationA> stager =
+                new DefaultStager<TestAnnotationA>( TestAnnotationA.class );
+        stager.register( new Stageable()
+        {
+            @Override
+            public void stage( StageHandler stageHandler )
+            {
+                Thread thread = new Thread( new Runnable()
+                {
+                    @Override
+                    public void run()
+                    {
+                        stager.register( new Stageable()
+                        {
+                            @Override
+                            public void stage( StageHandler stageHandler )
+                            {
+                                staged.set( true );
+                            }
+                        } );
+                    }
+                } );
+                thread.start();
+                try
+                {
+                    thread.join();
+                }
+                catch ( InterruptedException e )
+                {
+                    Thread.currentThread().interrupt();
+                }
+            }
+        } );
+
+        stager.stage();
+
+        Assert.assertTrue( staged.get() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/MultiLifeCycleObject.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/MultiLifeCycleObject.java
 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/MultiLifeCycleObject.java
new file mode 100644
index 0000000..615ad3b
--- /dev/null
+++ 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/MultiLifeCycleObject.java
@@ -0,0 +1,76 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import javax.inject.Singleton;
+
+@Singleton
+public class MultiLifeCycleObject
+{
+    private final StringBuilder str = new StringBuilder();
+
+    @TestAnnotationC
+    public void foo()
+    {
+        str.append( "c" );
+    }
+
+    @TestAnnotationA
+    public void aaa()
+    {
+        str.append( "a" );
+    }
+
+    @TestAnnotationB
+    public void bbb()
+    {
+        str.append( "b" );
+    }
+
+    @TestAnnotationA
+    public void mmm()
+    {
+        str.append( "a" );
+    }
+
+    @TestAnnotationB
+    public void nnn()
+    {
+        str.append( "b" );
+    }
+
+    @TestAnnotationB
+    public void qqq()
+    {
+        str.append( "b" );
+    }
+
+    @TestAnnotationA
+    public void zzz()
+    {
+        str.append( "a" );
+    }
+
+    @Override
+    public String toString()
+    {
+        return str.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/MultiLifeCycleTestCase.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/MultiLifeCycleTestCase.java
 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/MultiLifeCycleTestCase.java
new file mode 100644
index 0000000..0160ac6
--- /dev/null
+++ 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/MultiLifeCycleTestCase.java
@@ -0,0 +1,144 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import static com.google.inject.matcher.Matchers.any;
+import static java.util.Arrays.asList;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import javax.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+public class MultiLifeCycleTestCase
+{
+    @Test
+    public void testOrdering()
+    {
+        Module lifeCycleModule = new TestLifeCycleModule(
+            asList( TestAnnotationA.class, TestAnnotationB.class, 
TestAnnotationC.class ) );
+        MultiLifeCycleObject obj = Guice.createInjector( lifeCycleModule 
).getInstance( MultiLifeCycleObject.class );
+        Assert.assertEquals( "aaabbbc", obj.toString() );
+    }
+
+    public static class Foo
+    {
+        @Inject
+        public Foo( Stager<TestAnnotationA> stager )
+        {
+            System.out.println( stager.getStage() );
+        }
+    }
+
+    @Test
+    public void testStaging()
+    {
+        Module moduleA =
+            new TestLifeCycleStageModule( new DefaultStager<TestAnnotationA>( 
TestAnnotationA.class ) );
+        Module moduleB =
+            new TestLifeCycleStageModule( new DefaultStager<TestAnnotationB>( 
TestAnnotationB.class ) );
+        Module moduleC =
+            new TestLifeCycleStageModule( new DefaultStager<TestAnnotationC>( 
TestAnnotationC.class ) );
+
+        Injector injector = Guice.createInjector( moduleA, moduleB, moduleC );
+        MultiLifeCycleObject obj = injector.getInstance( 
MultiLifeCycleObject.class );
+
+        Assert.assertEquals( obj.toString(), "" );
+
+        injector.getInstance( LifeCycleStageModule.key( TestAnnotationA.class 
) ).stage();
+        Assert.assertEquals( "aaa", obj.toString() );
+        injector.getInstance( LifeCycleStageModule.key( TestAnnotationB.class 
) ).stage();
+        Assert.assertEquals( "aaabbb", obj.toString() );
+        injector.getInstance( LifeCycleStageModule.key( TestAnnotationC.class 
) ).stage();
+        Assert.assertEquals( "aaabbbc", obj.toString() );
+
+        injector.getInstance( Foo.class );
+    }
+
+    @Test
+    public void testStagingOrdering()
+    {
+        Module moduleA =
+            new TestLifeCycleStageModule( new DefaultStager<TestAnnotationA>( 
TestAnnotationA.class, DefaultStager.Order.FIRST_IN_FIRST_OUT ) );
+        Module moduleB =
+            new TestLifeCycleStageModule( new DefaultStager<TestAnnotationB>( 
TestAnnotationB.class, DefaultStager.Order.FIRST_IN_LAST_OUT ) );
+
+        final StringBuilder str = new StringBuilder();
+        Module m = new AbstractModule()
+        {
+            @Override
+            protected void configure()
+            {
+                binder().bind( StringBuilder.class ).toInstance( str );
+            }
+        };
+
+        Injector injector = Guice.createInjector( moduleA, moduleB, m );
+        injector.getInstance( StageObject1.class );
+        injector.getInstance( StageObject2.class );
+
+        injector.getInstance( LifeCycleStageModule.key( TestAnnotationA.class 
) ).stage();
+        Assert.assertEquals( "1a2a", str.toString() );
+        str.setLength( 0 );
+
+        injector.getInstance( LifeCycleStageModule.key( TestAnnotationB.class 
) ).stage();
+        Assert.assertEquals( "2b1b", str.toString() );
+    }
+
+    private static class TestLifeCycleModule extends LifeCycleModule
+    {
+
+        private final List<? extends Class<? extends Annotation>> annotations;
+
+        public TestLifeCycleModule( List<? extends Class<? extends 
Annotation>> annotations )
+        {
+            this.annotations = annotations;
+        }
+
+        @Override
+        protected void configure()
+        {
+            bindLifeCycle( annotations, any() );
+        }
+    }
+
+    private static class TestLifeCycleStageModule extends LifeCycleStageModule
+    {
+
+        private final Stager<?> stager;
+
+        public TestLifeCycleStageModule( Stager<?> stager )
+        {
+            this.stager = stager;
+        }
+
+        @Override
+        protected void configureBindings()
+        {
+            bindStager( stager );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StageObject1.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StageObject1.java
 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StageObject1.java
new file mode 100644
index 0000000..e5a899b
--- /dev/null
+++ 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StageObject1.java
@@ -0,0 +1,45 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import javax.inject.Inject;
+
+public class StageObject1
+{
+    private final StringBuilder str;
+
+    @Inject
+    public StageObject1( StringBuilder str )
+    {
+        this.str = str;
+    }
+
+    @TestAnnotationA
+    public void stageA()
+    {
+        str.append( "1a" );
+    }
+
+    @TestAnnotationB
+    public void stageB()
+    {
+        str.append( "1b" );
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StageObject2.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StageObject2.java
 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StageObject2.java
new file mode 100644
index 0000000..1929d7c
--- /dev/null
+++ 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StageObject2.java
@@ -0,0 +1,45 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import javax.inject.Inject;
+
+public class StageObject2
+{
+    private final StringBuilder str;
+
+    @Inject
+    public StageObject2( StringBuilder str )
+    {
+        this.str = str;
+    }
+
+    @TestAnnotationA
+    public void stageA()
+    {
+        str.append( "2a" );
+    }
+
+    @TestAnnotationB
+    public void stageB()
+    {
+        str.append( "2b" );
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StagingOrderTestCase.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StagingOrderTestCase.java
 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StagingOrderTestCase.java
new file mode 100644
index 0000000..287367c
--- /dev/null
+++ 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/StagingOrderTestCase.java
@@ -0,0 +1,85 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class StagingOrderTestCase
+{
+    @Test
+    public void testFifo()
+    {
+        List<Integer> order = new ArrayList<Integer>();
+        DefaultStager<TestAnnotationA> stager = makeStager( order, 
DefaultStager.Order.FIRST_IN_FIRST_OUT );
+        stager.stage();
+
+        Assert.assertEquals( Arrays.asList( 1, 2, 3 ), order );
+    }
+
+    @Test
+    public void testFilo()
+    {
+        List<Integer> order = new ArrayList<Integer>();
+        DefaultStager<TestAnnotationA> stager = makeStager( order, 
DefaultStager.Order.FIRST_IN_LAST_OUT );
+        stager.stage();
+
+        Assert.assertEquals( Arrays.asList( 3, 2, 1 ), order );
+    }
+
+    private DefaultStager<TestAnnotationA> makeStager( final List<Integer> 
order, DefaultStager.Order stagingOrder )
+    {
+        Stageable stageable1 = new Stageable()
+        {
+            @Override
+            public void stage( StageHandler stageHandler )
+            {
+                order.add( 1 );
+            }
+        };
+        Stageable stageable2 = new Stageable()
+        {
+            @Override
+            public void stage( StageHandler stageHandler )
+            {
+                order.add( 2 );
+            }
+        };
+        Stageable stageable3 = new Stageable()
+        {
+            @Override
+            public void stage( StageHandler stageHandler )
+            {
+                order.add( 3 );
+            }
+        };
+
+        DefaultStager<TestAnnotationA> stager =
+            new DefaultStager<TestAnnotationA>( TestAnnotationA.class, 
stagingOrder );
+        stager.register( stageable1 );
+        stager.register( stageable2 );
+        stager.register( stageable3 );
+        return stager;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/TestAnnotationA.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/TestAnnotationA.java
 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/TestAnnotationA.java
new file mode 100644
index 0000000..1e17c5e
--- /dev/null
+++ 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/TestAnnotationA.java
@@ -0,0 +1,33 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface TestAnnotationA
+{
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c1f94a46/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/TestAnnotationB.java
----------------------------------------------------------------------
diff --git 
a/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/TestAnnotationB.java
 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/TestAnnotationB.java
new file mode 100644
index 0000000..ec26c62
--- /dev/null
+++ 
b/server/container/guice/onami/src/test/java/org/apache/james/onami/lifecycle/TestAnnotationB.java
@@ -0,0 +1,33 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.onami.lifecycle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Retention( RUNTIME )
+@Target( METHOD )
+public @interface TestAnnotationB
+{
+
+}


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

Reply via email to