/*******************************************************************************
* Copyright (c) 2012 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.cdi.internal.core.impl;
import java.util.ArrayList;
import java.util.Collection;
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 org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IType;
import org.jboss.tools.cdi.core.IBean;
import org.jboss.tools.cdi.core.IClassBean;
import org.jboss.tools.cdi.core.IDecorator;
import org.jboss.tools.cdi.core.IInjectionPoint;
import org.jboss.tools.cdi.core.IInterceptor;
import org.jboss.tools.cdi.core.IInterceptorBinding;
import org.jboss.tools.cdi.core.IQualifier;
import org.jboss.tools.cdi.core.IScope;
import org.jboss.tools.cdi.core.IStereotype;
import org.jboss.tools.cdi.internal.core.impl.definition.TypeDefinition;
import org.jboss.tools.common.java.IParametedType;
public class CDICache implements Cloneable {
static Collection<IBean> EMPTY = Collections.emptyList();
private Map<String, StereotypeElement> stereotypes = new HashMap<String, StereotypeElement>();
private Map<IPath, StereotypeElement> stereotypesByPath = new HashMap<IPath, StereotypeElement>();
private Map<String, InterceptorBindingElement> interceptorBindings = new HashMap<String, InterceptorBindingElement>();
private Map<IPath, InterceptorBindingElement> interceptorBindingsByPath = new HashMap<IPath, InterceptorBindingElement>();
private Map<String, QualifierElement> qualifiers = new HashMap<String, QualifierElement>();
private Map<IPath, QualifierElement> qualifiersByPath = new HashMap<IPath, QualifierElement>();
private Map<String, ScopeElement> scopes = new HashMap<String, ScopeElement>();
private Map<IPath, ScopeElement> scopesByPath = new HashMap<IPath, ScopeElement>();
private Set<IBean> allBeans = new HashSet<IBean>();
private Set<IBean> declaredBeans = new HashSet<IBean>();
private Map<IPath, List<IBean>> beansByPath = new HashMap<IPath, List<IBean>>();
private Map<String, Set<IBean>> beansByName = new HashMap<String, Set<IBean>>();
private List<Set<IBean>> beansByTypes = new ArrayList<Set<IBean>>();
private Set<IBean> namedBeans = new HashSet<IBean>();
protected Map<IType, IClassBean> classBeans = new HashMap<IType, IClassBean>();
private Set<IBean> alternatives = new HashSet<IBean>();
private Set<IDecorator> decorators = new HashSet<IDecorator>();
private Set<IInterceptor> interceptors = new HashSet<IInterceptor>();
protected Set<IType> allTypes = new HashSet<IType>();
protected Map<TypeDefinition, ClassBean> definitionToClassbeans = new HashMap<TypeDefinition, ClassBean>();
private Map<String, Set<IInjectionPoint>> injectionPointsByType = new HashMap<String, Set<IInjectionPoint>>();
private int beansByTypeSize;
private int objectIndex;
public CDICache() {
setBeansByTypeSize(21);
}
public synchronized void setBeansByTypeSize(int beansByTypeSize) {
List<Set<IBean>> beansByTypes = new ArrayList<Set<IBean>>();
for (int i = 0; i < beansByTypeSize; i++) beansByTypes.add(new HashSet<IBean>());
this.beansByTypes = beansByTypes;
this.beansByTypeSize = beansByTypeSize;
objectIndex = Math.abs("java.lang.Object".hashCode()) % beansByTypeSize;
}
private int toTypeIndex(IType type) {
return Math.abs(type.getFullyQualifiedName().hashCode()) % beansByTypeSize;
}
public synchronized IBean[] getBeans() {
return allBeans.toArray(new IBean[allBeans.size()]);
}
public Collection<IBean> getAllBeans() {
return allBeans;
}
public synchronized Collection<IBean> getDeclaredBeans() {
return new ArrayList<IBean>(declaredBeans);
}
public synchronized IBean[] getBeansByLegalType(IParametedType type) {
if(type.getType() == null) return new IBean[0];
int index = toTypeIndex(type.getType());
Collection<IBean> bs = index == objectIndex ? allBeans : beansByTypes.get(index);
return bs.toArray(new IBean[bs.size()]);
}
public synchronized IQualifier[] getQualifiers() {
return qualifiers.values().toArray(new IQualifier[qualifiers.size()]);
}
public synchronized IStereotype[] getStereotypes() {
return stereotypes.values().toArray(new IStereotype[stereotypes.size()]);
}
public synchronized IBean[] getAlternatives() {
return alternatives.toArray(new IBean[alternatives.size()]);
}
public synchronized IDecorator[] getDecorators() {
return decorators.toArray(new IDecorator[decorators.size()]);
}
public synchronized IInterceptor[] getInterceptors() {
return interceptors.toArray(new IInterceptor[interceptors.size()]);
}
public synchronized StereotypeElement getStereotype(IPath path) {
return stereotypesByPath.get(path);
}
public StereotypeElement getStereotype(String qualifiedName) {
return stereotypes.get(qualifiedName.replace('$', '.'));
}
public synchronized IInterceptorBinding[] getInterceptorBindings() {
return interceptorBindings.values().toArray(new IInterceptorBinding[interceptorBindings.size()]);
}
/*
* (non-Javadoc)
* @see org.jboss.tools.cdi.core.IBeanManager#getInterceptorBinding(java.lang.String)
*/
public InterceptorBindingElement getInterceptorBinding(String qualifiedName) {
return interceptorBindings.get(qualifiedName.replace('$', '.'));
}
/*
* (non-Javadoc)
* @see org.jboss.tools.cdi.core.IBeanManager#getInterceptorBinding(org.eclipse.core.runtime.IPath)
*/
public IInterceptorBinding getInterceptorBinding(IPath path) {
return interceptorBindingsByPath.get(path);
}
public QualifierElement getQualifier(String qualifiedName) {
return qualifiers.get(qualifiedName.replace('$', '.'));
}
public QualifierElement getQualifier(IPath path) {
return qualifiersByPath.get(path);
}
public synchronized Set<String> getScopeNames() {
Set<String> result = new HashSet<String>();
result.addAll(scopes.keySet());
return result;
}
public ScopeElement getScope(String qualifiedName) {
return scopes.get(qualifiedName.replace('$', '.'));
}
public IScope getScope(IPath path) {
return scopesByPath.get(path);
}
public CDICache getModifiedCopy(IFile file, Collection<IBean> beans) {
CDICache p = null;
try {
p = (CDICache)clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
p.allBeans = new HashSet<IBean>();
synchronized(this) {
p.allBeans.addAll(allBeans);
}
Collection<IBean> oldBeans = getBeans(file.getFullPath());
p.allBeans.removeAll(oldBeans);
p.allBeans.addAll(beans);
p.beansByTypes = new ArrayList<Set<IBean>>();
for (int i = 0; i < beansByTypeSize; i++) {
Set<IBean> bs = new HashSet<IBean>(beansByTypes.get(i));
bs.removeAll(oldBeans);
bs.addAll(beans);
p.beansByTypes.add(bs);
}
Set<IBean> oldNamedBeans = null;
for (IBean b: oldBeans) {
if(b.getName() != null) {
if(oldNamedBeans == null) oldNamedBeans = new HashSet<IBean>();
oldNamedBeans.add(b);
}
}
Set<IBean> newNamedBeans = null;
for (IBean b: beans) {
if(b.getName() != null) {
if(newNamedBeans == null) newNamedBeans = new HashSet<IBean>();
newNamedBeans.add(b);
}
}
if(newNamedBeans != null || oldNamedBeans != null) {
p.namedBeans = new HashSet<IBean>();
p.beansByName = new HashMap<String, Set<IBean>>();
synchronized(this) {
p.namedBeans.addAll(namedBeans);
if(oldNamedBeans != null) p.namedBeans.removeAll(oldNamedBeans);
if(newNamedBeans != null) p.namedBeans.addAll(newNamedBeans);
for (String n: beansByName.keySet()) {
Set<IBean> bs = new HashSet<IBean>(beansByName.get(n));
p.beansByName.put(n, bs);
}
if(oldNamedBeans != null) {
for (IBean b: oldNamedBeans) {
String n = b.getName();
Set<IBean> bs = p.beansByName.get(n);
if(bs != null && bs.contains(b)) {
bs.remove(b);
}
}
}
if(newNamedBeans != null) {
for (IBean b: newNamedBeans) {
String n = b.getName();
Set<IBean> bs = p.beansByName.get(n);
if(bs == null) {
bs = new HashSet<IBean>();
p.beansByName.put(n, bs);
}
bs.add(b);
}
}
}
}
return p;
}
public synchronized Collection<IBean> getBeans(IPath path) {
return (beansByPath.containsKey(path)) ? new ArrayList<IBean>(beansByPath.get(path)) : EMPTY;
}
public Set<IInjectionPoint> getInjections(String fullyQualifiedTypeName) {
Set<IInjectionPoint> result = injectionPointsByType.get(fullyQualifiedTypeName);
if(result == null) result = Collections.emptySet();
return result;
}
public Collection<IBean> getNamedBeans() {
return namedBeans;
}
public boolean containsType(IType t) {
return allTypes.contains(t);
}
public Collection<IType> getAllTypes() {
return allTypes;
}
public Collection<IBean> getBeans(String name) {
return beansByName.containsKey(name) ? beansByName.get(name) : EMPTY;
}
public synchronized void addBean(IBean bean, boolean isDeclaredByThisProject) {
String name = bean.getName();
IPath path = bean.getSourcePath();
List<IBean> bs = beansByPath.get(path);
if(bs == null) {
bs = new ArrayList<IBean>();
beansByPath.put(path, bs);
}
bs.add(bean);
buildInjectionPoinsByType(bean);
boolean isAbstract = (bean instanceof ClassBean) && !((ClassBean)bean).getDefinition().hasBeanConstructor();
if(isAbstract) {
return;
}
if(name != null && name.length() > 0) {
Set<IBean> bsn = beansByName.get(name);
if(bsn == null) {
bsn = new HashSet<IBean>();
beansByName.put(name, bsn);
}
bsn.add(bean);
namedBeans.add(bean);
}
if(bean.isAlternative()) {
alternatives.add(bean);
}
if(bean instanceof IDecorator) {
decorators.add((IDecorator)bean);
}
if(bean instanceof IInterceptor) {
interceptors.add((IInterceptor)bean);
}
if(bean instanceof IClassBean) {
IClassBean c = (IClassBean)bean;
IType t = c.getBeanClass();
if(t != null && !classBeans.containsKey(t)) {
classBeans.put(t, c);
}
}
allBeans.add(bean);
if(isDeclaredByThisProject) {
declaredBeans.add(bean);
}
for (IParametedType t: bean.getLegalTypes()) {
if(t.getType() != null && t.getType().exists()) {
int index = toTypeIndex(t.getType());
if(index != objectIndex) {
beansByTypes.get(index).add(bean);
}
}
}
}
synchronized void buildInjectionPoinsByType(IBean b) {
Collection<IInjectionPoint> ps = b.getInjectionPoints();
for (IInjectionPoint p: ps) {
IParametedType t = p.getType();
if(t == null || t.getType() == null) continue;
String n = t.getType().getFullyQualifiedName();
Set<IInjectionPoint> s = injectionPointsByType.get(n);
if(s == null) {
s = new HashSet<IInjectionPoint>();
injectionPointsByType.put(n, s);
}
s.add(p);
}
}
public synchronized void clean() {
beansByPath.clear();
beansByName.clear();
namedBeans.clear();
alternatives.clear();
decorators.clear();
interceptors.clear();
allBeans.clear();
declaredBeans.clear();
injectionPointsByType.clear();
for (int i = 0; i < beansByTypeSize; i++) beansByTypes.get(i).clear();
}
public synchronized void cleanAnnotations() {
stereotypes.clear();
stereotypesByPath.clear();
interceptorBindings.clear();
qualifiers.clear();
qualifiersByPath.clear();
interceptorBindingsByPath.clear();
scopes.clear();
scopesByPath.clear();
}
public void add(StereotypeElement s) {
stereotypes.put(s.getDefinition().getQualifiedName().replace('$', '.'), s);
if(s.getDefinition().getResource() != null && s.getDefinition().getResource().getFullPath() != null) {
stereotypesByPath.put(s.getDefinition().getResource().getFullPath(), s);
}
}
public void add(InterceptorBindingElement s) {
interceptorBindings.put(s.getDefinition().getQualifiedName().replace('$', '.'), s);
if(s.getDefinition().getResource() != null && s.getDefinition().getResource().getFullPath() != null) {
interceptorBindingsByPath.put(s.getDefinition().getResource().getFullPath(), s);
}
}
public void add(QualifierElement s) {
qualifiers.put(s.getDefinition().getQualifiedName().replace('$', '.'), s);
if(s.getDefinition().getResource() != null && s.getDefinition().getResource().getFullPath() != null) {
qualifiersByPath.put(s.getDefinition().getResource().getFullPath(), s);
}
}
public void add(ScopeElement s) {
scopes.put(s.getDefinition().getQualifiedName().replace('$', '.'), s);
if(s.getDefinition().getResource() != null && s.getDefinition().getResource().getFullPath() != null) {
scopesByPath.put(s.getDefinition().getResource().getFullPath(), s);
}
}
}