| /******************************************************************************* |
| * Copyright (c) 2007 BEA Systems, Inc. |
| * 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 |
| *******************************************************************************/ |
| package org.eclipse.jst.j2ee.internal.classpathdep; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| 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.jdt.core.IClasspathAttribute; |
| import org.eclipse.jdt.core.IClasspathEntry; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jem.util.emf.workbench.ProjectUtilities; |
| import org.eclipse.jst.common.jdt.internal.javalite.IJavaProjectLite; |
| import org.eclipse.jst.common.jdt.internal.javalite.JavaCoreLite; |
| import org.eclipse.jst.j2ee.classpathdep.ClasspathDependencyUtil; |
| import org.eclipse.jst.j2ee.classpathdep.UpdateClasspathAttributeUtil; |
| import org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin; |
| import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities; |
| import org.eclipse.wst.common.frameworks.datamodel.AbstractDataModelOperation; |
| import org.eclipse.wst.common.frameworks.datamodel.IDataModel; |
| |
| /** |
| * DataModelOperation that updates the WTP component dependency attribute on the |
| * the classpath entries for the target Java project. |
| */ |
| public class UpdateClasspathAttributesOperation extends AbstractDataModelOperation implements UpdateClasspathAttributesDataModelProperties { |
| |
| public UpdateClasspathAttributesOperation(final IDataModel dataModel) { |
| super(dataModel); |
| } |
| |
| @Override |
| public IStatus execute(final IProgressMonitor monitor, final IAdaptable info) |
| throws ExecutionException { |
| final IProject project = ProjectUtilities.getProject(model.getStringProperty(PROJECT_NAME)); |
| final boolean webLibsOnly = JavaEEProjectUtilities.isDynamicWebProject(project) && !ClasspathDependencyEnablement.isAllowClasspathComponentDependency(); |
| |
| try { |
| if (project.hasNature(JavaCore.NATURE_ID)) { |
| final IJavaProject javaProject = JavaCore.create(project); |
| validateEdit(project); |
| final Map entriesToAdd = (Map) model.getProperty(ENTRIES_TO_ADD_ATTRIBUTE); |
| final boolean modifyComponentDep = model.getBooleanProperty(MODIFY_CLASSPATH_COMPONENT_DEPENDENCY); |
| if (entriesToAdd == null) { |
| final Map entriesToRemove = (Map ) model.getProperty(ENTRIES_TO_REMOVE_ATTRIBUTE); |
| if (entriesToRemove == null) { |
| final Map entriesToRuntimePath = (Map) model.getProperty(ENTRIES_WITH_ATTRIBUTE); |
| final Map entriesToAttrib = new HashMap(); |
| final Iterator i = entriesToRuntimePath.keySet().iterator(); |
| while (i.hasNext()) { |
| IClasspathEntry entry = (IClasspathEntry) i.next(); |
| IPath runtimePath = (IPath) entriesToRuntimePath.get(entry); |
| IClasspathAttribute attrib = ClasspathDependencyUtil.checkForComponentDependencyAttribute(entry, |
| modifyComponentDep ? DependencyAttributeType.CLASSPATH_COMPONENT_DEPENDENCY : DependencyAttributeType.CLASSPATH_COMPONENT_NONDEPENDENCY); |
| if (attrib == null) { |
| if (modifyComponentDep) { |
| attrib = UpdateClasspathAttributeUtil.createDependencyAttribute(runtimePath); |
| } else { |
| attrib = UpdateClasspathAttributeUtil.createNonDependencyAttribute(); |
| } |
| } |
| entriesToAttrib.put(entry, attrib); |
| } |
| updateDependencyAttributes(javaProject, entriesToAttrib, modifyComponentDep, webLibsOnly); |
| } else { |
| removeDependencyAttributes(javaProject, entriesToRemove, modifyComponentDep); |
| } |
| } else { |
| |
| addDependencyAttributes(javaProject, entriesToAdd, modifyComponentDep); |
| } |
| } |
| } catch (CoreException ce) { |
| J2EEPlugin.logError(ce); |
| return new Status(IStatus.ERROR, J2EEPlugin.PLUGIN_ID, 0, ce.getLocalizedMessage(), ce); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| /** |
| * Performs a validateEdit call on the files impacted by the operation. |
| */ |
| protected void validateEdit(final IProject project) throws CoreException { |
| final List affectedFiles = ProjectUtilities.getFilesAffectedByClasspathChange(project); |
| final IFile[] files = (IFile[]) affectedFiles.toArray(new IFile[affectedFiles.size()]); |
| final IStatus result = J2EEPlugin.getWorkspace().validateEdit(files, null); |
| if (!result.isOK()) { |
| throw new CoreException(result); |
| } |
| } |
| |
| /** |
| * Adds the WTP component dependency attribute to the specified classpath entries. |
| * @param javaProject Target Java project. |
| * @param entries Classpath entries to which the component dependency attribute should be added. |
| * @param modifyComponentDep True if adding the dependency attribute, false if adding the non-dependency attribute. |
| * @throws CoreException Thrown if an error is encountered. |
| */ |
| private void addDependencyAttributes(final IJavaProject javaProject, final Map entries, final boolean modifyComponentDep) throws CoreException { |
| alterDependencyAttributes(javaProject, entries, true, modifyComponentDep); |
| } |
| |
| /** |
| * Removes the WTP component dependency attribute from the specified classpath entries. |
| * @param javaProject Target Java project. |
| * @param entries Classpath entries from which the component dependency attribute should be removed. |
| * @param modifyComponentDep True if removing the dependency attribute, false if removing the non-dependency attribute. |
| * @throws CoreException Thrown if an error is encountered. |
| */ |
| private void removeDependencyAttributes(final IJavaProject javaProject, final Map entries, final boolean modifyComponentDep) throws CoreException { |
| alterDependencyAttributes(javaProject, entries, false, modifyComponentDep); |
| } |
| |
| private void alterDependencyAttributes(final IJavaProject javaProject, final Map entries, final boolean add, final boolean modifyComponentDep) throws CoreException { |
| final boolean isWebApp = JavaEEProjectUtilities.isDynamicWebProject(javaProject.getProject()); |
| final boolean webLibsOnly = isWebApp && !ClasspathDependencyEnablement.isAllowClasspathComponentDependency(); |
| final IJavaProjectLite javaProjectLite = JavaCoreLite.create(javaProject); |
| |
| // initialize to the set of raw entries with the attrib |
| final Map entriesWithAttrib = ClasspathDependencyUtil.getRawComponentClasspathDependencies(javaProjectLite, modifyComponentDep ? DependencyAttributeType.CLASSPATH_COMPONENT_DEPENDENCY : DependencyAttributeType.CLASSPATH_COMPONENT_NONDEPENDENCY, webLibsOnly); |
| |
| Iterator i = entries.keySet().iterator(); |
| while (i.hasNext()) { |
| final IClasspathEntry entry = (IClasspathEntry) i.next(); |
| if (add) { |
| if (getMatchingEntryIgnoreAttributes(entriesWithAttrib, entry) == null) { |
| IPath runtimePath = (IPath) entries.get(entry); |
| if (runtimePath == null) { |
| // compute the default runtime path |
| runtimePath = ClasspathDependencyUtil.getDefaultRuntimePath(isWebApp, ClasspathDependencyUtil.isClassFolderEntry(entry)); |
| } |
| IClasspathAttribute attrib = null; |
| if (modifyComponentDep) { |
| attrib = UpdateClasspathAttributeUtil.createDependencyAttribute(runtimePath); |
| } else { |
| attrib = UpdateClasspathAttributeUtil.createNonDependencyAttribute(); |
| } |
| entriesWithAttrib.put(entry, attrib); |
| } |
| } else { |
| IClasspathEntry matching = getMatchingEntryIgnoreAttributes(entriesWithAttrib, entry); |
| if (matching != null) { |
| entriesWithAttrib.remove(matching); |
| } |
| } |
| } |
| updateDependencyAttributes(javaProject, entriesWithAttrib, modifyComponentDep, webLibsOnly); |
| } |
| |
| private IClasspathEntry getMatchingEntryIgnoreAttributes(final Map entries, final IClasspathEntry entry) { |
| final Iterator i = entries.keySet().iterator(); |
| while (i.hasNext()) { |
| final IClasspathEntry e = (IClasspathEntry) i.next(); |
| if (e.getEntryKind() == entry.getEntryKind() |
| && e.getPath().equals(entry.getPath()) |
| && e.isExported() == entry.isExported()) { |
| return e; |
| } |
| } |
| return null; |
| |
| } |
| |
| /** |
| * Updates the specified Java project so that only the specified classpath entries have |
| * the WTP component dependency attribute. |
| * @param javaProject Target Java project. |
| * @param entries Classpath entries that should have the component dependency attribute. Map from IClasspathEntry |
| * to the IClasspathAttribute for the WTP classpath component dependency. |
| * @param modifyComponentDep True if modifying the dependency attribute, false if modifying the non-dependency attribute. |
| * @throws CoreException Thrown if an error is encountered. |
| */ |
| private void updateDependencyAttributes(final IJavaProject javaProject, final Map entriesWithAttrib, final boolean modifyComponentDep, final boolean webLibsOnly) throws CoreException { |
| if (javaProject == null || !javaProject.getProject().isAccessible()) { |
| return; |
| } |
| |
| final List updatedClasspath = new ArrayList(); |
| final IClasspathEntry[] rawClasspath = javaProject.getRawClasspath(); |
| boolean needToUpdateClasspath = false; |
| IClasspathAttribute attrib = UpdateClasspathAttributeUtil.createDependencyAttribute(); |
| if (!modifyComponentDep) { |
| attrib = UpdateClasspathAttributeUtil.createNonDependencyAttribute(); |
| } |
| for (int i = 0; i < rawClasspath.length; i++) { |
| IClasspathEntry entry = rawClasspath[i]; |
| final int kind = entry.getEntryKind(); |
| boolean hasAttribute = ClasspathDependencyUtil.checkForComponentDependencyAttribute(entry, |
| modifyComponentDep ? DependencyAttributeType.CLASSPATH_COMPONENT_DEPENDENCY : DependencyAttributeType.CLASSPATH_COMPONENT_NONDEPENDENCY, webLibsOnly) != null; |
| boolean shouldHaveAttribute = entriesWithAttrib.containsKey(entry); |
| boolean updateAttributes = false; |
| IClasspathAttribute[] updatedAttributes = null; |
| if (shouldHaveAttribute) { |
| if (!hasAttribute) { |
| // should have the attribute and currently missing it |
| attrib = (IClasspathAttribute) entriesWithAttrib.get(entry); |
| updatedAttributes = updateAttributes(entry.getExtraAttributes(), attrib, true); |
| needToUpdateClasspath = true; |
| updateAttributes = true; |
| } |
| } else if (hasAttribute) { |
| // should not have the attribute and currently has it |
| updatedAttributes = updateAttributes(entry.getExtraAttributes(), attrib, false); |
| needToUpdateClasspath = true; |
| updateAttributes = true; |
| } |
| |
| if (updateAttributes) { |
| switch(kind) { |
| case IClasspathEntry.CPE_CONTAINER: |
| entry = JavaCore.newContainerEntry(entry.getPath(), entry.getAccessRules(), updatedAttributes, entry.isExported()); |
| break; |
| case IClasspathEntry.CPE_LIBRARY: |
| entry = JavaCore.newLibraryEntry(entry.getPath(), entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.getAccessRules(), updatedAttributes, entry.isExported()); |
| break; |
| case IClasspathEntry.CPE_VARIABLE: |
| entry = JavaCore.newVariableEntry(entry.getPath(), entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.getAccessRules(), updatedAttributes, entry.isExported()); |
| break; |
| case IClasspathEntry.CPE_PROJECT: // although project entries are not yet supported, allow the attribute here and let the validator flag as an error |
| entry = JavaCore.newProjectEntry(entry.getPath(), entry.getAccessRules(), entry.combineAccessRules(), updatedAttributes, entry.isExported()); |
| break; |
| case IClasspathEntry.CPE_SOURCE: // although source entries are not supported, allow the attribute here and let the validator flag as an error |
| entry = JavaCore.newSourceEntry(entry.getPath(), entry.getInclusionPatterns(), entry.getExclusionPatterns(), entry.getOutputLocation(), updatedAttributes); |
| break; |
| } |
| } |
| |
| updatedClasspath.add(entry); |
| } |
| if (needToUpdateClasspath) { |
| final IClasspathEntry[] updatedCPArray = (IClasspathEntry[]) updatedClasspath.toArray(new IClasspathEntry[updatedClasspath.size()]); |
| javaProject.setRawClasspath(updatedCPArray, null); |
| } |
| } |
| |
| private IClasspathAttribute[] updateAttributes(final IClasspathAttribute[] currentAttribs, final IClasspathAttribute targetAttrib, final boolean add) { |
| final List updatedAttribs = new ArrayList(); |
| boolean hasAttrib = false; |
| for (int i = 0; i < currentAttribs.length; i++) { |
| if (currentAttribs[i].getName().equals(targetAttrib.getName())) { |
| hasAttrib = true; |
| if (!add) { |
| continue; |
| } |
| } |
| updatedAttribs.add(currentAttribs[i]); |
| } |
| if (add && !hasAttrib) { |
| updatedAttribs.add(targetAttrib); |
| } |
| return (IClasspathAttribute[]) updatedAttribs.toArray(new IClasspathAttribute[updatedAttribs.size()]); |
| } |
| } |