/******************************************************************************* * Copyright (c) 2008 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.seam.core; import java.io.File; import java.io.IOException; import java.util.Set; import java.util.StringTokenizer; import java.util.jar.Attributes; import java.util.jar.JarFile; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jst.j2ee.internal.project.J2EEProjectUtilities; import org.eclipse.jst.j2ee.project.EarUtilities; import org.eclipse.jst.j2ee.project.WebUtilities; import org.eclipse.wst.common.componentcore.ComponentCore; import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; import org.eclipse.wst.common.componentcore.resources.IVirtualReference; import org.jboss.tools.common.model.util.EclipseResourceUtil; import org.jboss.tools.common.text.ITextSourceReference; 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.jboss.tools.seam.core.project.facet.SeamRuntime; import org.jboss.tools.seam.internal.core.AbstractContextVariable; import org.jboss.tools.seam.internal.core.SeamComponentDeclaration; /** * @author Alexey Kazakov */ public class SeamUtil { public static void enableSeamSupport(IProject project) { if(project==null) { return; } try { WebModelPlugin.addNatureToProjectWithValidationSupport(project, KbBuilder.BUILDER_ID, IKbProject.NATURE_ID); WebModelPlugin.addNatureToProjectWithValidationSupport(project, SeamCoreBuilder.BUILDER_ID, ISeamProject.NATURE_ID); } catch (CoreException e) { SeamCorePlugin.getPluginLog().logError(e); } } /** * Returns Seam version from <Seam Runtime>/lib/jboss-seam.jar/META-INF/MANIFEST.MF * from Seam Runtime which is set for the project. * @param project * @return */ public static String getSeamVersionFromManifest(IProject project) { ISeamProject seamProject = SeamCorePlugin.getSeamProject(project, false); if(seamProject == null) { SeamCorePlugin.getPluginLog().logWarning("Can't find Seam Project for " + project.getName()); return null; } return getSeamVersionFromManifest(seamProject); } /** * Returns Seam version from <Seam Runtime>/lib/jboss-seam.jar/META-INF/MANIFEST.MF * from Seam Runtime which is set for the project. * @param project * @return */ public static String getSeamVersionFromManifest(ISeamProject project) { SeamRuntime runtime = project.getRuntime(); if(runtime==null) { SeamCorePlugin.getPluginLog().logWarning("Seam Runtime for " + project.getProject().getName() + " is null."); return null; } return getSeamVersionFromManifest(runtime); } private final static String SEAM_JAR_NAME = "jboss-seam.jar"; private final static String SEAM_VERSION_ATTRIBUTE_NAME = "Seam-Version"; private final static String IMPLEMENTATION_VERSION_ATTRIBUTE_NAME = "Implementation-Version"; /** * Returns Seam version from <Seam Runtime>/lib/jboss-seam.jar/META-INF/MANIFEST.MF * from Seam Runtime. * @param runtime * @return */ public static String getSeamVersionFromManifest(SeamRuntime runtime) { return getSeamVersionFromManifest(runtime.getHomeDir()); } /** * Returns trimmed Seam version from <SeamHome>/lib/jboss-seam.jar/META-INF/MANIFEST.MF * @param depth - number of segments of Seam version string. * @param seamHome * @return */ public static String getSeamVersionFromManifest(String seamHome, int depth) { return trimSeamVersion(getSeamVersionFromManifest(seamHome), depth); } /** * Returns true if two versions are matched. * For example "2.1.1.GA" matches "2.1" * @param version1 * @param version2 * @return */ public static boolean areSeamVersionsMatched(String version1, String version2) { String longerVersion = version1.length()>version2.length()?version1:version2; String shorterVersion = longerVersion==version1?version2:version1; StringTokenizer sSt = new StringTokenizer(shorterVersion, ".", false); StringTokenizer lSt = new StringTokenizer(longerVersion, ".", false); while (sSt.hasMoreElements() && lSt.hasMoreElements()) { if(!sSt.nextToken().equals(lSt.nextToken())) { return false; } } return true; } /** * Returns Seam version from <SeamHome>/lib/jboss-seam.jar/META-INF/MANIFEST.MF * @param seamHome * @return */ public static String getSeamVersionFromManifest(String seamHome) { File jarFile = new File(seamHome, "lib/" + SEAM_JAR_NAME); if(!jarFile.isFile()) { jarFile = new File(seamHome, SEAM_JAR_NAME); if(!jarFile.isFile()) { // Don't log this. See https://jira.jboss.org/browse/JBIDE-7038 // SeamCorePlugin.getPluginLog().logWarning(jarFile.getAbsolutePath() + " as well as " + new File(seamHome, "lib/" + seamJarName).getAbsolutePath() + " don't exist."); return null; } } try { JarFile jar = new JarFile(jarFile); Attributes attributes = jar.getManifest().getMainAttributes(); String version = attributes.getValue(SEAM_VERSION_ATTRIBUTE_NAME); if(version==null) { SeamCorePlugin.getPluginLog().logWarning("Can't get Seam-Version from " + jar.getName() + " MANIFEST."); version = attributes.getValue(IMPLEMENTATION_VERSION_ATTRIBUTE_NAME); if(version==null) { SeamCorePlugin.getPluginLog().logWarning("Can't get Implementation-Version from " + jar.getName() + " MANIFEST."); } } return version; } catch (IOException e) { SeamCorePlugin.getPluginLog().logError(e); return null; } } /** * Trims Seam version string. * For example "2.1.0.SP1" will be trimmed to 2.1 (depth=2); "2.1.1.GA" -> "2.1.1" (depth=3); "2.0.0.SP1" -> "2.0.0.SP1" (depth<1) * @param fullSeamVersion * @param depth - number of segments of Seam version string. * @return */ public static String trimSeamVersion(String fullSeamVersion, int depth) { if(fullSeamVersion==null || depth<1) { return fullSeamVersion; } StringBuffer version = new StringBuffer(); StringTokenizer st = new StringTokenizer(fullSeamVersion, ".", false); while (st.hasMoreElements() && depth>0) { version.append(st.nextToken()); depth--; if(st.hasMoreElements() && depth>0) { version.append('.'); } } return version.toString(); } /** * Converts seam project name to string which suitable for package names * @param projectNamePackage * @return */ public static String getSeamPackageName(String projectName){ if(projectName == null) return null; String packageName = projectName.toLowerCase(); if(packageName.indexOf(" ") >= 0) packageName = packageName.replace(" ", ""); if(packageName.indexOf("-") >= 0) packageName = packageName.replace("-", ""); if(packageName.indexOf("+") >= 0) packageName = packageName.replace("+", ""); if(packageName.indexOf("_") >= 0) packageName = packageName.replace("_", ""); while(packageName.indexOf("..") >= 0){ packageName = packageName.replace("..", "."); } return packageName; } /** * Finds referencing Seam war project * @param project * @return */ public static ISeamProject findReferencingSeamWarProjectForProject(IProject project) { return findReferencingSeamWarProjectForProject(project, true); } /** * Finds referencing Seam war project * @param project * @param searchInEARs if "true" then try to search web projects in parent EAR project. * @return */ public static ISeamProject findReferencingSeamWarProjectForProject(IProject project, boolean searchInEARs) { IProject[] referencing = J2EEProjectUtilities.getReferencingWebProjects(project); for (int i = 0; i < referencing.length; i++) { ISeamProject seamProject = SeamCorePlugin.getSeamProject(referencing[i], false); if(seamProject!=null) { return seamProject; } } if(searchInEARs) { referencing = EarUtilities.getReferencingEARProjects(project); for (int i = 0; i < referencing.length; i++) { ISeamProject seamProject = findReferencingSeamWarProjectForProject(referencing[i], false); if(seamProject!=null) { return seamProject; } } IVirtualComponent comp = ComponentCore.createComponent(project); IVirtualReference[] refComponents = null; if(comp!=null) { refComponents = comp.getReferences(); for (IVirtualReference virtualReference : refComponents) { IVirtualComponent component = virtualReference.getReferencedComponent(); if(component!=null && !component.isBinary() && WebUtilities.isDynamicWebComponent(component)) { ISeamProject seamProject = SeamCorePlugin.getSeamProject(component.getProject(), false); if(seamProject!=null) { return seamProject; } } } } } return null; } /** * @param element * @return Resource of seam model element */ public static IResource getComponentResourceWithName(ISeamElement element) { if(element instanceof ISeamComponent) { Set<ISeamComponentDeclaration> declarations = ((ISeamComponent)element).getAllDeclarations(); for (Object o : declarations) { SeamComponentDeclaration d = (SeamComponentDeclaration)o; ITextSourceReference location = d.getLocationFor(SeamComponentDeclaration.PATH_OF_NAME); if(!isEmptyLocation(location)) { return d.getResource(); } } } return element.getResource(); } /** * @param seam model element * @return location of name attribute */ public static ITextSourceReference getLocationOfName(ISeamElement element) { return getLocationOfAttribute(element, SeamComponentDeclaration.PATH_OF_NAME); } /** * @param seam model element * @return location of attribute */ public static ITextSourceReference getLocationOfAttribute(ISeamElement element, String attributeName) { ITextSourceReference location = null; if(element instanceof AbstractContextVariable) { location = ((AbstractContextVariable)element).getLocationFor(attributeName); } else if(element instanceof ISeamComponent) { Set<ISeamComponentDeclaration> declarations = ((ISeamComponent)element).getAllDeclarations(); for (ISeamComponentDeclaration d : declarations) { location = ((SeamComponentDeclaration)d).getLocationFor(attributeName); if(!isEmptyLocation(location)) { break; } } } else if(element instanceof SeamComponentDeclaration) { location = ((SeamComponentDeclaration)element).getLocationFor(attributeName); } if(isEmptyLocation(location) && element instanceof ITextSourceReference) { location = (ITextSourceReference)element; } return location; } public static boolean isEmptyLocation(ITextSourceReference location) { return (location == null //is dead location, we cannot now change provider to return null //because it may give rise to other errors. //In the future, null should be returned instead of 'dead' location //and correctly processed || location.getStartPosition() == 0 && location.getLength() == 0); } /** * @param resource * @return true if resource is Jar file */ public static boolean isJar(IPath path) { if(path == null) { throw new IllegalArgumentException(SeamCoreMessages.SEAM_VALIDATION_HELPER_RESOURCE_MUST_NOT_BE_NULL); } String ext = path.getFileExtension(); return ext != null && ext.equalsIgnoreCase("jar"); //$NON-NLS-1$ } /** * @param element * @return true if seam element packed in Jar file */ public static boolean isJar(ISeamElement element) { return isJar(element.getSourcePath()); } /** * @param componentXmlFile * @return IType of component for <ComponentName>.component.xml */ public static IType getClassTypeForComponentXml(IFile componentXmlFile, IProject rootProject) { String className = getClassNameForComponentXml(componentXmlFile, rootProject); if(className==null) { return null; } return findType(className, rootProject); } /** * @param type name * @return IType */ public static IType findType(String fullyQualifiedName, IProject rootProject) { try { IJavaProject jp = EclipseResourceUtil.getJavaProject(rootProject); return jp.findType(fullyQualifiedName); } catch (JavaModelException e) { SeamCorePlugin.getDefault().logError(e); return null; } } /** * @param componentXmlFile * @return name of component class for <ComponentName>.component.xml */ public static String getClassNameForComponentXml(IFile componentXmlFile, IProject rootProject) { String fileName = componentXmlFile.getName(); int firstDot = fileName.indexOf('.'); if(firstDot==-1) { return null; } String className = fileName.substring(0, firstDot); try { IJavaProject jp = EclipseResourceUtil.getJavaProject(rootProject); IPackageFragment packageFragment = jp.findPackageFragment(componentXmlFile.getFullPath().removeLastSegments(1)); if(packageFragment==null) { return null; } return packageFragment.getElementName() + "." + className; //$NON-NLS-1$ } catch (JavaModelException e) { SeamCorePlugin.getDefault().logError(e); return null; } } /** * Find a setter or a field for a property. * @param type * @param propertyName * @return IMethod (setter) or IFiled (field) */ public static IMember findProperty(IType type, String propertyName) { if(propertyName == null || propertyName.length()==0) { return null; } try { return findPropertyInHierarchy(type, propertyName); } catch (JavaModelException e) { SeamCorePlugin.getDefault().logError(e); } return null; } public static IMember findPropertyInHierarchy(IType type, String propertyName) throws JavaModelException { String firstLetter = propertyName.substring(0, 1).toUpperCase(); String nameWithoutFirstLetter = propertyName.substring(1); String setterName = "set" + firstLetter + nameWithoutFirstLetter; //$NON-NLS-1$ IMethod[] methods = type.getMethods(); for (int i = 0; i < methods.length; i++) { if(methods[i].getElementName().equals(setterName) && methods[i].getParameterNames().length==1) { return methods[i]; } } IField[] fields = type.getFields(); for (int i = 0; i < fields.length; i++) { if(fields[i].getElementName().equals(propertyName)) { return fields[i]; } } String superclassName = type.getSuperclassName(); if(superclassName!=null) { String[][] packages = type.resolveType(superclassName); if(packages!=null) { for (int i = 0; i < packages.length; i++) { String packageName = packages[i][0]; if(packageName!=null && packageName.length()>0) { packageName = packageName + "."; //$NON-NLS-1$ } else { packageName = ""; //$NON-NLS-1$ } String qName = packageName + packages[i][1]; IType superclass = type.getJavaProject().findType(qName); if(superclass!=null) { IMember property = findPropertyInHierarchy(superclass, propertyName); if(property!=null) { return property; } } } } } return null; } }