Skip to content

Commit

Permalink
Implement SessionScope for DI
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet committed Jun 10, 2024
1 parent 7d61be2 commit f43d279
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
* Indicates that the annotated bean has a lifespan limited to a given mojo execution,
* which means each mojo execution will result in a different instance being injected.
*
* TODO: this is currently not implemented
*
* @since 4.0.0
*/
@Scope
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
* Indicates that annotated component should be instantiated before session execution starts
* and discarded after session execution completes.
*
* TODO: this is currently not implemented
*
* @since 4.0.0
*/
@Scope
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@
*/
package org.apache.maven.execution.scope.internal;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.function.Supplier;

import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.name.Names;
import com.google.inject.util.Providers;
import org.apache.maven.execution.MojoExecutionEvent;
import org.apache.maven.execution.MojoExecutionListener;
Expand All @@ -37,7 +40,7 @@
/**
* MojoExecutionScope
*/
public class MojoExecutionScope implements Scope, MojoExecutionListener {
public class MojoExecutionScope implements Scope, org.apache.maven.di.Scope, MojoExecutionListener {
private static final Provider<Object> SEEDED_KEY_PROVIDER = () -> {
throw new IllegalStateException();
};
Expand Down Expand Up @@ -113,6 +116,17 @@ public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
};
}

@Override
public <T> Supplier<T> scope(org.apache.maven.di.Key<T> key, Annotation scope, Supplier<T> unscoped) {
Object qualifier = key.getQualifier();
Key k = qualifier != null
? Key.get(key.getType(), qualifier instanceof String s ? Names.named(s) : (Annotation) qualifier)
: Key.get(key.getType());
Provider<T> up = unscoped::get;
Provider<T> p = scope(k, up);
return p::get;
}

@SuppressWarnings({"unchecked"})
public static <T> Provider<T> seededKeyProvider() {
return (Provider<T>) SEEDED_KEY_PROVIDER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,18 @@
import com.google.inject.AbstractModule;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.name.Names;
import org.apache.maven.api.di.MojoExecutionScoped;
import org.apache.maven.api.di.SessionScoped;
import org.apache.maven.api.services.MavenException;
import org.apache.maven.di.Injector;
import org.apache.maven.di.Key;
import org.apache.maven.di.impl.Binding;
import org.apache.maven.di.impl.DIException;
import org.apache.maven.di.impl.InjectorImpl;
import org.apache.maven.execution.scope.internal.MojoExecutionScope;
import org.apache.maven.session.scope.internal.SessionScope;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;

@Named
class SisuDiBridgeModule extends AbstractModule {
Expand Down Expand Up @@ -121,6 +126,20 @@ public <Q> Supplier<Q> getCompiledBinding(Key<Q> key) {
.collect(Collectors.joining("\n - ", " - ", "")));
}
};
injector.bindScope(SessionScoped.class, () -> {
try {
return containerProvider.get().lookup(SessionScope.class);
} catch (ComponentLookupException e) {
throw new RuntimeException(e);
}
});
injector.bindScope(MojoExecutionScoped.class, () -> {
try {
return containerProvider.get().lookup(MojoExecutionScope.class);
} catch (ComponentLookupException e) {
throw new RuntimeException(e);
}
});
injector.bindInstance(Injector.class, injector);
bind(Injector.class).toInstance(injector);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,20 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.name.Names;

/**
* SessionScope
*/
public class SessionScope implements Scope {
public class SessionScope implements Scope, org.apache.maven.di.Scope {

private static final Provider<Object> SEEDED_KEY_PROVIDER = () -> {
throw new IllegalStateException();
Expand Down Expand Up @@ -103,6 +105,18 @@ public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
};
}

@SuppressWarnings("unchecked")
@Override
public <T> Supplier<T> scope(org.apache.maven.di.Key<T> key, Annotation scope, Supplier<T> unscoped) {
Object qualifier = key.getQualifier();
Key<?> k = qualifier != null
? Key.get(key.getType(), qualifier instanceof String s ? Names.named(s) : (Annotation) qualifier)
: Key.get(key.getType());
Provider<T> up = unscoped::get;
Provider<T> p = scope((Key<T>) k, up);
return p::get;
}

@SuppressWarnings("unchecked")
private <T> T createProxy(Key<T> key, Provider<T> unscoped) {
InvocationHandler dispatcher = (proxy, method, args) -> {
Expand Down
3 changes: 3 additions & 0 deletions maven-di/src/main/java/org/apache/maven/di/Injector.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.maven.di;

import java.lang.annotation.Annotation;
import java.util.function.Supplier;

import org.apache.maven.di.impl.InjectorImpl;

Expand All @@ -36,6 +37,8 @@ static Injector create() {

Injector bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope);

Injector bindScope(Class<? extends Annotation> scopeAnnotation, Supplier<Scope> scope);

Injector bindImplicit(Class<?> cls);

<T> Injector bindInstance(Class<T> cls, T instance);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
public class InjectorImpl implements Injector {

private final Map<Key<?>, Set<Binding<?>>> bindings = new HashMap<>();
private final Map<Class<? extends Annotation>, Scope> scopes = new HashMap<>();
private final Map<Class<? extends Annotation>, Supplier<Scope>> scopes = new HashMap<>();

public InjectorImpl() {
bindScope(Singleton.class, new SingletonScope());
Expand Down Expand Up @@ -87,6 +87,10 @@ public Injector discover(ClassLoader classLoader) {
}

public Injector bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
return bindScope(scopeAnnotation, () -> scope);
}

public Injector bindScope(Class<? extends Annotation> scopeAnnotation, Supplier<Scope> scope) {
if (scopes.put(scopeAnnotation, scope) != null) {
throw new DIException(
"Cannot rebind scope annotation class to a different implementation: " + scopeAnnotation);
Expand Down Expand Up @@ -204,7 +208,8 @@ protected <Q> Supplier<Q> compile(Binding<Q> binding) {
.map(Map.Entry::getValue)
.findFirst()
.orElseThrow(() -> new DIException("Scope not bound for annotation "
+ binding.getScope().getClass()));
+ binding.getScope().annotationType()))
.get();
compiled = scope.scope((Key<Q>) binding.getOriginalKey(), binding.getScope(), compiled);
}
return compiled;
Expand Down

0 comments on commit f43d279

Please sign in to comment.