/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * 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 *******************************************************************************/ package org.ebayopensource.turmeric.eclipse.utils.plugin; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.PropertyResourceBundle; import java.util.Set; import java.util.logging.Logger; import org.apache.commons.lang.StringUtils; import org.ebayopensource.turmeric.eclipse.utils.collections.ListUtil; import org.ebayopensource.turmeric.eclipse.utils.collections.SetUtil; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; 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.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaConventions; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jst.common.project.facet.JavaFacetUtils; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; /** * The Class JDTUtil. * * @author smathew * * Utility for JDT related functions */ public class JDTUtil { /** * @see org.eclipse.jdt.internal.compiler.impl.CompilerOptions.VERSION_1_4 */ @SuppressWarnings("restriction") private static final String COMPILER_OPTIONS_VERSION_1_4 = "1.4"; /** The Constant DEFAULT_COMPILER_VERSION. */ public static final String DEFAULT_COMPILER_VERSION = "1.6"; /** The Constant DOT. */ public static final String DOT = "."; /** * Pure Wrapper Call. * * @param name the name * @return the i status */ public static IStatus validateIdentifier(String name) { return JavaConventions.validateIdentifier(name, COMPILER_OPTIONS_VERSION_1_4, COMPILER_OPTIONS_VERSION_1_4); } /** * Pure Wrapper Call to * This validates a type name ie Whatever compiler takes. * eg: a. is not valid. * a is valid * * @param typeName the type name * @return the i status */ public static IStatus validateJavaTypeName(String typeName) { return JavaConventions.validateJavaTypeName(typeName, COMPILER_OPTIONS_VERSION_1_4, COMPILER_OPTIONS_VERSION_1_4); } /** * Validate method name. * * @param methodName the method name * @return True if the method name is valid */ public static IStatus validateMethodName(String methodName) { return JavaConventions.validateMethodName(methodName, COMPILER_OPTIONS_VERSION_1_4, COMPILER_OPTIONS_VERSION_1_4); } /** * Validate pacakge name. * * @param packageName the package name * @return the i status */ public static IStatus validatePacakgeName(String packageName) { return JavaConventions.validatePackageName(packageName, COMPILER_OPTIONS_VERSION_1_4, COMPILER_OPTIONS_VERSION_1_4); } /** * Adds the java support to eclipse project. * ie soa nature is added here. * Class Path container related linking etc.. * * @param project the project * @param sourceDirectories the source directories * @param defaultCompilerLevel the default compiler level * @param outputLocation the output location * @param monitor the monitor * @throws CoreException the core exception */ public static void addJavaSupport(IProject project, List<String> sourceDirectories, String defaultCompilerLevel, String outputLocation, IProgressMonitor monitor) throws CoreException { boolean changedClasspath = false; if (addJavaNature(project, monitor)) { changedClasspath = true; } // Configuring the Java Project final IJavaProject javaProject = JavaCore.create(project); final List<IClasspathEntry> classpath = JDTUtil.rawClasspath( javaProject, true); if (outputLocation.equals(javaProject.getOutputLocation()) == false) { final IFolder outputDirClasses = project.getFolder(outputLocation); javaProject.setOutputLocation(outputDirClasses.getFullPath(), monitor); changedClasspath = true; } // Dealing with the case where the root of the project is set to be the // src and bin destinations... bad... bad... for (final Iterator<IClasspathEntry> iterator = classpath.iterator(); iterator .hasNext();) { final IClasspathEntry entry = iterator.next(); if (entry.getEntryKind() != IClasspathEntry.CPE_SOURCE || !entry.getPath().equals( new Path("/" + project.getName()))) continue; iterator.remove(); changedClasspath |= true; } for (final String dir : sourceDirectories) { final IFolder source = project.getFolder(dir); // If the Java project existed previously, checking if directories // already exist in // its classpath. boolean found = false; for (final IClasspathEntry entry : classpath) { if (!entry.getPath().equals(source.getFullPath())) continue; found = true; break; } if (found) continue; changedClasspath |= true; classpath.add(JavaCore.newSourceEntry(source.getFullPath())); } ProgressUtil.progressOneStep(monitor, 10); // Adding the runtime library boolean found = false; for (final IClasspathEntry entry : classpath) { // All JRE Containers should have a prefix of // org.eclipse.jdt.launching.JRE_CONTAINER if (JavaRuntime.newDefaultJREContainerPath().isPrefixOf( entry.getPath()) && JavaRuntime.newDefaultJREContainerPath().equals( entry.getPath())) { found = true; break; } } if (!found) { changedClasspath = true; classpath.add(JavaRuntime.getDefaultJREContainerEntry()); } ProgressUtil.progressOneStep(monitor); // Configuring the classpath of the Java Project if (changedClasspath) { javaProject.setRawClasspath(classpath .toArray(new IClasspathEntry[0]), null); } IProjectFacetVersion projectFacetVersion = JavaFacetUtils.JAVA_60; if (StringUtils.isNotBlank(defaultCompilerLevel)) { try { projectFacetVersion = JavaFacetUtils.compilerLevelToFacet(defaultCompilerLevel); } catch (Exception e) { Logger.getLogger(JDTUtil.class.getName()).throwing(JDTUtil.class.getName(), "addJavaSupport", e); } } JavaFacetUtils.setCompilerLevel(project, projectFacetVersion); } /** * Resolve classpath to ur ls. * * @param bundle The plugin bundle to load jars * @param project The underlying SOA project * @return All jars in the runtime classpath of the provided bundle. * @throws Exception the exception */ public static Set<URL> resolveClasspathToURLs(final Bundle bundle, final IProject project) throws Exception{ final Map<String, URL> result = new LinkedHashMap<String, URL>(); // Object obj = bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH); // for (final String path : StringUtils.split(String.valueOf(obj), ",")) { // if (path.endsWith(".jar")) { // URL url = bundle.getEntry(path); // url = FileLocator.resolve(url); // result.put(new Path(url.getFile()).lastSegment(), url); // } // } //load missing jars from the project's classpath for (final URL url : resolveClasspathToURLs(project)) { final Path path = new Path(url.getFile()); final String fileName = path.lastSegment(); if (StringUtils.equalsIgnoreCase(path.getFileExtension(), "jar")) { if (result.containsKey(fileName) == false) result.put(fileName, url); } else if (result.containsKey(url.getFile()) == false) { result.put(url.getFile(), url); } } return SetUtil.linkedSet(result.values()); } /** * Resolves the projects class path container entries * Explodes the container out and return a Set of URL Path. * * @param project the project * @return the sets the * @throws Exception the exception */ public static Set<URL> resolveClasspathToURLs(final IProject project) throws Exception { return resolveClasspathToURLs(JavaCore.create(project)); } private static Set<URL> resolveClasspathToURLs(final IJavaProject javaProject) throws JavaModelException, IOException { final Set<URL> classpath = SetUtil.linkedSet(); resolveClasspathToURLs(javaProject, classpath, SetUtil .set(new String[0])); return classpath; } private static void resolveClasspathToURLs(final IJavaProject javaProject, final Set<URL> resolvedEntries, final Set<String> visited) throws JavaModelException, IOException { if (javaProject == null || !javaProject.exists()) return; final String projectName = javaProject.getProject().getName(); if (visited.contains(projectName)) return; visited.add(projectName); for (final IClasspathEntry entry : javaProject .getResolvedClasspath(true)) { if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { resolveClasspathToURLs(JavaCore.create(WorkspaceUtil .getProject(entry.getPath())), resolvedEntries, visited); } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { resolvedEntries.add(WorkspaceUtil.getLocation( entry.getPath()).toFile().toURI().toURL()); } else if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { IPath location = entry.getOutputLocation() != null ? entry.getOutputLocation() : javaProject.getOutputLocation(); if (location.toString().startsWith(WorkspaceUtil.PATH_SEPERATOR + projectName)) { //it happens that the path is not absolute location = javaProject.getProject().getFolder(location.removeFirstSegments(1)).getLocation(); } resolvedEntries.add(location.toFile().toURI().toURL()); } } } /** * Adds the natures. * * @param project the project * @param monitor the monitor * @param projectNatures the project natures * @return true, if successful * @throws CoreException the core exception */ public static boolean addNatures(final IProject project, final IProgressMonitor monitor, String... projectNatures) throws CoreException { if (project == null || projectNatures == null || projectNatures.length == 0) return false; List<String> additionalNatureIds = new ArrayList<String>(projectNatures.length); for (String natureId : projectNatures) { if (project.hasNature(natureId) == false) { additionalNatureIds.add(natureId); } } if (additionalNatureIds.isEmpty() == false) { // Adding the natures to the project. final IProjectDescription description = project.getDescription(); final List<String> natureIDs = ListUtil.array(description .getNatureIds()); natureIDs.addAll(additionalNatureIds); description.setNatureIds(natureIDs.toArray(new String[0])); project.setDescription(description, monitor); return true; } return false; } /** * Adds the java nature. * * @param project the project * @param monitor the monitor * @return true, if successful * @throws CoreException the core exception */ public static boolean addJavaNature(final IProject project, final IProgressMonitor monitor) throws CoreException { return addNatures(project, monitor, JavaCore.NATURE_ID); } /** * Raw classpath. * * @param project the project * @param readFromDisk the read from disk * @return the list * @throws JavaModelException the java model exception */ public static List<IClasspathEntry> rawClasspath(final IProject project, final boolean readFromDisk) throws JavaModelException { return rawClasspath(JavaCore.create(project), readFromDisk); } /** * Raw classpath. * * @param project the project * @param readFromDisk the read from disk * @return the list * @throws JavaModelException the java model exception */ public static List<IClasspathEntry> rawClasspath( final IJavaProject project, final boolean readFromDisk) throws JavaModelException { final List<IClasspathEntry> entries = ListUtil.list(); if (project == null || !project.getProject().isAccessible()) return entries; if (!readFromDisk && project.getProject().getFile(".classpath").isAccessible() && project.getProject().getFile(".classpath").isSynchronized( IResource.DEPTH_INFINITE)) ListUtil.add(entries, project.getRawClasspath()); else ListUtil.add(entries, project.readRawClasspath()); return entries; } /** * Checks if is classpath container. * * @param entry the entry * @param path the path * @return true, if is classpath container */ public static boolean isClasspathContainer(final IClasspathEntry entry, final String path) { return entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER && (path.equals(entry.getPath().segment(0))); } /** * Checks if is jRE classpath container. * * @param entry the entry * @return true, if is jRE classpath container */ public static boolean isJREClasspathContainer(final IClasspathEntry entry) { return isClasspathContainer(entry, JavaRuntime.JRE_CONTAINER); } /** * Gets the bundle info. * * @param bundle the bundle * @param needDetail the need detail * @return the bundle info */ public static String getBundleInfo(final Bundle bundle, final boolean needDetail) { final StringBuffer buf = new StringBuffer(); if (bundle != null) { buf.append(bundle.getSymbolicName()); Object versionID = bundle.getHeaders().get(Constants.BUNDLE_VERSION); if (versionID != null) { buf.append(" "); buf.append(versionID.toString()); } if (needDetail) { buf.append("\nManifest Headers:"); for (Enumeration<?> keys = bundle.getHeaders().keys(); keys.hasMoreElements() ;) { Object key = keys.nextElement(); buf.append(key); buf.append(" = "); buf.append(bundle.getHeaders().get(key)); buf.append("\n"); } } } return buf.toString(); } /** * Generate qualified class name using path seperator. * * @param classNameForPkg the class name for pkg * @param pkgPrefix the pkg prefix * @param genClassName the gen class name * @return the string */ public static String generateQualifiedClassNameUsingPathSeperator( String classNameForPkg, String pkgPrefix, String genClassName) { String genPkgName = null; int lastDotPos = classNameForPkg.lastIndexOf(DOT); if (lastDotPos > -1) { genPkgName = classNameForPkg.substring(0, lastDotPos) + WorkspaceUtil.PATH_SEPERATOR + pkgPrefix; } else { genPkgName = pkgPrefix; } genPkgName = StringUtils.replace(genPkgName, DOT, WorkspaceUtil.PATH_SEPERATOR); return genPkgName + WorkspaceUtil.PATH_SEPERATOR + genClassName; } /** * Gets the plugin properties. * * @param bundle the bundle * @param fileName the file name * @return the plugin properties * @throws IOException Signals that an I/O exception has occurred. */ public static PropertyResourceBundle getPluginProperties( final Bundle bundle, String fileName) throws IOException{ PropertyResourceBundle pluginProperties; if (StringUtils.isBlank(fileName)) { final Object object = bundle.getHeaders().get(Constants.BUNDLE_LOCALIZATION); fileName = object != null ? object.toString() + ".properties" : "plugin.properties"; } pluginProperties = new PropertyResourceBundle( FileLocator.openStream(bundle, new Path(fileName),false)); return pluginProperties; } /** * Gets the plugin properties. * * @param bundle the bundle * @return the plugin properties * @throws IOException Signals that an I/O exception has occurred. */ public static PropertyResourceBundle getPluginProperties( final Bundle bundle) throws IOException{ return getPluginProperties(bundle, null); } /** * Gets the source directories. * * @param project the project * @return the source directories */ public static List<IPath> getSourceDirectories(final IProject project) { final IJavaProject jProject = JavaCore.create(project); final List<IPath> srcEntries = new ArrayList<IPath>(); for (final IClasspathEntry entry : jProject.readRawClasspath()) { if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { srcEntries.add(entry.getPath()); } } return srcEntries; } /** * Convert class name to file path. * * @param className the class name * @return the i path */ public static IPath convertClassNameToFilePath(String className) { if (className == null) return null; final IPath path = new Path(StringUtils.replaceChars(className, ".", WorkspaceUtil.PATH_SEPERATOR)); return path.addFileExtension("java"); } }