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.MojoExecutionEvent;
029import org.apache.maven.execution.MojoExecutionListener;
030import org.apache.maven.execution.scope.MojoExecutionScoped;
031import org.apache.maven.execution.scope.WeakMojoExecutionListener;
032import org.apache.maven.plugin.MojoExecution;
033import org.apache.maven.plugin.MojoExecutionException;
034import org.apache.maven.project.MavenProject;
035import org.codehaus.plexus.PlexusContainer;
036import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
037
038import com.google.common.collect.Maps;
039import com.google.inject.AbstractModule;
040import com.google.inject.Key;
041import com.google.inject.Module;
042import com.google.inject.OutOfScopeException;
043import com.google.inject.Provider;
044import com.google.inject.Scope;
045import com.google.inject.util.Providers;
046
047@Named
048@Singleton
049public class MojoExecutionScope
050    implements Scope, MojoExecutionListener
051{
052    private static final Provider<Object> SEEDED_KEY_PROVIDER = new Provider<Object>()
053    {
054        public Object get()
055        {
056            throw new IllegalStateException();
057        }
058    };
059
060    private static final class ScopeState
061    {
062        public final Map<Key<?>, Provider<?>> seeded = Maps.newHashMap();
063
064        public final Map<Key<?>, Object> provided = Maps.newHashMap();
065    }
066
067    private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<LinkedList<ScopeState>>();
068
069    public MojoExecutionScope()
070    {
071    }
072
073    public void enter()
074    {
075        LinkedList<ScopeState> stack = values.get();
076        if ( stack == null )
077        {
078            stack = new LinkedList<ScopeState>();
079            values.set( stack );
080        }
081        stack.addFirst( new ScopeState() );
082    }
083
084    private ScopeState getScopeState()
085    {
086        LinkedList<ScopeState> stack = values.get();
087        if ( stack == null || stack.isEmpty() )
088        {
089            throw new IllegalStateException();
090        }
091        return stack.getFirst();
092    }
093
094    public void exit()
095        throws MojoExecutionException
096    {
097        final LinkedList<ScopeState> stack = values.get();
098        if ( stack == null || stack.isEmpty() )
099        {
100            throw new IllegalStateException();
101        }
102        stack.removeFirst();
103        if ( stack.isEmpty() )
104        {
105            values.remove();
106        }
107    }
108
109    public <T> void seed( Class<T> clazz, Provider<T> value )
110    {
111        getScopeState().seeded.put( Key.get( clazz ), value );
112    }
113
114    public <T> void seed( Class<T> clazz, final T value )
115    {
116        getScopeState().seeded.put( Key.get( clazz ), Providers.of( value ) );
117    }
118
119    public <T> Provider<T> scope( final Key<T> key, final Provider<T> unscoped )
120    {
121        return new Provider<T>()
122        {
123            @SuppressWarnings( "unchecked" )
124            public T get()
125            {
126                LinkedList<ScopeState> stack = values.get();
127                if ( stack == null || stack.isEmpty() )
128                {
129                    throw new OutOfScopeException( "Cannot access " + key + " outside of a scoping block" );
130                }
131
132                ScopeState state = stack.getFirst();
133
134                Provider<?> seeded = state.seeded.get( key );
135
136                if ( seeded != null )
137                {
138                    return (T) seeded.get();
139                }
140
141                T provided = (T) state.provided.get( key );
142                if ( provided == null && unscoped != null )
143                {
144                    provided = unscoped.get();
145                    state.provided.put( key, provided );
146                }
147
148                return provided;
149            }
150        };
151    }
152
153    @SuppressWarnings( { "unchecked" } )
154    public static <T> Provider<T> seededKeyProvider()
155    {
156        return (Provider<T>) SEEDED_KEY_PROVIDER;
157    }
158
159    public static Module getScopeModule( PlexusContainer container )
160        throws ComponentLookupException
161    {
162        final MojoExecutionScope scope = container.lookup( MojoExecutionScope.class );
163        return new AbstractModule()
164        {
165            @Override
166            protected void configure()
167            {
168                bindScope( MojoExecutionScoped.class, scope );
169
170                // standard scope bindings
171                bind( MavenProject.class ).toProvider( MojoExecutionScope.<MavenProject> seededKeyProvider() ).in( scope );
172                bind( MojoExecution.class ).toProvider( MojoExecutionScope.<MojoExecution> seededKeyProvider() ).in( scope );
173            }
174        };
175    }
176
177    public void beforeMojoExecution( MojoExecutionEvent event )
178        throws MojoExecutionException
179    {
180        for ( Object provided : getScopeState().provided.values() )
181        {
182            if ( provided instanceof WeakMojoExecutionListener )
183            {
184                ( (WeakMojoExecutionListener) provided ).beforeMojoExecution( event );
185            }
186        }
187    }
188
189    public void afterMojoExecutionSuccess( MojoExecutionEvent event )
190        throws MojoExecutionException
191    {
192        for ( Object provided : getScopeState().provided.values() )
193        {
194            if ( provided instanceof WeakMojoExecutionListener )
195            {
196                ( (WeakMojoExecutionListener) provided ).afterMojoExecutionSuccess( event );
197            }
198        }
199    }
200
201    public void afterExecutionFailure( MojoExecutionEvent event )
202    {
203        for ( Object provided : getScopeState().provided.values() )
204        {
205            if ( provided instanceof WeakMojoExecutionListener )
206            {
207                ( (WeakMojoExecutionListener) provided ).afterExecutionFailure( event );
208            }
209        }
210    }
211
212}