1 /*******************************************************************************
2 * Copyright (c) 2007, 2011 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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.fix;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Comparator;
18 import com.ibm.icu.text.Collator;
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.layout.GridData;
22 import org.eclipse.swt.layout.GridLayout;
23 import org.eclipse.swt.widgets.Composite;
24 import org.eclipse.swt.widgets.Text;
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IConfigurationElement;
28 import org.eclipse.core.runtime.IExtensionPoint;
29 import org.eclipse.core.runtime.ISafeRunnable;
30 import org.eclipse.core.runtime.IStatus;
31 import org.eclipse.core.runtime.Platform;
32 import org.eclipse.core.runtime.SafeRunner;
33 import org.eclipse.core.runtime.Status;
35 import org.eclipse.jface.util.SafeRunnable;
37 import org.eclipse.jdt.internal.corext.util.Messages;
39 import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
40 import org.eclipse.jdt.ui.cleanup.ICleanUp;
41 import org.eclipse.jdt.ui.cleanup.ICleanUpConfigurationUI;
42 import org.eclipse.jdt.ui.cleanup.ICleanUpOptionsInitializer;
44 import org.eclipse.jdt.internal.ui.IJavaStatusConstants;
45 import org.eclipse.jdt.internal.ui.JavaPlugin;
46 import org.eclipse.jdt.internal.ui.fix.MapCleanUpOptions;
47 import org.eclipse.jdt.internal.ui.preferences.cleanup.CleanUpTabPage;
48 import org.eclipse.jdt.internal.ui.preferences.cleanup.ContributedCleanUpTabPage;
51 * The clean up registry provides a set of clean ups and there corresponding UI representatives.
55 public class CleanUpRegistry {
57 private static final class ErrorPage implements ICleanUpConfigurationUI {
59 private final Exception fException;
61 private ErrorPage(Exception e) {
65 public Composite createContents(Composite parent) {
66 Composite result= new Composite(parent, SWT.NONE);
67 result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
68 result.setLayout(new GridLayout(1, false));
70 Text text= new Text(result, SWT.MULTI | SWT.BORDER | SWT.READ_ONLY);
71 text.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
72 text.setText(Messages.format(FixMessages.CleanUpRegistry_ErrorTabPage_description, fException.getLocalizedMessage()));
77 public int getCleanUpCount() {
81 public String getPreview() {
82 return FixMessages.CleanUpRegistry_ErrorTabPage_preview;
85 public int getSelectedCleanUpCount() {
89 public void setOptions(CleanUpOptions options) {
93 public static class CleanUpTabPageDescriptor {
95 private static final String ATTRIBUTE_ID_CLASS= "class"; //$NON-NLS-1$
96 private static final String ATTRIBUTE_ID_NAME= "name"; //$NON-NLS-1$
97 private static final String ATTRIBUTE_NAME_KIND= "cleanUpKind"; //$NON-NLS-1$
99 private final String fName;
100 private final IConfigurationElement fElement;
104 * @param element the configuration element
106 public CleanUpTabPageDescriptor(IConfigurationElement element) {
108 fName= element.getAttribute(ATTRIBUTE_ID_NAME);
109 String kind= fElement.getAttribute(ATTRIBUTE_NAME_KIND);
110 fKind= getCleanUpKind(kind);
112 JavaPlugin.logErrorMessage(Messages.format(FixMessages.CleanUpRegistry_WrongKindForConfigurationUI_error, new String[] { fName, element.getContributor().getName(),
117 * @return the name of the tab
119 public String getName() {
124 * @return the kind of clean up
126 public int getKind() {
131 * @return new instance of a tab page
133 public CleanUpTabPage createTabPage() {
135 ICleanUpConfigurationUI page= (ICleanUpConfigurationUI)fElement.createExecutableExtension(ATTRIBUTE_ID_CLASS);
136 if (page instanceof CleanUpTabPage)
137 return (CleanUpTabPage)page;
139 return new ContributedCleanUpTabPage(page);
140 } catch (final CoreException e) {
142 return new ContributedCleanUpTabPage(new ErrorPage(e));
147 private static class CleanUpDescriptor {
149 private static final String ATTRIBUTE_ID_CLASS= "class"; //$NON-NLS-1$
150 private static final String ATTRIBURE_ID_RUNAFTER= "runAfter"; //$NON-NLS-1$
151 private static final String ATTRIBUTE_ID_ID= "id"; //$NON-NLS-1$
153 private final IConfigurationElement fElement;
154 private final String fId;
155 private final String fRunAfter;
158 * @param element the configuration element
160 public CleanUpDescriptor(IConfigurationElement element) {
162 fId= element.getAttribute(ATTRIBUTE_ID_ID);
163 fRunAfter= element.getAttribute(ATTRIBURE_ID_RUNAFTER);
167 * @return the unique id of this clean up
169 public String getId() {
174 * @return the id of the clean up which must run before this clean up or
175 * <strong>null</strong> if none specified
177 public String getRunAfter() {
182 * @return the clean up or <code>null</code> if the clean up could not be instantiated
184 public ICleanUp createCleanUp() {
186 return (ICleanUp)fElement.createExecutableExtension(ATTRIBUTE_ID_CLASS);
187 } catch (CoreException e) {
188 String msg= Messages.format(FixMessages.CleanUpRegistry_cleanUpCreation_error, new String[] { fElement.getAttribute(ATTRIBUTE_ID_ID), fElement.getContributor().getName() });
189 JavaPlugin.logErrorStatus(msg, e.getStatus());
195 private static final class CleanUpInitializerDescriptor {
197 private static final String ATTRIBUTE_NAME_CLASS= "class"; //$NON-NLS-1$
198 private static final String ATTRIBUTE_NAME_KIND= "cleanUpKind"; //$NON-NLS-1$
200 private final IConfigurationElement fElement;
202 private final int fKind;
204 private ICleanUpOptionsInitializer fOptionsProvider;
206 public CleanUpInitializerDescriptor(IConfigurationElement element) {
208 String kind= fElement.getAttribute(ATTRIBUTE_NAME_KIND);
209 fKind= getCleanUpKind(kind);
211 JavaPlugin.logErrorMessage(Messages.format(FixMessages.CleanUpRegistry_UnknownInitializerKind_errorMessage, new String[] { element.getContributor().getName(), kind }));
214 public int getKind() {
218 public ICleanUpOptionsInitializer getOptionsInitializer() {
219 if (fOptionsProvider == null) {
221 fOptionsProvider= (ICleanUpOptionsInitializer)fElement.createExecutableExtension(ATTRIBUTE_NAME_CLASS);
222 } catch (CoreException e) {
224 fOptionsProvider= new ICleanUpOptionsInitializer() {
225 public void setDefaultOptions(CleanUpOptions options) {
230 return fOptionsProvider;
234 private static final String EXTENSION_POINT_NAME= "cleanUps"; //$NON-NLS-1$
235 private static final String CLEAN_UP_CONFIGURATION_ELEMENT_NAME= "cleanUp"; //$NON-NLS-1$
236 private static final String TABPAGE_CONFIGURATION_ELEMENT_NAME= "cleanUpConfigurationUI"; //$NON-NLS-1$
238 private static final String CLEAN_UP_INITIALIZER_CONFIGURATION_ELEMENT_NAME= "cleanUpOptionsInitializer"; //$NON-NLS-1$
239 private static final String ATTRIBUTE_KIND_TYPE_SAVE_ACTION= "saveAction"; //$NON-NLS-1$
240 private static final String ATTRIBUTE_KIND_TYPE_CLEAN_UP= "cleanUp"; //$NON-NLS-1$
242 private CleanUpDescriptor[] fCleanUpDescriptors;
243 private CleanUpTabPageDescriptor[] fPageDescriptors;
245 private CleanUpInitializerDescriptor[] fCleanUpInitializerDescriptors;
248 * Creates and returns the registered clean ups that don't fail upon creation.
250 * @return an array of clean ups
252 public synchronized ICleanUp[] createCleanUps() {
253 return createCleanUps(null);
257 * Creates and returns the registered clean ups that don't fail upon creation.
259 * @param ids the ids of the clean ups to create, or <code>null</code> to create all
260 * @return an array of clean ups
263 public synchronized ICleanUp[] createCleanUps(Set<String> ids) {
264 ensureCleanUpsRegistered();
265 ArrayList<ICleanUp> result= new ArrayList<ICleanUp>(fCleanUpDescriptors.length);
266 for (int i= 0; i < fCleanUpDescriptors.length; i++) {
267 if (ids == null || ids.contains(fCleanUpDescriptors[i].getId())) {
268 ICleanUp cleanUp= fCleanUpDescriptors[i].createCleanUp();
273 return result.toArray(new ICleanUp[result.size()]);
277 * @param kind the kind of clean up for which to retrieve the configuratin pages
279 * @return set of clean up tab page descriptors
281 * @see CleanUpConstants#DEFAULT_CLEAN_UP_OPTIONS
282 * @see CleanUpConstants#DEFAULT_SAVE_ACTION_OPTIONS
284 public synchronized CleanUpTabPageDescriptor[] getCleanUpTabPageDescriptors(int kind) {
285 ensurePagesRegistered();
287 ArrayList<CleanUpTabPageDescriptor> result= new ArrayList<CleanUpTabPageDescriptor>();
288 for (int i= 0; i < fPageDescriptors.length; i++) {
289 if (fPageDescriptors[i].getKind() == kind)
290 result.add(fPageDescriptors[i]);
292 return result.toArray(new CleanUpTabPageDescriptor[result.size()]);
296 * Returns the default options for the specified clean up kind.
298 * @param kind the kind of clean up for which to retrieve the options
299 * @return the default options
301 * @see CleanUpConstants#DEFAULT_CLEAN_UP_OPTIONS
302 * @see CleanUpConstants#DEFAULT_SAVE_ACTION_OPTIONS
304 public MapCleanUpOptions getDefaultOptions(int kind) {
305 ensureCleanUpInitializersRegistered();
307 CleanUpOptions options= new CleanUpOptions();
308 for (int i= 0; i < fCleanUpInitializerDescriptors.length; i++) {
309 CleanUpInitializerDescriptor descriptor= fCleanUpInitializerDescriptors[i];
310 if (descriptor.getKind() == kind) {
311 descriptor.getOptionsInitializer().setDefaultOptions(options);
314 MapCleanUpOptions mapCleanUpOptions= new MapCleanUpOptions();
315 mapCleanUpOptions.addAll(options);
316 return mapCleanUpOptions;
319 private synchronized void ensureCleanUpsRegistered() {
320 if (fCleanUpDescriptors != null)
324 final ArrayList<CleanUpDescriptor> descriptors= new ArrayList<CleanUpDescriptor>();
326 IExtensionPoint point= Platform.getExtensionRegistry().getExtensionPoint(JavaPlugin.getPluginId(), EXTENSION_POINT_NAME);
327 IConfigurationElement[] elements= point.getConfigurationElements();
328 for (int i= 0; i < elements.length; i++) {
329 IConfigurationElement element= elements[i];
331 if (CLEAN_UP_CONFIGURATION_ELEMENT_NAME.equals(element.getName())) {
332 descriptors.add(new CleanUpDescriptor(element));
337 // Make sure we filter those who fail or misbehave
338 for (int i= 0; i < descriptors.size(); i++) {
339 final CleanUpDescriptor cleanUpDescriptor= descriptors.get(i);
340 final boolean disable[]= new boolean[1];
341 ISafeRunnable runnable= new SafeRunnable() {
343 public void run() throws Exception {
344 ICleanUp cleanUp= cleanUpDescriptor.createCleanUp();
348 cleanUp.setOptions(new CleanUpOptions());
349 String[] enbledSteps= cleanUp.getStepDescriptions();
350 if (enbledSteps != null && enbledSteps.length > 0) {
351 JavaPlugin.logErrorMessage(
352 Messages.format(FixMessages.CleanUpRegistry_cleanUpAlwaysEnabled_error, new String[] { cleanUpDescriptor.getId(),
353 cleanUpDescriptor.fElement.getContributor().getName() }));
359 public void handleException(Throwable t) {
361 String message= Messages.format(FixMessages.CleanUpRegistry_cleanUpCreation_error, new String[] { cleanUpDescriptor.getId(),
362 cleanUpDescriptor.fElement.getContributor().getName() });
363 IStatus status= new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, t);
364 JavaPlugin.log(status);
368 SafeRunner.run(runnable);
370 descriptors.remove(i--);
373 fCleanUpDescriptors= descriptors.toArray(new CleanUpDescriptor[descriptors.size()]);
374 sort(fCleanUpDescriptors);
378 private static void sort(CleanUpDescriptor[] data) {
381 mainLoop: for (int i= 0; i < data.length; i++) {
382 String runAfter= data[i].getRunAfter();
383 if (runAfter == null)
386 for (int j= jStart; j < data.length; j++) {
387 String jID= data[j].getId();
388 if (runAfter.equals(jID)) {
389 if (lastSwapI == i && j >= lastSwapJ) {
390 JavaPlugin.logErrorMessage("Problem reading cleanUps extensions: cannot satisfy rule for '" + data[i].getId() + "' to runAfter '" + runAfter + "'"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
400 for (int j= 0; j < jStart; j++) {
401 String jID= data[j].getId();
402 if (runAfter.equals(jID))
405 JavaPlugin.logErrorMessage("Problem reading cleanUps extensions: cannot satisfy rule for '" + data[i].getId() + "' to runAfter '" + runAfter + "' because the runAfter clean up does not exist."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
409 private static void swap(CleanUpDescriptor[] data, int i, int j) {
410 CleanUpDescriptor o= data[i];
415 private synchronized void ensurePagesRegistered() {
416 if (fPageDescriptors != null)
419 ArrayList<CleanUpTabPageDescriptor> result= new ArrayList<CleanUpTabPageDescriptor>();
421 IExtensionPoint point= Platform.getExtensionRegistry().getExtensionPoint(JavaPlugin.getPluginId(), EXTENSION_POINT_NAME);
422 IConfigurationElement[] elements= point.getConfigurationElements();
423 for (int i= 0; i < elements.length; i++) {
424 IConfigurationElement element= elements[i];
426 if (TABPAGE_CONFIGURATION_ELEMENT_NAME.equals(element.getName())) {
427 result.add(new CleanUpTabPageDescriptor(element));
431 fPageDescriptors= result.toArray(new CleanUpTabPageDescriptor[result.size()]);
432 Arrays.sort(fPageDescriptors, new Comparator<CleanUpTabPageDescriptor>() {
433 public int compare(CleanUpTabPageDescriptor o1, CleanUpTabPageDescriptor o2) {
434 String name1= o1.getName();
435 String name2= o2.getName();
436 return Collator.getInstance().compare(name1.replaceAll("&", ""), name2.replaceAll("&", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
441 private synchronized void ensureCleanUpInitializersRegistered() {
442 if (fCleanUpInitializerDescriptors != null)
445 ArrayList<CleanUpInitializerDescriptor> result= new ArrayList<CleanUpInitializerDescriptor>();
447 IExtensionPoint point= Platform.getExtensionRegistry().getExtensionPoint(JavaPlugin.getPluginId(), EXTENSION_POINT_NAME);
448 IConfigurationElement[] elements= point.getConfigurationElements();
449 for (int i= 0; i < elements.length; i++) {
450 IConfigurationElement element= elements[i];
452 if (CLEAN_UP_INITIALIZER_CONFIGURATION_ELEMENT_NAME.equals(element.getName())) {
453 result.add(new CleanUpInitializerDescriptor(element));
457 fCleanUpInitializerDescriptors= result.toArray(new CleanUpInitializerDescriptor[result.size()]);
460 private static int getCleanUpKind(String kind) {
461 if (kind.equals(ATTRIBUTE_KIND_TYPE_CLEAN_UP)) {
462 return CleanUpConstants.DEFAULT_CLEAN_UP_OPTIONS;
463 } else if (kind.equals(ATTRIBUTE_KIND_TYPE_SAVE_ACTION)) {
464 return CleanUpConstants.DEFAULT_SAVE_ACTION_OPTIONS;