1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.jdt.internal.core; 15 16 import org.eclipse.core.resources.*; 17 import org.eclipse.core.runtime.CoreException; 18 import org.eclipse.core.runtime.IPath; 19 import org.eclipse.jdt.core.*; 20 import org.eclipse.jdt.internal.core.util.Messages; 21 22 public class CopyPackageFragmentRootOperation extends JavaModelOperation { 23 IPath destination; 24 int updateResourceFlags; 25 int updateModelFlags; 26 IClasspathEntry sibling; 27 CopyPackageFragmentRootOperation( IPackageFragmentRoot root, IPath destination, int updateResourceFlags, int updateModelFlags, IClasspathEntry sibling)28 public CopyPackageFragmentRootOperation( 29 IPackageFragmentRoot root, 30 IPath destination, 31 int updateResourceFlags, 32 int updateModelFlags, 33 IClasspathEntry sibling) { 34 35 super(root); 36 this.destination = destination; 37 this.updateResourceFlags = updateResourceFlags; 38 this.updateModelFlags = updateModelFlags; 39 this.sibling = sibling; 40 } 41 @Override executeOperation()42 protected void executeOperation() throws JavaModelException { 43 44 IPackageFragmentRoot root = (IPackageFragmentRoot)getElementToProcess(); 45 IClasspathEntry rootEntry = root.getRawClasspathEntry(); 46 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); 47 48 // copy resource 49 if (!root.isExternal() && (this.updateModelFlags & IPackageFragmentRoot.NO_RESOURCE_MODIFICATION) == 0) { 50 copyResource(root, rootEntry, workspaceRoot); 51 } 52 53 // update classpath if needed 54 if ((this.updateModelFlags & IPackageFragmentRoot.DESTINATION_PROJECT_CLASSPATH) != 0) { 55 addEntryToClasspath(rootEntry, workspaceRoot); 56 } 57 } copyResource( IPackageFragmentRoot root, IClasspathEntry rootEntry, final IWorkspaceRoot workspaceRoot)58 protected void copyResource( 59 IPackageFragmentRoot root, 60 IClasspathEntry rootEntry, 61 final IWorkspaceRoot workspaceRoot) 62 throws JavaModelException { 63 final char[][] exclusionPatterns = ((ClasspathEntry)rootEntry).fullExclusionPatternChars(); 64 IResource rootResource = ((JavaElement) root).resource(); 65 if (root.getKind() == IPackageFragmentRoot.K_BINARY || exclusionPatterns == null) { 66 try { 67 IResource destRes; 68 if ((this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0) { 69 if (rootEntry.getPath().equals(this.destination)) return; 70 if ((destRes = workspaceRoot.findMember(this.destination)) != null) { 71 destRes.delete(this.updateResourceFlags, this.progressMonitor); 72 } 73 } 74 rootResource.copy(this.destination, this.updateResourceFlags, this.progressMonitor); 75 } catch (CoreException e) { 76 throw new JavaModelException(e); 77 } 78 } else { 79 final int sourceSegmentCount = rootEntry.getPath().segmentCount(); 80 final IFolder destFolder = workspaceRoot.getFolder(this.destination); 81 final IPath[] nestedFolders = getNestedFolders(root); 82 IResourceProxyVisitor visitor = new IResourceProxyVisitor() { 83 @Override 84 public boolean visit(IResourceProxy proxy) throws CoreException { 85 if (proxy.getType() == IResource.FOLDER) { 86 IPath path = proxy.requestFullPath(); 87 if (prefixesOneOf(path, nestedFolders)) { 88 if (equalsOneOf(path, nestedFolders)) { 89 // nested source folder 90 return false; 91 } else { 92 // folder containing nested source folder 93 IFolder folder = destFolder.getFolder(path.removeFirstSegments(sourceSegmentCount)); 94 if ((CopyPackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0 95 && folder.exists()) { 96 return true; 97 } 98 folder.create(CopyPackageFragmentRootOperation.this.updateResourceFlags, true, CopyPackageFragmentRootOperation.this.progressMonitor); 99 return true; 100 } 101 } else { 102 // subtree doesn't contain any nested source folders 103 IPath destPath = CopyPackageFragmentRootOperation.this.destination.append(path.removeFirstSegments(sourceSegmentCount)); 104 IResource destRes; 105 if ((CopyPackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0 106 && (destRes = workspaceRoot.findMember(destPath)) != null) { 107 destRes.delete(CopyPackageFragmentRootOperation.this.updateResourceFlags, CopyPackageFragmentRootOperation.this.progressMonitor); 108 } 109 proxy.requestResource().copy(destPath, CopyPackageFragmentRootOperation.this.updateResourceFlags, CopyPackageFragmentRootOperation.this.progressMonitor); 110 return false; 111 } 112 } else { 113 IPath path = proxy.requestFullPath(); 114 IPath destPath = CopyPackageFragmentRootOperation.this.destination.append(path.removeFirstSegments(sourceSegmentCount)); 115 IResource destRes; 116 if ((CopyPackageFragmentRootOperation.this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0 117 && (destRes = workspaceRoot.findMember(destPath)) != null) { 118 destRes.delete(CopyPackageFragmentRootOperation.this.updateResourceFlags, CopyPackageFragmentRootOperation.this.progressMonitor); 119 } 120 proxy.requestResource().copy(destPath, CopyPackageFragmentRootOperation.this.updateResourceFlags, CopyPackageFragmentRootOperation.this.progressMonitor); 121 return false; 122 } 123 } 124 }; 125 try { 126 rootResource.accept(visitor, IResource.NONE); 127 } catch (CoreException e) { 128 throw new JavaModelException(e); 129 } 130 } 131 setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 132 } addEntryToClasspath(IClasspathEntry rootEntry, IWorkspaceRoot workspaceRoot)133 protected void addEntryToClasspath(IClasspathEntry rootEntry, IWorkspaceRoot workspaceRoot) throws JavaModelException { 134 135 IProject destProject = workspaceRoot.getProject(this.destination.segment(0)); 136 IJavaProject jProject = JavaCore.create(destProject); 137 IClasspathEntry[] classpath = jProject.getRawClasspath(); 138 int length = classpath.length; 139 IClasspathEntry[] newClasspath; 140 141 // case of existing entry and REPLACE was specified 142 if ((this.updateModelFlags & IPackageFragmentRoot.REPLACE) != 0) { 143 // find existing entry 144 for (int i = 0; i < length; i++) { 145 if (this.destination.equals(classpath[i].getPath())) { 146 newClasspath = new IClasspathEntry[length]; 147 System.arraycopy(classpath, 0, newClasspath, 0, length); 148 newClasspath[i] = copy(rootEntry); 149 jProject.setRawClasspath(newClasspath, this.progressMonitor); 150 return; 151 } 152 } 153 } 154 155 // other cases 156 int position; 157 if (this.sibling == null) { 158 // insert at the end 159 position = length; 160 } else { 161 // insert before sibling 162 position = -1; 163 for (int i = 0; i < length; i++) { 164 if (this.sibling.equals(classpath[i])) { 165 position = i; 166 break; 167 } 168 } 169 } 170 if (position == -1) { 171 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, this.sibling.toString())); 172 } 173 newClasspath = new IClasspathEntry[length+1]; 174 if (position != 0) { 175 System.arraycopy(classpath, 0, newClasspath, 0, position); 176 } 177 if (position != length) { 178 System.arraycopy(classpath, position, newClasspath, position+1, length-position); 179 } 180 IClasspathEntry newEntry = copy(rootEntry); 181 newClasspath[position] = newEntry; 182 jProject.setRawClasspath(newClasspath, this.progressMonitor); 183 } 184 /* 185 * Copies the given classpath entry replacing its path with the destination path 186 * if it is a source folder or a library. 187 */ copy(IClasspathEntry entry)188 protected IClasspathEntry copy(IClasspathEntry entry) throws JavaModelException { 189 switch (entry.getEntryKind()) { 190 case IClasspathEntry.CPE_CONTAINER: 191 return JavaCore.newContainerEntry(entry.getPath(), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported()); 192 case IClasspathEntry.CPE_LIBRARY: 193 try { 194 return JavaCore.newLibraryEntry(this.destination, entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported()); 195 } catch (ClasspathEntry.AssertionFailedException e) { 196 IJavaModelStatus status = new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage()); 197 throw new JavaModelException(status); 198 } 199 case IClasspathEntry.CPE_PROJECT: 200 return JavaCore.newProjectEntry(entry.getPath(), entry.getAccessRules(), entry.combineAccessRules(), entry.getExtraAttributes(), entry.isExported()); 201 case IClasspathEntry.CPE_SOURCE: 202 return JavaCore.newSourceEntry(this.destination, entry.getInclusionPatterns(), entry.getExclusionPatterns(), entry.getOutputLocation(), entry.getExtraAttributes()); 203 case IClasspathEntry.CPE_VARIABLE: 204 try { 205 return JavaCore.newVariableEntry(entry.getPath(), entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported()); 206 } catch (ClasspathEntry.AssertionFailedException e) { 207 IJavaModelStatus status = new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage()); 208 throw new JavaModelException(status); 209 } 210 default: 211 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, getElementToProcess())); 212 } 213 } 214 @Override verify()215 public IJavaModelStatus verify() { 216 IJavaModelStatus status = super.verify(); 217 if (!status.isOK()) { 218 return status; 219 } 220 PackageFragmentRoot root = (PackageFragmentRoot)getElementToProcess(); 221 if (root == null || !root.exists()) { 222 return new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, root); 223 } 224 225 IResource resource = root.resource(); 226 if (resource instanceof IFolder) { 227 if (resource.isLinked()) { 228 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_RESOURCE, root); 229 } 230 } 231 232 if ((this.updateModelFlags & IPackageFragmentRoot.DESTINATION_PROJECT_CLASSPATH) != 0) { 233 String destProjectName = this.destination.segment(0); 234 IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(destProjectName); 235 if (JavaProject.hasJavaNature(project)) { 236 try { 237 IJavaProject destProject = JavaCore.create(project); 238 IClasspathEntry[] destClasspath = destProject.getRawClasspath(); 239 boolean foundSibling = false; 240 boolean foundExistingEntry = false; 241 for (int i = 0, length = destClasspath.length; i < length; i++) { 242 IClasspathEntry entry = destClasspath[i]; 243 if (entry.equals(this.sibling)) { 244 foundSibling = true; 245 break; 246 } 247 if (entry.getPath().equals(this.destination)) { 248 foundExistingEntry = true; 249 } 250 } 251 if (this.sibling != null && !foundSibling) { 252 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, this.sibling.toString()); 253 } 254 if (foundExistingEntry && (this.updateModelFlags & IPackageFragmentRoot.REPLACE) == 0) { 255 return new JavaModelStatus( 256 IJavaModelStatusConstants.NAME_COLLISION, 257 Messages.bind(Messages.status_nameCollision, new String[] {this.destination.toString()})); 258 } 259 } catch (JavaModelException e) { 260 return e.getJavaModelStatus(); 261 } 262 } 263 } 264 265 return JavaModelStatus.VERIFIED_OK; 266 } 267 } 268