]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/ui/org/eclipse/jdt/internal/ui/actions/FindBrokenNLSKeysAction.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / ui / org / eclipse / jdt / internal / ui / actions / FindBrokenNLSKeysAction.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2012 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.ui.actions;
12
13import java.util.ArrayList;
14import java.util.Collection;
15import java.util.HashMap;
16import java.util.List;
17
18import org.eclipse.core.runtime.CoreException;
19import org.eclipse.core.runtime.IPath;
20
21import org.eclipse.core.resources.IContainer;
22import org.eclipse.core.resources.IFile;
23import org.eclipse.core.resources.IFolder;
24import org.eclipse.core.resources.IResource;
25import org.eclipse.core.resources.IStorage;
26
27import org.eclipse.jface.dialogs.MessageDialog;
28import org.eclipse.jface.viewers.ISelectionProvider;
29import org.eclipse.jface.viewers.IStructuredSelection;
30import org.eclipse.jface.viewers.StructuredSelection;
31
32import org.eclipse.jface.text.ITextSelection;
33
34import org.eclipse.ui.IWorkbenchSite;
35import org.eclipse.ui.IWorkingSet;
36
37import org.eclipse.jdt.core.ICompilationUnit;
38import org.eclipse.jdt.core.IField;
39import org.eclipse.jdt.core.IImportDeclaration;
40import org.eclipse.jdt.core.IInitializer;
41import org.eclipse.jdt.core.IJavaElement;
42import org.eclipse.jdt.core.IJavaProject;
43import org.eclipse.jdt.core.IMethod;
44import org.eclipse.jdt.core.IPackageFragment;
45import org.eclipse.jdt.core.IPackageFragmentRoot;
46import org.eclipse.jdt.core.IType;
47import org.eclipse.jdt.core.JavaCore;
48import org.eclipse.jdt.core.JavaModelException;
49import org.eclipse.jdt.core.dom.Modifier;
50
51import org.eclipse.jdt.internal.corext.refactoring.nls.NLSHintHelper;
52import org.eclipse.jdt.internal.corext.refactoring.nls.NLSRefactoring;
53
54import org.eclipse.jdt.ui.IWorkingCopyManager;
55import org.eclipse.jdt.ui.actions.SelectionDispatchAction;
56
57import org.eclipse.jdt.internal.ui.JavaPlugin;
58import org.eclipse.jdt.internal.ui.browsing.LogicalPackage;
59import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
60import org.eclipse.jdt.internal.ui.refactoring.nls.search.SearchBrokenNLSKeysUtil;
61import org.eclipse.jdt.internal.ui.workingsets.IWorkingSetIDs;
62
63public class FindBrokenNLSKeysAction extends SelectionDispatchAction {
64
65 private static class SearchPatternData {
66
67 private final IType fAccessorType;
68 private final IFile fPropertyFile;
69
70 public SearchPatternData(IType accessorType, IFile propertyFile) {
71 fAccessorType= accessorType;
72 fPropertyFile= propertyFile;
73 }
74
75 public IFile getPropertyFile() {
76 return fPropertyFile;
77 }
78
79 public IType getWrapperClass() {
80 return fAccessorType;
81 }
82
83 }
84
85 //TODO: Add to API: IJavaEditorActionDefinitionIds
86 public static final String FIND_BROKEN_NLS_KEYS_ACTION_ID= "org.eclipse.jdt.ui.edit.text.java.find.broken.nls.keys"; //$NON-NLS-1$
87
88 //TODO: Add to API: JdtActionConstants
89 public static final String ACTION_HANDLER_ID= "org.eclipse.jdt.ui.actions.FindNLSProblems"; //$NON-NLS-1$
90
91 private static final String JAVA_LANG_STRING= "QString;"; //$NON-NLS-1$
92
93 private JavaEditor fEditor;
94
95 public FindBrokenNLSKeysAction(IWorkbenchSite site) {
96 super(site);
97 setText(ActionMessages.FindNLSProblemsAction_Name);
98 setToolTipText(ActionMessages.FindNLSProblemsAction_ToolTip);
99 setDescription(ActionMessages.FindNLSProblemsAction_Description);
100 }
101
102 /**
103 * Note: This constructor is for internal use only. Clients should not call this constructor.
104 * @param editor the Java editor
105 */
106 public FindBrokenNLSKeysAction(JavaEditor editor) {
107 this(editor.getEditorSite());
108 fEditor= editor;
109 setEnabled(getCompilationUnit(editor) != null);
110 }
111
112 /* (non-Javadoc)
113 * Method declared on SelectionDispatchAction.
114 */
115 @Override
116 public void run(ITextSelection selection) {
117 ISelectionProvider selectionProvider= fEditor.getSelectionProvider();
118 if (selectionProvider == null)
119 return;
120
121 run(new StructuredSelection(selectionProvider.getSelection()));
122 }
123
124 /* (non-Javadoc)
125 * Method declared on SelectionDispatchAction.
126 */
127 @Override
128 public void run(IStructuredSelection selection) {
129 if (selection.size() == 1) {
130 Object firstElement= selection.getFirstElement();
131 if (firstElement instanceof IJavaElement) {
132 IJavaElement javaElement= (IJavaElement) firstElement;
133 if (!ActionUtil.isProcessable(getShell(), javaElement)) {
134 return;
135 }
136 }
137 }
138
139 SearchPatternData[] data= getNLSFiles(selection);
140 if (data == null || data.length == 0) {
141 MessageDialog.openInformation(getShell(), ActionMessages.FindNLSProblemsAction_ErrorDialogTitle, ActionMessages.FindNLSProblemsAction_NoPropertieFilesFoundErrorDescription);
142 return;
143 }
144
145 String scope= "workspace"; //$NON-NLS-1$
146 if (selection.size() == 1) {
147 Object firstElement= selection.getFirstElement();
148 if (firstElement instanceof IJavaElement) {
149 scope= ((IJavaElement)firstElement).getElementName();
150 } else if (firstElement instanceof IFile) {
151 scope= ((IFile)firstElement).getName();
152 } else if (firstElement instanceof IFolder) {
153 scope= ((IFolder)firstElement).getName();
154 }
155 }
156 run(data, scope);
157 }
158
159 private void run(SearchPatternData[] data, String scope) {
160 List<IType> wrappers= new ArrayList<IType>();
161 List<IFile> properties= new ArrayList<IFile>();
162 for (int i= 0; i < data.length; i++) {
163 SearchPatternData current= data[i];
164 if (current.getWrapperClass() != null || current.getPropertyFile() != null) {
165 wrappers.add(current.getWrapperClass());
166 properties.add(current.getPropertyFile());
167 }
168 }
169 IType[] accessorClasses= wrappers.toArray(new IType[wrappers.size()]);
170 IFile[] propertieFiles= properties.toArray(new IFile[properties.size()]);
171 SearchBrokenNLSKeysUtil.search(scope, accessorClasses, propertieFiles);
172 }
173
174 /* (non-Javadoc)
175 * Method declared on SelectionDispatchAction.
176 */
177 @Override
178 public void selectionChanged(ITextSelection selection) {
179 ISelectionProvider selectionProvider= fEditor.getSelectionProvider();
180 if (selectionProvider == null) {
181 setEnabled(false);
182 } else {
183 selectionChanged(new StructuredSelection(selectionProvider.getSelection()));
184 }
185 }
186
187 /* (non-Javadoc)
188 * Method declared on SelectionDispatchAction.
189 */
190 @Override
191 public void selectionChanged(IStructuredSelection selection) {
192 setEnabled(canEnable(selection));
193 }
194
195 private SearchPatternData[] getNLSFiles(IStructuredSelection selection) {
196 Object[] selectedElements= selection.toArray();
197 HashMap<IType, SearchPatternData> result= new HashMap<IType, SearchPatternData>();
198
199 collectNLSFilesFromResources(selectedElements, result);
200 collectNLSFilesFromJavaElements(selectedElements, result);
201
202 Collection<SearchPatternData> values= result.values();
203 return values.toArray(new SearchPatternData[values.size()]);
204 }
205
206 private boolean canEnable(IStructuredSelection selection) {
207 Object[] selected= selection.toArray();
208 for (int i= 0; i < selected.length; i++) {
209 try {
210 if (selected[i] instanceof IJavaElement) {
211 IJavaElement elem= (IJavaElement) selected[i];
212 if (elem.exists()) {
213 switch (elem.getElementType()) {
214 case IJavaElement.TYPE:
215 if (elem.getParent().getElementType() == IJavaElement.COMPILATION_UNIT) {
216 return true;
217 }
218 return false;
219 case IJavaElement.COMPILATION_UNIT:
220 return true;
221 case IJavaElement.IMPORT_CONTAINER:
222 return false;
223 case IJavaElement.PACKAGE_FRAGMENT:
224 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
225 IPackageFragmentRoot root= (IPackageFragmentRoot) elem.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
226 return (root.getKind() == IPackageFragmentRoot.K_SOURCE);
227 case IJavaElement.JAVA_PROJECT:
228 return true;
229 }
230 }
231 } else if (selected[i] instanceof LogicalPackage) {
232 return true;
233 } else if (selected[i] instanceof IFile) {
234 IFile file= (IFile)selected[i];
235 if ("properties".equalsIgnoreCase(file.getFileExtension())) //$NON-NLS-1$
236 return true;
237 } else if (selected[i] instanceof IWorkingSet) {
238 IWorkingSet workingSet= (IWorkingSet) selected[i];
239 return IWorkingSetIDs.JAVA.equals(workingSet.getId());
240 }
241 } catch (JavaModelException e) {
242 if (!e.isDoesNotExist()) {
243 JavaPlugin.log(e);
244 }
245 }
246 }
247 return false;
248 }
249
250 private void collectNLSFilesFromResources(Object[] objects, HashMap<IType, SearchPatternData> result) {
251 try {
252 for (int i= 0; i < objects.length; i++) {
253 Object object= objects[i];
254
255 IResource resource= null;
256 if (object instanceof IWorkingSet) {
257 IWorkingSet workingSet= (IWorkingSet) object;
258 collectNLSFilesFromResources(workingSet.getElements(), result);
259 } else if (object instanceof IJavaElement) {
260 resource= ((IJavaElement) object).getCorrespondingResource();
261 } else if (object instanceof IResource) {
262 resource= (IResource) object;
263 } else if (object instanceof LogicalPackage) {
264 LogicalPackage logicalPackage= (LogicalPackage)object;
265 resource= logicalPackage.getJavaProject().getProject();
266 }
267
268 if (resource instanceof IContainer) {
269 collectNLSFilesFromResources(((IContainer)resource).members(), result);
270 } else if (resource instanceof IFile) {
271 SearchPatternData data= tryIfPropertyFileSelected((IFile) resource);
272 if (data != null && !result.containsKey(data.fAccessorType)) {
273 result.put(data.fAccessorType, data);
274 }
275 }
276 }
277 } catch (JavaModelException e) {
278 if (!e.isDoesNotExist()) {
279 JavaPlugin.log(e);
280 }
281 } catch (CoreException e) {
282 JavaPlugin.log(e);
283 }
284 }
285
286 private void collectNLSFilesFromJavaElements(Object[] objects, HashMap<IType, SearchPatternData> result) {
287 try {
288 for (int i= 0; i < objects.length; i++) {
289 if (objects[i] instanceof IJavaElement) {
290 IJavaElement elem= (IJavaElement) objects[i];
291 if (elem.exists()) {
292 switch (elem.getElementType()) {
293 case IJavaElement.TYPE:
294 if (elem.getParent().getElementType() == IJavaElement.COMPILATION_UNIT) {
295 ICompilationUnit unit= (ICompilationUnit)elem.getParent();
296 IType[] types= unit.getTypes();
297 if (types.length > 0 && !result.containsKey(types[0])) {
298 SearchPatternData data= tryIfPropertyCuSelected(unit);
299 if (data != null)
300 result.put(data.fAccessorType, data);
301 }
302 }
303 break;
304 case IJavaElement.COMPILATION_UNIT:
305 ICompilationUnit unit= (ICompilationUnit)elem;
306 IType[] types= unit.getTypes();
307 if (types.length > 0 && !result.containsKey(types[0])) {
308 SearchPatternData data= tryIfPropertyCuSelected(unit);
309 if (data != null)
310 result.put(data.fAccessorType, data);
311 }
312 break;
313 case IJavaElement.PACKAGE_FRAGMENT:
314 IPackageFragment fragment= (IPackageFragment)elem;
315 if (fragment.getKind() == IPackageFragmentRoot.K_SOURCE)
316 collectNLSFilesFromJavaElements(fragment.getChildren(), result);
317 break;
318 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
319 {
320 IPackageFragmentRoot root= (IPackageFragmentRoot) elem;
321 if (root.getKind() == IPackageFragmentRoot.K_SOURCE)
322 collectNLSFilesFromJavaElements(root.getChildren(), result);
323 break;
324 }
325 case IJavaElement.JAVA_PROJECT:
326 {
327 IJavaProject javaProject= (IJavaProject)elem;
328 IPackageFragmentRoot[] allPackageFragmentRoots= javaProject.getAllPackageFragmentRoots();
329 for (int j= 0; j < allPackageFragmentRoots.length; j++) {
330 IPackageFragmentRoot root= allPackageFragmentRoots[j];
331 if (root.getKind() == IPackageFragmentRoot.K_SOURCE) {
332 if (javaProject.equals(root.getJavaProject())) {
333 collectNLSFilesFromJavaElements(new Object[] {root}, result);
334 }
335 }
336 }
337 break;
338 }
339 }
340 }
341 } else if (objects[i] instanceof LogicalPackage) {
342 LogicalPackage logicalPackage= (LogicalPackage)objects[i];
343 collectNLSFilesFromJavaElements(new Object[] {logicalPackage.getJavaProject()}, result);
344 } else if (objects[i] instanceof IWorkingSet) {
345 IWorkingSet workingSet= (IWorkingSet) objects[i];
346 collectNLSFilesFromJavaElements(workingSet.getElements(), result);
347 }
348 }
349 } catch (JavaModelException e) {
350 if (!e.isDoesNotExist()) {
351 JavaPlugin.log(e);
352 }
353 }
354 }
355
356 private SearchPatternData tryIfPropertyCuSelected(ICompilationUnit compilationUnit) throws JavaModelException {
357 IStorage bundle= getResourceBundle(compilationUnit);
358 if (!(bundle instanceof IFile))
359 return null;
360
361 return new SearchPatternData(compilationUnit.getTypes()[0], (IFile) bundle);
362 }
363
364 public static IStorage getResourceBundle(ICompilationUnit compilationUnit) throws JavaModelException {
365 if (compilationUnit == null)
366 return null;
367
368 if (!ActionUtil.isOnBuildPath(compilationUnit))
369 return null;
370
371 IType[] types= compilationUnit.getTypes();
372 if (types.length != 1)
373 return null;
374
375 if (!isPotentialNLSAccessor(compilationUnit))
376 return null;
377
378 return NLSHintHelper.getResourceBundle(compilationUnit);
379 }
380
381 /*
382 * Be conservative, for every unit this returns true an AST will to be created!
383 */
384 private static boolean isPotentialNLSAccessor(ICompilationUnit unit) throws JavaModelException {
385 IType type= unit.getTypes()[0];
386 if (!type.exists())
387 return false;
388
389 IField bundleNameField= getBundleNameField(type.getFields());
390 if (bundleNameField == null)
391 return false;
392
393 if (importsOSGIUtil(unit)) { //new school
394 IInitializer[] initializers= type.getInitializers();
395 for (int i= 0; i < initializers.length; i++) {
396 if (Modifier.isStatic(initializers[0].getFlags()))
397 return true;
398 }
399 } else { //old school
400 IMethod[] methods= type.getMethods();
401 for (int i= 0; i < methods.length; i++) {
402 IMethod method= methods[i];
403 if (isValueAccessor(method))
404 return true;
405 }
406 }
407
408 return false;
409 }
410
411 private static boolean importsOSGIUtil(ICompilationUnit unit) throws JavaModelException {
412 IImportDeclaration[] imports= unit.getImports();
413 for (int i= 0; i < imports.length; i++) {
414 if (imports[i].getElementName().startsWith("org.eclipse.osgi.util.")) //$NON-NLS-1$
415 return true;
416 }
417
418 return false;
419 }
420
421 private static boolean isValueAccessor(IMethod method) throws JavaModelException {
422 if (!"getString".equals(method.getElementName())) //$NON-NLS-1$
423 return false;
424
425 int flags= method.getFlags();
426 if (!Modifier.isStatic(flags) || !Modifier.isPublic(flags))
427 return false;
428
429 String returnType= method.getReturnType();
430 if (!JAVA_LANG_STRING.equals(returnType))
431 return false;
432
433 String[] parameters= method.getParameterTypes();
434 if (parameters.length != 1 || !JAVA_LANG_STRING.equals(parameters[0]))
435 return false;
436
437 return true;
438 }
439
440 private static IField getBundleNameField(IField[] fields) {
441 for (int i= 0; i < fields.length; i++) {
442 if ("BUNDLE_NAME".equals(fields[i].getElementName())) //$NON-NLS-1$
443 return fields[i];
444 }
445
446 return null;
447 }
448
449 private SearchPatternData tryIfPropertyFileSelected(IFile file) {
450 IType accessorType= getAccessorType(file);
451 return (accessorType != null) ? new SearchPatternData(accessorType, file) : null;
452 }
453
454 public static IType getAccessorType(IFile file) {
455 if (!"properties".equalsIgnoreCase(file.getFileExtension())) //$NON-NLS-1$
456 return null;
457
458 IPath propertyFullPath= file.getFullPath();
459 // Try to find a corresponding CU
460 String[] javaExtensions= JavaCore.getJavaLikeExtensions();
461 for (int i= 0; i < javaExtensions.length; i++) {
462 String extension= javaExtensions[i];
463 IPath cuPath= propertyFullPath.removeFileExtension().addFileExtension(extension);
464 IFile cuFile= (IFile)JavaPlugin.getWorkspace().getRoot().findMember(cuPath);
465
466 if (cuFile == null) { //try with uppercase first char
467 String filename= cuPath.removeFileExtension().lastSegment();
468 if (filename != null && filename.length() > 0) {
469 filename= Character.toUpperCase(filename.charAt(0)) + filename.substring(1);
470 IPath dirPath= propertyFullPath.removeLastSegments(1).addTrailingSeparator();
471 cuPath= dirPath.append(filename).addFileExtension(extension);
472 cuFile= (IFile)JavaPlugin.getWorkspace().getRoot().findMember(cuPath);
473 }
474 }
475
476 if (cuFile != null && cuFile.exists()) {
477 IJavaElement element= JavaCore.create(cuFile);
478 if (element != null && element.exists() && element.getElementType() == IJavaElement.COMPILATION_UNIT && ActionUtil.isOnBuildPath(element)) {
479 ICompilationUnit compilationUnit= (ICompilationUnit)element;
480 IType type= compilationUnit.findPrimaryType();
481 if (type != null) {
482 String resourceBundleName= NLSHintHelper.getResourceBundleName(compilationUnit);
483 if (resourceBundleName != null) {
484 String resourceName= resourceBundleName + NLSRefactoring.PROPERTY_FILE_EXT;
485 String name= file.getName();
486 if (resourceName.endsWith(name)) {
487 return type;
488 }
489 }
490 }
491 }
492 }
493 }
494
495 return null;
496 }
497
498 private static ICompilationUnit getCompilationUnit(JavaEditor editor) {
499 IWorkingCopyManager manager= JavaPlugin.getDefault().getWorkingCopyManager();
500 ICompilationUnit cu= manager.getWorkingCopy(editor.getEditorInput());
501 return cu;
502 }
503
504}