Skip to content

Commit

Permalink
Arc - add built in beans for BM, Event, Instance. Add automated tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
manovotn committed Aug 2, 2019
1 parent 1d9806f commit 0b90666
Show file tree
Hide file tree
Showing 7 changed files with 445 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
import javax.enterprise.context.Dependent;
import javax.enterprise.context.Destroyed;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Event;
import javax.enterprise.inject.AmbiguousResolutionException;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
Expand Down Expand Up @@ -107,6 +109,9 @@ public ArcContainerImpl() {
transitiveInterceptorBindings.put(entry.getKey(), entry.getValue());
}
}
// register built-in beans
addBuiltInBeans();

Collections.sort(interceptors, (i1, i2) -> Integer.compare(i2.getPriority(), i1.getPriority()));

resolved = new ComputingCache<>(this::resolve);
Expand All @@ -118,6 +123,13 @@ public ArcContainerImpl() {
}
}

private void addBuiltInBeans() {
// BeanManager, Event<?>, Instance<?>
beans.add(new BeanManagerBean());
beans.add(new EventBean());
beans.add(new InstanceBean());
}

void init() {
requireRunning();
// Fire an event with qualifier @Initialized(ApplicationScoped.class)
Expand Down Expand Up @@ -575,13 +587,24 @@ private void requireRunning() {

private static final class Resolvable {

private static final Set<Type> BUILT_IN_TYPES = new HashSet<>(Arrays.asList(Event.class, Instance.class));
private static final Annotation[] ANY_QUALIFIER = new Annotation[] { Any.Literal.INSTANCE };

final Type requiredType;

final Annotation[] qualifiers;

Resolvable(Type requiredType, Annotation[] qualifiers) {
this.requiredType = requiredType;
this.qualifiers = qualifiers;
// if the type is any of BUILT_IN_TYPES, the resolution simplifies type to raw type and ignores qualifiers
// this is so that every injection point matches the bean we provide for that type
Type rawType = Reflections.getRawType(requiredType);
if (BUILT_IN_TYPES.contains(rawType)) {
this.requiredType = rawType;
this.qualifiers = ANY_QUALIFIER;
} else {
this.requiredType = requiredType;
this.qualifiers = qualifiers;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.quarkus.arc;

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.BeanManager;

public class BeanManagerBean extends BuiltInBean<BeanManager> {

private static final Set<Type> BM_TYPES = Collections
.unmodifiableSet(new HashSet<>(Arrays.asList(Object.class, BeanManager.class)));

@Override
public Set<Type> getTypes() {
return BM_TYPES;
}

@Override
public BeanManager get(CreationalContext<BeanManager> creationalContext) {
BeanManager instance = new BeanManagerProvider<>().get(creationalContext);
CreationalContextImpl.addDependencyToParent((InjectableBean<BeanManager>) InjectionPointProvider.get().getBean(),
instance, creationalContext);
return instance;
}

@Override
public Class<?> getBeanClass() {
return BeanManagerImpl.class;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.quarkus.arc;

import java.lang.annotation.Annotation;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;

/**
* Common class for all built-in beans.
*
*/
public abstract class BuiltInBean<T> implements InjectableBean<T> {

@Override
public String getIdentifier() {
return sha1(toString());
}

@Override
public Class<? extends Annotation> getScope() {
return Dependent.class;
}

@Override
public T create(CreationalContext<T> creationalContext) {
return get(creationalContext);
}

// copy of io.quarkus.arc.processor.Hashes#sha1
private String sha1(String value) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder(40);
for (int i = 0; i < digest.length; ++i) {
sb.append(Integer.toHexString((digest[i] & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.quarkus.arc;

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Event;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.util.TypeLiteral;

public class EventBean extends BuiltInBean<Event<?>> {

public static final Set<Type> EVENT_TYPES = Collections
.unmodifiableSet(new HashSet<>(Arrays.asList(Event.class, new TypeLiteral<Event<Object>>() {
}.getType(), Object.class)));

@Override
public Set<Type> getTypes() {
return EVENT_TYPES;
}

@Override
public Event<?> get(CreationalContext<Event<?>> creationalContext) {
// Obtain current IP to get the required type and qualifiers
InjectionPoint ip = InjectionPointProvider.get();
EventImpl<?> instance = new EventImpl<>(ip.getType(), ip.getQualifiers());
CreationalContextImpl.addDependencyToParent((InjectableBean<Event<?>>) ip.getBean(), instance, creationalContext);
return instance;
}

@Override
public Class<?> getBeanClass() {
return EventImpl.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.quarkus.arc;

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.util.TypeLiteral;

public class InstanceBean extends BuiltInBean<Instance<?>> {

public static final Set<Type> INSTANCE_TYPES = Collections
.unmodifiableSet(new HashSet<>(Arrays.asList(Instance.class, new TypeLiteral<Instance<Object>>() {
}.getType(), Object.class)));

@Override
public Set<Type> getTypes() {
return INSTANCE_TYPES;
}

@Override
public Class<?> getBeanClass() {
return InstanceImpl.class;
}

@Override
public Instance<?> get(CreationalContext<Instance<?>> creationalContext) {
// Obtain current IP to get the required type and qualifiers
InjectionPoint ip = InjectionPointProvider.get();
InstanceImpl<Instance<?>> instance = new InstanceImpl<Instance<?>>((InjectableBean<?>) ip.getBean(), ip.getType(),
ip.getQualifiers(), (CreationalContextImpl<?>) creationalContext, Collections.EMPTY_SET, ip.getMember(), 0);
CreationalContextImpl.addDependencyToParent((InjectableBean<Instance<?>>) ip.getBean(), instance, creationalContext);
return instance;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package io.quarkus.arc;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;

/**
Expand Down Expand Up @@ -109,4 +115,41 @@ static <T> T cast(Object obj) {
return (T) obj;
}

public static <T> Class<T> getRawType(Type type) {
if (type instanceof Class<?>) {
return (Class<T>) type;
}
if (type instanceof ParameterizedType) {
if (((ParameterizedType) type).getRawType() instanceof Class<?>) {
return (Class<T>) ((ParameterizedType) type).getRawType();
}
}
if (type instanceof TypeVariable<?>) {
TypeVariable<?> variable = (TypeVariable<?>) type;
Type[] bounds = variable.getBounds();
return getBound(bounds);
}
if (type instanceof WildcardType) {
WildcardType wildcard = (WildcardType) type;
return getBound(wildcard.getUpperBounds());
}
if (type instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) type;
Class<?> rawType = getRawType(genericArrayType.getGenericComponentType());
if (rawType != null) {
return (Class<T>) Array.newInstance(rawType, 0).getClass();
}
}
return null;
}

@SuppressWarnings("unchecked")
private static <T> Class<T> getBound(Type[] bounds) {
if (bounds.length == 0) {
return (Class<T>) Object.class;
} else {
return getRawType(bounds[0]);
}
}

}
Loading

0 comments on commit 0b90666

Please sign in to comment.