Skip to main content

This CGIT instance is deprecated, and repositories have been moved to Gitlab or Github. See the repository descriptions for specific locations.

summaryrefslogtreecommitdiffstats
blob: d794a3e431bcc8d7a8aa073772a207b8def61df3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
/*******************************************************************************
 * Copyright (c) 2001, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jem.workbench.utility;

/*
 * $RCSfile: JavaModelListener.java,v $ $Revision: 1.2 $ $Date: 2006/02/06 23:49:37 $
 */

import java.util.*;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.*;

/**
 * An element change listener to listen for Java Model changes. It breaks the notification up into individual method calls to make it easier to walk
 * the notification tree.
 * 
 * @since 1.2.0
 */
public abstract class JavaModelListener implements IElementChangedListener {

	/**
	 * Construct with listening only for {@link ElementChangedEvent#POST_CHANGE} events.
	 * 
	 * 
	 * @since 1.2.0
	 */
	public JavaModelListener() {
		this(ElementChangedEvent.POST_CHANGE);
	}

	/**
	 * Construct with supplying the type of events to listen for.
	 * 
	 * @param eventsToListen
	 *            or'd together event listening types. See {@link ElementChangedEvent} for the types.
	 * 
	 * @since 1.2.0
	 */
	public JavaModelListener(int eventsToListen) {
		JavaCore.addElementChangedListener(this, eventsToListen);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jdt.core.IElementChangedListener#elementChanged(org.eclipse.jdt.core.ElementChangedEvent)
	 */
	public void elementChanged(ElementChangedEvent event) {
		processDelta((IJavaElementDelta) event.getSource());
	}

	/**
	 * Generally dispatch the children of the delta. Normally this method should not be overridden.
	 * 
	 * @param element
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processChildren(IJavaElement element, IJavaElementDelta delta) {
		IJavaElementDelta[] children = delta.getAffectedChildren();
		for (int i = 0; i < children.length; i++) {
			processDelta(children[i]);
		}
	}

	/**
	 * Source content has changed. The default is to do nothing. Subclasses may override to perform own functions.
	 * 
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processContentChanged(IJavaElementDelta delta) {
	}

	/**
	 * Dispatch the java element delta. This method should normally not be overridden. One
	 * usage would be to add delta types that are to be processed and dispatched by the
	 * subclasses. For example also dispatch on {@link IJavaElement#IMPORT_CONTAINER}. Subclasses
	 * should call <code>super.processDelta(IJavaElementDelta)</code> if it is not one they
	 * are interested in.
	 * 
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	public void processDelta(IJavaElementDelta delta) {
		IJavaElement element = delta.getElement();

		switch (element.getElementType()) {
			case IJavaElement.JAVA_MODEL:
				processJavaElementChanged((IJavaModel) element, delta);
				break;
			case IJavaElement.JAVA_PROJECT:
				processJavaElementChanged((IJavaProject) element, delta);
				break;
			case IJavaElement.PACKAGE_FRAGMENT_ROOT:
				processJavaElementChanged((IPackageFragmentRoot) element, delta);
				break;
			case IJavaElement.PACKAGE_FRAGMENT:
				processJavaElementChanged((IPackageFragment) element, delta);
				break;
			case IJavaElement.COMPILATION_UNIT:
				processJavaElementChanged((ICompilationUnit) element, delta);
				processContentChanged(delta);
				break;
			case IJavaElement.CLASS_FILE:
				processJavaElementChanged((IClassFile) element, delta);
				break;
			case IJavaElement.TYPE:
				processJavaElementChanged((IType) element, delta);
				break;
			// Note: if we are to update the Method/Field adapters, we should process the
			// IJavaElement.METHOD and IJavaElement.FIELD
		}
	}

	/**
	 * Process the classfile changed event. The default is to do nothing. It will not walk any children of the delta either. Subclasses may override
	 * to perform their own functions.
	 * 
	 * @param element
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processJavaElementChanged(IClassFile element, IJavaElementDelta delta) {
	}

	/**
	 * Process the compilation unit changed event. The default is to process the children of the delta. Subclasses may override to perform their own
	 * functions. If they wish to walk the children they should then also call
	 * <code>super.processJavaElementChanged(ICompilationUnit, IJavaElementDelta)</code>.
	 * 
	 * @param element
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processJavaElementChanged(ICompilationUnit element, IJavaElementDelta delta) {
		processChildren(element, delta);
	}

	/**
	 * Process the java model changed event. The default is to process the children of the delta. Subclasses may override to perform their own
	 * functions. If they wish to walk the children they should then also call
	 * <code>super.processJavaElementChanged(IJavaModel, IJavaElementDelta)</code>.
	 * 
	 * @param element
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processJavaElementChanged(IJavaModel element, IJavaElementDelta delta) {
		processChildren(element, delta);
	}

	/**
	 * Process the java project changed event. The default is to process the children of the delta. Subclasses may override to perform their own
	 * functions. If they wish to walk the children they should then also call
	 * <code>super.processJavaElementChanged(IJavaProject, IJavaElementDelta)</code>.
	 * 
	 * @param element
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processJavaElementChanged(IJavaProject element, IJavaElementDelta delta) {
		processChildren(element, delta);
	}

	/**
	 * Process the package fragment changed event. The default is to process the children of the delta. Subclasses may override to perform their own
	 * functions. If they wish to walk the children they should then also call
	 * <code>super.processJavaElementChanged(IPackageFragment, IJavaElementDelta)</code>.
	 * 
	 * @param element
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processJavaElementChanged(IPackageFragment element, IJavaElementDelta delta) {
		processChildren(element, delta);
	}

	/**
	 * Process the package fragment root changed event. The default is to process the children of the delta. Subclasses may override to perform their
	 * own functions. If they wish to walk the children they should then also call
	 * <code>super.processJavaElementChanged(IPackageFragmentRoot, IJavaElementDelta)</code>.
	 * 
	 * @param element
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processJavaElementChanged(IPackageFragmentRoot element, IJavaElementDelta delta) {
		processChildren(element, delta);
	}

	/**
	 * Process the IType changed event. The default is to do nothing. It will not walk any children of the delta either. Subclasses may override to
	 * perform their own functions.
	 * 
	 * @param element
	 * @param delta
	 * 
	 * @since 1.2.0
	 */
	protected void processJavaElementChanged(IType element, IJavaElementDelta delta) {
	}

	/**
	 * Answers whether this element delta is a classpath change. I.e. something added/removed/moved around for the classpath. This should only be
	 * called for a delta that is for an {@link IPackageFragmentRoot}. Should be called from an override of
	 * {@link #processJavaElementChanged(IPackageFragmentRoot, IJavaElementDelta)}
	 * 
	 * @param delta
	 * @return <code>true</code> if it is classpath change or <code>false</code> if not.
	 * 
	 * @since 1.2.0
	 */
	protected boolean isClassPathChange(IJavaElementDelta delta) {
		int flags = delta.getFlags();
		return (delta.getKind() == IJavaElementDelta.CHANGED && ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0)
				|| ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) || ((flags & IJavaElementDelta.F_REORDER) != 0));
	}

	/**
	 * Answer whether the change is this is a raw classpath change, or if a file that is in the root of the project was changed that also can mean a
	 * raw classpath change. This must only be called for a delta that is for an {@link IJavaProject}.
	 * <p>
	 * See {@link IJavaElementDelta.#F_CLASSPATH_CHANGED} and {@link #isAlsoClasspathChange(IPath)} for details.
	 * 
	 * @param delta
	 * @return
	 * 
	 * @since 1.2.0
	 */
	protected boolean isClasspathResourceChange(IJavaElementDelta delta) {
		if ((delta.getFlags() & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0)
			return true;
		IResourceDelta[] resources = delta.getResourceDeltas();
		if (resources == null)
			return false;
		IPath path = null;
		for (int i = 0; i < resources.length; i++) {
			if (resources[i].getKind() == IResourceDelta.CHANGED) {
				path = resources[i].getProjectRelativePath();
				if (isAlsoClasspathChange(path))
					return true;
			}
		}
		return false;
	}

	/**
	 * Answers whether the file specified by the path is one that when changed can result in a classpath change. This is called from
	 * {@link #isClasspathResourceChange(IJavaElementDelta)}. The file must be in the root of the project. The default is <code>false</code>.
	 * Subclasses may override.
	 * 
	 * @param path
	 * @return <code>true</code> if this file being changed would result in a classpath change, <code>false</code> if not.
	 * 
	 * @since 1.2.0
	 */
	protected boolean isAlsoClasspathChange(IPath path) {
		return false;
	}

	/**
	 * Answers whether the given java project is in the classpath (including recursive). This currently will not walk through containers (such as the
	 * PDE container). Only through the direct and recursive project references. The java project is determined by subclasses, see
	 * {@link #getJavaProject()}.
	 * 
	 * @param javaProject
	 * @return <code>true</code> if project is in classpath or <code>false</code> if not.
	 * 
	 * @since 1.2.0
	 */
	protected boolean isInClasspath(IJavaProject javaProject) {
		IJavaProject listenerJavaProject = getJavaProject();
		if (javaProject.equals(listenerJavaProject))
			return true;
		return isInClasspath(javaProject, listenerJavaProject, true, new HashSet());
	}

	/**
	 * The java project for this listener. Subclasses must provide a java project.
	 * 
	 * @return the java project. <code>null</code> is not valid.
	 * 
	 * @since 1.2.0
	 */
	protected abstract IJavaProject getJavaProject();

	/*
	 * test to see if the testProject is in the classpath (including from any referenced projects) of the target project. Keep track of those already
	 * visited so as not to visit again. Too late to make private. But it should not be overridden.
	 */
	protected boolean isInClasspath(IJavaProject testProject, IJavaProject targetProject, boolean isFirstLevel, Set visited) {
		if (visited.contains(targetProject))
			return false;
		visited.add(targetProject);
		IClasspathEntry[] entries = null;
		try {
			entries = targetProject.getRawClasspath();
		} catch (JavaModelException e) {
			return false;
		}
		IClasspathEntry entry, resEntry;
		IJavaProject proj = null;
		List projects = null;
		for (int i = 0; i < entries.length; i++) {
			entry = entries[i];
			if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
				resEntry = JavaCore.getResolvedClasspathEntry(entry);
				proj = getJavaProject(entry);
				if (isFirstLevel || resEntry.isExported()) {
					if (proj.equals(testProject))
						return true;
					else {
						if (projects == null)
							projects = new ArrayList();
						projects.add(proj);
					}
				}
			}
		}
		return isInClasspath(testProject, projects, false, visited);
	}

	/*
	 * See if the testProject is in the classpath of any of the list of projects or in any project that an entry in the list may of visited. Too late
	 * to make private. But it should not be overridden.
	 */
	protected boolean isInClasspath(IJavaProject testProject, List someJavaProjects, boolean isFirstLevel, Set visited) {
		if (someJavaProjects == null)
			return false;
		int size = someJavaProjects.size();
		IJavaProject javaProj = null;
		for (int i = 0; i < size; i++) {
			javaProj = (IJavaProject) someJavaProjects.get(i);
			return isInClasspath(testProject, javaProj, isFirstLevel, visited);
		}
		return false;
	}

	/**
	 * Get the java project that classpath entry is for. This should only be called on classpath entries of type {@link IClasspathEntry#CPE_PROJECT}
	 * 
	 * @param entry
	 *            classpath entry of type {@link IClasspathEntry#CPE_PROJECT}.
	 * @return the java project for this entry. The project might not actually exist. That is not verified.
	 * 
	 * @since 1.2.0
	 */
	protected IJavaProject getJavaProject(IClasspathEntry entry) {
		IProject proj = getWorkspaceRoot().getProject(entry.getPath().segment(0));
		if (proj != null)
			return JavaCore.create(proj);
		return null;
	}

	/**
	 * Get the workspace root. A utility method.
	 * @return the workspace root.
	 * 
	 * @since 1.2.0
	 */
	protected IWorkspaceRoot getWorkspaceRoot() {
		return ResourcesPlugin.getWorkspace().getRoot();
	}
}

Back to the top