Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MNG-7459] Revert "[3.8.x][MNG-7347] SessionScoped beans should be singletons for a given session" #715

Merged
merged 1 commit into from May 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -90,12 +90,8 @@ public void buildProject( MavenSession session, MavenSession rootSession, Reacto

// session may be different from rootSession seeded in DefaultMaven
// explicitly seed the right session here to make sure it is used by Guice
final boolean scoped = session != rootSession;
if ( scoped )
{
sessionScope.enter();
sessionScope.seed( MavenSession.class, session );
}
sessionScope.enter( reactorContext.getSessionScopeMemento() );
sessionScope.seed( MavenSession.class, session );
try
{

Expand Down Expand Up @@ -149,10 +145,7 @@ public void buildProject( MavenSession session, MavenSession rootSession, Reacto
}
finally
{
if ( scoped )
{
sessionScope.exit();
}
sessionScope.exit();

session.setCurrentProject( null );

Expand Down
Expand Up @@ -107,7 +107,8 @@ public void execute( MavenSession session )
ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() );
reactorContext =
new ReactorContext( result, projectIndex, oldContextClassLoader, reactorBuildStatus );
new ReactorContext( result, projectIndex, oldContextClassLoader, reactorBuildStatus,
sessionScope.memento() );

String builderId = session.getRequest().getBuilderId();
Builder builder = builders.get( builderId );
Expand Down
Expand Up @@ -20,6 +20,7 @@
*/

import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.session.scope.internal.SessionScope;

/**
* Context that is fixed for the entire reactor build.
Expand All @@ -39,13 +40,17 @@ public class ReactorContext

private final ReactorBuildStatus reactorBuildStatus;

private final SessionScope.Memento sessionScope;

public ReactorContext( MavenExecutionResult result, ProjectIndex projectIndex,
ClassLoader originalContextClassLoader, ReactorBuildStatus reactorBuildStatus )
ClassLoader originalContextClassLoader, ReactorBuildStatus reactorBuildStatus,
SessionScope.Memento sessionScope )
{
this.result = result;
this.projectIndex = projectIndex;
this.originalContextClassLoader = originalContextClassLoader;
this.reactorBuildStatus = reactorBuildStatus;
this.sessionScope = sessionScope;
}

public ReactorBuildStatus getReactorBuildStatus()
Expand All @@ -68,4 +73,11 @@ public ClassLoader getOriginalContextClassLoader()
return originalContextClassLoader;
}

/**
* @since 3.3.0
*/
public SessionScope.Memento getSessionScopeMemento()
{
return sessionScope;
}
}
Expand Up @@ -19,23 +19,35 @@
* under the License.
*/

import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.util.Providers;

/**
* SessionScope
*/
public class SessionScope
implements Scope
{
/**
* @since 3.3.0
*/
public static class Memento
{
final Map<Key<?>, Provider<?>> seeded;

Memento( final Map<Key<?>, Provider<?>> seeded )
{
this.seeded = Collections.unmodifiableMap( new HashMap<>( seeded ) );
}
}

private static final Provider<Object> SEEDED_KEY_PROVIDER = new Provider<Object>()
{
Expand All @@ -48,127 +60,110 @@ public Object get()
/**
* ScopeState
*/
protected static final class ScopeState
private static final class ScopeState
{
private final ConcurrentMap<Key<?>, CachingProvider<?>> provided = new ConcurrentHashMap<>();
private final Map<Key<?>, Provider<?>> seeded = new HashMap<>();

public <T> void seed( Class<T> clazz, Provider<T> value )
{
provided.put( Key.get( clazz ), new CachingProvider<>( value ) );
}
private final Map<Key<?>, Object> provided = new HashMap<>();
}

@SuppressWarnings( "unchecked" )
public <T> Provider<T> scope( Key<T> key, final Provider<T> unscoped )
{
Provider<?> provider = provided.get( key );
if ( provider == null )
{
CachingProvider<?> newValue = new CachingProvider<>( unscoped );
provider = provided.putIfAbsent( key, newValue );
if ( provider == null )
{
provider = newValue;
}
}
return ( Provider<T> ) provider;
}
private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<>();

public Collection<CachingProvider<?>> providers()
public void enter()
{
LinkedList<ScopeState> stack = values.get();
if ( stack == null )
{
return provided.values();
stack = new LinkedList<>();
values.set( stack );
}

stack.addFirst( new ScopeState() );
}

private final List<ScopeState> values = new CopyOnWriteArrayList<>();

public void enter()
/**
* @since 3.3.0
*/
public void enter( Memento memento )
{
values.add( 0, new ScopeState() );
enter();
getScopeState().seeded.putAll( memento.seeded );
}

protected ScopeState getScopeState()
private ScopeState getScopeState()
{
if ( values.isEmpty() )
LinkedList<ScopeState> stack = values.get();
if ( stack == null || stack.isEmpty() )
{
throw new OutOfScopeException( "Cannot access session scope outside of a scoping block" );
throw new IllegalStateException();
}
return values.get( 0 );
return stack.getFirst();
}

public void exit()
{
if ( values.isEmpty() )
final LinkedList<ScopeState> stack = values.get();
if ( stack == null || stack.isEmpty() )
{
throw new IllegalStateException();
}
values.remove( 0 );
stack.removeFirst();
if ( stack.isEmpty() )
{
values.remove();
}
}

/**
* @since 3.3.0
*/
public Memento memento()
{
LinkedList<ScopeState> stack = values.get();
return new Memento( stack != null ? stack.getFirst().seeded : Collections.<Key<?>, Provider<?>>emptyMap() );
}

public <T> void seed( Class<T> clazz, Provider<T> value )
{
getScopeState().seed( clazz, value );
getScopeState().seeded.put( Key.get( clazz ), value );
}

public <T> void seed( Class<T> clazz, final T value )
{
seed( clazz, new Provider<T>()
{
@Override
public T get()
{
return value;
}
} );
getScopeState().seeded.put( Key.get( clazz ), Providers.of( value ) );
}

public <T> Provider<T> scope( final Key<T> key, final Provider<T> unscoped )
{
// Lazy evaluating provider
return new Provider<T>()
{
@Override
@SuppressWarnings( "unchecked" )
public T get()
{
return getScopeState().scope( key, unscoped ).get();
}
};
}
LinkedList<ScopeState> stack = values.get();
if ( stack == null || stack.isEmpty() )
{
throw new OutOfScopeException( "Cannot access " + key + " outside of a scoping block" );
}

/**
* CachingProvider
* @param <T>
*/
protected static class CachingProvider<T> implements Provider<T>
{
private final Provider<T> provider;
private volatile T value;
ScopeState state = stack.getFirst();

CachingProvider( Provider<T> provider )
{
this.provider = provider;
}
Provider<?> seeded = state.seeded.get( key );

public T value()
{
return value;
}
if ( seeded != null )
{
return (T) seeded.get();
}

@Override
public T get()
{
if ( value == null )
{
synchronized ( this )
T provided = (T) state.provided.get( key );
if ( provided == null && unscoped != null )
{
if ( value == null )
{
value = provider.get();
}
provided = unscoped.get();
state.provided.put( key, provided );
}

return provided;
}
return value;
}
};
}

@SuppressWarnings( { "unchecked" } )
Expand Down