Skip to content

Commit

Permalink
Add a map of <type, Beans that are assignable to the type> to TypeSaf…
Browse files Browse the repository at this point in the history
…eBeanResolver

This provides a large boost to the resolver's performance when there are a large number of beans
  • Loading branch information
stuartwdouglas authored and pmuir committed Nov 16, 2010
1 parent 472a28e commit 28379af
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 2 deletions.
Expand Up @@ -18,19 +18,32 @@

import static org.jboss.weld.util.reflection.Reflections.cast;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;

import javax.enterprise.event.Event;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.Bean;
import javax.inject.Provider;

import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.util.Beans;
import org.jboss.weld.util.LazyValueHolder;
import org.jboss.weld.util.reflection.Reflections;

import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.common.primitives.Primitives;

/**
* @author pmuir
Expand All @@ -42,6 +55,8 @@ public class TypeSafeBeanResolver<T extends Bean<?>> extends TypeSafeResolver<Re
private final BeanManagerImpl beanManager;
private final ConcurrentMap<Set<Bean<?>>, Set<Bean<?>>> disambiguatedBeans;

private final LazyValueHolder<Map<Type, ArrayList<T>>> beansByType;

public static class BeanDisambiguation implements Function<Set<Bean<?>>, Set<Bean<?>>>
{

Expand Down Expand Up @@ -73,11 +88,63 @@ public Set<Bean<?>> apply(Set<Bean<?>> from)

}

public TypeSafeBeanResolver(BeanManagerImpl beanManager, Iterable<T> beans)
public TypeSafeBeanResolver(BeanManagerImpl beanManager, final Iterable<T> beans)
{
super(beans);
this.beanManager = beanManager;
this.disambiguatedBeans = new MapMaker().makeComputingMap(new BeanDisambiguation());
// beansByType stores a map of a type to all beans that are assignable to
// that type
this.beansByType = new LazyValueHolder<Map<Type, ArrayList<T>>>()
{

@Override
protected Map<Type, ArrayList<T>> computeValue()
{
Map<Type, ArrayList<T>> val = new HashMap<Type, ArrayList<T>>();
for (T bean : beans)
{
for (Type type : bean.getTypes())
{
if (!val.containsKey(type))
{
val.put(type, new ArrayList<T>());
}
val.get(type).add(bean);
if (type instanceof ParameterizedType)
{
// add the raw type as well
Type rawType = ((ParameterizedType) type).getRawType();
if (!val.containsKey(rawType))
{
val.put(rawType, new ArrayList<T>());
}
val.get(rawType).add(bean);
}
else if (type instanceof Class<?>)
{
// deal with primitives
Class<?> clazz = (Class<?>) type;
if (clazz.isPrimitive())
{
clazz = Primitives.wrap(clazz);
if (!val.containsKey(clazz))
{
val.put(clazz, new ArrayList<T>());
}
val.get(clazz).add(bean);
}
}
}
}
for (Entry<Type, ArrayList<T>> entry : val.entrySet())
{
entry.getValue().trimToSize();
}
return val;
}
};

}

@Override
Expand All @@ -86,6 +153,49 @@ protected boolean matches(Resolvable resolvable, T bean)
return Reflections.matches(resolvable.getTypes(), bean.getTypes()) && Beans.containsAllQualifiers(resolvable.getQualifiers(), bean.getQualifiers(), beanManager);
}

@Override
protected Iterable<? extends T> getAllBeans(Resolvable resolvable)
{
if (resolvable.getTypes().contains(Object.class) || Instance.class.equals(resolvable.getJavaClass()) || Event.class.equals(resolvable.getJavaClass()) || Provider.class.equals(resolvable.getJavaClass()) || resolvable.getTypes().contains(Serializable.class))
{
return super.getAllBeans(resolvable);
}
Set<T> beans = new HashSet<T>();
for (Type type : resolvable.getTypes())
{
List<T> beansForType = beansByType.get().get(type);
if (beansForType != null)
{
beans.addAll(beansForType);
}
if (type instanceof ParameterizedType)
{
// we also need to consider the raw type
Type rawType = ((ParameterizedType) type).getRawType();
beansForType = beansByType.get().get(rawType);
if (beansForType != null)
{
beans.addAll(beansForType);
}
}
else if (type instanceof Class<?>)
{
// primitives
Class<?> clazz = (Class<?>) type;
if (clazz.isPrimitive())
{
clazz = Primitives.wrap(clazz);
beansForType = beansByType.get().get(clazz);
if (beansForType != null)
{
beans.addAll(beansForType);
}
}
}
}
return beans;
}

/**
* @return the manager
*/
Expand Down Expand Up @@ -125,6 +235,7 @@ public void clear()
{
super.clear();
this.disambiguatedBeans.clear();
this.beansByType.clear();
}

}
Expand Up @@ -46,6 +46,12 @@ protected boolean matches(Resolvable resolvable, Decorator<?> bean)
&& getBeanManager().getEnabled().getDecorator(bean.getBeanClass()) != null;
}

@Override
protected Iterable<? extends Decorator<?>> getAllBeans(Resolvable resolvable)
{
return getAllBeans();
}

@Override
protected Set<Decorator<?>> sortResult(Set<Decorator<?>> matchedDecorators)
{
Expand Down
Expand Up @@ -97,7 +97,7 @@ public Set<T> resolve(R resolvable)
private Set<T> findMatching(R resolvable)
{
Set<T> result = new HashSet<T>();
for (T bean : allBeans)
for (T bean : getAllBeans(resolvable))
{
if (matches(resolvable, bean))
{
Expand All @@ -107,6 +107,16 @@ private Set<T> findMatching(R resolvable)
return result;
}

protected Iterable<? extends T> getAllBeans(R resolvable)
{
return allBeans;
}

protected Iterable<? extends T> getAllBeans()
{
return allBeans;
}

protected abstract Set<T> filterResult(Set<T> matched);

protected abstract Set<T> sortResult(Set<T> matched);
Expand Down
57 changes: 57 additions & 0 deletions impl/src/main/java/org/jboss/weld/util/LazyValueHolder.java
@@ -0,0 +1,57 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.util;

/**
* Represents a lazily computed value.
*
* @author Stuart Douglas
*
*/
public abstract class LazyValueHolder<T>
{
private volatile T value;

private Object lock = new Object();

public T get()
{
T valueCopy = value;
if (valueCopy != null)
{
return valueCopy;
}
synchronized (lock)
{
if (value == null)
{
value = computeValue();
}
return value;
}
}

public void clear()
{
synchronized (lock)
{
value = null;
}
}

protected abstract T computeValue();
}

0 comments on commit 28379af

Please sign in to comment.