/******************************************************************************* * Copyright (c) 2009 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.core; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeMap; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.tools.ant.util.FileUtils; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IAnnotatable; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeParameter; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.internal.core.JarPackageFragmentRoot; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jst.j2ee.project.facet.IJ2EEFacetConstants; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.eclipse.wst.common.componentcore.ComponentCore; import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; import org.eclipse.wst.common.componentcore.resources.IVirtualFolder; import org.eclipse.wst.common.project.facet.core.IFacetedProject; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; import org.jboss.tools.cdi.internal.core.impl.CDIProjectAsYouType; import org.jboss.tools.cdi.internal.core.impl.ClassBean; import org.jboss.tools.cdi.internal.core.project.facet.CDIFacetInstallDelegate; import org.jboss.tools.cdi.internal.core.validation.AnnotationValidationDelegate; import org.jboss.tools.cdi.internal.core.validation.CDICoreValidator; import org.jboss.tools.common.EclipseUtil; import org.jboss.tools.common.java.IAnnotated; import org.jboss.tools.common.java.IAnnotationDeclaration; import org.jboss.tools.common.java.IAnnotationType; import org.jboss.tools.common.java.IJavaReference; import org.jboss.tools.common.java.IJavaSourceReference; import org.jboss.tools.common.java.IParametedType; import org.jboss.tools.common.model.util.EclipseJavaUtil; import org.jboss.tools.common.model.util.EclipseResourceUtil; import org.jboss.tools.common.text.ITextSourceReference; import org.jboss.tools.common.zip.UnzipOperation; import org.jboss.tools.jst.web.WebModelPlugin; import org.jboss.tools.jst.web.kb.IKbProject; import org.jboss.tools.jst.web.kb.internal.KbBuilder; import org.osgi.framework.Bundle; /** * @author Alexey Kazakov */ public class CDIUtil { private static File TEMPLATE_FOLDER; /** * Adds CDI and KB builders to the project. * * @param project */ public static void enableCDI(IProject project, IProgressMonitor monitor) { enableCDI(project, null, monitor); } /** * Adds CDI and KB builders to the project. * * @param project * @param generateBeansXml */ public static void enableCDI(IProject project, boolean generateBeansXml, IProgressMonitor monitor) { enableCDI(project, generateBeansXml?CDIVersion.getLatestDefaultVersion():null, monitor); } private static final String BEANS_XML_1_0_TEMPLATE_NAME = "beans.xml"; private static final String BEANS_XML_1_1_TEMPLATE_NAME = "beans11.xml"; /** * Adds CDI and KB builders to the project. * * @param project * @param version the version of beans.xml if it should be created. If null then beans.xml should not be created. */ public static void enableCDI(IProject project, CDIVersion beansXmlVersion, IProgressMonitor monitor) { try { WebModelPlugin.addNatureToProjectWithValidationSupport(project, KbBuilder.BUILDER_ID, IKbProject.NATURE_ID); WebModelPlugin.addNatureToProjectWithValidationSupport(project, CDICoreBuilder.BUILDER_ID, CDICoreNature.NATURE_ID); if(beansXmlVersion!=null) { File beansXml = getBeansXml(project); if(beansXml!=null && !beansXml.exists()) { // Create an empty beans.xml beansXml.getParentFile().mkdir(); String templateName = beansXmlVersion == CDIVersion.CDI_1_0?BEANS_XML_1_0_TEMPLATE_NAME:BEANS_XML_1_1_TEMPLATE_NAME; try { FileUtils.getFileUtils().copyFile(new File(getTemplatesFolder(), templateName), beansXml, null, false, false); } catch (IOException e) { CDICorePlugin.getDefault().logError(e); } } project.refreshLocal(IResource.DEPTH_INFINITE, monitor); } IProject[] ps = project.getWorkspace().getRoot().getProjects(); for (IProject p: ps) { CDICoreNature n = CDICorePlugin.getCDI(p, false); if(n != null && n.isStorageResolved()) { n.getClassPath().validateProjectDependencies(); } } } catch (CoreException e) { CDICorePlugin.getDefault().logError(e); } } /** * Removes CDI builder from the project. * * @param project */ public static void disableCDI(IProject project) { try { EclipseUtil.removeNatureFromProject(project, CDICoreNature.NATURE_ID); CDICoreValidator.cleanProject(project); } catch (CoreException e) { CDICorePlugin.getDefault().logError(e); } } /** * Calculate path to templates folder * * @return path to templates * @throws IOException if templates folder not found */ public static File getTemplatesFolder() throws IOException { if(TEMPLATE_FOLDER==null) { Bundle bundle = CDICorePlugin.getDefault().getBundle(); String version = bundle.getVersion().toString(); IPath stateLocation = Platform.getStateLocation(bundle); File templatesDir = FileLocator.getBundleFile(bundle); if(templatesDir.isFile()) { File toCopy = new File(stateLocation.toFile(),version); if(!toCopy.exists()) { toCopy.mkdirs(); UnzipOperation unZip = new UnzipOperation(templatesDir.getAbsolutePath()); unZip.execute(toCopy,"templates.*"); } templatesDir = toCopy; } TEMPLATE_FOLDER = new File(templatesDir,"templates"); } return TEMPLATE_FOLDER; } private static final String BEANS_XML_FILE_NAME = "beans.xml"; //$NON-NLS-1$ /** * Returns java.io.File which represents beans.xml for the project. * If the project is a faceted Java project then <src>/META-INF/beans.xml will be return. * If there are a few source folders then the folder which contains META-INF folder will be return. * If there are a few source folders but no any META-INF in them then null will be return. * If the project is a faceted WAR then /<WebContent>/WEB-INF/beans.xml will be return. * The beans.xml may or may not exist. * @param project the project * @return java.io.File which represents beans.xml for the project. * @throws CoreException */ public static File getBeansXml(IProject project) throws CoreException { IFacetedProject facetedProject = ProjectFacetsManager.create(project); if(facetedProject!=null) { IProjectFacetVersion webVersion = facetedProject.getProjectFacetVersion(IJ2EEFacetConstants.DYNAMIC_WEB_FACET); if(webVersion!=null) { // WAR IVirtualComponent com = ComponentCore.createComponent(project); if(com!=null && com.getRootFolder()!=null) { IVirtualFolder webInf = com.getRootFolder().getFolder(new Path("/WEB-INF")); //$NON-NLS-1$ if(webInf!=null) { IContainer webInfFolder = webInf.getUnderlyingFolder(); if(webInfFolder.isAccessible()) { File file = new File(webInfFolder.getLocation().toFile(), BEANS_XML_FILE_NAME); return file; } } } } else if(facetedProject.getProjectFacetVersion(ProjectFacetsManager.getProjectFacet(IJ2EEFacetConstants.JAVA))!=null) { // JAR Set<IFolder> sources = EclipseResourceUtil.getSourceFolders(project); if(sources.size()==1) { return new File(sources.iterator().next().getLocation().toFile(), "META-INF/beans.xml"); //$NON-NLS-1$ } else { for (IFolder src : sources) { IFolder metaInf = src.getFolder("META-INF"); if(metaInf!=null && metaInf.isAccessible()) { return new File(metaInf.getLocation().toFile(), BEANS_XML_FILE_NAME); } } } } } return null; } /** * Finds CDI injected point in beans for particular java element. * * @param beans * @param element */ public static IInjectionPoint findInjectionPoint(Collection<IBean> beans, IJavaElement element, int position) { if (!(element instanceof IField) && !(element instanceof IMethod) && !(element instanceof ILocalVariable)) { return null; } for (IBean bean : beans) { Collection<IInjectionPoint> injectionPoints = bean.getInjectionPoints(); for (IInjectionPoint iPoint : injectionPoints) { if (element != null && iPoint.isDeclaredFor(element)) { return iPoint; } else if(iPoint instanceof IInjectionPointParameter && position != 0){ if(iPoint.getStartPosition() <= position && (iPoint.getStartPosition()+iPoint.getLength()) >= position) { return iPoint; } } } } return null; } /** * Sorts CDI beans which may be injected. The following order will be used: * 1) selected alternative beans * 2) nonalternative beans * 3) non-seleceted alternatives * 4) decorators * 5) interceptors * * @param beans */ public static List<IBean> sortBeans(Collection<IBean> beans) { TreeMap<String, IBean> alternativeBeans = new TreeMap<String, IBean>(); TreeMap<String, IBean> selectedAlternativeBeans = new TreeMap<String, IBean>(); TreeMap<String, IBean> nonAlternativeBeans = new TreeMap<String, IBean>(); TreeMap<String, IBean> decorators = new TreeMap<String, IBean>(); TreeMap<String, IBean> interceptors = new TreeMap<String, IBean>(); for (IBean bean : beans) { if (bean.isSelectedAlternative()) { selectedAlternativeBeans.put(bean.getElementName(), bean); } else if (bean.isAlternative()) { alternativeBeans.put(bean.getElementName(), bean); } else if (bean instanceof IDecorator) { decorators.put(bean.getElementName(), bean); } else if (bean instanceof IInterceptor) { interceptors.put(bean.getElementName(), bean); } else { nonAlternativeBeans.put(bean.getElementName(), bean); } } ArrayList<IBean> sortedBeans = new ArrayList<IBean>(); sortedBeans.addAll(selectedAlternativeBeans.values()); sortedBeans.addAll(nonAlternativeBeans.values()); sortedBeans.addAll(alternativeBeans.values()); sortedBeans.addAll(decorators.values()); sortedBeans.addAll(interceptors.values()); return sortedBeans; } /** * Checks if the bean has @Depended scope. If it has different scope then @Depended * then returns this scope declaration or a stereotype which declares the * scope. Otherwise returns null. * * @param bean * @param scopeTypeName * @return */ public static IAnnotationDeclaration getDifferentScopeDeclarationThanDepentend(IScoped scoped) { return getAnotherScopeDeclaration(scoped, CDIConstants.DEPENDENT_ANNOTATION_TYPE_NAME); } /** * Checks if the bean has @ApplicationScoped scope. If it has different scope then @ApplicationScoped * then returns this scope declaration or a stereotype which declares the * scope. Otherwise returns null. * * @param bean * @param scopeTypeName * @return */ public static IAnnotationDeclaration getDifferentScopeDeclarationThanApplicationScoped(IScoped scoped) { return getAnotherScopeDeclaration(scoped, CDIConstants.APPLICATION_SCOPED_ANNOTATION_TYPE_NAME); } /** * Checks if the bean has given scope. If it has different scope then given * then returns this scope declaration or a stereotype which declares the * scope. Otherwise returns null. * * @param bean * @param scopeTypeName * @return */ public static IAnnotationDeclaration getAnotherScopeDeclaration(IScoped scoped, String scopeTypeName) { IScope scope = scoped.getScope(); if(scope == null) { return null; } if (!scopeTypeName.equals(scope.getSourceType().getFullyQualifiedName())) { Collection<IScopeDeclaration> scopeDeclarations = scoped.getScopeDeclarations(); if (!scopeDeclarations.isEmpty()) { return scopeDeclarations.iterator().next(); } if (scoped instanceof IStereotyped) { Collection<IStereotypeDeclaration> stereoTypeDeclarations = ((IStereotyped) scoped).getStereotypeDeclarations(); for (IStereotypeDeclaration stereotypeDeclaration : stereoTypeDeclarations) { IStereotype stereotype = stereotypeDeclaration.getStereotype(); IScope stereotypeScope = stereotype.getScope(); if (stereotypeScope != null && !scopeTypeName.equals(stereotypeScope.getSourceType().getFullyQualifiedName())) { return stereotypeDeclaration; } } } } return null; } /** * Returns the scope annotation declaration if it exists in the bean. If the * scope declared in a stereotype then returns this stereotype declaration. * Returns null if there is not this scope declaration neither corresponding * stereotype declaration. * * @param bean * @param scopeTypeName * @return */ public static IAnnotationDeclaration getScopeDeclaration(IBean bean, String scopeTypeName) { IScope scope = bean.getScope(); if (scopeTypeName.equals(scope.getSourceType().getFullyQualifiedName())) { Collection<IScopeDeclaration> scopeDeclarations = bean.getScopeDeclarations(); for (IScopeDeclaration scopeDeclaration : scopeDeclarations) { if (scopeTypeName.equals(scopeDeclaration.getScope().getSourceType().getFullyQualifiedName())) { return scopeDeclaration; } } Collection<IStereotypeDeclaration> stereoTypeDeclarations = bean.getStereotypeDeclarations(); for (IStereotypeDeclaration stereotypeDeclaration : stereoTypeDeclarations) { IScope stereotypeScope = stereotypeDeclaration.getStereotype().getScope(); if (stereotypeScope != null && scopeTypeName.equals(stereotypeScope.getSourceType().getFullyQualifiedName())) { return stereotypeDeclaration; } } } return null; } /** * Returns the annotation declaration if it exists in the annotated element. If the * annotation declared in a stereotype then returns this stereotype declaration. * Returns null if there is not this annotation declaration neither corresponding * stereotype declaration. Doesn't check if a stereotype is inherited or not. * * @param bean * @param scopeTypeName * @return */ public static IAnnotationDeclaration getAnnotationDeclaration(IAnnotated annotated, ICDIAnnotation annotation) { List<IAnnotationDeclaration> annotations = annotated.getAnnotations(); for (IAnnotationDeclaration annotationDeclaration : annotations) { IAnnotationType annotationElement = annotationDeclaration.getAnnotation(); if(annotationElement!=null && annotation.equals(annotationElement)) { return annotationDeclaration; } } if(annotated instanceof IStereotyped) { Collection<IStereotypeDeclaration> stereoTypeDeclarations = ((IStereotyped)annotated).getStereotypeDeclarations(); for (IStereotypeDeclaration stereotypeDeclaration : stereoTypeDeclarations) { if(getAnnotationDeclaration(stereotypeDeclaration.getStereotype(), annotation) != null) { return stereotypeDeclaration; } } } return null; } /** * Returns the annotation declaration directly or indirectly declared for this element. * For instance some annotation directly declared for the element may declare wanted annotation then the method will return this declaration. * So the returned declaration may be from a resource other than the resource of the element. * Returns null if no declaration found. * * @param injection * @param qualifierTypeName * @return */ public static IAnnotationDeclaration getAnnotationDeclaration(IAnnotated element, String annotationTypeName) { List<IAnnotationDeclaration> declarations = element.getAnnotations(); for (IAnnotationDeclaration declaration : declarations) { IAnnotationType type = declaration.getAnnotation(); if(type!=null) { if(annotationTypeName.equals(type.getSourceType().getFullyQualifiedName())) { return declaration; } if(type instanceof IAnnotated) { IAnnotationDeclaration decl = getAnnotationDeclaration((IAnnotated)type, annotationTypeName); if(decl!=null) { return decl; } } } } return null; } /** * Returns @Named declaration or the stereotype declaration if it declares @Named. * * @param stereotyped * @return */ public static IAnnotationDeclaration getNamedDeclaration(IBean bean) { return getQualifierDeclaration(bean, CDIConstants.NAMED_QUALIFIER_TYPE_NAME); } /** * Return the qualifier declaration or the stereotype or @Specializes declaration if it declares this qualifier. * * @param stereotyped * @return */ public static IAnnotationDeclaration getQualifierDeclaration(IBean bean, String qualifierTypeName) { IAnnotationDeclaration declaration = getQualifiedStereotypeDeclaration(bean, qualifierTypeName); if(declaration == null) { declaration = getQualifiedSpecializesDeclaration(bean, qualifierTypeName); } return declaration; } /** * Returns the @Specializes declaration of the bean if the specialized bean declares the given qualifier. * * @param bean * @param qualifierTypeName * @return */ public static IAnnotationDeclaration getQualifiedSpecializesDeclaration(IBean bean, String qualifierTypeName) { IBean specializedBean = bean.getSpecializedBean(); return specializedBean!=null?getQualifierDeclaration(specializedBean, qualifierTypeName):null; } /** * Return the stereotype declaration which declares the given qualifier. * * @param stereotyped * @return */ public static IAnnotationDeclaration getQualifiedStereotypeDeclaration(IStereotyped stereotyped, String qualifierTypeName) { IAnnotationDeclaration qualifierDeclaration = stereotyped.getAnnotation(qualifierTypeName); if (qualifierDeclaration != null) { return qualifierDeclaration; } Collection<IStereotypeDeclaration> stereotypeDeclarations = stereotyped.getStereotypeDeclarations(); for (IStereotypeDeclaration declaration : stereotypeDeclarations) { if (getQualifiedStereotypeDeclaration(declaration.getStereotype(), qualifierTypeName) != null) { return declaration; } } return null; } /** * Return the stereotype declaration which declares @Named. * * @param stereotyped * @return */ public static IAnnotationDeclaration getNamedStereotypeDeclaration(IStereotyped stereotyped) { return getQualifiedStereotypeDeclaration(stereotyped, CDIConstants.NAMED_QUALIFIER_TYPE_NAME); } /** * Returns all found annotations for parameters of the method. * * @param method * @param annotationTypeName * @return */ public static Collection<ITextSourceReference> getAnnotationPossitions(IBeanMethod method, String annotationTypeName) { List<IParameter> params = method.getParameters(); Collection<ITextSourceReference> declarations = new HashSet<ITextSourceReference>(); for (IParameter param : params) { ITextSourceReference declaration = param.getAnnotationPosition(annotationTypeName); if (declaration != null) { declarations.add(declaration); } } return declarations; } /** * Returns true if the class bean is a session bean. * * @param bean * @return */ public static IAnnotationDeclaration getSessionDeclaration(IClassBean bean) { IAnnotationDeclaration declaration = bean.getAnnotation(CDIConstants.STATEFUL_ANNOTATION_TYPE_NAME); if(declaration!=null) { return declaration; } declaration = bean.getAnnotation(CDIConstants.STATELESS_ANNOTATION_TYPE_NAME); if(declaration!=null) { return declaration; } declaration = bean.getAnnotation(CDIConstants.SINGLETON_ANNOTATION_TYPE_NAME); return declaration; } /** * Returns true if the class bean is a session bean. * * @param bean * @return */ public static boolean isSessionBean(IBean bean) { return bean instanceof ISessionBean || (bean instanceof IClassBean && (bean.getAnnotation(CDIConstants.STATEFUL_ANNOTATION_TYPE_NAME)!=null || bean.getAnnotation(CDIConstants.STATELESS_ANNOTATION_TYPE_NAME)!=null || bean.getAnnotation(CDIConstants.SINGLETON_ANNOTATION_TYPE_NAME)!=null)); } /** * Returns true if the class bean is a decorator. * * @param bean * @return */ public static boolean isDecorator(IBean bean) { return bean instanceof IDecorator || (bean instanceof IClassBean && bean.getAnnotation(CDIConstants.DECORATOR_STEREOTYPE_TYPE_NAME)!=null); } /** * Returns true if the class bean is an interceptor. * * @param bean * @return */ public static boolean isInterceptor(IBean bean) { return bean instanceof IInterceptor || (bean instanceof IClassBean && bean.getAnnotation(CDIConstants.INTERCEPTOR_ANNOTATION_TYPE_NAME)!=null); } /** * Returns false if the method is a non-static method of the session bean class, and the method is not a business method of the session bean. * * @param bean * @param method * @return */ public static boolean isBusinessOrStaticMethod(ISessionBean bean, IBeanMethod method) { return getBusinessMethodDeclaration(bean, method)!=null; } /** * Returns the set of interfaces annotated @Local for the session bean. * Returns an empty set if there is no such interfaces or if the bean class (or any supper class) annotated @LocalBean. * * @param bean * @return */ public static Set<IType> getLocalInterfaces(ISessionBean bean) { Set<IType> sourceTypes = new HashSet<IType>(); try { for (IParametedType type : bean.getLegalTypes()) { IType sourceType = type.getType(); if (sourceType == null) { continue; } // Check if the class annotated @LocalBean IAnnotation[] annotations = sourceType.getAnnotations(); for (IAnnotation annotation : annotations) { if(CDIConstants.LOCAL_BEAN_ANNOTATION_TYPE_NAME.equals(annotation.getElementName()) || "LocalBean".equals(annotation.getElementName())) { return Collections.emptySet(); } } if(sourceType.isInterface()) { IAnnotation annotation = sourceType.getAnnotation(CDIConstants.LOCAL_ANNOTATION_TYPE_NAME); if (!annotation.exists()) { annotation = sourceType.getAnnotation("Local"); //$NON-NLS-N1 } if (annotation.exists() && CDIConstants.LOCAL_ANNOTATION_TYPE_NAME.equals(EclipseJavaUtil.resolveType(sourceType, "Local"))) { //$NON-NLS-N1 sourceTypes.add(sourceType); } } } } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return sourceTypes; } /** * Returns IMethod of @Local interface which is implemented by given business method if such an interface is defined. * If such an interface is not define then return then check if the method is static or public, not final and doesn't start with "ejb". * If so then return this method, otherwise return null. * * @param bean * @param method * @return */ public static IMethod getBusinessMethodDeclaration(ISessionBean bean, IBeanMethod method) { try { int flags = method.getMethod().getFlags(); if(Flags.isStatic(flags)) { return method.getMethod(); } else if (!Flags.isFinal(flags) && Flags.isPublic(flags)) { if(bean.getAnnotation(CDIConstants.SINGLETON_ANNOTATION_TYPE_NAME)!=null) { return method.getMethod(); } Set<IType> sourceTypes = getLocalInterfaces(bean); if(sourceTypes.isEmpty()) { return method.getMethod(); } for (IType sourceType : sourceTypes) { IMethod[] methods = sourceType.getMethods(); for (IMethod iMethod : methods) { if (method.getMethod().isSimilar(iMethod)) { return iMethod; } } } return null; } } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return null; } /** * Finds the method which is overridden by the given method. Or null if this method overrides nothing. * * @param method * @return */ public static IMethod getOverridingMethodDeclaration(IBeanMethod method) { IClassBean bean = method.getClassBean(); Map<IType, IMethod> foundMethods = new HashMap<IType, IMethod>(); try { if (Flags.isStatic(method.getMethod().getFlags())) { return null; } for (IParametedType type : bean.getLegalTypes()) { IType sourceType = type.getType(); if (sourceType == null || sourceType.isInterface()) { continue; } IMethod[] methods = sourceType.getMethods(); for (IMethod iMethod : methods) { if (method.getMethod().isSimilar(iMethod)) { foundMethods.put(iMethod.getDeclaringType(), iMethod); } } } if(foundMethods.size()==1) { return foundMethods.values().iterator().next(); } else if(foundMethods.size()>1) { IType type = bean.getBeanClass(); IType superClass = getSuperClass(type); while(superClass!=null) { IMethod m = foundMethods.get(superClass); if(m!=null) { return m; } superClass = getSuperClass(superClass); } } } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return null; } /** * Finds the method which is overridden by the given method. Or null if this method overrides nothing. * * @param method * @return */ public static IMethod getDirectOverridingMethodDeclaration(IBeanMethod method) { IClassBean bean = method.getClassBean(); try { if (Flags.isStatic(method.getMethod().getFlags())) { return null; } IType type = bean.getBeanClass(); IType superClass = getSuperClass(type); if(superClass!=null) { IMethod[] methods = superClass.getMethods(); for (IMethod iMethod : methods) { if (method.getMethod().isSimilar(iMethod)) { return iMethod; } } } } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return null; } /** * Returns all the injection point parameters of the bean class. * * @param bean * @return */ public static Collection<IInjectionPointParameter> getInjectionPointParameters(IClassBean bean) { Collection<IInjectionPoint> points = bean.getInjectionPoints(); Collection<IInjectionPointParameter> params = new ArrayList<IInjectionPointParameter>(); for (IInjectionPoint injection : points) { if(injection instanceof IInjectionPointParameter) { params.add((IInjectionPointParameter)injection); } } return params; } /** * Returns true if the method is generic * * @param method * @return */ public static boolean isMethodGeneric(IBeanMethod method) { try { return method.getMethod().getTypeParameters().length>0; } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return false; } /** * Returns true if the method is static * * @param method * @return */ public static boolean isMethodStatic(IBeanMethod method) { try { return Flags.isStatic(method.getMethod().getFlags()); } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return false; } /** * Returns true if the method is abstract * * @param method * @return */ public static boolean isMethodAbstract(IBeanMethod method) { try { return Flags.isAbstract(method.getMethod().getFlags()); } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return false; } /** * Checks if the bean member has a type variable as a type. * If the bean member is a field then checks its type. * If the bean member is a parameter of a method then checks its type. * If the bean member is a method then checks its return type. * * @param member * @param checkGenericMethod if true then checks if this member use a type variable which is declared in the generic method (in case of the member is a method). * @return */ public static boolean isTypeVariable(IBeanMember member, boolean checkGenericMethod) { try { String[] typeVariableSegnatures = member.getClassBean().getBeanClass().getTypeParameterSignatures(); List<String> variables = new ArrayList<String>(); for (String variableSig : typeVariableSegnatures) { variables.add(Signature.getTypeVariable(variableSig)); } if(checkGenericMethod) { ITypeParameter[] typeParams = null; if(member instanceof IParameter) { typeParams = ((IParameter)member).getBeanMethod().getMethod().getTypeParameters(); } if(member instanceof IBeanMethod) { typeParams = ((IBeanMethod)member).getMethod().getTypeParameters(); } if(typeParams!=null) { for (ITypeParameter param : typeParams) { variables.add(param.getElementName()); } } } String signature = null; if(member instanceof IBeanField) { signature = ((IBeanField)member).getField().getTypeSignature(); } else if(member instanceof IParameter) { if(((IParameter)member).getType()==null) { return false; } signature = ((IParameter)member).getType().getSignature(); } else if(member instanceof IBeanMethod) { signature = ((IBeanMethod)member).getMethod().getReturnType(); } boolean checkArrayType = CDIVersion.CDI_1_2.equals(member.getCDIProject().getVersion()); return isTypeVariable(variables, signature, checkArrayType); } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return false; } private static boolean isTypeVariable(List<String> typeVariables, String signature, boolean checkArrayType) { if(signature==null) { return false; } String typeString = Signature.toString(signature); for (String variableName : typeVariables) { if(typeString.equals(variableName) || (checkArrayType && typeString.startsWith(variableName + "["))) { return true; } } return false; } private static IType getSuperClass(IType type) throws JavaModelException { String superclassName = type.getSuperclassName(); if(superclassName!=null) { String fullySuperclassName = EclipseJavaUtil.resolveType(type, superclassName); if(fullySuperclassName!=null&&!fullySuperclassName.equals("java.lang.Object")) { //$NON-NLS-1$ if(fullySuperclassName.equals(type.getFullyQualifiedName())) { return null; } IType superType = type.getJavaProject().findType(fullySuperclassName); return superType; } } return null; } /** * Returns true if the member annotated @NonBinding. * * @param sourceType the type where the member is declared * @param member * @return */ public static boolean hasNonBindingAnnotationDeclaration(IType sourceType, IAnnotatable member) { return hasAnnotationDeclaration(sourceType, member, CDIConstants.NON_BINDING_ANNOTATION_TYPE_NAME); } /** * Returns true if the member has the given annotation. * * @param sourceType the type where the member is declared * @param member * @param annotationTypeName * @return */ public static boolean hasAnnotationDeclaration(IType sourceType, IAnnotatable member, String annotationTypeName) { try { IAnnotation[] annotations = member.getAnnotations(); String simpleAnnotationTypeName = annotationTypeName; int lastDot = annotationTypeName.lastIndexOf('.'); if(lastDot>-1) { simpleAnnotationTypeName = simpleAnnotationTypeName.substring(lastDot + 1); } for (IAnnotation annotation : annotations) { if(annotationTypeName.equals(annotation.getElementName())) { return true; } if(simpleAnnotationTypeName.equals(annotation.getElementName())) { String fullAnnotationclassName = EclipseJavaUtil.resolveType(sourceType, simpleAnnotationTypeName); if(fullAnnotationclassName!=null) { IType annotationType = sourceType.getJavaProject().findType(fullAnnotationclassName); if(annotationType!=null && annotationType.getFullyQualifiedName().equals(annotationTypeName)) { return true; } } } } } catch (JavaModelException e) { CDICorePlugin.getDefault().logError(e); } return false; } /** * Converts ISourceRange to ITextSourceReference * * @param range * @return */ public static ITextSourceReference convertToSourceReference(final ISourceRange range, final IResource resource, final IMember javaElement) { if(javaElement == null || javaElement.getResource() == null || !javaElement.getResource().equals(resource)) { return new ITextSourceReference() { public int getStartPosition() { return range.getOffset(); } public int getLength() { return range.getLength(); } public IResource getResource() { return resource; } }; } else { return new IJavaSourceReference() { public IMember getSourceMember() { return javaElement; } public IJavaElement getSourceElement() { return javaElement; } public int getStartPosition() { return range.getOffset(); } public IResource getResource() { return resource; } public int getLength() { return range.getLength(); } }; } } /** * Converts ITypeDeclaration reference to IJavaSourceReference if * 1) javaElement is not null, * 2) reference and javaElement are declared in the same resource * * @param reference * @param javaElement * @return */ public static ITextSourceReference convertToJavaSourceReference(final ITextSourceReference reference, final IMember javaElement) { if(reference instanceof IJavaSourceReference || javaElement == null || (reference.getResource() != null && !(reference.getResource().equals(javaElement.getResource())))) { return reference; } return new IJavaSourceReference() { public IMember getSourceMember() { return javaElement; } public IJavaElement getSourceElement() { return javaElement; } public int getStartPosition() { return reference.getStartPosition(); } public IResource getResource() { return reference.getResource(); } public int getLength() { return reference.getLength(); } }; } /** * Returns true if the injection point declares @Default qualifier or doesn't declare any qualifier at all. * * @param point * @return */ public static boolean containsDefaultQualifier(IInjectionPoint point) { Collection<IQualifierDeclaration> declarations = point.getQualifierDeclarations(); if(declarations.isEmpty()) { return true; } for (IQualifierDeclaration declaration : declarations) { if(CDIConstants.DEFAULT_QUALIFIER_TYPE_NAME.equals(declaration.getQualifier().getSourceType().getFullyQualifiedName())) { return true; } } return false; } /** * Build a CDI model for the project if it hasn't built yet and show a Progress dialog. * * @param project * @return the CDI nature for the project */ public static CDICoreNature getCDINatureWithProgress(final IProject project){ final CDICoreNature cdiNature = CDICorePlugin.getCDI(project, false); if(cdiNature == null) { return null; } boolean resolved = cdiNature.isStorageResolved(); if(resolved) { for (CDICoreNature p: cdiNature.getCDIProjects(true)) { if(!p.isStorageResolved()) { resolved = false; break; } } } if(!resolved){ if (Display.getCurrent() != null) { try{ PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress(){ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask(CDICoreMessages.CDI_UTIL_BUILD_CDI_MODEL, 10); monitor.worked(3); cdiNature.resolve(); Set<CDICoreNature> ps = cdiNature.getCDIProjects(true); Iterator<CDICoreNature> it = ps.iterator(); while(it.hasNext()) { CDICoreNature n = it.next(); if(n.isStorageResolved()) it.remove(); } if(ps.isEmpty()) { monitor.worked(7); } else { int delta = (ps.size() == 1) ? 7 : ps.size() == 2 ? 3 : ps.size() == 3 ? 2 : 1; for (CDICoreNature p: ps) { p.resolve(); monitor.worked(delta); } } } }); }catch(InterruptedException ie){ CDICorePlugin.getDefault().logError(ie); }catch(InvocationTargetException ite){ CDICorePlugin.getDefault().logError(ite); } } else { cdiNature.resolve(); } } return cdiNature; } public static Collection<IInterceptorBinding> getAllInterceptorBindings(IInterceptorBinded binded) { Collection<IInterceptorBinding> result = new ArrayList<IInterceptorBinding>(); for (IInterceptorBindingDeclaration d: collectAdditionalInterceptorBindingDeclaratios(binded, new HashSet<IInterceptorBindingDeclaration>())) { IInterceptorBinding b = d.getInterceptorBinding(); if(b != null) result.add(b); } return result; } /** * Collect all the interceptor binding declarations from the bean class or method including all the inherited bindings. * @param binded bean class or method * * @return */ public static Collection<IInterceptorBindingDeclaration> getAllInterceptorBindingDeclaratios(IInterceptorBinded binded) { return collectAdditionalInterceptorBindingDeclaratios(binded, new HashSet<IInterceptorBindingDeclaration>()); } private static Collection<IInterceptorBindingDeclaration> collectAdditionalInterceptorBindingDeclaratios(IInterceptorBinded binded, Set<IInterceptorBindingDeclaration> result) { for (IInterceptorBindingDeclaration declaration : binded.getInterceptorBindingDeclarations(true)) { if(!result.contains(declaration)) { result.add(declaration); IInterceptorBinding binding = declaration.getInterceptorBinding(); if(binding != null) { collectAdditionalInterceptorBindingDeclaratios(binding, result); } if(binding instanceof IStereotyped) { collectAdditionalInterceptorBindingDeclaratiosFromStereotyps((IStereotyped)binding, result); } } } if(binded instanceof IStereotyped) { collectAdditionalInterceptorBindingDeclaratiosFromStereotyps((IStereotyped)binded, result); } return result; } private static Set<IInterceptorBindingDeclaration> collectAdditionalInterceptorBindingDeclaratiosFromStereotyps(IStereotyped stereotyped, Set<IInterceptorBindingDeclaration> result) { Set<IStereotypeDeclaration> stereotypeDeclarations = collectInheritedStereotypDeclarations(stereotyped, new HashSet<IStereotypeDeclaration>()); if(stereotyped instanceof ClassBean) { stereotypeDeclarations.addAll(((ClassBean)stereotyped).getInheritedStereotypDeclarations()); } for (IStereotypeDeclaration stereotypeDeclaration : stereotypeDeclarations) { collectAdditionalInterceptorBindingDeclaratios(stereotypeDeclaration.getStereotype(), result); } return result; } private static Set<IStereotypeDeclaration> collectInheritedStereotypDeclarations(IStereotyped stereotyped, Set<IStereotypeDeclaration> result) { for (IStereotypeDeclaration declaration : stereotyped.getStereotypeDeclarations()) { if(!result.contains(declaration)) { result.add(declaration); collectInheritedStereotypDeclarations(declaration.getStereotype(), result); } } return result; } /** * Check all the values of @Target declaration of the annotation. * Returns null if there is no @Target at all. Returns true if any of the variants presents. * For example this method will return true for {{TYPE, FIELD, METHOD}, {TYPE}} for @Target(TYPE) * @param annotationType * @param variants * @return * @throws JavaModelException */ public static Boolean checkTargetAnnotation(IAnnotationType annotationType, String[][] variants) throws JavaModelException { IAnnotationDeclaration target = annotationType.getAnnotationDeclaration(CDIConstants.TARGET_ANNOTATION_TYPE_NAME); return target == null?null:checkTargetAnnotation(target, variants); } /** * Check all the values of @Target declaration * Returns true if any of the variants presents. * For example this method will return true for {{TYPE, FIELD, METHOD}, {TYPE}} for @Target(TYPE) * @param target * @param variants * @return * @throws JavaModelException */ public static boolean checkTargetAnnotation(IAnnotationDeclaration target, String[][] variants) throws JavaModelException { Set<String> vs = getTargetAnnotationValues(target); boolean ok = false; for (int i = 0; i < variants.length; i++) { if(vs.size() == variants[i].length) { boolean ok2 = true; String[] values = variants[i]; for (String s: values) { if(!vs.contains(s)) { ok2 = false; break; } } if(ok2) { ok = true; break; } } } return ok; } /** * Returns values of @Tagret declaration of the annotation type. * @param target * @return * @throws JavaModelException */ public static Set<String> getTargetAnnotationValues(IAnnotationDeclaration target) throws JavaModelException { Set<String> result = new HashSet<String>(); Object o = target.getMemberValue(null); if(o instanceof Object[]) { Object[] os = (Object[])o; for (Object q: os) { String s = q.toString(); int i = s.lastIndexOf('.'); if(i >= 0 && AnnotationValidationDelegate.ELEMENT_TYPE_TYPE_NAME.equals(s.substring(0, i))) { s = s.substring(i + 1); result.add(s); } } } else if(o != null) { String s = o.toString(); int i = s.lastIndexOf('.'); if(i >= 0 && AnnotationValidationDelegate.ELEMENT_TYPE_TYPE_NAME.equals(s.substring(0, i))) { s = s.substring(i + 1); result.add(s); } } return result; } /** * returns set of IBean elements filtered in order to have unique IJavaElement * @param cdiProject * @param attemptToResolveAmbiguousDependency * @param injectionPoint * @return */ public static Collection<IBean> getFilteredBeans(ICDIProject cdiProject, boolean attemptToResolveAmbiguousDependency, IInjectionPoint injectionPoint){ HashSet<IJavaElement> elements = new HashSet<IJavaElement>(); Collection<IBean> result = new ArrayList<IBean>(); for(IBean bean : cdiProject.getBeans(attemptToResolveAmbiguousDependency, injectionPoint)){ IJavaElement element = getJavaElement(bean); if(!elements.contains(element)){ elements.add(element); result.add(bean); } } return result; } /** * returns set of IBean elements filtered in order to have unique IJavaElement * @param cdiProject * @param path * @return */ public static Collection<IBean> getFilteredBeans(ICDIProject cdiProject, IPath path){ HashSet<IJavaElement> elements = new HashSet<IJavaElement>(); Collection<IBean> result = new ArrayList<IBean>(); for(IBean bean : cdiProject.getBeans(path)){ IJavaElement element = getJavaElement(bean); if(!elements.contains(element)){ elements.add(element); result.add(bean); } } return result; } public static List<IBean> getSortedBeans(ICDIProject cdiProject, boolean attemptToResolveAmbiguousDependency, IInjectionPoint injectionPoint){ Collection<IBean> beans = getFilteredBeans(cdiProject, attemptToResolveAmbiguousDependency, injectionPoint); return sortBeans(beans); } public static List<IBean> getSortedBeans(ICDIProject cdiProject, IPath path){ Collection<IBean> beans = getFilteredBeans(cdiProject, path); return sortBeans(beans); } public static IJavaElement getJavaElement(ICDIElement cdiElement){ if(cdiElement instanceof IJavaReference) return ((IJavaReference)cdiElement).getSourceMember(); if(cdiElement instanceof IBean) return ((IBean)cdiElement).getBeanClass(); else if(cdiElement instanceof IInjectionPointParameter){ IMethod method = ((IInjectionPointParameter)cdiElement).getBeanMethod().getMethod(); return getParameter(method, ((IInjectionPointParameter)cdiElement).getName()); } return null; } public static ILocalVariable getParameter(IMethod method, String name){ try{ for(ILocalVariable param : method.getParameters()){ if(param.getElementName().equals(name)) return param; } }catch(JavaModelException ex){ CDICorePlugin.getDefault().logError(ex); } return null; } public static ICDIProject getCDIProject(IFile file, CDICoreNature cdiNature, boolean asYouType){ ICDIProject cdiProject = cdiNature.getDelegate(); if(asYouType && file != null){ return new CDIProjectAsYouType(cdiProject, file); }else{ return cdiProject; } } /** * Returns null or CDI version see * - CDIVersion.CDI_1_0; * - CDIVersion.CDI_1_1; * Implemented algorithm requests for types in the project classpath: * - If CDIConstants.VETOED_ANNOTATION_TYPE_NAME type is available, * version is set to CDIVersion.CDI_1_1, * - else if CDIConstants.QUALIFIER_ANNOTATION_TYPE_NAME is available, * version is set to CDIVersion.CDI_1_0, * - otherwise version is undefined. * In future, the algorithm may be subjected to changes. * * @param project * @return */ public static CDIVersion getCDIVersion(IProject project) { IJavaProject jp = EclipseResourceUtil.getJavaProject(project); if(jp == null) return CDIVersion.CDI_UNKNOWN; try { if(EclipseJavaUtil.findType(jp, CDIConstants.VETOED_ANNOTATION_TYPE_NAME) != null) { IFacetedProject facetedProject = ProjectFacetsManager.create(project); if(facetedProject != null) { IProjectFacetVersion v = facetedProject.getProjectFacetVersion(CDIFacetInstallDelegate.CDI_FACET); if(v != null) { if(v.equals(CDIFacetInstallDelegate.CDI_11)) { return CDIVersion.CDI_1_1; } } } String v = getCDIImplementationVersion(project); if(v != null && v.startsWith("1.1")) { return CDIVersion.CDI_1_1; } return CDIVersion.CDI_1_2; } else if(EclipseJavaUtil.findType(jp, CDIConstants.QUALIFIER_ANNOTATION_TYPE_NAME) != null) { return CDIVersion.CDI_1_0; } } catch (CoreException e) { CDICorePlugin.getDefault().logError(e); } return CDIVersion.CDI_UNKNOWN; } /** * Returns implementation version of 'jsf-api.jar' if it is included into class path; * returns null if 'cdi-api*.jar' is not found in the class path. * * @param project * @return * @throws CoreException */ public static String getCDIImplementationVersion(IProject project) throws CoreException { try { InputStream content = readManifest(project); if(content != null) { Properties p = new Properties(); p.load(content); return p.getProperty("Specification-Version"); } } catch (IOException e) { throw new CoreException(new Status(IStatus.ERROR, CDICorePlugin.PLUGIN_ID, "Failed to read manifest in cdi-api.jar in project " + project.getName(), e)); } return null; } /** * Returns input stream with content of META-INF/MANIFEST.MF of selected jar file; * returns null if jar file is not found in the class path. * * @param project * @param jarName * @return * @throws CoreException * @throws IOException */ public static InputStream readManifest(IProject project) throws CoreException, IOException { IPackageFragmentRoot library = findLibrary(project); if(library instanceof JarPackageFragmentRoot) { ZipFile zip = ((JarPackageFragmentRoot)library).getJar(); ZipEntry entry = zip.getEntry("META-INF/MANIFEST.MF"); if(entry != null) { InputStream is = zip.getInputStream(entry); if(is != null) { return is; } } } return null; } /** * Returns root object of Java Model for selected jar file; * returns null if jar file is not found in the class path. * * * @param project * @param jarName * @return * @throws JavaModelException */ public static IPackageFragmentRoot findLibrary(IProject project) throws JavaModelException { if(project == null || !project.isAccessible()) { return null; } IJavaProject javaProject = JavaCore.create(project); if(javaProject == null || !javaProject.exists()) { return null; } for (IPackageFragmentRoot fragmentRoot : javaProject.getAllPackageFragmentRoots()) { IPath resource = fragmentRoot.getPath(); if(resource != null && resource.lastSegment().startsWith("cdi-api")) { return fragmentRoot; } } return null; } }