/*******************************************************************************
* 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.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.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageDeclaration;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.ui.IWorkingCopyManager;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.jboss.tools.cdi.core.CDIConstants;
import org.jboss.tools.cdi.core.CDICoreNature;
import org.jboss.tools.cdi.core.CDICorePlugin;
import org.jboss.tools.cdi.core.CDIVersion;
import org.jboss.tools.cdi.core.IBean;
import org.jboss.tools.cdi.core.IBeanMember;
import org.jboss.tools.cdi.core.IBeanMethod;
import org.jboss.tools.cdi.core.ICDIElement;
import org.jboss.tools.cdi.core.ICDIProject;
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.IObserverMethod;
import org.jboss.tools.cdi.core.IParameter;
import org.jboss.tools.cdi.core.IProducer;
import org.jboss.tools.cdi.core.IProducerMethod;
import org.jboss.tools.cdi.core.IQualifier;
import org.jboss.tools.cdi.core.IQualifierDeclaration;
import org.jboss.tools.cdi.core.IScope;
import org.jboss.tools.cdi.core.IStereotype;
import org.jboss.tools.cdi.internal.core.impl.definition.AnnotationDefinition;
import org.jboss.tools.cdi.internal.core.impl.definition.DefinitionContext;
import org.jboss.tools.cdi.internal.core.impl.definition.TypeDefinition;
import org.jboss.tools.cdi.internal.core.scanner.CDIBuilderDelegate;
import org.jboss.tools.cdi.internal.core.scanner.FileSet;
import org.jboss.tools.cdi.internal.core.scanner.ImplementationCollector;
import org.jboss.tools.cdi.internal.core.scanner.lib.BeanArchiveDetector;
import org.jboss.tools.common.CommonPlugin;
import org.jboss.tools.common.java.IJavaReference;
import org.jboss.tools.common.java.IParametedType;
import org.jboss.tools.common.text.INodeReference;
/**
*
* @author Viacheslav Kabanovich
*
*/
public class CDIProjectAsYouType implements ICDIProject, ICDIElement {
ICDIProject project;
IFile file;
Collection<IBean> beans = new ArrayList<IBean>();
StereotypeElement stereotype;
QualifierElement qualifier;
ScopeElement scope;
IInterceptorBinding interceptorBinding;
public CDIProjectAsYouType(ICDIProject project, IFile file) {
if(file.getProject() != project.getNature().getProject()) {
/**
* Validation is done in context of the root project,
* however, at present as-you-type project based on the root project
* appears to be too complicated to implement, so that currently
* it will be based on the project of the file itself.
*/
ICDIProject p = CDICorePlugin.getCDIProject(file.getProject(), true);
if(p != null) project = p;
}
this.project = project;
this.file = file;
JavaModelManager manager = JavaModelManager.getJavaModelManager();
try {
manager.cacheZipFiles(this);
build();
} catch (CoreException e) {
CDICorePlugin.getDefault().logError(e);
} finally {
manager.flushZipFiles(this);
}
CDIProject p = ((CDIProject)project).getModifiedCopy(file, beans);
if(p != null) {
this.project = p;
}
}
public CDIVersion getVersion() {
return project.getVersion();
}
private void build() throws CoreException {
DefinitionContext context = project.getNature().getDefinitions().getCleanCopy();
FileSet fileSet = new FileSet();
if(file.getName().endsWith(".java")) {
ICompilationUnit unit = findCompilationUnit();// EclipseUtil.getCompilationUnit(file);
if(unit!=null) {
if(file.getName().equals("package-info.java")) {
IPackageDeclaration[] pkg = unit.getPackageDeclarations();
if(pkg != null && pkg.length > 0) {
fileSet.add(file.getFullPath(), pkg[0]);
// if(incremental) {
// IResource[] ms = file.getParent().members();
// for (IResource m: ms) {
// if(m instanceof IFile && !m.getName().equals("package-info.java")) {
// visit(m);
// }
// }
// }
}
} else {
IType[] ts = unit.getTypes();
if(getNature().getBeanDiscoveryMode() == BeanArchiveDetector.NONE) {
ts = new IType[0];
}
if(ts.length > 0 && getNature().getBeanDiscoveryMode() == BeanArchiveDetector.ANNOTATED) {
ts = BeanArchiveDetector.getAnnotatedTypes(ts, getNature());
}
fileSet.add(file.getFullPath(), ts);
}
}
}
CDIBuilderDelegate builder = new CDIBuilderDelegate();
builder.build(fileSet, context);
rebuildAnnotationTypes(context.getAllAnnotations());
rebuildBeans(context.getTypeDefinitions());
}
private ICompilationUnit findCompilationUnit() {
IWorkbench workbench = CommonPlugin.getDefault().getWorkbench();
if(workbench != null) {
IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
for (IWorkbenchWindow window: windows) {
if(window.getShell() != null) {
IWorkbenchPage[] pages = window.getPages();
for (IWorkbenchPage page: pages) {
IEditorReference[] rs = page.getEditorReferences();
for (IEditorReference r: rs) {
IEditorPart part = r.getEditor(false);
if(part != null) {
IFile file = getFile(part);
if(file != null && file.equals(this.file) && part instanceof CompilationUnitEditor) {
IWorkingCopyManager manager= JavaUI.getWorkingCopyManager();
ICompilationUnit unit= manager.getWorkingCopy(part.getEditorInput());
if(unit != null) {
try {
unit.reconcile(ICompilationUnit.NO_AST,
false /* don't force problem detection */,
null /* use primary owner */,
null /* no progress monitor */);
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
return unit;
}
}
}
}
}
}
}
}
return null;
}
private IFile getFile(IEditorPart part) {
IEditorInput input = part.getEditorInput();
return (input instanceof IFileEditorInput) ? ((IFileEditorInput)input).getFile() : null;
}
synchronized void rebuildAnnotationTypes(List<AnnotationDefinition> ds) {
for (AnnotationDefinition d: ds) {
if(d.getResource() == null || !d.getResource().getFullPath().equals(file.getFullPath())) {
continue;
}
// System.out.println("Annotation " + d.getQualifiedName());
if((d.getKind() & AnnotationDefinition.STEREOTYPE) > 0) {
StereotypeElement s = new StereotypeElement();
initAnnotationElement(s, d);
stereotype = s;
}
if((d.getKind() & AnnotationDefinition.INTERCEPTOR_BINDING) > 0) {
InterceptorBindingElement s = new InterceptorBindingElement();
initAnnotationElement(s, d);
interceptorBinding = s;
}
if((d.getKind() & AnnotationDefinition.QUALIFIER) > 0) {
QualifierElement s = new QualifierElement();
initAnnotationElement(s, d);
qualifier = s;
}
if((d.getKind() & AnnotationDefinition.SCOPE) > 0) {
ScopeElement s = new ScopeElement();
initAnnotationElement(s, d);
scope = s;
}
}
}
private void initAnnotationElement(CDIAnnotationElement s, AnnotationDefinition d) {
s.setDefinition(d);
s.setParent((CDIElement)project);
IPath r = d.getType().getPath();
if(r != null) {
s.setSourcePath(r);
}
}
void rebuildBeans(List<TypeDefinition> typeDefinitions) {
// Set<String> vetoedTypes = n.getAllVetoedTypes();
List<IBean> beans = new ArrayList<IBean>();
Set<IType> newAllTypes = new HashSet<IType>();
for (TypeDefinition d: typeDefinitions) {
newAllTypes.add(d.getType());
}
Map<TypeDefinition, ClassBean> newDefinitionToClassbeans = new HashMap<TypeDefinition, ClassBean>();
Map<IType, IClassBean> newClassBeans = new HashMap<IType, IClassBean>();
ImplementationCollector ic = new ImplementationCollector(typeDefinitions);
for (TypeDefinition typeDefinition : typeDefinitions) {
ClassBean bean = null;
if(typeDefinition.getInterceptorAnnotation() != null || ic.isInterceptor(typeDefinition.getType())) {
bean = new InterceptorBean();
} else if(typeDefinition.getDecoratorAnnotation() != null || ic.isDecorator(typeDefinition.getType())) {
bean = new DecoratorBean();
} else if(typeDefinition.getStatefulAnnotation() != null || typeDefinition.getStatelessAnnotation() != null || typeDefinition.getSingletonAnnotation() != null) {
bean = new SessionBean();
} else {
bean = new ClassBean();
}
/*
* Parent can be either 'this' or 'project'. In the second case, it is an original project
* that will return 'unmodified' data. In the first case, correctness of 'declaring project'
* needs attention.
*/
bean.setParent(this);
bean.setDefinition(typeDefinition);
newDefinitionToClassbeans.put(typeDefinition, bean);
String typeName = typeDefinition.getType().getFullyQualifiedName();
if(!typeDefinition.isVetoed()
//Type is defined in another project and modified/replaced in config in this (dependent) project
//We should reject type definition based on type, but we have to accept
&& !(/*vetoedTypes.contains(typeName)*/false && getNature().getDefinitions().getTypeDefinition(typeName) == null && typeDefinition.getOriginalDefinition() == null)) {
if(typeDefinition.hasBeanConstructor()) {
beans.add(bean);
newClassBeans.put(typeDefinition.getType(), bean);
} else {
beans.add(bean);
}
for (IProducer producer: bean.getProducers()) {
beans.add(producer);
}
}
}
for (IClassBean bean: newClassBeans.values()) {
IParametedType s = ((ClassBean)bean).getSuperType();
if(s != null && s.getType() != null) {
IClassBean superClassBean = newClassBeans.get(s.getType());
if(superClassBean == null) superClassBean = project.getBeanClass(s.getType());
if(bean instanceof ClassBean) {
((ClassBean)bean).setSuperClassBean(superClassBean);
}
}
}
for (IBean bean: beans) {
addBean(bean);
}
}
public void addBean(IBean bean) {
beans.add(bean);
//TODO
}
@Override
public IBean[] getBeans() {
return project.getBeans();
}
@Override
public Collection<IBean> getNamedBeans(boolean attemptToResolveAmbiguousNames) {
return project.getNamedBeans(attemptToResolveAmbiguousNames);
}
@Override
public Collection<IBean> getBeans(String name,
boolean attemptToResolveAmbiguousNames) {
return project.getBeans(name, attemptToResolveAmbiguousNames);
}
@Override
public Collection<IBean> getBeans(boolean attemptToResolveAmbiguousDependency,
IParametedType beanType, IQualifierDeclaration... qualifiers) {
return project.getBeans(attemptToResolveAmbiguousDependency, beanType, qualifiers);
}
@Override
public Collection<IBean> getBeans(boolean attemptToResolveAmbiguousDependency,
IParametedType beanType, IType... qualifiers) {
return project.getBeans(attemptToResolveAmbiguousDependency, beanType, qualifiers);
}
@Override
public Collection<IBean> getBeans(boolean attemptToResolveAmbiguousDependency,
String fullyQualifiedBeanType,
String... fullyQualifiedQualifiersTypes) {
return project.getBeans(attemptToResolveAmbiguousDependency, fullyQualifiedBeanType, fullyQualifiedQualifiersTypes);
}
@Override
public Collection<IBean> getBeans(boolean attemptToResolveAmbiguousDependency,
IInjectionPoint injectionPoint) {
return project.getBeans(attemptToResolveAmbiguousDependency, injectionPoint);
}
@Override
public IClassBean getBeanClass(IType type) {
return project.getBeanClass(type);
}
@Override
public Collection<IBean> getBeans(IPath path) {
if(path.equals(file.getFullPath())) {
return beans;
}
return project.getBeans(path);
}
@Override
public Collection<IBean> getBeans(IJavaElement element) {
if(element.getResource() != null && element.getResource().getFullPath().equals(file.getFullPath())) {
Set<IBean> result = new HashSet<IBean>();
for (IBean bean: beans) {
if(bean instanceof IJavaReference) {
if(((IJavaReference)bean).getSourceMember().equals(element)) {
result.add(bean);
}
}
}
return result;
}
return project.getBeans(element);
}
@Override
public IQualifier[] getQualifiers() {
return project.getQualifiers();
}
@Override
public IStereotype[] getStereotypes() {
return project.getStereotypes();
}
@Override
public IBean[] getAlternatives() {
return project.getAlternatives();
}
@Override
public IDecorator[] getDecorators() {
return project.getDecorators();
}
@Override
public IInterceptor[] getInterceptors() {
return project.getInterceptors();
}
@Override
public IStereotype getStereotype(String qualifiedName) {
return project.getStereotype(qualifiedName);
}
@Override
public IStereotype getStereotype(IPath path) {
if(path.equals(file.getFullPath())) {
return stereotype;
}
return project.getStereotype(path);
}
@Override
public IStereotype getStereotype(IType type) {
return getStereotype(type.getPath());
}
@Override
public IInterceptorBinding[] getInterceptorBindings() {
return project.getInterceptorBindings();
}
@Override
public IInterceptorBinding getInterceptorBinding(String qualifiedName) {
return project.getInterceptorBinding(qualifiedName);
}
@Override
public IInterceptorBinding getInterceptorBinding(IPath path) {
if(path.equals(file.getFullPath())) {
return interceptorBinding;
}
return project.getInterceptorBinding(path);
}
@Override
public IQualifier getQualifier(String qualifiedName) {
return project.getQualifier(qualifiedName);
}
@Override
public IQualifier getQualifier(IPath path) {
if(path.equals(file.getFullPath())) {
return qualifier;
}
return project.getQualifier(path);
}
@Override
public Collection<String> getScopeNames() {
return project.getScopeNames();
}
@Override
public IScope getScope(String qualifiedName) {
return project.getScope(qualifiedName);
}
@Override
public IScope getScope(IPath path) {
if(path.equals(file.getFullPath())) {
return scope;
}
return project.getScope(path);
}
@Override
public Collection<IObserverMethod> resolveObserverMethods(IInjectionPoint injectionPoint) {
// TODO resolve in file
return project.resolveObserverMethods(injectionPoint);
}
@Override
public Collection<IInjectionPoint> findObservedEvents(IParameter observedEventParameter) {
// TODO find in file
return project.findObservedEvents(observedEventParameter);
}
@Override
public Collection<IBean> resolve(Collection<IBean> beans) {
return project.resolve(beans);
}
@Override
public Collection<IBeanMethod> resolveDisposers(IProducerMethod producer) {
return project.resolveDisposers(producer);
}
public Collection<IBeanMethod> resolveDisposers(IProducer producer) {
return project.resolveDisposers(producer);
}
@Override
public boolean isScope(IType annotationType) {
return project.isScope(annotationType);
}
@Override
public boolean isNormalScope(IType annotationType) {
return project.isNormalScope(annotationType);
}
@Override
public boolean isPassivatingScope(IType annotationType) {
return project.isPassivatingScope(annotationType);
}
@Override
public boolean isQualifier(IType annotationType) {
return project.isQualifier(annotationType);
}
@Override
public boolean isStereotype(IType annotationType) {
return project.isStereotype(annotationType);
}
@Override
public List<INodeReference> getAlternativeClasses() {
return project.getAlternativeClasses();
}
@Override
public List<INodeReference> getAlternativeStereotypes() {
return project.getAlternativeStereotypes();
}
@Override
public List<INodeReference> getAlternatives(String fullyQualifiedTypeName) {
return project.getAlternatives(fullyQualifiedTypeName);
}
@Override
public List<INodeReference> getDecoratorClasses() {
return project.getDecoratorClasses();
}
@Override
public List<INodeReference> getDecoratorClasses(String fullyQualifiedTypeName) {
return project.getDecoratorClasses(fullyQualifiedTypeName);
}
@Override
public List<INodeReference> getInterceptorClasses() {
return project.getInterceptorClasses();
}
@Override
public List<INodeReference> getInterceptorClasses(String fullyQualifiedTypeName) {
return project.getInterceptorClasses(fullyQualifiedTypeName);
}
@Override
public Collection<IInjectionPoint> getInjections(String fullyQualifiedTypeName) {
return project.getInjections(fullyQualifiedTypeName);
}
@Override
public CDICoreNature getNature() {
return project.getNature();
}
@Override
public void setNature(CDICoreNature n) {
//nothing
}
@Override
public void update(boolean updateDependent) {
//nothing
}
/**
*
*/
@Override
public ICDIProject getCDIProject() {
return this;
}
@Override
public ICDIProject getDeclaringProject() {
return ((ICDIElement)project).getDeclaringProject();
}
@Override
public IPath getSourcePath() {
return getResource().getFullPath();
}
@Override
public IResource getResource() {
return getNature().getProject();
}
@Override
public boolean exists() {
return true;
}
@Override
public String getElementName() {
return getNature().getProject().getName();
}
@Override
public boolean isTypeAlternative(String qualifiedName) {
return project.isTypeAlternative(qualifiedName);
}
@Override
public boolean isStereotypeAlternative(String qualifiedName) {
return project.isStereotypeAlternative(qualifiedName);
}
@Override
public boolean isClassAlternativeActivated(String fullQualifiedTypeName) {
return project.isClassAlternativeActivated(fullQualifiedTypeName);
}
@Override
public int getId() {
return ((ICDIElement)project).getId();
}
}