/*******************************************************************************
* Copyright (c) 2000, 2008 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.core;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaModelStatus;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
public class MovePackageFragmentRootOperation extends CopyPackageFragmentRootOperation {
/*
* Renames the classpath entries equal to the given path in the given project.
* If an entry with the destination path already existed, remove it.
*/
protected void renameEntryInClasspath(IPath rootPath, IJavaProject project) throws JavaModelException {
IClasspathEntry[] classpath= project.getRawClasspath();
IClasspathEntry[] newClasspath= null;
int cpLength= classpath.length;
int newCPIndex= -1;
for (int i= 0; i < cpLength; i++) {
IClasspathEntry entry= classpath[i];
IPath entryPath= entry.getPath();
if (rootPath.equals(entryPath)) {
// rename entry
if (newClasspath == null) {
newClasspath= new IClasspathEntry[cpLength];
System.arraycopy(classpath, 0, newClasspath, 0, i);
newCPIndex= i;
}
newClasspath[newCPIndex++]= copy(entry);
} else if (this.destination.equals(entryPath)) {
// remove entry equals to destination
if (newClasspath == null) {
newClasspath= new IClasspathEntry[cpLength];
System.arraycopy(classpath, 0, newClasspath, 0, i);
newCPIndex= i;
}
} else if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
// update exclusion/inclusion patterns
IPath projectRelativePath= rootPath.removeFirstSegments(1);
IPath[] newExclusionPatterns= renamePatterns(projectRelativePath, entry.getExclusionPatterns());
IPath[] newInclusionPatterns= renamePatterns(projectRelativePath, entry.getInclusionPatterns());
if (newExclusionPatterns != null || newInclusionPatterns != null) {
if (newClasspath == null) {
newClasspath= new IClasspathEntry[cpLength];
System.arraycopy(classpath, 0, newClasspath, 0, i);
newCPIndex= i;
}
newClasspath[newCPIndex++]=
JavaCore.newSourceEntry(
entry.getPath(),
newInclusionPatterns == null ? entry.getInclusionPatterns() : newInclusionPatterns,
newExclusionPatterns == null ? entry.getExclusionPatterns() : newExclusionPatterns,
entry.getOutputLocation(),
entry.getExtraAttributes());
} else if (newClasspath != null) {
newClasspath[newCPIndex++]= entry;
}
} else if (newClasspath != null) {
newClasspath[newCPIndex++]= entry;
}
}
if (newClasspath != null) {
if (newCPIndex < newClasspath.length) {
System.arraycopy(newClasspath, 0, newClasspath= new IClasspathEntry[newCPIndex], 0, newCPIndex);
}
IJavaModelStatus status= JavaConventions.validateClasspath(project, newClasspath, project.getOutputLocation());
if (status.isOK())
project.setRawClasspath(newClasspath, this.progressMonitor);
// don't update classpath if status is not ok to avoid JavaModelException (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129991)
}
}
private IPath[] renamePatterns(IPath rootPath, IPath[] patterns) {
IPath[] newPatterns= null;
int newPatternsIndex= -1;
for (int i= 0, length= patterns.length; i < length; i++) {
IPath pattern= patterns[i];
if (pattern.equals(rootPath)) {
if (newPatterns == null) {
newPatterns= new IPath[length];
System.arraycopy(patterns, 0, newPatterns, 0, i);
newPatternsIndex= i;
}
IPath newPattern= this.destination.removeFirstSegments(1);
if (pattern.hasTrailingSeparator())
newPattern= newPattern.addTrailingSeparator();
newPatterns[newPatternsIndex++]= newPattern;
}
}
return newPatterns;
}
public MovePackageFragmentRootOperation(
IPackageFragmentRoot root,
IPath destination,
int updateResourceFlags,
int updateModelFlags,
IClasspathEntry sibling) {
super(
root,
destination,
updateResourceFlags,
updateModelFlags,
sibling);
}
protected void executeOperation() throws JavaModelException {
IPackageFragmentRoot root= (IPackageFragmentRoot)getElementToProcess();
IClasspathEntry rootEntry= root.getRawClasspathEntry();
IWorkspaceRoot workspaceRoot= ResourcesPlugin.getWorkspace().getRoot();
// move resource
if (!root.isExternal() && (this.updateModelFlags & IPackageFragmentRoot.NO_RESOURCE_MODIFICATION) == 0) {
moveResource(root, rootEntry, workspaceRoot);
}
// update refering projects classpath excluding orignating project
IJavaProject originatingProject= root.getJavaProject();
if ((this.updateModelFlags & IPackageFragmentRoot.OTHER_REFERRING_PROJECTS_CLASSPATH) != 0) {
updateReferringProjectClasspaths(rootEntry.getPath(), originatingProject);
}
boolean isRename= this.destination.segment(0).equals(originatingProject.getElementName());
boolean updateOriginating= (this.updateModelFlags & IPackageFragmentRoot.ORIGINATING_PROJECT_CLASSPATH) != 0;
boolean updateDestination= (this.updateModelFlags & IPackageFragmentRoot.DESTINATION_PROJECT_CLASSPATH) != 0;
// update originating classpath
if (updateOriginating) {
if (isRename && updateDestination) {
renameEntryInClasspath(rootEntry.getPath(), originatingProject);
} else {
removeEntryFromClasspath(rootEntry.getPath(), originatingProject);
}
}
// update destination classpath
if (updateDestination) {
if (!isRename || !updateOriginating) {
addEntryToClasspath(rootEntry, workspaceRoot);
} // else reference has been updated when updating originating project classpath
}
}
protected void moveResource(
IPackageFragmentRoot root,
IClasspathEntry rootEntry,
final IWorkspaceRoot workspaceRoot)
throws JavaModelException {
final char[][] exclusionPatterns= ((ClasspathEntry)rootEntry).fullExclusionPatternChars();
IResource rootResource= ((JavaElement)root).resource();
if (rootEntry.getEntryKind() != IClasspathEntry.CPE_SOURCE || exclusionPatterns == null) {
try {
IResource destRes;
if ((this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0
&& (destRes= workspaceRoot.findMember(this.destination)) != null) {
destRes.delete(this.updateResourceFlags, this.progressMonitor);
}
rootResource.move(this.destination, this.updateResourceFlags, this.progressMonitor);
} catch (CoreException e) {
throw new JavaModelException(e);
}
} else {
final int sourceSegmentCount= rootEntry.getPath().segmentCount();
final IFolder destFolder= workspaceRoot.getFolder(this.destination);
final IPath[] nestedFolders= getNestedFolders(root);
IResourceProxyVisitor visitor= new IResourceProxyVisitor() {
public boolean visit(IResourceProxy proxy) throws CoreException {
if (proxy.getType() == IResource.FOLDER) {
IPath path= proxy.requestFullPath();
if (prefixesOneOf(path, nestedFolders)) {
if (equalsOneOf(path, nestedFolders)) {
// nested source folder
return false;
} else {
// folder containing nested source folder
IFolder folder= destFolder.getFolder(path.removeFirstSegments(sourceSegmentCount));
if ((MovePackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0
&& folder.exists()) {
return true;
}
folder.create(MovePackageFragmentRootOperation.this.updateResourceFlags, true, MovePackageFragmentRootOperation.this.progressMonitor);
return true;
}
} else {
// subtree doesn't contain any nested source folders
IPath destPath= MovePackageFragmentRootOperation.this.destination.append(path.removeFirstSegments(sourceSegmentCount));
IResource destRes;
if ((MovePackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0
&& (destRes= workspaceRoot.findMember(destPath)) != null) {
destRes.delete(MovePackageFragmentRootOperation.this.updateResourceFlags, MovePackageFragmentRootOperation.this.progressMonitor);
}
proxy.requestResource().move(destPath, MovePackageFragmentRootOperation.this.updateResourceFlags, MovePackageFragmentRootOperation.this.progressMonitor);
return false;
}
} else {
IPath path= proxy.requestFullPath();
IPath destPath= MovePackageFragmentRootOperation.this.destination.append(path.removeFirstSegments(sourceSegmentCount));
IResource destRes;
if ((MovePackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0
&& (destRes= workspaceRoot.findMember(destPath)) != null) {
destRes.delete(MovePackageFragmentRootOperation.this.updateResourceFlags, MovePackageFragmentRootOperation.this.progressMonitor);
}
proxy.requestResource().move(destPath, MovePackageFragmentRootOperation.this.updateResourceFlags, MovePackageFragmentRootOperation.this.progressMonitor);
return false;
}
}
};
try {
rootResource.accept(visitor, IResource.NONE);
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
}
/*
* Renames the classpath entries equal to the given path in all Java projects.
*/
protected void updateReferringProjectClasspaths(IPath rootPath, IJavaProject projectOfRoot) throws JavaModelException {
IJavaModel model= getJavaModel();
IJavaProject[] projects= model.getJavaProjects();
for (int i= 0, length= projects.length; i < length; i++) {
IJavaProject project= projects[i];
if (project.equals(projectOfRoot))
continue;
renameEntryInClasspath(rootPath, project);
}
}
/*
* Removes the classpath entry equal to the given path from the given project's classpath.
*/
protected void removeEntryFromClasspath(IPath rootPath, IJavaProject project) throws JavaModelException {
IClasspathEntry[] classpath= project.getRawClasspath();
IClasspathEntry[] newClasspath= null;
int cpLength= classpath.length;
int newCPIndex= -1;
for (int i= 0; i < cpLength; i++) {
IClasspathEntry entry= classpath[i];
if (rootPath.equals(entry.getPath())) {
if (newClasspath == null) {
newClasspath= new IClasspathEntry[cpLength];
System.arraycopy(classpath, 0, newClasspath, 0, i);
newCPIndex= i;
}
} else if (newClasspath != null) {
newClasspath[newCPIndex++]= entry;
}
}
if (newClasspath != null) {
if (newCPIndex < newClasspath.length) {
System.arraycopy(newClasspath, 0, newClasspath= new IClasspathEntry[newCPIndex], 0, newCPIndex);
}
project.setRawClasspath(newClasspath, this.progressMonitor);
}
}
}