| /******************************************************************************* |
| * Copyright (c) 2000, 2010 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.ui.wizards.buildpaths; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.swt.widgets.Shell; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.core.resources.ResourcesPlugin; |
| |
| import org.eclipse.jface.dialogs.MessageDialog; |
| |
| import org.eclipse.jdt.core.ClasspathContainerInitializer; |
| import org.eclipse.jdt.core.IClasspathAttribute; |
| import org.eclipse.jdt.core.IClasspathContainer; |
| import org.eclipse.jdt.core.IClasspathEntry; |
| import org.eclipse.jdt.core.IJavaModel; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| |
| import org.eclipse.jdt.launching.JavaRuntime; |
| import org.eclipse.jdt.launching.environments.IExecutionEnvironment; |
| |
| import org.eclipse.jdt.ui.JavaUI; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; |
| |
| /** |
| * |
| */ |
| public class BuildPathSupport { |
| |
| public static final String JRE_PREF_PAGE_ID= "org.eclipse.jdt.debug.ui.preferences.VMPreferencePage"; //$NON-NLS-1$ |
| public static final String EE_PREF_PAGE_ID= "org.eclipse.jdt.debug.ui.jreProfiles"; //$NON-NLS-1$ |
| |
| /* see also ComplianceConfigurationBlock#PREFS_COMPLIANCE */ |
| private static final String[] PREFS_COMPLIANCE= new String[] { |
| JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.COMPILER_PB_ENUM_IDENTIFIER, |
| JavaCore.COMPILER_SOURCE, JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, |
| JavaCore.COMPILER_COMPLIANCE |
| }; |
| |
| |
| private BuildPathSupport() { |
| super(); |
| } |
| |
| /** |
| * Returns a deprecation message for a classpath variable name. |
| * |
| * @param variableName classpath variable name |
| * @return the deprecation message, or <code>null</code> iff |
| * <code>variableName</code> is not a classpath variable or the |
| * variable is not deprecated |
| */ |
| public static String getDeprecationMessage(String variableName) { |
| String deprecationMessage= JavaCore.getClasspathVariableDeprecationMessage(variableName); |
| if (deprecationMessage == null ) |
| return null; |
| else |
| return Messages.format(NewWizardMessages.BuildPathSupport_deprecated, |
| new Object[] {variableName, deprecationMessage}); |
| } |
| |
| /** |
| * Finds a source attachment for a new archive in the existing classpaths. |
| * @param elem The new classpath entry |
| * @return A path to be taken for the source attachment or <code>null</code> |
| */ |
| public static IPath guessSourceAttachment(CPListElement elem) { |
| if (elem.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { |
| return null; |
| } |
| IJavaProject currProject= elem.getJavaProject(); // can be null |
| try { |
| IJavaModel jmodel= JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()); |
| IJavaProject[] jprojects= jmodel.getJavaProjects(); |
| for (int i= 0; i < jprojects.length; i++) { |
| IJavaProject curr= jprojects[i]; |
| if (!curr.equals(currProject)) { |
| IClasspathEntry[] entries= curr.getRawClasspath(); |
| for (int k= 0; k < entries.length; k++) { |
| IClasspathEntry entry= entries[k]; |
| if (entry.getEntryKind() == elem.getEntryKind() |
| && entry.getPath().equals(elem.getPath())) { |
| IPath attachPath= entry.getSourceAttachmentPath(); |
| if (attachPath != null && !attachPath.isEmpty()) { |
| return attachPath; |
| } |
| } |
| } |
| } |
| } |
| } catch (JavaModelException e) { |
| JavaPlugin.log(e.getStatus()); |
| } |
| return null; |
| } |
| |
| /** |
| * Finds a javadoc location for a new archive in the existing classpaths. |
| * @param elem The new classpath entry |
| * @return A javadoc location found in a similar classpath entry or <code>null</code>. |
| */ |
| public static String guessJavadocLocation(CPListElement elem) { |
| if (elem.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { |
| return null; |
| } |
| IJavaProject currProject= elem.getJavaProject(); // can be null |
| try { |
| // try if the jar itself contains the source |
| IJavaModel jmodel= JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()); |
| IJavaProject[] jprojects= jmodel.getJavaProjects(); |
| for (int i= 0; i < jprojects.length; i++) { |
| IJavaProject curr= jprojects[i]; |
| if (!curr.equals(currProject)) { |
| IClasspathEntry[] entries= curr.getRawClasspath(); |
| for (int k= 0; k < entries.length; k++) { |
| IClasspathEntry entry= entries[k]; |
| if (entry.getEntryKind() == elem.getEntryKind() && entry.getPath().equals(elem.getPath())) { |
| IClasspathAttribute[] attributes= entry.getExtraAttributes(); |
| for (int n= 0; n < attributes.length; n++) { |
| IClasspathAttribute attrib= attributes[n]; |
| if (IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME.equals(attrib.getName())) { |
| return attrib.getValue(); |
| } |
| } |
| } |
| } |
| } |
| } |
| } catch (JavaModelException e) { |
| JavaPlugin.log(e.getStatus()); |
| } |
| return null; |
| } |
| |
| private static class UpdatedClasspathContainer implements IClasspathContainer { |
| |
| private IClasspathEntry[] fNewEntries; |
| private IClasspathContainer fOriginal; |
| |
| public UpdatedClasspathContainer(IClasspathContainer original, IClasspathEntry[] newEntries) { |
| fNewEntries= newEntries; |
| fOriginal= original; |
| } |
| |
| public IClasspathEntry[] getClasspathEntries() { |
| return fNewEntries; |
| } |
| |
| public String getDescription() { |
| return fOriginal.getDescription(); |
| } |
| |
| public int getKind() { |
| return fOriginal.getKind(); |
| } |
| |
| public IPath getPath() { |
| return fOriginal.getPath(); |
| } |
| } |
| |
| /** |
| * Apply a modified classpath entry to the classpath. The classpath entry can also be from a classpath container. |
| * @param shell If not null and the entry could not be found on the projects classpath, a dialog will ask to put the entry on the classpath |
| * @param newEntry The modified entry. The entry's kind or path must be unchanged. |
| * @param changedAttributes The attributes that have changed. See {@link CPListElement} for constants values. |
| * @param jproject Project where the entry belongs to |
| * @param containerPath The path of the entry's parent container or <code>null</code> if the entry is not in a container |
| * @param isReferencedEntry <code>true</code> iff the entry has a {@link IClasspathEntry#getReferencingEntry() referencing entry} |
| * @param monitor The progress monitor to use |
| * @throws CoreException if the update failed |
| */ |
| public static void modifyClasspathEntry(Shell shell, IClasspathEntry newEntry, String[] changedAttributes, IJavaProject jproject, IPath containerPath, boolean isReferencedEntry, IProgressMonitor monitor) throws CoreException { |
| if (containerPath != null) { |
| updateContainerClasspath(jproject, containerPath, newEntry, changedAttributes, monitor); |
| } else if (isReferencedEntry) { |
| updateReferencedClasspathEntry(jproject, newEntry, changedAttributes, monitor); |
| } else { |
| updateProjectClasspath(shell, jproject, newEntry, changedAttributes, monitor); |
| } |
| } |
| |
| private static void updateContainerClasspath(IJavaProject jproject, IPath containerPath, IClasspathEntry newEntry, String[] changedAttributes, IProgressMonitor monitor) throws CoreException { |
| IClasspathContainer container= JavaCore.getClasspathContainer(containerPath, jproject); |
| if (container == null) { |
| throw new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.ERROR, "Container " + containerPath + " cannot be resolved", null)); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| IClasspathEntry[] entries= container.getClasspathEntries(); |
| IClasspathEntry[] newEntries= new IClasspathEntry[entries.length]; |
| for (int i= 0; i < entries.length; i++) { |
| IClasspathEntry curr= entries[i]; |
| if (curr.getEntryKind() == newEntry.getEntryKind() && curr.getPath().equals(newEntry.getPath())) { |
| newEntries[i]= getUpdatedEntry(curr, newEntry, changedAttributes, jproject); |
| } else { |
| newEntries[i]= curr; |
| } |
| } |
| requestContainerUpdate(jproject, container, newEntries); |
| monitor.worked(1); |
| } |
| |
| private static IClasspathEntry getUpdatedEntry(IClasspathEntry currEntry, IClasspathEntry updatedEntry, String[] updatedAttributes, IJavaProject jproject) { |
| if (updatedAttributes == null) { |
| return updatedEntry; // used updated entry 'as is' |
| } |
| CPListElement currElem= CPListElement.createFromExisting(currEntry, jproject); |
| CPListElement newElem= CPListElement.createFromExisting(updatedEntry, jproject); |
| for (int i= 0; i < updatedAttributes.length; i++) { |
| String attrib= updatedAttributes[i]; |
| currElem.setAttribute(attrib, newElem.getAttribute(attrib)); |
| } |
| return currElem.getClasspathEntry(); |
| } |
| |
| /** |
| * Request a container update. |
| * @param jproject The project of the container |
| * @param container The container to request a change to |
| * @param newEntries The updated entries |
| * @throws CoreException if the request failed |
| */ |
| public static void requestContainerUpdate(IJavaProject jproject, IClasspathContainer container, IClasspathEntry[] newEntries) throws CoreException { |
| IPath containerPath= container.getPath(); |
| IClasspathContainer updatedContainer= new UpdatedClasspathContainer(container, newEntries); |
| ClasspathContainerInitializer initializer= JavaCore.getClasspathContainerInitializer(containerPath.segment(0)); |
| if (initializer != null) { |
| initializer.requestClasspathContainerUpdate(containerPath, jproject, updatedContainer); |
| } |
| } |
| |
| private static void updateProjectClasspath(Shell shell, IJavaProject jproject, IClasspathEntry newEntry, String[] changedAttributes, IProgressMonitor monitor) throws JavaModelException { |
| IClasspathEntry[] oldClasspath= jproject.getRawClasspath(); |
| int nEntries= oldClasspath.length; |
| ArrayList newEntries= new ArrayList(nEntries + 1); |
| int entryKind= newEntry.getEntryKind(); |
| IPath jarPath= newEntry.getPath(); |
| boolean found= false; |
| for (int i= 0; i < nEntries; i++) { |
| IClasspathEntry curr= oldClasspath[i]; |
| if (curr.getEntryKind() == entryKind && curr.getPath().equals(jarPath)) { |
| // add modified entry |
| newEntries.add(getUpdatedEntry(curr, newEntry, changedAttributes, jproject)); |
| found= true; |
| } else { |
| newEntries.add(curr); |
| } |
| } |
| if (!found) { |
| if (!putJarOnClasspathDialog(shell)) { |
| return; |
| } |
| // add new |
| newEntries.add(newEntry); |
| } |
| IClasspathEntry[] newClasspath= (IClasspathEntry[]) newEntries.toArray(new IClasspathEntry[newEntries.size()]); |
| jproject.setRawClasspath(newClasspath, monitor); |
| } |
| |
| private static boolean putJarOnClasspathDialog(final Shell shell) { |
| if (shell == null) { |
| return false; |
| } |
| |
| final boolean[] result= new boolean[1]; |
| shell.getDisplay().syncExec(new Runnable() { |
| public void run() { |
| String title= NewWizardMessages.BuildPathSupport_putoncpdialog_title; |
| String message= NewWizardMessages.BuildPathSupport_putoncpdialog_message; |
| result[0]= MessageDialog.openQuestion(shell, title, message); |
| } |
| }); |
| return result[0]; |
| } |
| |
| /** |
| * Apply a modified referenced classpath entry to the classpath. |
| * @param newReferencedEntry the modified entry. The entry's kind or path must be unchanged. |
| * @param changedAttributes the attributes that have changed. See {@link CPListElement} for constants values. |
| * @param jproject project where the entry belongs to |
| * @param monitor the progress monitor to use |
| * @throws CoreException if the update failed |
| */ |
| private static void updateReferencedClasspathEntry(IJavaProject jproject, IClasspathEntry newReferencedEntry, String[] changedAttributes, IProgressMonitor monitor) throws CoreException { |
| IClasspathEntry[] oldReferencedClasspath= jproject.getReferencedClasspathEntries(); |
| int nEntries= oldReferencedClasspath.length; |
| ArrayList newReferencedEntries= new ArrayList(nEntries + 1); |
| int entryKind= newReferencedEntry.getEntryKind(); |
| IPath jarPath= newReferencedEntry.getPath(); |
| boolean found= false; |
| for (int i= 0; i < nEntries; i++) { |
| IClasspathEntry curr= oldReferencedClasspath[i]; |
| if (curr.getEntryKind() == entryKind && curr.getPath().equals(jarPath)) { |
| // add modified entry |
| newReferencedEntries.add(getUpdatedEntry(curr, newReferencedEntry, changedAttributes, jproject)); |
| found= true; |
| } else { |
| newReferencedEntries.add(curr); |
| } |
| } |
| if (!found) { |
| newReferencedEntries.add(newReferencedEntry); |
| } |
| IClasspathEntry[] newReferencedClasspath= (IClasspathEntry[]) newReferencedEntries.toArray(new IClasspathEntry[newReferencedEntries.size()]); |
| |
| jproject.setRawClasspath(jproject.getRawClasspath(), newReferencedClasspath, jproject.getOutputLocation(), monitor); |
| } |
| |
| /** |
| * Sets the default compiler compliance options iff <code>modifiedClassPathEntries</code> |
| * contains a classpath container entry that is modified or new and that points to an execution |
| * environment. Does nothing if the EE or the options could not be resolved. |
| * |
| * @param javaProject the Java project |
| * @param modifiedClassPathEntries a list of {@link CPListElement} |
| * |
| * @see #getEEOptions(IExecutionEnvironment) |
| * |
| * @since 3.5 |
| */ |
| public static void setEEComplianceOptions(IJavaProject javaProject, List modifiedClassPathEntries) { |
| for (Iterator iter= modifiedClassPathEntries.iterator(); iter.hasNext();) { |
| CPListElement entry= (CPListElement)iter.next(); |
| if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { |
| IPath path= entry.getPath(); |
| if (! path.equals(entry.getOrginalPath())) { |
| String eeID= JavaRuntime.getExecutionEnvironmentId(path); |
| if (eeID != null) { |
| setEEComplianceOptions(javaProject, eeID, null); |
| return; |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Sets the default compiler compliance options based on the given execution environment. |
| * Does nothing if the EE or the options could not be resolved. |
| * |
| * @param javaProject the Java project |
| * @param eeID the execution environment ID |
| * @param newProjectCompliance compliance to set for a new project, can be <code>null</code> |
| * |
| * @see #getEEOptions(IExecutionEnvironment) |
| * |
| * @since 3.5 |
| */ |
| public static void setEEComplianceOptions(IJavaProject javaProject, String eeID, String newProjectCompliance) { |
| IExecutionEnvironment ee= JavaRuntime.getExecutionEnvironmentsManager().getEnvironment(eeID); |
| if (ee != null) { |
| Map options= javaProject.getOptions(false); |
| Map eeOptions= getEEOptions(ee); |
| if (eeOptions != null) { |
| for (int i= 0; i < PREFS_COMPLIANCE.length; i++) { |
| String option= PREFS_COMPLIANCE[i]; |
| options.put(option, eeOptions.get(option)); |
| } |
| |
| if (newProjectCompliance != null) { |
| JavaModelUtil.setDefaultClassfileOptions(options, newProjectCompliance); // complete compliance options |
| } |
| |
| String option= JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE; |
| String inlineJSR= (String)eeOptions.get(option); |
| if (inlineJSR != null) { |
| options.put(option, inlineJSR); |
| } |
| |
| javaProject.setOptions(options); |
| } |
| } |
| } |
| |
| /** |
| * Returns the compliance options from the given EE. If the result is not <code>null</code>, |
| * it contains at least these core options: |
| * <ul> |
| * <li>{@link JavaCore#COMPILER_COMPLIANCE}</li> |
| * <li>{@link JavaCore#COMPILER_SOURCE}</li> |
| * <li>{@link JavaCore#COMPILER_CODEGEN_TARGET_PLATFORM}</li> |
| * <li>{@link JavaCore#COMPILER_PB_ASSERT_IDENTIFIER}</li> |
| * <li>{@link JavaCore#COMPILER_PB_ENUM_IDENTIFIER}</li> |
| * <li>{@link JavaCore#COMPILER_CODEGEN_INLINE_JSR_BYTECODE} for compliance levels 1.5 and greater</li> |
| * </ul> |
| * |
| * @param ee the EE, can be <code>null</code> |
| * @return the options, or <code>null</code> if none |
| * @since 3.5 |
| */ |
| public static Map getEEOptions(IExecutionEnvironment ee) { |
| if (ee == null) |
| return null; |
| Map eeOptions= ee.getComplianceOptions(); |
| if (eeOptions == null) |
| return null; |
| |
| Object complianceOption= eeOptions.get(JavaCore.COMPILER_COMPLIANCE); |
| if (!(complianceOption instanceof String)) |
| return null; |
| |
| // eeOptions can miss some options, make sure they are complete: |
| HashMap options= new HashMap(); |
| JavaModelUtil.setComplianceOptions(options, (String)complianceOption); |
| options.putAll(eeOptions); |
| return options; |
| } |
| } |