View Javadoc
1   package org.apache.onami.lifecycle.warmup;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import com.google.inject.ConfigurationException;
23  import com.google.inject.TypeLiteral;
24  import com.google.inject.spi.Dependency;
25  import com.google.inject.spi.InjectionPoint;
26  import jsr166y.RecursiveAction;
27  import org.apache.onami.lifecycle.core.StageHandler;
28  import org.apache.onami.lifecycle.core.Stageable;
29  
30  import java.util.ArrayList;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Set;
35  import java.util.concurrent.ConcurrentMap;
36  
37  /**
38   * Fork-join task that performs the warm ups
39   */
40  class WarmUpTask
41      extends RecursiveAction
42  {
43      private final StageHandler stageHandler;
44  
45      private final TypeLiteral<?> typeLiteral;
46  
47      private final Map<TypeLiteral<?>, Set<Stageable>> reverseLookup;
48  
49      private final ConcurrentMap<TypeLiteral<?>, WarmUpTask> inProgress;
50  
51      static final TypeLiteral<?> ROOT = new TypeLiteral<Object>(){};
52  
53      /**
54       * @param stageHandler the stage handler passed to {@link org.apache.onami.lifecycle.core.Stager#stage(org.apache.onami.lifecycle.core.StageHandler)}
55       * @param typeLiteral the type associated with the object being warmed up
56       * @param reverseLookup the full list of types-to-stagers that were registered
57       * @param inProgress which tasks are already warming up (to avoid duplicates)
58       */
59      WarmUpTask( StageHandler stageHandler, TypeLiteral<?> typeLiteral,
60                  Map<TypeLiteral<?>, Set<Stageable>> reverseLookup, ConcurrentMap<TypeLiteral<?>, WarmUpTask> inProgress )
61      {
62          this.stageHandler = stageHandler;
63          this.typeLiteral = typeLiteral;
64          this.reverseLookup = reverseLookup;
65          this.inProgress = inProgress;
66      }
67  
68      @Override
69      protected void compute()
70      {
71          List<WarmUpTask> tasksToJoin = new ArrayList<WarmUpTask>();
72          if ( typeLiteral == ROOT )
73          {
74              // this is the root task - just start all the known tasks
75              computeRoot( tasksToJoin );
76          }
77          else
78          {
79              internalCompute( tasksToJoin );
80          }
81  
82          // wait for dependent tasks to finish
83          for ( WarmUpTask task : tasksToJoin )
84          {
85              task.join();
86          }
87  
88          // finally do the execution
89  
90          Set<Stageable> stageables = reverseLookup.get( typeLiteral );
91          if ( stageables != null )
92          {
93              for ( Stageable stageable : stageables )
94              {
95                  if ( Thread.currentThread().isInterrupted() )
96                  {
97                      // Warmup is taking too long - thread was interrupted.
98                      // Skip other stageables.
99                      break;
100                 }
101                 stageable.stage( stageHandler );
102             }
103         }
104     }
105 
106     private void computeRoot( List<WarmUpTask> tasksToJoin )
107     {
108         for ( TypeLiteral<?> typeLiteral : reverseLookup.keySet() )
109         {
110             WarmUpTask warmUpTask = new WarmUpTask( stageHandler, typeLiteral, reverseLookup, inProgress );
111             startTask( tasksToJoin, warmUpTask );
112         }
113     }
114 
115     private void internalCompute( List<WarmUpTask> tasksToJoin )
116     {
117         List<WarmUpTask> childTasks = new ArrayList<WarmUpTask>();
118         addDependency( childTasks, getConstructorInjectionPoint( typeLiteral ) );
119         for ( InjectionPoint injectionPoint : getMethodInjectionPoints( typeLiteral ) )
120         {
121             addDependency( childTasks, injectionPoint );
122         }
123 
124         for ( WarmUpTask childTask : childTasks )
125         {
126             startTask( tasksToJoin, childTask );
127         }
128     }
129 
130     private void startTask( List<WarmUpTask> tasksToJoin, WarmUpTask childTask )
131     {
132         WarmUpTask existingTask = inProgress.putIfAbsent( childTask.typeLiteral, childTask );
133         if ( existingTask == null )
134         {
135             childTask.fork();
136             tasksToJoin.add( childTask );
137         }
138         else
139         {
140             tasksToJoin.add( existingTask );
141         }
142     }
143 
144     private void addDependency( List<WarmUpTask> childTasks, InjectionPoint injectionPoint )
145     {
146         if ( injectionPoint != null )
147         {
148             List<Dependency<?>> dependencies = injectionPoint.getDependencies();
149             for ( Dependency<?> dependency : dependencies )
150             {
151                 // create a task for any dependencies. Note: even if the dependency isn't
152                 // a registered stager it must be created as a task as its dependencies
153                 // may be stagers
154                 TypeLiteral<?> dependencyTypeLiteral = dependency.getKey().getTypeLiteral();
155                 childTasks.add(
156                     new WarmUpTask( stageHandler, dependencyTypeLiteral, reverseLookup, inProgress ) );
157             }
158         }
159     }
160 
161     private Set<InjectionPoint> getMethodInjectionPoints( TypeLiteral<?> type )
162     {
163         try
164         {
165             return InjectionPoint.forInstanceMethodsAndFields( type );
166         }
167         catch ( ConfigurationException e )
168         {
169             // ignore
170         }
171         return new HashSet<InjectionPoint>();
172     }
173 
174     private InjectionPoint getConstructorInjectionPoint( TypeLiteral<?> type )
175     {
176         try
177         {
178             return InjectionPoint.forConstructorOf( type );
179         }
180         catch ( ConfigurationException e )
181         {
182             // ignore
183         }
184         return null;
185     }
186 }