]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-before/ui/org/eclipse/jdt/internal/ui/text/java/ProposalSorterHandle.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / ui / org / eclipse / jdt / internal / ui / text / java / ProposalSorterHandle.java
1 /*******************************************************************************
2  * Copyright (c) 2005, 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  *     Marcel Bruch <bruch@cs.tu-darmstadt.de> - [content assist] Allow to re-sort proposals - https://bugs.eclipse.org/bugs/show_bug.cgi?id=350991
11  *******************************************************************************/
12 package org.eclipse.jdt.internal.ui.text.java;
13
14 import java.util.Collections;
15 import java.util.List;
16
17 import org.eclipse.core.runtime.Assert;
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.runtime.IConfigurationElement;
20 import org.eclipse.core.runtime.IStatus;
21 import org.eclipse.core.runtime.InvalidRegistryObjectException;
22 import org.eclipse.core.runtime.PerformanceStats;
23 import org.eclipse.core.runtime.Status;
24
25 import org.eclipse.jface.text.contentassist.ICompletionProposal;
26
27 import org.eclipse.jdt.internal.corext.util.Messages;
28
29 import org.eclipse.jdt.ui.text.java.AbstractProposalSorter;
30 import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext;
31
32 import org.eclipse.jdt.internal.ui.JavaPlugin;
33
34 /**
35  * The description of an extension to the
36  * <code>org.eclipse.jdt.ui.javaCompletionProposalSorters</code> extension point. Instances are
37  * immutable.
38  *
39  * @since 3.2
40  */
41 public final class ProposalSorterHandle {
42         /** The extension schema name of the id attribute. */
43         private static final String ID= "id"; //$NON-NLS-1$
44         /** The extension schema name of the name attribute. */
45         private static final String NAME= "name"; //$NON-NLS-1$
46         /** The extension schema name of the class attribute. */
47         private static final String CLASS= "class"; //$NON-NLS-1$
48         /** The name of the performance event used to trace extensions. */
49         private static final String PERFORMANCE_EVENT= JavaPlugin.getPluginId() + "/perf/content_assist_sorters/extensions"; //$NON-NLS-1$
50         /**
51          * If <code>true</code>, execution time of extensions is measured and extensions may be
52          * disabled if execution takes too long.
53          */
54         private static final boolean MEASURE_PERFORMANCE= PerformanceStats.isEnabled(PERFORMANCE_EVENT);
55         /** The one and only operation name. */
56         private static final String SORT= "sort"; //$NON-NLS-1$
57
58         /** The identifier of the extension. */
59         private final String fId;
60         /** The name of the extension. */
61         private final String fName;
62         /** The class name of the provided <code>AbstractProposalSorter</code>. */
63         private final String fClass;
64         /** The configuration element of this extension. */
65         private final IConfigurationElement fElement;
66         /** The computer, if instantiated, <code>null</code> otherwise. */
67         private AbstractProposalSorter fSorter;
68
69         /**
70          * Creates a new descriptor.
71          *
72          * @param element the configuration element to read
73          * @throws InvalidRegistryObjectException if the configuration element is not valid any longer
74          * @throws CoreException if the configuration does not contain mandatory attributes
75          */
76         ProposalSorterHandle(IConfigurationElement element) throws InvalidRegistryObjectException, CoreException {
77                 Assert.isLegal(element != null);
78
79                 fElement= element;
80                 fId= element.getAttribute(ID);
81                 checkNotNull(fId, ID);
82
83                 String name= element.getAttribute(NAME);
84                 if (name == null)
85                         fName= fId;
86                 else
87                         fName= name;
88
89                 fClass= element.getAttribute(CLASS);
90                 checkNotNull(fClass, CLASS);
91         }
92
93         /**
94          * Checks that the given attribute value is not <code>null</code>.
95          *
96          * @param value the value to check if not null
97          * @param attribute the attribute
98          * @throws InvalidRegistryObjectException if the registry element is no longer valid
99          * @throws CoreException if <code>value</code> is <code>null</code>
100          */
101         private void checkNotNull(Object value, String attribute) throws InvalidRegistryObjectException, CoreException {
102                 if (value == null) {
103                         Object[] args= { getId(), fElement.getContributor().getName(), attribute };
104                         String message= Messages.format(JavaTextMessages.CompletionProposalComputerDescriptor_illegal_attribute_message, args);
105                         IStatus status= new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IStatus.OK, message, null);
106                         throw new CoreException(status);
107                 }
108         }
109
110         /**
111          * Returns the identifier of the described extension.
112          *
113          * @return Returns the id
114          */
115         public String getId() {
116                 return fId;
117         }
118
119         /**
120          * Returns the name of the described extension.
121          *
122          * @return Returns the name
123          */
124         public String getName() {
125                 return fName;
126         }
127
128         /**
129          * Returns a cached instance of the sorter as described in the extension's xml. The sorter is
130          * {@link #createSorter() created} the first time that this method is called and then cached.
131          *
132          * @return a new instance of the proposal sorter as described by this descriptor
133          * @throws CoreException if the creation fails
134          * @throws InvalidRegistryObjectException if the extension is not valid any longer (e.g. due to
135          *         plug-in unloading)
136          */
137         synchronized AbstractProposalSorter getSorter() throws CoreException, InvalidRegistryObjectException {
138                 if (fSorter == null)
139                         fSorter= createSorter();
140                 return fSorter;
141         }
142
143         /**
144          * Returns a new instance of the sorter as described in the
145          * extension's xml.
146          *
147          * @return a new instance of the completion proposal computer as
148          *         described by this descriptor
149          * @throws CoreException if the creation fails
150          * @throws InvalidRegistryObjectException if the extension is not
151          *         valid any longer (e.g. due to plug-in unloading)
152          */
153         private AbstractProposalSorter createSorter() throws CoreException, InvalidRegistryObjectException {
154                 return (AbstractProposalSorter) fElement.createExecutableExtension(CLASS);
155         }
156
157         /**
158          * Safely computes completion proposals through the described extension. If the extension throws
159          * an exception or otherwise does not adhere to the contract described in
160          * {@link AbstractProposalSorter}, the list is returned as is.
161          *
162          * @param context the invocation context passed on to the extension
163          * @param proposals the list of computed completion proposals to be sorted (element type:
164          *        {@link org.eclipse.jface.text.contentassist.ICompletionProposal}), must be writable
165          */
166         public void sortProposals(ContentAssistInvocationContext context, List<ICompletionProposal> proposals) {
167                 IStatus status;
168                 try {
169                         AbstractProposalSorter sorter= getSorter();
170
171                         PerformanceStats stats= startMeter(SORT, sorter);
172
173                         sorter.beginSorting(context);
174                         Collections.sort(proposals, sorter);
175                         sorter.endSorting();
176
177                         status= stopMeter(stats, SORT);
178
179                         // valid result
180                         if (status == null)
181                                 return;
182
183                         status= createAPIViolationStatus(SORT);
184
185                 } catch (InvalidRegistryObjectException x) {
186                         status= createExceptionStatus(x);
187                 } catch (CoreException x) {
188                         status= createExceptionStatus(x);
189                 } catch (RuntimeException x) {
190                         status= createExceptionStatus(x);
191                 }
192
193                 JavaPlugin.log(status);
194                 return;
195         }
196
197         private IStatus stopMeter(final PerformanceStats stats, String operation) {
198                 if (MEASURE_PERFORMANCE) {
199                         stats.endRun();
200                         if (stats.isFailure())
201                                 return createPerformanceStatus(operation);
202                 }
203                 return null;
204         }
205
206         private PerformanceStats startMeter(String context, AbstractProposalSorter sorter) {
207                 final PerformanceStats stats;
208                 if (MEASURE_PERFORMANCE) {
209                         stats= PerformanceStats.getStats(PERFORMANCE_EVENT, sorter);
210                         stats.startRun(context);
211                 } else {
212                         stats= null;
213                 }
214                 return stats;
215         }
216
217         Status createExceptionStatus(InvalidRegistryObjectException x) {
218                 // extension has become invalid - log & disable
219                 String disable= createBlameMessage();
220                 String reason= JavaTextMessages.CompletionProposalComputerDescriptor_reason_invalid;
221                 return new Status(IStatus.INFO, JavaPlugin.getPluginId(), IStatus.OK, disable + " " + reason, x); //$NON-NLS-1$
222         }
223
224         Status createExceptionStatus(CoreException x) {
225                 // unable to instantiate the extension - log & disable
226                 String disable= createBlameMessage();
227                 String reason= JavaTextMessages.CompletionProposalComputerDescriptor_reason_instantiation;
228                 return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK, disable + " " + reason, x); //$NON-NLS-1$
229         }
230
231         Status createExceptionStatus(RuntimeException x) {
232                 // misbehaving extension - log & disable
233                 String disable= createBlameMessage();
234                 String reason= JavaTextMessages.CompletionProposalComputerDescriptor_reason_runtime_ex;
235                 return new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IStatus.OK, disable + " " + reason, x); //$NON-NLS-1$
236         }
237
238         private Status createAPIViolationStatus(String operation) {
239                 String disable= createBlameMessage();
240                 Object[] args= {operation};
241                 String reason= Messages.format(JavaTextMessages.CompletionProposalComputerDescriptor_reason_API, args);
242                 return new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IStatus.OK, disable + " " + reason, null); //$NON-NLS-1$
243         }
244
245         private Status createPerformanceStatus(String operation) {
246                 String disable= createBlameMessage();
247                 Object[] args= {operation};
248                 String reason= Messages.format(JavaTextMessages.CompletionProposalComputerDescriptor_reason_performance, args);
249                 return new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IStatus.OK, disable + " " + reason, null); //$NON-NLS-1$
250         }
251
252         private String createBlameMessage() {
253                 Object[] args= { getName(), getId() };
254                 String disable= Messages.format(JavaTextMessages.ProposalSorterHandle_blame, args);
255                 return disable;
256         }
257
258         /**
259          * Returns the error message from the described extension, <code>null</code> for no error.
260          *
261          * @return the error message from the described extension, <code>null</code> for no error
262          */
263         public String getErrorMessage() {
264                 return null;
265         }
266
267 }