/**
* Copyright (c) 2010, 2012 Darmstadt University of Technology.
* 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:
* Marcel Bruch - initial API and implementation.
* Olav Lenz - externalize Strings.
*/
package org.eclipse.recommenders.internal.rcp;
import static org.eclipse.jdt.core.IJavaElementDelta.*;
import static org.eclipse.recommenders.utils.Checks.cast;
import java.util.Set;
import javax.inject.Inject;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IElementChangedListener;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaElementDelta;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.recommenders.internal.rcp.l10n.Messages;
import org.eclipse.recommenders.rcp.JavaModelEvents.CompilationUnitAdded;
import org.eclipse.recommenders.rcp.JavaModelEvents.CompilationUnitChanged;
import org.eclipse.recommenders.rcp.JavaModelEvents.CompilationUnitRemoved;
import org.eclipse.recommenders.rcp.JavaModelEvents.CompilationUnitSaved;
import org.eclipse.recommenders.rcp.JavaModelEvents.JarPackageFragmentRootAdded;
import org.eclipse.recommenders.rcp.JavaModelEvents.JarPackageFragmentRootRemoved;
import org.eclipse.recommenders.rcp.JavaModelEvents.JavaProjectClosed;
import org.eclipse.recommenders.rcp.JavaModelEvents.JavaProjectOpened;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
@SuppressWarnings("restriction")
public class JavaModelEventsService implements IElementChangedListener {
private final EventBus bus;
private final IWorkspaceRoot workspace;
@Inject
public JavaModelEventsService(final EventBus bus, final IWorkspaceRoot workspace) {
this.bus = bus;
this.workspace = workspace;
simulateProjectOpenEvents();
}
private void simulateProjectOpenEvents() {
new SimulateOpenJavaProjectsJob(Messages.JOB_NAME_INITIALIZING_PROJECTS).schedule();
}
@Override
public void elementChanged(final ElementChangedEvent event) {
final IJavaElementDelta delta = event.getDelta();
process(delta);
}
private void process(final IJavaElementDelta delta) {
if (isChildAffectedByChange(delta)) {
for (final IJavaElementDelta child : delta.getAffectedChildren()) {
process(child);
}
}
if (isProjectChangedEvent(delta)) {
processProjectChangedEvent(delta);
} else if (isCompilationUnitChangedEvent(delta)) {
processCompilationUnitChangedEvent(delta);
} else if (isJarPackageFragementRootChangedEvent(delta)) {
processJarPackageFragementRootChangedEvent(delta);
}
}
private boolean isChildAffectedByChange(final IJavaElementDelta delta) {
return (delta.getFlags() & IJavaElementDelta.F_CHILDREN) != 0;
}
private boolean isProjectChangedEvent(final IJavaElementDelta delta) {
final IJavaElement changedElement = delta.getElement();
final IJavaProject javaProject = delta.getElement().getJavaProject();
return javaProject != null && changedElement == javaProject;
}
private void processProjectChangedEvent(final IJavaElementDelta delta) {
final IJavaProject javaProject = cast(delta.getElement());
if (isProjectOpenedEvent(delta)) {
fireProjectOpenedEvent(javaProject);
} else if (isProjectClosedEvent(delta)) {
fireProjectClosedEvent(javaProject);
}
}
private boolean isProjectOpenedEvent(final IJavaElementDelta delta) {
final boolean added = (delta.getKind() & IJavaElementDelta.ADDED) != 0;
final boolean opened = (delta.getFlags() & IJavaElementDelta.F_OPENED) != 0;
return added || opened;
}
private void fireProjectOpenedEvent(final IJavaProject javaProject) {
bus.post(new JavaProjectOpened(javaProject));
}
private boolean isProjectClosedEvent(final IJavaElementDelta delta) {
final boolean removed = (delta.getKind() & IJavaElementDelta.REMOVED) != 0;
final boolean closed = (delta.getFlags() & IJavaElementDelta.F_CLOSED) != 0;
return removed || closed;
}
private void fireProjectClosedEvent(final IJavaProject javaProject) {
bus.post(new JavaProjectClosed(javaProject));
}
private boolean isCompilationUnitChangedEvent(final IJavaElementDelta delta) {
return delta.getElement() instanceof ICompilationUnit;
}
private void processCompilationUnitChangedEvent(final IJavaElementDelta delta) {
final ICompilationUnit cu = cast(delta.getElement());
switch (delta.getKind()) {
case IJavaElementDelta.ADDED:
fireCompilationUnitAddedEvent(cu);
break;
case IJavaElementDelta.CHANGED:
if (isCompilationUnitSavedEvent(delta)) {
fireCompilationUnitSavedEvent(cu);
} else {
fireCompilationUnitChangedEvent(cu);
}
break;
case IJavaElementDelta.REMOVED:
fireCompilationUnitRemovedEvent(cu);
break;
}
}
private void fireCompilationUnitAddedEvent(final ICompilationUnit cu) {
bus.post(new CompilationUnitAdded(cu));
}
private boolean isCompilationUnitSavedEvent(final IJavaElementDelta delta) {
final int flags = delta.getFlags() & IJavaElementDelta.F_PRIMARY_RESOURCE;
return flags > 0;
}
private void fireCompilationUnitSavedEvent(final ICompilationUnit cu) {
bus.post(new CompilationUnitSaved(cu));
}
private void fireCompilationUnitChangedEvent(final ICompilationUnit cu) {
bus.post(new CompilationUnitChanged(cu));
}
private void fireCompilationUnitRemovedEvent(final ICompilationUnit cu) {
bus.post(new CompilationUnitRemoved(cu));
}
private boolean isJarPackageFragementRootChangedEvent(final IJavaElementDelta delta) {
return delta.getElement() instanceof JarPackageFragmentRoot;
}
private void processJarPackageFragementRootChangedEvent(final IJavaElementDelta delta) {
switch (delta.getKind()) {
case IJavaElementDelta.ADDED:
fireJarPackageFragementRootAddedEvent(delta);
return;
case IJavaElementDelta.REMOVED:
fireJarPackageFragementRootRemoved(delta);
return;
case IJavaElementDelta.CHANGED:
switch (delta.getFlags()) {
case F_ADDED_TO_CLASSPATH:
fireJarPackageFragementRootAddedEvent(delta);
return;
case F_REMOVED_FROM_CLASSPATH:
fireJarPackageFragementRootRemoved(delta);
return;
}
}
}
private void fireJarPackageFragementRootAddedEvent(final IJavaElementDelta delta) {
bus.post(new JarPackageFragmentRootAdded((JarPackageFragmentRoot) delta.getElement()));
}
private void fireJarPackageFragementRootRemoved(final IJavaElementDelta delta) {
bus.post(new JarPackageFragmentRootRemoved((JarPackageFragmentRoot) delta.getElement()));
}
private Set<IProject> getAllOpenProjects() {
final Set<IProject> result = Sets.newHashSet();
final IProject[] projects = workspace.getProjects();
for (final IProject project : projects) {
if (project.isAccessible()) {
result.add(project);
}
}
return result;
}
private IJavaProject toJavaProject(final IProject project) {
return JavaCore.create(project);
}
private final class SimulateOpenJavaProjectsJob extends WorkspaceJob {
private SimulateOpenJavaProjectsJob(final String name) {
super(name);
}
@Override
public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException {
final Set<IProject> openProjects = getAllOpenProjects();
monitor.beginTask("", openProjects.size()); //$NON-NLS-1$
for (final IProject project : openProjects) {
if (JavaProject.hasJavaNature(project)) {
final IJavaProject javaProject = toJavaProject(project);
fireProjectOpenedEvent(javaProject);
}
monitor.worked(1);
}
monitor.done();
return Status.OK_STATUS;
}
}
}