blob: c328f25b0b0e52ef350f88f612fd691456ffdfa8 [file] [log] [blame]
/***************************************************************************************************
* 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().getBundle().getSymbolicName());
// 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); //$NON-NLS-1$
}
}
}
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"); //$NON-NLS-1$
return;
}
// Make the Struts config. editor the default.
traceFiner(file, "Unsetting."); //$NON-NLS-1$
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); //$NON-NLS-1$ //$NON-NLS-2$
}
/** @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;
}
}