You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@onami.apache.org by ra...@apache.org on 2013/03/14 19:21:31 UTC

svn commit: r1456589 - in /incubator/onami/trunk/lifecycle/warmup: main/java/org/apache/onami/lifecycle/warmup/ test/ test/java/ test/java/org/ test/java/org/apachi/ test/java/org/apachi/onami/ test/java/org/apachi/onami/lifecycle/ test/java/org/apachi...

Author: randgalt
Date: Thu Mar 14 18:21:30 2013
New Revision: 1456589

URL: http://svn.apache.org/r1456589
Log:
Initial pass at warm up is done

Added:
    incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpTask.java   (with props)
    incubator/onami/trunk/lifecycle/warmup/test/
    incubator/onami/trunk/lifecycle/warmup/test/java/
    incubator/onami/trunk/lifecycle/warmup/test/java/org/
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag1.java   (with props)
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag2.java   (with props)
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag3.java   (with props)
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag4.java   (with props)
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Flat.java
      - copied, changed from r1456588, incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Recorder.java   (with props)
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/RecorderSleepSettings.java   (with props)
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/TestWarmUpManager.java   (with props)
    incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/WarmUpWithException.java
      - copied, changed from r1456588, incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java
Modified:
    incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java
    incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpModule.java
    incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUper.java

Modified: incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java?rev=1456589&r1=1456588&r2=1456589&view=diff
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java (original)
+++ incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java Thu Mar 14 18:21:30 2013
@@ -27,8 +27,8 @@ import static java.lang.annotation.Eleme
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 @Documented
-@Retention(RUNTIME)
-@Target(METHOD)
+@Retention( RUNTIME )
+@Target( METHOD )
 public @interface WarmUp
 {
 

Modified: incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpModule.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpModule.java?rev=1456589&r1=1456588&r2=1456589&view=diff
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpModule.java (original)
+++ incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpModule.java Thu Mar 14 18:21:30 2013
@@ -1,11 +1,32 @@
 package org.apache.onami.lifecycle.warmup;
 
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 import com.google.inject.AbstractModule;
 import com.google.inject.TypeLiteral;
 import com.google.inject.matcher.Matcher;
 import org.apache.onami.lifecycle.core.LifeCycleStageModule;
+import org.apache.onami.lifecycle.core.StageableTypeMapper;
 
 import java.lang.annotation.Annotation;
+import java.util.concurrent.TimeUnit;
 
 import static com.google.inject.matcher.Matchers.any;
 
@@ -14,6 +35,8 @@ public class WarmUpModule<A extends Anno
 {
     private final LifeCycleStageModule<A> lifeCycleStageModule;
 
+    private static final long DEFAULT_WAIT_MS = TimeUnit.DAYS.toMillis( Integer.MAX_VALUE );    // essentially forever
+
     public WarmUpModule( Class<A> stage )
     {
         this( stage, any() );
@@ -28,7 +51,7 @@ public class WarmUpModule<A extends Anno
      */
     public WarmUpModule( Class<A> stage, Matcher<? super TypeLiteral<?>> typeMatcher )
     {
-        WarmUper<A> stager = new WarmUper<A>( stage );
+        WarmUper<A> stager = new WarmUper<A>( stage, DEFAULT_WAIT_MS );
         lifeCycleStageModule =
             LifeCycleStageModule.builder( stage ).withTypeMatcher( typeMatcher ).withStager( stager ).withTypeMapper(
                 stager ).build();
@@ -44,16 +67,16 @@ public class WarmUpModule<A extends Anno
         return new WarmUpModule<WarmUp>( WarmUp.class, typeMatcher );
     }
 
-    public static LifeCycleStageModule.Builder<WarmUp> builder()
+    public static Builder<WarmUp> builder()
     {
-        WarmUper<WarmUp> stager = new WarmUper<WarmUp>( WarmUp.class );
-        return LifeCycleStageModule.builder( WarmUp.class ).withStager( stager ).withTypeMapper( stager );
+        WarmUper<WarmUp> stager = new WarmUper<WarmUp>( WarmUp.class, DEFAULT_WAIT_MS );
+        return new Builder<WarmUp>( WarmUp.class, stager ).withTypeMapper( stager );
     }
 
-    public static <A extends Annotation> LifeCycleStageModule.Builder<A> builder( Class<A> stage )
+    public static <A extends Annotation> Builder<A> builder( Class<A> stage )
     {
-        WarmUper<A> stager = new WarmUper<A>( stage );
-        return LifeCycleStageModule.builder( stage ).withStager( stager ).withTypeMapper( stager );
+        WarmUper<A> stager = new WarmUper<A>( stage, DEFAULT_WAIT_MS );
+        return new Builder<A>( stage, stager ).withTypeMapper( stager );
     }
 
     @Override
@@ -61,4 +84,65 @@ public class WarmUpModule<A extends Anno
     {
         binder().install( lifeCycleStageModule );
     }
+
+    public static class Builder<A extends Annotation>
+    {
+        private final WarmUper<A> stager;
+
+        private LifeCycleStageModule.Builder<A> internalBuilder;
+
+        Builder( Class<A> annotationClass, WarmUper<A> stager )
+        {
+            this.stager = stager;
+            internalBuilder = LifeCycleStageModule.builder( annotationClass ).withStager( stager );
+        }
+
+        /**
+         * Builds {@link LifeCycleStageModule} with given settings.
+         *
+         * @return {@link LifeCycleStageModule} with given settings.
+         */
+        public LifeCycleStageModule<A> build()
+        {
+            return internalBuilder.build();
+        }
+
+        /**
+         * Sets the filter for injectee types.
+         *
+         * @param typeMatcher the filter for injectee types.
+         * @return self
+         */
+        public Builder<A> withTypeMatcher( Matcher<? super TypeLiteral<?>> typeMatcher )
+        {
+            internalBuilder.withTypeMatcher( typeMatcher );
+            return this;
+        }
+
+        /**
+         * Sets the container to register mappings from {@link org.apache.onami.lifecycle.core.Stageable}s to the types that created them.
+         *
+         * @param typeMapper container to map {@link org.apache.onami.lifecycle.core.Stageable}s to types
+         * @return self
+         */
+        public Builder<A> withTypeMapper( StageableTypeMapper<A> typeMapper )
+        {
+            internalBuilder.withTypeMapper( typeMapper );
+            return this;
+        }
+
+        /**
+         * When the warm up is staged, it will wait until this maximum time for warm ups to finish.
+         * The default is to wait forever
+         *
+         * @param maxWait max time to wait
+         * @param unit    time unit
+         * @return self
+         */
+        public Builder<A> withMaxWait( long maxWait, TimeUnit unit )
+        {
+            stager.setMaxWait( maxWait, unit );
+            return this;
+        }
+    }
 }

Added: incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpTask.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpTask.java?rev=1456589&view=auto
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpTask.java (added)
+++ incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpTask.java Thu Mar 14 18:21:30 2013
@@ -0,0 +1,167 @@
+package org.apache.onami.lifecycle.warmup;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.ConfigurationException;
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.InjectionPoint;
+import jsr166y.RecursiveAction;
+import org.apache.onami.lifecycle.core.StageHandler;
+import org.apache.onami.lifecycle.core.Stageable;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+class WarmUpTask
+    extends RecursiveAction
+{
+    private final StageHandler stageHandler;
+
+    private final TypeLiteral<?> typeLiteral;
+
+    private final Map<TypeLiteral<?>, Set<Stageable>> reverseLookup;
+
+    private final ConcurrentMap<TypeLiteral<?>, WarmUpTask> inProgress;
+
+    WarmUpTask( StageHandler stageHandler, TypeLiteral<?> typeLiteral,
+                Map<TypeLiteral<?>, Set<Stageable>> reverseLookup, ConcurrentMap<TypeLiteral<?>, WarmUpTask> inProgress )
+    {
+        this.stageHandler = stageHandler;
+        this.typeLiteral = typeLiteral;
+        this.reverseLookup = reverseLookup;
+        this.inProgress = inProgress;
+    }
+
+    @Override
+    protected void compute()
+    {
+        List<WarmUpTask> tasksToJoin = new ArrayList<WarmUpTask>();
+        if ( typeLiteral == null )
+        {
+            computeRoot( tasksToJoin );
+        }
+        else
+        {
+            internalCompute( tasksToJoin );
+        }
+
+        for ( WarmUpTask task : tasksToJoin )
+        {
+            task.join();
+        }
+
+        Set<Stageable> stageables = reverseLookup.get( typeLiteral );
+        if ( stageables != null )
+        {
+            for ( Stageable stageable : stageables )
+            {
+                stageable.stage( stageHandler );
+            }
+        }
+    }
+
+    private void computeRoot( List<WarmUpTask> tasksToJoin )
+    {
+        for ( TypeLiteral<?> typeLiteral : reverseLookup.keySet() )
+        {
+            WarmUpTask warmUpTask = new WarmUpTask( stageHandler, typeLiteral, reverseLookup, inProgress );
+            startTask( tasksToJoin, warmUpTask );
+        }
+
+        for ( WarmUpTask task : tasksToJoin )
+        {
+            task.join();
+        }
+    }
+
+    private void internalCompute( List<WarmUpTask> tasksToJoin )
+    {
+        List<WarmUpTask> childTasks = new ArrayList<WarmUpTask>();
+        addDependency( childTasks, getConstructorInjectionPoint( typeLiteral ) );
+        for ( InjectionPoint injectionPoint : getMethodInjectionPoints( typeLiteral ) )
+        {
+            addDependency( childTasks, injectionPoint );
+        }
+
+        for ( WarmUpTask childTask : childTasks )
+        {
+            startTask( tasksToJoin, childTask );
+        }
+    }
+
+    private void startTask( List<WarmUpTask> tasksToJoin, WarmUpTask childTask )
+    {
+        WarmUpTask existingTask = inProgress.putIfAbsent( childTask.typeLiteral, childTask );
+        if ( existingTask == null )
+        {
+            childTask.fork();
+            tasksToJoin.add( childTask );
+        }
+        else
+        {
+            tasksToJoin.add( existingTask );
+        }
+    }
+
+    private void addDependency( List<WarmUpTask> childTasks, InjectionPoint injectionPoint )
+    {
+        if ( injectionPoint != null )
+        {
+            List<Dependency<?>> dependencies = injectionPoint.getDependencies();
+            for ( Dependency<?> dependency : dependencies )
+            {
+                TypeLiteral<?> dependencyTypeLiteral = dependency.getKey().getTypeLiteral();
+                childTasks.add(
+                    new WarmUpTask( stageHandler, dependencyTypeLiteral, reverseLookup, inProgress ) );
+            }
+        }
+    }
+
+    private Set<InjectionPoint> getMethodInjectionPoints( TypeLiteral<?> type )
+    {
+        try
+        {
+            return InjectionPoint.forInstanceMethodsAndFields( type );
+        }
+        catch ( ConfigurationException e )
+        {
+            // ignore
+        }
+        return new HashSet<InjectionPoint>();
+    }
+
+    private InjectionPoint getConstructorInjectionPoint( TypeLiteral<?> type )
+    {
+        try
+        {
+            return InjectionPoint.forConstructorOf( type );
+        }
+        catch ( ConfigurationException e )
+        {
+            // ignore
+        }
+        return null;
+    }
+}

Propchange: incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpTask.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpTask.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUpTask.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUper.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUper.java?rev=1456589&r1=1456588&r2=1456589&view=diff
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUper.java (original)
+++ incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUper.java Thu Mar 14 18:21:30 2013
@@ -20,6 +20,7 @@ package org.apache.onami.lifecycle.warmu
  */
 
 import com.google.inject.TypeLiteral;
+import jsr166y.ForkJoinPool;
 import org.apache.onami.lifecycle.core.NoOpStageHandler;
 import org.apache.onami.lifecycle.core.StageHandler;
 import org.apache.onami.lifecycle.core.Stageable;
@@ -28,10 +29,14 @@ import org.apache.onami.lifecycle.core.S
 import sun.java2d.Disposer;
 
 import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
-import java.util.Queue;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Default {@link Disposer} implementation.
@@ -41,24 +46,43 @@ import java.util.concurrent.ConcurrentLi
 public class WarmUper<A extends Annotation>
     implements Stager<A>, StageableTypeMapper<A>
 {
-    private final Queue<Stageable> stageables = new ConcurrentLinkedQueue<Stageable>();
-    private final Map<Stageable, TypeLiteral<?>> types = new ConcurrentHashMap<Stageable, TypeLiteral<?>>();
+    private final ConcurrentMap<TypeLiteral<?>, Set<Stageable>> reverseLookup =
+        new ConcurrentHashMap<TypeLiteral<?>, Set<Stageable>>();
 
     private final Class<A> stage;
 
-    public WarmUper( Class<A> stage )
+    private volatile long maxMs;
+
+    public WarmUper( Class<A> stage, long maxMs )
     {
         this.stage = stage;
+        this.maxMs = maxMs;
+    }
+
+    /**
+     * When the warm up is staged, it will wait until this maximum time for warm ups to finish.
+     * The default is to wait forever
+     *
+     * @param maxWait max time to wait
+     * @param unit    time unit
+     */
+    public void setMaxWait( long maxWait, TimeUnit unit )
+    {
+        this.maxMs = unit.toMillis( maxWait );
     }
 
     public <I> void registerType( Stageable stageable, TypeLiteral<I> parentType )
     {
-        types.put( stageable, parentType );
+        Set<Stageable> newList = Collections.newSetFromMap( new ConcurrentHashMap<Stageable, Boolean>() );
+        Set<Stageable> oldList = reverseLookup.putIfAbsent( parentType, newList );
+        Set<Stageable> useList = ( oldList != null ) ? oldList : newList;
+        useList.add( stageable );
+
     }
 
     public void register( Stageable stageable )
     {
-        stageables.add( stageable );
+        // this is a NOP for warm up. Use registerType instead
     }
 
     public void stage()
@@ -68,6 +92,29 @@ public class WarmUper<A extends Annotati
 
     public void stage( StageHandler stageHandler )
     {
+        Map<TypeLiteral<?>, Set<Stageable>> localCopy = new HashMap<TypeLiteral<?>, Set<Stageable>>();
+        localCopy.putAll( reverseLookup );
+        reverseLookup.clear();
+
+        ForkJoinPool forkJoinPool = new ForkJoinPool();
+        ConcurrentMap<TypeLiteral<?>, WarmUpTask> inProgress = new ConcurrentHashMap<TypeLiteral<?>, WarmUpTask>();
+        forkJoinPool.submit( new WarmUpTask( stageHandler, null, localCopy, inProgress ) );
+        forkJoinPool.shutdown();
+
+        try
+        {
+            boolean success = forkJoinPool.awaitTermination( maxMs, TimeUnit.MILLISECONDS );
+            if ( !success )
+            {
+                forkJoinPool.shutdownNow();
+                throw new RuntimeException( new TimeoutException( "Warm up stager timed out" ) );
+            }
+        }
+        catch ( InterruptedException e )
+        {
+            Thread.currentThread().interrupt();
+        }
+
     }
 
     public Class<A> getStage()

Added: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag1.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag1.java?rev=1456589&view=auto
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag1.java (added)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag1.java Thu Mar 14 18:21:30 2013
@@ -0,0 +1,95 @@
+package org.apachi.onami.lifecycle.warmup;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.onami.lifecycle.warmup.WarmUp;
+
+public class Dag1
+{
+    /*
+        3 Classes all with warmups
+
+            B
+          <
+        A
+          <
+            C
+     */
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class A
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public A( Recorder recorder, B b, C c )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "A" );
+        }
+    }
+
+    @Singleton
+    public static class B
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public B( Recorder recorder )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "B" );
+        }
+    }
+
+    @Singleton
+    public static class C
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public C( Recorder recorder )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "C" );
+        }
+    }
+}

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag1.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag1.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag1.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag2.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag2.java?rev=1456589&view=auto
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag2.java (added)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag2.java Thu Mar 14 18:21:30 2013
@@ -0,0 +1,242 @@
+package org.apachi.onami.lifecycle.warmup;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.onami.lifecycle.warmup.WarmUp;
+
+public class Dag2
+{
+    /*
+        3 tiers of classes all with warmups
+
+             B1
+           <    >
+        A1        C1
+           <    >
+             B2
+           <    >
+        A2        C2
+           <    >
+             B3
+           <    >
+        A3        C3
+           <    >
+             B4
+     */
+
+    @Singleton
+    public static class C1
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public C1( Recorder recorder )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "C1" );
+        }
+    }
+
+    @Singleton
+    public static class C2
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public C2( Recorder recorder )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "C2" );
+        }
+    }
+
+    @Singleton
+    public static class C3
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public C3( Recorder recorder )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "C3" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class B1
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public B1( Recorder recorder, C1 c1 )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "B1" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class B2
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public B2( Recorder recorder, C1 c1, C2 c2 )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "B2" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class B3
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public B3( Recorder recorder, C2 c2, C3 c3 )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "B3" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class B4
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public B4( Recorder recorder, C3 c3 )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "B4" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class A1
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public A1( Recorder recorder, B1 b1, B2 b2 )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "A1" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class A2
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public A2( Recorder recorder, B2 b2, B3 b3 )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "A2" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class A3
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public A3( Recorder recorder, B3 b3, B4 b4 )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "A3" );
+        }
+    }
+}

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag2.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag2.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag2.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag3.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag3.java?rev=1456589&view=auto
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag3.java (added)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag3.java Thu Mar 14 18:21:30 2013
@@ -0,0 +1,142 @@
+package org.apachi.onami.lifecycle.warmup;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.onami.lifecycle.warmup.WarmUp;
+
+public class Dag3
+{
+    /*
+        Mix of classes with/without warmups and
+        dependencies that cross tiers
+
+
+                  C
+                <      >
+            BnW
+          <
+        A       ==>       D
+          <
+            B
+                <      >
+                  CnW
+     */
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class A
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public A( Recorder recorder, BnW bnw, B b, D d )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "A" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class B
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public B( Recorder recorder, CnW cnw )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "B" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class BnW
+    {
+        @Inject
+        public BnW( C c )
+        {
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class C
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public C( Recorder recorder, D d )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "C" );
+        }
+    }
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class CnW
+    {
+        @Inject
+        public CnW( D d )
+        {
+        }
+    }
+
+    @Singleton
+    public static class D
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public D( Recorder recorder )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "D" );
+        }
+    }
+}

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag3.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag3.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag3.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag4.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag4.java?rev=1456589&view=auto
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag4.java (added)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag4.java Thu Mar 14 18:21:30 2013
@@ -0,0 +1,157 @@
+package org.apachi.onami.lifecycle.warmup;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.onami.lifecycle.warmup.WarmUp;
+
+public class Dag4
+{
+    /*
+                    E
+                  <   <
+                D       \
+              <   <     \
+            B       F   \
+          <             \
+        A               \
+          <             \
+            C  - - - - -
+     */
+
+    @SuppressWarnings( "UnusedParameters" )
+    @Singleton
+    public static class A
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public A( Recorder recorder, B b, C c )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "A" );
+        }
+    }
+
+    @Singleton
+    @SuppressWarnings( "UnusedParameters" )
+    public static class B
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public B( Recorder recorder, D d )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "B" );
+        }
+    }
+
+    @Singleton
+    @SuppressWarnings( "UnusedParameters" )
+    public static class C
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public C( Recorder recorder, E e )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "C" );
+        }
+    }
+
+    @Singleton
+    @SuppressWarnings( "UnusedParameters" )
+    public static class D
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public D( Recorder recorder, E e, F f )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "D" );
+        }
+    }
+
+    @Singleton
+    public static class E
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public E( Recorder recorder )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "E" );
+        }
+    }
+
+    @Singleton
+    public static class F
+    {
+        private final Recorder recorder;
+
+        @Inject
+        public F( Recorder recorder )
+        {
+            this.recorder = recorder;
+        }
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "F" );
+        }
+    }
+}

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag4.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag4.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Dag4.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Flat.java (from r1456588, incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java)
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Flat.java?p2=incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Flat.java&p1=incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java&r1=1456588&r2=1456589&rev=1456589&view=diff
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java (original)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Flat.java Thu Mar 14 18:21:30 2013
@@ -1,4 +1,4 @@
-package org.apache.onami.lifecycle.warmup;
+package org.apachi.onami.lifecycle.warmup;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,38 @@ package org.apache.onami.lifecycle.warmu
  * under the License.
  */
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-@Documented
-@Retention(RUNTIME)
-@Target(METHOD)
-public @interface WarmUp
+import com.google.inject.Singleton;
+import org.apache.onami.lifecycle.warmup.WarmUp;
+
+public class Flat
 {
+    /*
+        Root classes without dependencies
+     */
+
+    @Singleton
+    public static class A
+    {
+        public volatile Recorder recorder;
+
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "A" );
+        }
+    }
+
+    @Singleton
+    public static class B
+    {
+        public volatile Recorder recorder;
 
+        @WarmUp
+        public void warmUp()
+            throws InterruptedException
+        {
+            recorder.record( "B" );
+        }
+    }
 }

Added: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Recorder.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Recorder.java?rev=1456589&view=auto
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Recorder.java (added)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Recorder.java Thu Mar 14 18:21:30 2013
@@ -0,0 +1,89 @@
+package org.apachi.onami.lifecycle.warmup;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Singleton
+public class Recorder
+{
+    private final List<String> recordings = new ArrayList<String>();
+
+    private final List<String> interruptions = new ArrayList<String>();
+
+    private final RecorderSleepSettings recorderSleepSettings;
+
+    private final Set<Set<String>> concurrents = new HashSet<Set<String>>();
+
+    private final Set<String> activeConcurrents = new HashSet<String>();
+
+    @Inject
+    public Recorder( RecorderSleepSettings recorderSleepSettings )
+    {
+        this.recorderSleepSettings = recorderSleepSettings;
+    }
+
+    public synchronized void record( String s )
+        throws InterruptedException
+    {
+
+        recordings.add( s );
+
+        Long sleepMs = recorderSleepSettings.getSleepMsFor( s );
+
+        activeConcurrents.add( s );
+        try
+        {
+            concurrents.add( new HashSet<String>( activeConcurrents ) );
+            wait( sleepMs );
+        }
+        catch ( InterruptedException e )
+        {
+            interruptions.add( s );
+            Thread.currentThread().interrupt();
+            throw e;
+        }
+        finally
+        {
+            activeConcurrents.remove( s );
+        }
+    }
+
+    public synchronized List<String> getRecordings()
+    {
+        return new ArrayList<String>( recordings );
+    }
+
+    public synchronized List<String> getInterruptions()
+    {
+        return new ArrayList<String>( interruptions );
+    }
+
+    public synchronized Set<Set<String>> getConcurrents()
+    {
+        return new HashSet<Set<String>>( concurrents );
+    }
+}

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Recorder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Recorder.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/Recorder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/RecorderSleepSettings.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/RecorderSleepSettings.java?rev=1456589&view=auto
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/RecorderSleepSettings.java (added)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/RecorderSleepSettings.java Thu Mar 14 18:21:30 2013
@@ -0,0 +1,65 @@
+package org.apachi.onami.lifecycle.warmup;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.Singleton;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+@Singleton
+public class RecorderSleepSettings
+{
+    private static final int DEFAULT_SLEEP_MS = 1000;
+
+    private final AtomicLong baseSleepMs = new AtomicLong( DEFAULT_SLEEP_MS );
+
+    private final Map<String, Long> baseSleepMsForString = new HashMap<String, Long>();
+
+    private final AtomicBoolean randomize = new AtomicBoolean( true );
+
+    public void setBaseSleep( long time, TimeUnit unit )
+    {
+        baseSleepMs.set( unit.toMillis( time ) );
+    }
+
+    public void setBaseSleepFor( String s, long time, TimeUnit unit )
+    {
+        baseSleepMsForString.put( s, unit.toMillis( time ) );
+    }
+
+    public long getSleepMsFor( String s )
+    {
+        long sleepMs = baseSleepMsForString.containsKey( s ) ? baseSleepMsForString.get( s ) : baseSleepMs.get();
+        if ( randomize.get() )
+        {
+            sleepMs = ( (int) ( sleepMs * Math.random() ) + 1 );
+        }
+        return sleepMs;
+    }
+
+    public void setRandomize( boolean randomize )
+    {
+        this.randomize.set( randomize );
+    }
+}

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/RecorderSleepSettings.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/RecorderSleepSettings.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/RecorderSleepSettings.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/TestWarmUpManager.java
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/TestWarmUpManager.java?rev=1456589&view=auto
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/TestWarmUpManager.java (added)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/TestWarmUpManager.java Thu Mar 14 18:21:30 2013
@@ -0,0 +1,285 @@
+package org.apachi.onami.lifecycle.warmup;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import org.apache.onami.lifecycle.core.LifeCycleStageModule;
+import org.apache.onami.lifecycle.core.StageHandler;
+import org.apache.onami.lifecycle.core.Stager;
+import org.apache.onami.lifecycle.warmup.WarmUp;
+import org.apache.onami.lifecycle.warmup.WarmUpModule;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class TestWarmUpManager
+{
+    @SuppressWarnings( "ThrowableResultOfMethodCallIgnored" )
+    @Test
+    public void testErrors()
+        throws Exception
+    {
+        AbstractModule module = new AbstractModule()
+        {
+            @Override
+            protected void configure()
+            {
+                binder().bind( WarmUpWithException.class ).asEagerSingleton();
+            }
+        };
+        Injector injector = Guice.createInjector( WarmUpModule.newWarmUpModule(), module );
+
+        final AtomicInteger errorCount = new AtomicInteger( 0 );
+        StageHandler stageHandler = new StageHandler()
+        {
+            public <I> void onSuccess( I injectee )
+            {
+            }
+
+            public <I, E extends Throwable> void onError( I injectee, E error )
+            {
+                errorCount.incrementAndGet();
+            }
+        };
+        injector.getInstance( LifeCycleStageModule.key( WarmUp.class ) ).stage( stageHandler );
+        Assert.assertEquals( errorCount.get(), 1 );
+    }
+
+    @Test
+    public void testDag1()
+        throws Exception
+    {
+        Injector injector = Guice.createInjector( WarmUpModule.newWarmUpModule() );
+        injector.getInstance( Dag1.A.class );
+        injector.getInstance( LifeCycleStageModule.key( WarmUp.class ) ).stage();
+        Recorder recorder = injector.getInstance( Recorder.class );
+
+        System.out.println( recorder.getRecordings() );
+        System.out.println( recorder.getConcurrents() );
+
+        assertSingleExecution( recorder );
+        assertNotConcurrent( recorder, "A", "B" );
+        assertNotConcurrent( recorder, "A", "C" );
+
+        Assert.assertEquals( recorder.getInterruptions().size(), 0 );
+        assertOrdering( recorder, "A", "B" );
+        assertOrdering( recorder, "A", "C" );
+    }
+
+    @Test
+    public void testDag2()
+        throws Exception
+    {
+        Injector injector = Guice.createInjector( WarmUpModule.newWarmUpModule() );
+        injector.getInstance( Dag2.A1.class );
+        injector.getInstance( Dag2.A2.class );
+        injector.getInstance( Dag2.A3.class );
+        injector.getInstance( LifeCycleStageModule.key( WarmUp.class ) ).stage();
+        Recorder recorder = injector.getInstance( Recorder.class );
+
+        System.out.println( recorder.getRecordings() );
+        System.out.println( recorder.getConcurrents() );
+
+        assertSingleExecution( recorder );
+
+        assertNotConcurrent( recorder, "A1", "B1" );
+        assertNotConcurrent( recorder, "A1", "B2" );
+        assertNotConcurrent( recorder, "B1", "C1" );
+        assertNotConcurrent( recorder, "B2", "C1" );
+        assertNotConcurrent( recorder, "A2", "B2" );
+        assertNotConcurrent( recorder, "A2", "B3" );
+        assertNotConcurrent( recorder, "B2", "C2" );
+        assertNotConcurrent( recorder, "B3", "C2" );
+        assertNotConcurrent( recorder, "A3", "B3" );
+        assertNotConcurrent( recorder, "A3", "B4" );
+        assertNotConcurrent( recorder, "B3", "C3" );
+        assertNotConcurrent( recorder, "B4", "C3" );
+
+        Assert.assertEquals( recorder.getInterruptions().size(), 0 );
+        assertOrdering( recorder, "A1", "B1" );
+        assertOrdering( recorder, "B1", "C1" );
+        assertOrdering( recorder, "A1", "B2" );
+        assertOrdering( recorder, "B2", "C1" );
+        assertOrdering( recorder, "A2", "B2" );
+        assertOrdering( recorder, "B2", "C2" );
+        assertOrdering( recorder, "A2", "B3" );
+        assertOrdering( recorder, "B3", "C2" );
+        assertOrdering( recorder, "A3", "B3" );
+        assertOrdering( recorder, "B3", "C3" );
+        assertOrdering( recorder, "A3", "B4" );
+        assertOrdering( recorder, "B4", "C3" );
+    }
+
+    @Test
+    public void testDag3()
+        throws Exception
+    {
+        Injector injector = Guice.createInjector( WarmUpModule.newWarmUpModule() );
+        injector.getInstance( Dag3.A.class );
+        injector.getInstance( LifeCycleStageModule.key( WarmUp.class ) ).stage();
+        Recorder recorder = injector.getInstance( Recorder.class );
+
+        System.out.println( recorder.getRecordings() );
+        System.out.println( recorder.getConcurrents() );
+
+        assertSingleExecution( recorder );
+
+        assertNotConcurrent( recorder, "C", "D" );
+        assertNotConcurrent( recorder, "B", "D" );
+        assertNotConcurrent( recorder, "A", "B" );
+        assertNotConcurrent( recorder, "A", "C" );
+
+        Assert.assertEquals( recorder.getInterruptions().size(), 0 );
+        assertOrdering( recorder, "A", "C" );
+        assertOrdering( recorder, "C", "D" );
+        assertOrdering( recorder, "A", "D" );
+        assertOrdering( recorder, "B", "D" );
+    }
+
+    @Test
+    public void testDag4()
+        throws Exception
+    {
+        Module module = new AbstractModule()
+        {
+            @Override
+            protected void configure()
+            {
+                RecorderSleepSettings recorderSleepSettings = new RecorderSleepSettings();
+                recorderSleepSettings.setBaseSleepFor( "E", 1, TimeUnit.MILLISECONDS );
+                recorderSleepSettings.setRandomize( false );
+                bind( RecorderSleepSettings.class ).toInstance( recorderSleepSettings );
+            }
+        };
+        Injector injector = Guice.createInjector( WarmUpModule.newWarmUpModule(), module );
+        injector.getInstance( Dag4.A.class );
+        injector.getInstance( LifeCycleStageModule.key( WarmUp.class ) ).stage();
+        Recorder recorder = injector.getInstance( Recorder.class );
+
+        System.out.println( recorder.getRecordings() );
+        System.out.println( recorder.getConcurrents() );
+
+        assertSingleExecution( recorder );
+        Assert.assertEquals( recorder.getInterruptions().size(), 0 );
+        assertOrdering( recorder, "D", "E" );
+        assertOrdering( recorder, "C", "E" );
+        assertOrdering( recorder, "B", "D" );
+        assertOrdering( recorder, "A", "B" );
+    }
+
+    @Test
+    public void testFlat()
+        throws Exception
+    {
+        Injector injector = Guice.createInjector( WarmUpModule.newWarmUpModule() );
+        Recorder recorder = injector.getInstance( Recorder.class );
+        injector.getInstance( Flat.A.class ).recorder = recorder;
+        injector.getInstance( Flat.B.class ).recorder = recorder;
+        injector.getInstance( LifeCycleStageModule.key( WarmUp.class ) ).stage();
+
+        System.out.println( recorder.getRecordings() );
+        System.out.println( recorder.getConcurrents() );
+
+        assertSingleExecution( recorder );
+        Assert.assertEquals( recorder.getInterruptions().size(), 0 );
+        Assert.assertTrue( recorder.getRecordings().indexOf( "A" ) >= 0 );
+        Assert.assertTrue( recorder.getRecordings().indexOf( "B" ) >= 0 );
+    }
+
+    @Test
+    public void testStuck()
+        throws Exception
+    {
+        Module module = new AbstractModule()
+        {
+            @Override
+            protected void configure()
+            {
+                RecorderSleepSettings recorderSleepSettings = new RecorderSleepSettings();
+                recorderSleepSettings.setBaseSleepFor( "C", 1, TimeUnit.DAYS );
+                bind( RecorderSleepSettings.class ).toInstance( recorderSleepSettings );
+            }
+        };
+        LifeCycleStageModule<WarmUp> warmUpModule = WarmUpModule.builder().withMaxWait( 1, TimeUnit.SECONDS ).build();
+        Injector injector = Guice.createInjector( warmUpModule, module );
+        injector.getInstance( Dag1.A.class );
+        Stager<WarmUp> stager = injector.getInstance( LifeCycleStageModule.key( WarmUp.class ) );
+
+        boolean succeeded;
+        try
+        {
+            stager.stage();
+            succeeded = true;
+        }
+        catch ( RuntimeException e )
+        {
+            succeeded = false;
+            Assert.assertTrue( e.getCause() instanceof TimeoutException );
+        }
+        Recorder recorder = injector.getInstance( Recorder.class );
+
+        System.out.println( recorder.getRecordings() );
+        System.out.println( recorder.getConcurrents() );
+
+        assertSingleExecution( recorder );
+        Assert.assertFalse( succeeded );
+        Assert.assertTrue( recorder.getRecordings().contains( "B" ) );
+        Assert.assertEquals( recorder.getInterruptions(), Arrays.asList( "C" ) );
+    }
+
+    private void assertSingleExecution( Recorder recorder )
+    {
+        Set<String> duplicateCheck = new HashSet<String>();
+        for ( String s : recorder.getRecordings() )
+        {
+            Assert.assertFalse( s + " ran more than once: " + recorder.getRecordings(), duplicateCheck.contains( s ) );
+            duplicateCheck.add( s );
+        }
+    }
+
+    private void assertOrdering( Recorder recorder, String base, String dependency )
+    {
+        int baseIndex = recorder.getRecordings().indexOf( base );
+        int dependencyIndex = recorder.getRecordings().indexOf( dependency );
+
+        Assert.assertTrue( baseIndex >= 0 );
+        Assert.assertTrue( dependencyIndex >= 0 );
+        Assert.assertTrue( "baseIndex: " + baseIndex + " - dependencyIndex: " + dependencyIndex,
+                           baseIndex > dependencyIndex );
+    }
+
+    private void assertNotConcurrent( Recorder recorder, String task1, String task2 )
+    {
+        for ( Set<String> s : recorder.getConcurrents() )
+        {
+            Assert.assertTrue( String.format( "Incorrect concurrency for %s and %s: %s", task1, task2, s ),
+                               !s.contains( task1 ) || !s.contains( task2 ) );
+        }
+    }
+}

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/TestWarmUpManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/TestWarmUpManager.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/TestWarmUpManager.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/WarmUpWithException.java (from r1456588, incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java)
URL: http://svn.apache.org/viewvc/incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/WarmUpWithException.java?p2=incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/WarmUpWithException.java&p1=incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java&r1=1456588&r2=1456589&rev=1456589&view=diff
==============================================================================
--- incubator/onami/trunk/lifecycle/warmup/main/java/org/apache/onami/lifecycle/warmup/WarmUp.java (original)
+++ incubator/onami/trunk/lifecycle/warmup/test/java/org/apachi/onami/lifecycle/warmup/WarmUpWithException.java Thu Mar 14 18:21:30 2013
@@ -1,4 +1,4 @@
-package org.apache.onami.lifecycle.warmup;
+package org.apachi.onami.lifecycle.warmup;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,17 +19,18 @@ package org.apache.onami.lifecycle.warmu
  * under the License.
  */
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
+import org.apache.onami.lifecycle.warmup.WarmUp;
 
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-@Documented
-@Retention(RUNTIME)
-@Target(METHOD)
-public @interface WarmUp
+public class WarmUpWithException
 {
+    @WarmUp
+    public void warmUp()
+    {
+        System.out.println( getNull().toString() );   // generate NPE
+    }
 
+    private Object getNull()
+    {
+        return null;
+    }
 }