/*******************************************************************************
* Copyright (c) 2004, 2009 Spring IDE Developers
* 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:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.beans.core.internal.model.resources;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.springframework.ide.eclipse.beans.core.BeansCoreUtils;
import org.springframework.ide.eclipse.beans.core.model.IBeansConfig;
import org.springframework.ide.eclipse.beans.core.model.IBeansProject;
import org.springframework.ide.eclipse.beans.core.model.locate.BeansConfigLocatorDefinition;
import org.springframework.ide.eclipse.beans.core.model.locate.BeansConfigLocatorFactory;
import org.springframework.ide.eclipse.core.SpringCoreUtils;
import org.springframework.ide.eclipse.core.internal.model.resources.SpringResourceChangeListener;
/**
* Implementation of {@link IResourceChangeListener} which detects modifications to Spring projects
* (add/remove Spring beans nature, open/close and delete) and Spring beans configurations (change
* and delete).
* <p>
* An implementation of {@link IBeansResourceChangeEvents} has to be provided. Here are callbacks
* defined for the different events.
* @author Torsten Juergeleit
* @author Christian Dupuis
*/
public class BeansResourceChangeListener extends SpringResourceChangeListener {
private IBeansResourceChangeEvents events;
public BeansResourceChangeListener(IBeansResourceChangeEvents events) {
super(events);
this.events = events;
}
@Override
protected IResourceDeltaVisitor getVisitor(int eventType) {
return new BeansResourceVisitor(eventType);
}
/**
* Checks if a given <code>file</code> requires a refresh of the auto detected
* {@link IBeansConfig}s.
* <p>
* This is checked by asking every contributed {@link BeansConfigLocatorDefinition}.
*/
public static boolean requiresRefresh(IFile file) {
for (final BeansConfigLocatorDefinition locator : BeansConfigLocatorFactory
.getBeansConfigLocatorDefinitions()) {
try {
if (locator.isEnabled(file.getProject())
&& locator.getBeansConfigLocator().supports(file.getProject())
&& locator.getBeansConfigLocator().requiresRefresh(file)) {
return true;
}
}
catch (Exception e) {
// Make sure that a extension contribution can't crash the resource listener
}
}
return false;
}
/**
* Internal resource delta visitor.
*/
protected class BeansResourceVisitor extends SpringResourceVisitor {
public BeansResourceVisitor(int eventType) {
super(eventType);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean resourceAdded(IResource resource) {
if (resource instanceof IFile) {
IFile file = (IFile) resource;
if (isProjectDescriptionFile(file)) {
if (SpringCoreUtils.isSpringProject(file)) {
events.projectDescriptionChanged(file, eventType);
}
}
// Test for auto detected config before testing for normal config as otherwise
// the auto-detected config will morph into a manual configured and added to .springBeans
else if (isAutoDetectedConfig(file)) {
events.configAdded(file, eventType, IBeansConfig.Type.AUTO_DETECTED);
}
else if (BeansCoreUtils.isBeansConfig(file)) {
events.configAdded(file, eventType);
}
return false;
}
return super.resourceAdded(resource);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean resourceChanged(IResource resource, int flags) {
if (resource instanceof IFile) {
if ((flags & IResourceDelta.CONTENT) != 0) {
IFile file = (IFile) resource;
if (isProjectDescriptionFile(file)) {
if (SpringCoreUtils.isSpringProject(file)) {
events.projectDescriptionChanged(file, eventType);
}
}
// Test for auto detected config before testing for normal config as otherwise
// the auto-detected config will morph into a manual configured and added to .springBeans
else if (isAutoDetectedConfig(file)) {
events.configAdded(file, eventType, IBeansConfig.Type.AUTO_DETECTED);
}
else if (BeansCoreUtils.isBeansConfig(file, true)) {
events.configChanged(file, eventType);
}
else if (requiresRefresh(file)) {
events.listenedFileChanged(file, eventType);
}
}
return false;
}
return super.resourceChanged(resource, flags);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean resourceRemoved(IResource resource) {
if (resource instanceof IFile) {
if (BeansCoreUtils.isBeansConfig(resource)) {
events.configRemoved((IFile) resource, eventType);
}
else if (requiresRefresh((IFile) resource)) {
events.listenedFileChanged((IFile) resource, eventType);
}
return false;
}
return super.resourceRemoved(resource);
}
/**
* Checks if the given <code>resource</code> represents a .springBeans project description.
*/
private boolean isProjectDescriptionFile(IResource resource) {
return resource != null
&& resource.isAccessible()
&& resource.getType() == IResource.FILE
&& ((resource.getFullPath().segmentCount() == 2 && resource.getName().equals(
IBeansProject.DESCRIPTION_FILE)) || SpringCoreUtils
.isManifest(resource));
}
/**
* Checks if the given <code>file</code> is an auto detected {@link IBeansConfig}.
*/
private boolean isAutoDetectedConfig(IFile file) {
for (final BeansConfigLocatorDefinition locator : BeansConfigLocatorFactory
.getBeansConfigLocatorDefinitions()) {
try {
if (locator.isEnabled(file.getProject())
&& locator.getBeansConfigLocator().supports(file.getProject())) {
if (locator.getBeansConfigLocator().isBeansConfig(file)) {
return true;
}
}
}
catch (Exception e) {
// Make sure that a extension contribution can't crash the resource listener
}
}
return false;
}
}
}