001package org.apache.maven.execution.scope.internal;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.LinkedList;
023import java.util.Map;
024
025import javax.inject.Named;
026import javax.inject.Singleton;
027
028import org.apache.maven.execution.MavenSession;
029import org.apache.maven.execution.MojoExecutionEvent;
030import org.apache.maven.execution.MojoExecutionListener;
031import org.apache.maven.execution.scope.MojoExecutionScoped;
032import org.apache.maven.execution.scope.WeakMojoExecutionListener;
033import org.apache.maven.plugin.MojoExecution;
034import org.apache.maven.plugin.MojoExecutionException;
035import org.apache.maven.project.MavenProject;
036import org.codehaus.plexus.PlexusContainer;
037import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
038
039import com.google.common.collect.Maps;
040import com.google.inject.AbstractModule;
041import com.google.inject.Key;
042import com.google.inject.Module;
043import com.google.inject.OutOfScopeException;
044import com.google.inject.Provider;
045import com.google.inject.Scope;
046import com.google.inject.util.Providers;
047
048@Named
049@Singleton
050public class MojoExecutionScope
051    implements Scope, MojoExecutionListener
052{
053    private static final Provider<Object> SEEDED_KEY_PROVIDER = new Provider<Object>()
054    {
055        public Object get()
056        {
057            throw new IllegalStateException();
058        }
059    };
060
061    private static final class ScopeState
062    {
063        public final Map<Key<?>, Provider<?>> seeded = Maps.newHashMap();
064
065        public final Map<Key<?>, Object> provided = Maps.newHashMap();
066    }
067
068    private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<LinkedList<ScopeState>>();
069
070    public MojoExecutionScope()
071    {
072    }
073
074    public void enter()
075    {
076        LinkedList<ScopeState> stack = values.get();
077        if ( stack == null )
078        {
079            stack = new LinkedList<ScopeState>();
080            values.set( stack );
081        }
082        stack.addFirst( new ScopeState() );
083    }
084
085    private ScopeState getScopeState()
086    {
087        LinkedList<ScopeState> stack = values.get();
088        if ( stack == null || stack.isEmpty() )
089        {
090            throw new IllegalStateException();
091        }
092        return stack.getFirst();
093    }
094
095    public void exit()
096        throws MojoExecutionException
097    {
098        final LinkedList<ScopeState> stack = values.get();
099        if ( stack == null || stack.isEmpty() )
100        {
101            throw new IllegalStateException();
102        }
103        stack.removeFirst();
104        if ( stack.isEmpty() )
105        {
106            values.remove();
107        }
108    }
109
110    public <T> void seed( Class<T> clazz, Provider<T> value )
111    {
112        getScopeState().seeded.put( Key.get( clazz ), value );
113    }
114
115    public <T> void seed( Class<T> clazz, final T value )
116    {
117        getScopeState().seeded.put( Key.get( clazz ), Providers.of( value ) );
118    }
119
120    public <T> Provider<T> scope( final Key<T> key, final Provider<T> unscoped )
121    {
122        return new Provider<T>()
123        {
124            @SuppressWarnings( "unchecked" )
125            public T get()
126            {
127                LinkedList<ScopeState> stack = values.get();
128                if ( stack == null || stack.isEmpty() )
129                {
130                    throw new OutOfScopeException( "Cannot access " + key + " outside of a scoping block" );
131                }
132
133                ScopeState state = stack.getFirst();
134
135                Provider<?> seeded = state.seeded.get( key );
136
137                if ( seeded != null )
138                {
139                    return (T) seeded.get();
140                }
141
142                T provided = (T) state.provided.get( key );
143                if ( provided == null && unscoped != null )
144                {
145                    provided = unscoped.get();
146                    state.provided.put( key, provided );
147                }
148
149                return provided;
150            }
151        };
152    }
153
154    @SuppressWarnings( { "unchecked" } )
155    public static <T> Provider<T> seededKeyProvider()
156    {
157        return (Provider<T>) SEEDED_KEY_PROVIDER;
158    }
159
160    public static Module getScopeModule( PlexusContainer container )
161        throws ComponentLookupException
162    {
163        final MojoExecutionScope scope = container.lookup( MojoExecutionScope.class );
164        return new AbstractModule()
165        {
166            @Override
167            protected void configure()
168            {
169                bindScope( MojoExecutionScoped.class, scope );
170
171                // standard scope bindings
172                bind( MavenSession.class ).toProvider( MojoExecutionScope.<MavenSession> seededKeyProvider() ).in( scope );
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 ( Object provided : getScopeState().provided.values() )
183        {
184            if ( provided instanceof WeakMojoExecutionListener )
185            {
186                ( (WeakMojoExecutionListener) provided ).beforeMojoExecution( event );
187            }
188        }
189    }
190
191    public void afterMojoExecutionSuccess( MojoExecutionEvent event )
192        throws MojoExecutionException
193    {
194        for ( Object provided : getScopeState().provided.values() )
195        {
196            if ( provided instanceof WeakMojoExecutionListener )
197            {
198                ( (WeakMojoExecutionListener) provided ).afterMojoExecutionSuccess( event );
199            }
200        }
201    }
202
203    public void afterExecutionFailure( MojoExecutionEvent event )
204    {
205        for ( Object provided : getScopeState().provided.values() )
206        {
207            if ( provided instanceof WeakMojoExecutionListener )
208            {
209                ( (WeakMojoExecutionListener) provided ).afterExecutionFailure( event );
210            }
211        }
212    }
213
214}