1 /******************************************************************************* 2 * Copyright (c) 2000, 2012 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.debug.core.refactoring; 15 16 import java.util.ArrayList; 17 import java.util.List; 18 19 import org.eclipse.core.resources.IFile; 20 import org.eclipse.core.runtime.CoreException; 21 import org.eclipse.debug.core.DebugPlugin; 22 import org.eclipse.debug.core.ILaunchConfiguration; 23 import org.eclipse.jdt.core.IJavaElement; 24 import org.eclipse.jdt.core.IJavaProject; 25 import org.eclipse.jdt.core.IPackageFragment; 26 import org.eclipse.jdt.core.IPackageFragmentRoot; 27 import org.eclipse.jdt.core.IType; 28 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; 29 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; 30 import org.eclipse.ltk.core.refactoring.Change; 31 import org.eclipse.ltk.core.refactoring.CompositeChange; 32 33 /** 34 * 35 * provides methods to create refactoring changes 36 */ 37 public class JDTDebugRefactoringUtil { 38 39 /** 40 * Take a list of Changes, and return a unique Change, a CompositeChange, or null. 41 */ createChangeFromList(List<Change> changes, String changeLabel)42 public static Change createChangeFromList(List<Change> changes, String changeLabel) { 43 int nbChanges= changes.size(); 44 switch (nbChanges) { 45 case 0: 46 return null; 47 case 1: 48 return changes.get(0); 49 default: 50 return new CompositeChange(changeLabel, changes.toArray(new Change[changes.size()])); 51 } 52 } 53 54 /** 55 * Returns the new container name for the given project and launch configuration 56 * @param javaProject the java to get the new container name for 57 * @param launchConfiguration the associated launch configuration 58 * @return the new container name 59 * @since 3.2 60 */ computeNewContainerName(ILaunchConfiguration launchConfiguration)61 protected static String computeNewContainerName(ILaunchConfiguration launchConfiguration) { 62 IFile file = launchConfiguration.getFile(); 63 if (file != null) { 64 return file.getParent().getProjectRelativePath().toString(); 65 } 66 return null; 67 } 68 69 /** 70 * Returns a change for the given launch configuration if the launch configuration needs to 71 * be updated for this IType change. It specifically looks to see if the main type of the launch configuration 72 * is an inner type of the given IType. 73 * @param config the launch configuration 74 * @param type the type to check for 75 * @param newfqname the new fully qualified name 76 * @param pname the new project name 77 * @return the <code>Change</code> for this outer type 78 * @throws CoreException 79 * @since 3.2 80 */ createChangesForOuterTypeChange(ILaunchConfiguration config, IType type, String newfqname, String pname)81 protected static Change createChangesForOuterTypeChange(ILaunchConfiguration config, IType type, String newfqname, String pname) throws CoreException { 82 IType[] innerTypes = type.getTypes(); 83 if(innerTypes.length == 0) { 84 return null; 85 } 86 Change change = null; 87 String mtname = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, (String)null); 88 for (int i= 0; i < innerTypes.length; i++) { 89 String newTypeName = newfqname + '$' + innerTypes[i].getElementName(); 90 // if it matches, check the type 91 if (innerTypes[i].getFullyQualifiedName().equals(mtname)) { 92 return new LaunchConfigurationProjectMainTypeChange(config, newTypeName, pname); 93 } 94 // if it's not the type, check the inner types 95 change = createChangesForOuterTypeChange(config, innerTypes[i], newTypeName, pname); 96 } 97 return change; 98 } 99 100 /** 101 * Provides a public mechanism for creating the <code>Change</code> for moving a package 102 * @param packageFragment the fragment to move 103 * @param destination the destination to move it to 104 * @return the <code>Change</code> for moving the package 105 * @throws CoreException 106 * @since 3.2 107 */ createChangesForPackageMove(IPackageFragment pfragment, IPackageFragmentRoot destination)108 public static Change createChangesForPackageMove(IPackageFragment pfragment, IPackageFragmentRoot destination) throws CoreException { 109 List<Change> changes = new ArrayList<>(); 110 ILaunchConfiguration[] configs = getJavaTypeLaunchConfigurations(pfragment.getJavaProject().getElementName()); 111 String mtname = null; 112 for (int i= 0; i < configs.length; i++) { 113 mtname = configs[i].getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, (String)null); 114 if(mtname != null) { 115 if(mtname.lastIndexOf(pfragment.getElementName()) > -1) { 116 changes.add(new LaunchConfigurationProjectMainTypeChange(configs[i], null, destination.getJavaProject().getElementName())); 117 } 118 } 119 } 120 return JDTDebugRefactoringUtil.createChangeFromList(changes, RefactoringMessages.LaunchConfigurationProjectMainTypeChange_7); 121 } 122 123 /** 124 * Provides a public mechanism for creating the <code>Change</code> for renaming a package 125 * @param packageFragment the fragment to rename 126 * @param newName the new name for the fragment 127 * @return the Change for the renaming 128 * @throws CoreException 129 * @since 3.2 130 */ createChangesForPackageRename(IPackageFragment pfragment, String newname)131 public static Change createChangesForPackageRename(IPackageFragment pfragment, String newname) throws CoreException { 132 List<Change> changes = new ArrayList<>(); 133 ILaunchConfiguration[] configs = getJavaTypeLaunchConfigurations(pfragment.getJavaProject().getElementName()); 134 String mtname; 135 for (int i= 0; i < configs.length; i++) { 136 mtname = configs[i].getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, (String)null); 137 if(mtname != null) { 138 String pkname = ""; //$NON-NLS-1$ 139 int index = mtname.lastIndexOf('.'); 140 if(index > 0) { 141 pkname = mtname.substring(0, index); 142 } 143 if (pfragment.getElementName().equals(pkname)) { 144 String ntname = newname + '.' + mtname.substring(index + 1); 145 changes.add(new LaunchConfigurationProjectMainTypeChange(configs[i], ntname, null)); 146 } 147 } 148 else { 149 changes.add(new LaunchConfigurationProjectMainTypeChange(configs[i], null, null)); 150 } 151 } 152 return JDTDebugRefactoringUtil.createChangeFromList(changes, RefactoringMessages.LaunchConfigurationProjectMainTypeChange_7); 153 } 154 155 /** 156 * Provides a public mechanism for creating the <code>Change</code> for renaming a project 157 * @param javaProject the project to rename 158 * @param newProjectName the new name for the project 159 * @return the Change for the project rename 160 * @throws CoreException 161 * @since 3.2 162 */ createChangesForProjectRename(IJavaProject project, String newname)163 public static Change createChangesForProjectRename(IJavaProject project, String newname) throws CoreException { 164 List<Change> changes = new ArrayList<>(); 165 ILaunchConfiguration[] configs = getJavaTypeLaunchConfigurations(project.getElementName()); 166 LaunchConfigurationProjectMainTypeChange change = null; 167 for (int i= 0; i < configs.length; i++) { 168 change = new LaunchConfigurationProjectMainTypeChange(configs[i], null, newname); 169 String newcname = computeNewContainerName(configs[i]); 170 if (newcname != null) { 171 change.setNewContainerName(newcname); 172 } 173 changes.add(change); 174 } 175 return JDTDebugRefactoringUtil.createChangeFromList(changes, RefactoringMessages.LaunchConfigurationProjectMainTypeChange_7); 176 } 177 178 /** 179 * Creates a <code>Change</code> for a type change 180 * @param type the type that is changing 181 * @param newfqname the new fully qualified name 182 * @param pname the project name 183 * @return the <code>Change</code> for changing the specified type 184 * @throws CoreException 185 * @since 3.2 186 */ createChangesForTypeChange(IType type, String newfqname, String pname)187 protected static Change createChangesForTypeChange(IType type, String newfqname, String pname) throws CoreException { 188 List<Change> changes = new ArrayList<>(); 189 String typename = type.getFullyQualifiedName(); 190 ILaunchConfiguration[] configs = getJavaTypeLaunchConfigurations(type.getJavaProject().getElementName()); 191 String mtname; 192 for (int i= 0; i < configs.length; i++) { 193 mtname = configs[i].getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, (String)null); 194 if (typename.equals(mtname)) { 195 changes.add(new LaunchConfigurationProjectMainTypeChange(configs[i], newfqname, pname)); 196 } 197 else { 198 Change change = createChangesForOuterTypeChange(configs[i], type, newfqname, pname); 199 if (change != null) { 200 changes.add(change); 201 } 202 } 203 } 204 return JDTDebugRefactoringUtil.createChangeFromList(changes, RefactoringMessages.LaunchConfigurationProjectMainTypeChange_7); 205 } 206 207 /** 208 * Provides a public mechanism for creating the <code>Change</code> for moving a type 209 * @param type the type being moved 210 * @param destination the destination to move the type to 211 * @return the <code>Change</code> for the type move 212 * @throws CoreException 213 * @since 3.2 214 */ createChangesForTypeMove(IType type, IJavaElement destination)215 public static Change createChangesForTypeMove(IType type, IJavaElement destination) throws CoreException { 216 IJavaProject pdestination = destination.getJavaProject(); 217 String newpname = null; 218 if (!type.getJavaProject().equals(pdestination)) { 219 newpname = pdestination.getElementName(); 220 } 221 String newfqname = type.getElementName(); 222 if (destination instanceof IType) { 223 newfqname = ((IType)destination).getFullyQualifiedName() + '$' + type.getElementName(); 224 } 225 else if (destination instanceof IPackageFragment) { 226 if (!((IPackageFragment) destination).isDefaultPackage()) { 227 newfqname = destination.getElementName() + '.' + type.getElementName(); 228 } 229 } 230 return createChangesForTypeChange(type, newfqname, newpname); 231 } 232 233 /** 234 * Provides a public mechanism for creating the <code>Change</code> for renaming a type 235 * @param type the type to rename 236 * @param newname the new name for the type 237 * @return the <code>Change</code> for the type rename 238 * @throws CoreException 239 * @since 3.2 240 */ createChangesForTypeRename(IType type, String newname)241 public static Change createChangesForTypeRename(IType type, String newname) throws CoreException { 242 IType dtype = type.getDeclaringType(); 243 String newfqname = newname; 244 if (dtype == null) { 245 IPackageFragment packageFragment = type.getPackageFragment(); 246 if (!packageFragment.isDefaultPackage()) { 247 newfqname = packageFragment.getElementName() + '.' + newname; 248 } 249 } 250 else { 251 newfqname = dtype.getFullyQualifiedName() + '$' + newname; 252 } 253 return createChangesForTypeChange(type, newfqname, null); 254 } 255 256 /** 257 * Returns a listing of configurations that have a specific project name attribute in them 258 * @param pname the project attribute to compare against 259 * @return the list of java type launch configurations that have the specified project attribute 260 * @since 3.2 261 */ getJavaTypeLaunchConfigurations(String pname)262 protected static ILaunchConfiguration[] getJavaTypeLaunchConfigurations(String pname) { 263 try { 264 ILaunchConfiguration[] configs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(); 265 ArrayList<ILaunchConfiguration> list = new ArrayList<>(); 266 String attrib; 267 for(int i = 0; i < configs.length; i++) { 268 attrib = configs[i].getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null); 269 if(attrib != null) { 270 if(attrib.equals(pname)) { 271 list.add(configs[i]); 272 } 273 } 274 } 275 return list.toArray(new ILaunchConfiguration[list.size()]); 276 } 277 catch(CoreException e) {JDIDebugPlugin.log(e);} 278 return new ILaunchConfiguration[0]; 279 } 280 281 } 282