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