/*******************************************************************************
* 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.IProject;
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.IJavaModelStatus;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.util.Messages;
public class CopyPackageFragmentRootOperation extends JavaModelOperation {
IPath destination;
int updateResourceFlags;
int updateModelFlags;
IClasspathEntry sibling;
public CopyPackageFragmentRootOperation(
IPackageFragmentRoot root,
IPath destination,
int updateResourceFlags,
int updateModelFlags,
IClasspathEntry sibling) {
super(root);
this.destination= destination;
this.updateResourceFlags= updateResourceFlags;
this.updateModelFlags= updateModelFlags;
this.sibling= sibling;
}
protected void executeOperation() throws JavaModelException {
IPackageFragmentRoot root= (IPackageFragmentRoot)getElementToProcess();
IClasspathEntry rootEntry= root.getRawClasspathEntry();
IWorkspaceRoot workspaceRoot= ResourcesPlugin.getWorkspace().getRoot();
// copy resource
if (!root.isExternal() && (this.updateModelFlags & IPackageFragmentRoot.NO_RESOURCE_MODIFICATION) == 0) {
copyResource(root, rootEntry, workspaceRoot);
}
// update classpath if needed
if ((this.updateModelFlags & IPackageFragmentRoot.DESTINATION_PROJECT_CLASSPATH) != 0) {
addEntryToClasspath(rootEntry, workspaceRoot);
}
}
protected void copyResource(
IPackageFragmentRoot root,
IClasspathEntry rootEntry,
final IWorkspaceRoot workspaceRoot)
throws JavaModelException {
final char[][] exclusionPatterns= ((ClasspathEntry)rootEntry).fullExclusionPatternChars();
IResource rootResource= ((JavaElement)root).resource();
if (root.getKind() == IPackageFragmentRoot.K_BINARY || exclusionPatterns == null) {
try {
IResource destRes;
if ((this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0) {
if (rootEntry.getPath().equals(this.destination))
return;
if ((destRes= workspaceRoot.findMember(this.destination)) != null) {
destRes.delete(this.updateResourceFlags, this.progressMonitor);
}
}
rootResource.copy(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 ((CopyPackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0
&& folder.exists()) {
return true;
}
folder.create(CopyPackageFragmentRootOperation.this.updateResourceFlags, true, CopyPackageFragmentRootOperation.this.progressMonitor);
return true;
}
} else {
// subtree doesn't contain any nested source folders
IPath destPath= CopyPackageFragmentRootOperation.this.destination.append(path.removeFirstSegments(sourceSegmentCount));
IResource destRes;
if ((CopyPackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0
&& (destRes= workspaceRoot.findMember(destPath)) != null) {
destRes.delete(CopyPackageFragmentRootOperation.this.updateResourceFlags, CopyPackageFragmentRootOperation.this.progressMonitor);
}
proxy.requestResource().copy(destPath, CopyPackageFragmentRootOperation.this.updateResourceFlags, CopyPackageFragmentRootOperation.this.progressMonitor);
return false;
}
} else {
IPath path= proxy.requestFullPath();
IPath destPath= CopyPackageFragmentRootOperation.this.destination.append(path.removeFirstSegments(sourceSegmentCount));
IResource destRes;
if ((CopyPackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0
&& (destRes= workspaceRoot.findMember(destPath)) != null) {
destRes.delete(CopyPackageFragmentRootOperation.this.updateResourceFlags, CopyPackageFragmentRootOperation.this.progressMonitor);
}
proxy.requestResource().copy(destPath, CopyPackageFragmentRootOperation.this.updateResourceFlags, CopyPackageFragmentRootOperation.this.progressMonitor);
return false;
}
}
};
try {
rootResource.accept(visitor, IResource.NONE);
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
}
protected void addEntryToClasspath(IClasspathEntry rootEntry, IWorkspaceRoot workspaceRoot) throws JavaModelException {
IProject destProject= workspaceRoot.getProject(this.destination.segment(0));
IJavaProject jProject= JavaCore.create(destProject);
IClasspathEntry[] classpath= jProject.getRawClasspath();
int length= classpath.length;
IClasspathEntry[] newClasspath;
// case of existing entry and REPLACE was specified
if ((this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0) {
// find existing entry
for (int i= 0; i < length; i++) {
if (this.destination.equals(classpath[i].getPath())) {
newClasspath= new IClasspathEntry[length];
System.arraycopy(classpath, 0, newClasspath, 0, length);
newClasspath[i]= copy(rootEntry);
jProject.setRawClasspath(newClasspath, this.progressMonitor);
return;
}
}
}
// other cases
int position;
if (this.sibling == null) {
// insert at the end
position= length;
} else {
// insert before sibling
position= -1;
for (int i= 0; i < length; i++) {
if (this.sibling.equals(classpath[i])) {
position= i;
break;
}
}
}
if (position == -1) {
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, this.sibling.toString()));
}
newClasspath= new IClasspathEntry[length + 1];
if (position != 0) {
System.arraycopy(classpath, 0, newClasspath, 0, position);
}
if (position != length) {
System.arraycopy(classpath, position, newClasspath, position + 1, length - position);
}
IClasspathEntry newEntry= copy(rootEntry);
newClasspath[position]= newEntry;
jProject.setRawClasspath(newClasspath, this.progressMonitor);
}
/*
* Copies the given classpath entry replacing its path with the destination path
* if it is a source folder or a library.
*/
protected IClasspathEntry copy(IClasspathEntry entry) throws JavaModelException {
switch (entry.getEntryKind()) {
case IClasspathEntry.CPE_CONTAINER:
return JavaCore.newContainerEntry(entry.getPath(), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported());
case IClasspathEntry.CPE_LIBRARY:
try {
return JavaCore.newLibraryEntry(this.destination, entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.getAccessRules(), entry.getExtraAttributes(),
entry.isExported());
} catch (ClasspathEntry.AssertionFailedException e) {
IJavaModelStatus status= new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
throw new JavaModelException(status);
}
case IClasspathEntry.CPE_PROJECT:
return JavaCore.newProjectEntry(entry.getPath(), entry.getAccessRules(), entry.combineAccessRules(), entry.getExtraAttributes(), entry.isExported());
case IClasspathEntry.CPE_SOURCE:
return JavaCore.newSourceEntry(this.destination, entry.getInclusionPatterns(), entry.getExclusionPatterns(), entry.getOutputLocation(), entry.getExtraAttributes());
case IClasspathEntry.CPE_VARIABLE:
try {
return JavaCore.newVariableEntry(entry.getPath(), entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.getAccessRules(), entry.getExtraAttributes(),
entry.isExported());
} catch (ClasspathEntry.AssertionFailedException e) {
IJavaModelStatus status= new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
throw new JavaModelException(status);
}
default:
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, getElementToProcess()));
}
}
public IJavaModelStatus verify() {
IJavaModelStatus status= super.verify();
if (!status.isOK()) {
return status;
}
PackageFragmentRoot root= (PackageFragmentRoot)getElementToProcess();
if (root == null || !root.exists()) {
return new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, root);
}
IResource resource= root.resource();
if (resource instanceof IFolder) {
if (resource.isLinked()) {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_RESOURCE, root);
}
}
if ((this.updateModelFlags & IPackageFragmentRoot.DESTINATION_PROJECT_CLASSPATH) != 0) {
String destProjectName= this.destination.segment(0);
IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(destProjectName);
if (JavaProject.hasJavaNature(project)) {
try {
IJavaProject destProject= JavaCore.create(project);
IClasspathEntry[] destClasspath= destProject.getRawClasspath();
boolean foundSibling= false;
boolean foundExistingEntry= false;
for (int i= 0, length= destClasspath.length; i < length; i++) {
IClasspathEntry entry= destClasspath[i];
if (entry.equals(this.sibling)) {
foundSibling= true;
break;
}
if (entry.getPath().equals(this.destination)) {
foundExistingEntry= true;
}
}
if (this.sibling != null && !foundSibling) {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, this.sibling.toString());
}
if (foundExistingEntry && (this.updateModelFlags & IPackageFragmentRoot.REPLACE) == 0) {
return new JavaModelStatus(
IJavaModelStatusConstants.NAME_COLLISION,
Messages.bind(Messages.status_nameCollision, new String[] { this.destination.toString() }));
}
} catch (JavaModelException e) {
return e.getJavaModelStatus();
}
}
}
return JavaModelStatus.VERIFIED_OK;
}
}