Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 3ef5323a67e3c748d3dcc10c1d1132c373565b6e (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
/***************************************************************************************************
 * Copyright (c) 2005, 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.jst.jsf.facesconfig.util;

import java.util.LinkedList;
import java.util.ListIterator;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.ISaveContext;
import org.eclipse.core.resources.ISaveParticipant;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jst.jsf.facesconfig.FacesConfigPlugin;
import org.eclipse.jst.jsf.facesconfig.internal.Logger;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wst.common.componentcore.internal.util.ComponentUtilities;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;

/**
 * This class is responsible for the following:
 * <ol>
 * <li>Ensure that the Struts nature is added to any project to which a Struts
 * config. file is added.</li>
 * <li>Ensure that the Struts nature is added to any project to which a diagram
 * file is added.</li>
 * <li>Restart project(s) if/as apporopriate when a Struts config. file is
 * modified.
 * </ol>
 * It arguably should be multiple classes, but the things it does are closely
 * related and splitting it up would result in duplicate work as well as
 * multiple delta traversals.
 * 
 * This class is not intended for external use. 
 * Should NOT be referenced or extended externally.
 */
final class FacesResourceChangeListener implements IResourceChangeListener,
		IResourceDeltaVisitor, ISaveParticipant, IResourceVisitor {

	/** The singleton instance. */
	private static FacesResourceChangeListener listener;
	private static boolean restartInProgress = false;
	private LinkedList facesConfigChangeListeners = new LinkedList();
	
	private static IPreferenceStore preferenceStore = null;

	private static final QualifiedName EDITOR_KEY = new QualifiedName(
			"org.eclipse.ui.internal.registry.ResourceEditorRegistry", "EditorProperty");//$NON-NLS-2$//$NON-NLS-1$

	/** Start up the singleton instance. */
	public static void startup() {

		// Bail if we're already started.
		if (listener != null)
			return;

		// Create the singleton instance.
		listener = new FacesResourceChangeListener();

		// Register as resource change listener.
		ResourcesPlugin.getWorkspace().addResourceChangeListener(
				listener,
				IResourceChangeEvent.PRE_BUILD + IResourceChangeEvent.POST_BUILD);
	}

	/** Shutdown the singleton instance. */
	public static void shutdown() {

		// Bail if we're not started.
		if (listener == null)
			return;

		// Deregister as save participant.
		ResourcesPlugin.getWorkspace().removeSaveParticipant(FacesConfigPlugin.getPlugin());

		// Deregister as resource change listener.
		ResourcesPlugin.getWorkspace().removeResourceChangeListener(listener);

		// Dereference the singleton instance.
		listener = null;
	}

	/**
	 * Only this class can create instances.
	 */
	private FacesResourceChangeListener() {
        // no local instantiation
	}

	/**
	 * Process a resource change event. This should be invoked only from the
	 * workbench.
	 * 
	 * @see IResourceChangeListener#resourceChanged(IResourceChangeEvent)
	 */
	public void resourceChanged(IResourceChangeEvent event) {

		IResourceDelta delta = event.getDelta();
		if (delta != null) {
			FacesConfigChangeEvent facesConfigChangeEvent = new FacesConfigChangeEvent();
			fireFacesConfigChangeEvent(facesConfigChangeEvent);

			try {
				delta.accept(this);
			} catch (CoreException ignored) {
				Logger.log(this, ignored);
			}
		}

		// Restart projects, if necessary.
		if ((delta != null) && (event.getType() == IResourceChangeEvent.POST_BUILD)) {
			FacesConfigRestartServerResourceDeltaVisitor visitor = new FacesConfigRestartServerResourceDeltaVisitor();
			try {
				delta.accept(visitor);
			} catch (CoreException ignored) {
				Logger.log(this, ignored);
			}
			//restartComponents(visitor.getComponents());
		}
	}

	/**
	 * Visit a resource delta. This should be invoked only from the
	 * IResourceDelta.accept() method invoked above.
	 * 
	 * @see IResourceDeltaVisitor#visit(IResourceDelta)
	 */
	public boolean visit(IResourceDelta delta) throws CoreException {

		// Check for and handle it if it's a Struts config. file.
		checkForFacesConfigFile(delta);

		// Done.
		return true;
	}

	private void checkForFacesConfigFile(IResourceDelta delta) {
		boolean isAdded = delta.getKind() == IResourceDelta.ADDED;
		if (isAdded
				|| ((delta.getKind() == IResourceDelta.CHANGED) && ((delta.getFlags() & (IResourceDelta.CONTENT
						| IResourceDelta.TYPE | IResourceDelta.SYNC | IResourceDelta.REPLACED)) != 0))) {
			checkForFacesConfigFile(delta.getResource(), !isAdded);
		}
	}

	private void checkForFacesConfigFile(IResource resource, boolean ignoreNonFacesProjects) {
		if (resource.getType() == IResource.FILE) {

			// See if the file is a Struts config. file.
			// If the file was just added, we check the file regardless of
			// whether or not it is in a Struts project.
			// Otherwise, a file in a non-Struts project is considered to not be
			// a Struts config. file.
			IFile file = (IFile) resource;
			if (FacesConfigUtil.isFacesConfigFile(file, ignoreNonFacesProjects)) {

				// Ensure that the project has the Struts nature.
				// TODO:
				// StrutsNatureRuntime.ensureProjectHasStrutsNature(file.getProject());
				IVirtualComponent component = ComponentUtilities.findComponent(file);
				if (component != null) {
					restartServerIfNecessary(component);
					// Try to register the SCFE as the default editor.
					setRegistration(file);
				}
			} else {
				// Try to unregister the SCFE as the default editor.
				unsetRegistration(file);
			}
		}
	}

	/**
	 * Look to see if the persisted resource level property keyed by EDITOR_KEY
	 * has ben set yet. If not then set it to the SCFE.
	 * 
	 * @param file
	 *            The FCF
	 */
	private void setRegistration(IFile file) {
		String editorID = null;
		try {
			editorID = file.getPersistentProperty(EDITOR_KEY);
		} catch (CoreException e) {
            // suppress core exception
		}
		if (editorID == null) {
			try {
				file.setPersistentProperty(EDITOR_KEY, FacesConfigPlugin.FACES_CONFIG_EDITOR_ID);
			} catch (CoreException e) {
				Logger.log(file, "Failed to set the vcurrent editor to SCFE", e);
			}
		}
	}

	private void unsetRegistration(IFile file) {
		// If the default editor for this file is not the Struts config. editor,
		// then we're done.
		IEditorRegistry registry = PlatformUI.getWorkbench().getEditorRegistry();
		IEditorDescriptor userEditor = registry.getDefaultEditor(file.getFullPath().toString());
		if ((userEditor == null)
				|| !FacesConfigPlugin.FACES_CONFIG_EDITOR_ID.equals(userEditor.getId())) {
			traceFiner(file, "Not unsetting: Default already not Faces config. editor");
			return;
		}

		// Make the Struts config. editor the default.
		traceFiner(file, "Unsetting.");
		IEditorDescriptor[] editors = registry.getEditors(file.getFullPath().toString());
		if (editors.length > 1) {
			registry.setDefaultEditor(file.getFullPath().toString(), editors[1].getId());
		}
	}

	//private boolean isRestarting = false;
	//private Collection restartableComponents = new HashSet();

/*	private void restartComponents(Collection components) {
		restartableComponents.addAll(components);
		if (!isRestarting) {
			isRestarting = true;
			try {
				while (!restartableComponents.isEmpty()) {
					IVirtualComponent component = (IVirtualComponent) restartableComponents.iterator().next();
					try {
						ServerRestartUtil.restartComponent(component, true);
					} finally {
						restartableComponents.remove(component);
					}
				}
			} finally {
				isRestarting = false;
			}

		}
	}

*/	private void traceFiner(IFile file, String message) {
		String fileName = file.getProjectRelativePath().toString();
		Logger.trace("FacesconfigPlugin", this, fileName + ": " + message);
	}

	/** @see ISaveParticipant#doneSaving(ISaveContext) */
	public void doneSaving(ISaveContext context) {
        // nothing to do
	}

	/** @see ISaveParticipant#prepareToSave(ISaveContext) */
	public void prepareToSave(ISaveContext context) throws CoreException {
        // nothing to do
	}

	/** @see ISaveParticipant#rollback(ISaveContext) */
	public void rollback(ISaveContext context) {
	    // nothing to do
	}

	/** @see ISaveParticipant#saving(ISaveContext) */
	public void saving(ISaveContext context) throws CoreException {
		context.needDelta();
	}

	/**
	 * Visit a resource. This should be invoked only from the
	 * IResource.accept(IResourceVisitor) invocation, above.
	 * 
	 * @see IResourceVisitor#visit(IResource)
	 */
	public boolean visit(IResource resource) {

		// Check for and handle a Struts config. file.
		checkForFacesConfigFile(resource, true);

		// Continue.
		return true;
	}

	private void restartServerIfNecessary(IVirtualComponent component) {
		if(!restartInProgress) {
			// check against preference about whether to automatically restart
			boolean restart = false;
			if (FacesResourceChangeListener.preferenceStore != null) {
				restart = FacesResourceChangeListener.preferenceStore.getBoolean(IFacesconfigPreferences.PREFSKEY_SERVER_RESTART);
			}
			if(restart) {
				restartInProgress = true;
				// we'll ask that just the containing EAR is restarted, but it may cycle the whole server if running on Portal

				//ServerRestartUtil.restartComponent(component, true);
				restartInProgress = false;
			}
		}
	}

	/**
	 * @return Returns the listener.
	 */
	public static FacesResourceChangeListener getFacesResourceChangeListener() {
		if (listener == null) {
			listener = new FacesResourceChangeListener();
			// Register as resource change listener.
			ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_BUILD);
		}
		return listener;
	}
	
	/**
	 * Adds a change listener to the list of listeners that will be notified
	 * when a change is fired.
	 * 
	 * @param facesConfigChangeListener
	 */
	public void addFacesConfigChangeListener(IFacesConfigChangeListener facesConfigChangeListener) {
		facesConfigChangeListeners.add(facesConfigChangeListener);
	}
	/**
	 * Removes the listener from the list.
	 * 
	 * @param facesConfigChangeListener
	 */
	public void removeFacesConfigChangeListener(IFacesConfigChangeListener facesConfigChangeListener) {
		facesConfigChangeListeners.remove(facesConfigChangeListener);
	}
	
	private void fireFacesConfigChangeEvent(IFacesConfigChangeEvent event) {
		LinkedList localCopy;
		synchronized( this ) {
			localCopy = (LinkedList)facesConfigChangeListeners.clone();
		}
		for ( ListIterator iter = localCopy.listIterator(); iter.hasNext(); ) {
			IFacesConfigChangeListener facesConfigChangeListener = (IFacesConfigChangeListener)iter.next();
			facesConfigChangeListener.resourceChanged(event);
		}
	}

	/** 
	 * Set the internally used preference store to preferenceStore
	 * 
	 * @param preferenceStore
	 */
	public static void setPreferenceStore(IPreferenceStore preferenceStore) {
		FacesResourceChangeListener.preferenceStore = preferenceStore;
	}
}

Back to the top