View Javadoc
1   package org.apache.maven.execution.scope.internal;
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 java.util.Collection;
23  import java.util.IdentityHashMap;
24  import java.util.LinkedList;
25  import java.util.Map;
26  
27  import javax.inject.Named;
28  import javax.inject.Singleton;
29  
30  import org.apache.maven.execution.MojoExecutionEvent;
31  import org.apache.maven.execution.MojoExecutionListener;
32  import org.apache.maven.execution.scope.MojoExecutionScoped;
33  import org.apache.maven.execution.scope.WeakMojoExecutionListener;
34  import org.apache.maven.plugin.MojoExecution;
35  import org.apache.maven.plugin.MojoExecutionException;
36  import org.apache.maven.project.MavenProject;
37  import org.codehaus.plexus.PlexusContainer;
38  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
39  
40  import com.google.common.collect.Maps;
41  import com.google.inject.AbstractModule;
42  import com.google.inject.Key;
43  import com.google.inject.Module;
44  import com.google.inject.OutOfScopeException;
45  import com.google.inject.Provider;
46  import com.google.inject.Scope;
47  import com.google.inject.util.Providers;
48  
49  @Named
50  @Singleton
51  public class MojoExecutionScope
52      implements Scope, MojoExecutionListener
53  {
54      private static final Provider<Object> SEEDED_KEY_PROVIDER = new Provider<Object>()
55      {
56          public Object get()
57          {
58              throw new IllegalStateException();
59          }
60      };
61  
62      private static final class ScopeState
63      {
64          public final Map<Key<?>, Provider<?>> seeded = Maps.newHashMap();
65  
66          public final Map<Key<?>, Object> provided = Maps.newHashMap();
67      }
68  
69      private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<LinkedList<ScopeState>>();
70  
71      public MojoExecutionScope()
72      {
73      }
74  
75      public void enter()
76      {
77          LinkedList<ScopeState> stack = values.get();
78          if ( stack == null )
79          {
80              stack = new LinkedList<ScopeState>();
81              values.set( stack );
82          }
83          stack.addFirst( new ScopeState() );
84      }
85  
86      private ScopeState getScopeState()
87      {
88          LinkedList<ScopeState> stack = values.get();
89          if ( stack == null || stack.isEmpty() )
90          {
91              throw new IllegalStateException();
92          }
93          return stack.getFirst();
94      }
95  
96      public void exit()
97          throws MojoExecutionException
98      {
99          final LinkedList<ScopeState> stack = values.get();
100         if ( stack == null || stack.isEmpty() )
101         {
102             throw new IllegalStateException();
103         }
104         stack.removeFirst();
105         if ( stack.isEmpty() )
106         {
107             values.remove();
108         }
109     }
110 
111     public <T> void seed( Class<T> clazz, Provider<T> value )
112     {
113         getScopeState().seeded.put( Key.get( clazz ), value );
114     }
115 
116     public <T> void seed( Class<T> clazz, final T value )
117     {
118         getScopeState().seeded.put( Key.get( clazz ), Providers.of( value ) );
119     }
120 
121     public <T> Provider<T> scope( final Key<T> key, final Provider<T> unscoped )
122     {
123         return new Provider<T>()
124         {
125             @SuppressWarnings( "unchecked" )
126             public T get()
127             {
128                 LinkedList<ScopeState> stack = values.get();
129                 if ( stack == null || stack.isEmpty() )
130                 {
131                     throw new OutOfScopeException( "Cannot access " + key + " outside of a scoping block" );
132                 }
133 
134                 ScopeState state = stack.getFirst();
135 
136                 Provider<?> seeded = state.seeded.get( key );
137 
138                 if ( seeded != null )
139                 {
140                     return (T) seeded.get();
141                 }
142 
143                 T provided = (T) state.provided.get( key );
144                 if ( provided == null && unscoped != null )
145                 {
146                     provided = unscoped.get();
147                     state.provided.put( key, provided );
148                 }
149 
150                 return provided;
151             }
152         };
153     }
154 
155     @SuppressWarnings( { "unchecked" } )
156     public static <T> Provider<T> seededKeyProvider()
157     {
158         return (Provider<T>) SEEDED_KEY_PROVIDER;
159     }
160 
161     public static Module getScopeModule( PlexusContainer container )
162         throws ComponentLookupException
163     {
164         final MojoExecutionScope scope = container.lookup( MojoExecutionScope.class );
165         return new AbstractModule()
166         {
167             @Override
168             protected void configure()
169             {
170                 bindScope( MojoExecutionScoped.class, scope );
171 
172                 // standard scope bindings
173                 bind( MavenProject.class ).toProvider( MojoExecutionScope.<MavenProject> seededKeyProvider() ).in( scope );
174                 bind( MojoExecution.class ).toProvider( MojoExecutionScope.<MojoExecution> seededKeyProvider() ).in( scope );
175             }
176         };
177     }
178 
179     public void beforeMojoExecution( MojoExecutionEvent event )
180         throws MojoExecutionException
181     {
182         for ( WeakMojoExecutionListener provided : getProvidedListeners() )
183         {
184             provided.beforeMojoExecution( event );
185         }
186     }
187 
188     public void afterMojoExecutionSuccess( MojoExecutionEvent event )
189         throws MojoExecutionException
190     {
191         for ( WeakMojoExecutionListener provided : getProvidedListeners() )
192         {
193             provided.afterMojoExecutionSuccess( event );
194         }
195     }
196 
197     public void afterExecutionFailure( MojoExecutionEvent event )
198     {
199         for ( WeakMojoExecutionListener provided : getProvidedListeners() )
200         {
201             provided.afterExecutionFailure( event );
202         }
203     }
204 
205     private Collection<WeakMojoExecutionListener> getProvidedListeners()
206     {
207         // the same instance can be provided multiple times under different Key's
208         // deduplicate instances to avoid redundant beforeXXX/afterXXX callbacks
209         IdentityHashMap<WeakMojoExecutionListener, Object> listeners =
210             new IdentityHashMap<WeakMojoExecutionListener, Object>();
211         for ( Object provided : getScopeState().provided.values() )
212         {
213             if ( provided instanceof WeakMojoExecutionListener )
214             {
215                 listeners.put( (WeakMojoExecutionListener) provided, null );
216             }
217         }
218         return listeners.keySet();
219     }
220 }