org.eclipselabs.spray.runtime.xtext.ui.builder.JdtToBeBuiltComputerExt.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipselabs.spray.runtime.xtext.ui.builder.JdtToBeBuiltComputerExt.java

Source

/** ****************************************************************************
 * Copyright (c)  The Spray Project.
 * 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:
 *     Spray Dev Team - initial API and implementation
 **************************************************************************** */
package org.eclipselabs.spray.runtime.xtext.ui.builder;

import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.resources.IWorkspace.ProjectOrder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jdt.core.IJarEntryResource;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.xtext.builder.impl.QueuedBuildData;
import org.eclipse.xtext.builder.impl.ToBeBuilt;
import org.eclipse.xtext.builder.impl.ToBeBuiltComputer;
import org.eclipse.xtext.common.types.access.jdt.TypeURIHelper;
import org.eclipse.xtext.common.types.ui.notification.TypeResourceDescription;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IResourceDescription.Delta;
import org.eclipse.xtext.resource.impl.ChangedResourceDescriptionDelta;
import org.eclipse.xtext.ui.XtextProjectHelper;
import org.eclipse.xtext.ui.resource.JarEntryLocator;
import org.eclipse.xtext.ui.resource.PackageFragmentRootWalker;
import org.eclipse.xtext.ui.util.IJdtHelper;
import org.eclipse.xtext.util.Pair;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import javax.inject.Inject;
import com.google.inject.Singleton;

@SuppressWarnings("restriction")
public class JdtToBeBuiltComputerExt extends ToBeBuiltComputer {

    private final static Logger log = Logger.getLogger(JdtToBeBuiltComputerExt.class);

    @Inject
    private TypeURIHelper typeURIHelper;

    @Inject
    private QueuedBuildData queuedBuildData;

    @Inject
    private ModificationStampCache modificationStampCache;

    @Inject
    private IJdtHelper jdtHelper;

    @Singleton
    public static class ModificationStampCache {
        protected Map<String, Long> projectToModificationStamp = Maps.newHashMap();
    }

    @Override
    public ToBeBuilt removeProject(IProject project, IProgressMonitor monitor) {
        ToBeBuilt toBeBuilt = super.removeProject(project, monitor);
        if (toBeBuilt.getToBeDeleted().isEmpty() && toBeBuilt.getToBeUpdated().isEmpty())
            return toBeBuilt;
        modificationStampCache.projectToModificationStamp.clear();
        return toBeBuilt;
    }

    @Override
    public ToBeBuilt updateProject(final IProject project, IProgressMonitor monitor) throws CoreException {
        SubMonitor progress = SubMonitor.convert(monitor, 2);
        final ToBeBuilt toBeBuilt = super.updateProject(project, progress.newChild(1));
        if (!project.isAccessible() || progress.isCanceled())
            return toBeBuilt;
        IJavaProject javaProject = JavaCore.create(project);
        if (javaProject.exists()) {
            IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
            progress.setWorkRemaining(roots.length);
            final Set<String> previouslyBuilt = Sets.newHashSet();
            final Set<String> subsequentlyBuilt = Sets.newHashSet();
            final JarEntryLocator locator = new JarEntryLocator();
            for (final IPackageFragmentRoot root : roots) {
                if (progress.isCanceled())
                    return toBeBuilt;
                if (shouldHandle(root)) {
                    try {
                        final Map<String, Long> updated = Maps.newHashMap();
                        new PackageFragmentRootWalker<Boolean>() {
                            @Override
                            protected Boolean handle(IJarEntryResource jarEntry, TraversalState state) {
                                URI uri = locator.getURI(root, jarEntry, state);
                                if (isValid(uri, jarEntry)) {
                                    if (wasFragmentRootAlreadyProcessed(uri))
                                        return Boolean.TRUE; // abort traversal
                                    if (log.isDebugEnabled())
                                        log.debug("Scheduling: " + project.getName() + " - " + uri);
                                    toBeBuilt.getToBeDeleted().add(uri);
                                    toBeBuilt.getToBeUpdated().add(uri);
                                }
                                return null;
                            }

                            protected boolean wasFragmentRootAlreadyProcessed(URI uri) {
                                Iterable<Pair<IStorage, IProject>> storages = getMapper().getStorages(uri);
                                for (Pair<IStorage, IProject> pair : storages) {
                                    IProject otherProject = pair.getSecond();
                                    // Spray issue#127 workaround
                                    if (".org.eclipse.jdt.core.external.folders".equals(otherProject.getName())
                                            && uri.lastSegment().endsWith(".ecore"))
                                        return false;
                                    if (!pair.getSecond().equals(project)) {
                                        if (previouslyBuilt.contains(otherProject.getName()))
                                            return true;
                                        if (!subsequentlyBuilt.contains(otherProject.getName())) {
                                            boolean process = XtextProjectHelper.hasNature(otherProject);
                                            String otherName = otherProject.getName();
                                            if (!process) {
                                                process = otherProject.isAccessible() && otherProject.isHidden();
                                                if (process) {
                                                    Long previousStamp = modificationStampCache.projectToModificationStamp
                                                            .get(otherName);
                                                    if (previousStamp == null || otherProject
                                                            .getModificationStamp() > previousStamp.longValue()) {
                                                        process = false;
                                                        updated.put(otherName, otherProject.getModificationStamp());
                                                    }
                                                }
                                            }
                                            if (process) {
                                                ProjectOrder projectOrder = project.getWorkspace()
                                                        .computeProjectOrder(
                                                                new IProject[] { project, otherProject });
                                                if (!projectOrder.hasCycles) {
                                                    if (otherProject.equals(projectOrder.projects[0])) {
                                                        previouslyBuilt.add(otherName);
                                                        return true;
                                                    } else {
                                                        subsequentlyBuilt.add(otherName);
                                                    }
                                                } else {
                                                    subsequentlyBuilt.add(otherName);
                                                }
                                            }
                                        }
                                    }
                                }
                                return false;
                            }
                        }.traverse(root, true);
                        synchronized (modificationStampCache) {
                            modificationStampCache.projectToModificationStamp.putAll(updated);
                        }
                    } catch (JavaModelException ex) {
                        if (!ex.isDoesNotExist())
                            log.error(ex.getMessage(), ex);
                    }
                }
                progress.worked(1);
            }
        }
        return toBeBuilt;
    }

    /**
     * Handle all fragment roots that are on the classpath and not a source folder.
     */
    private boolean shouldHandle(IPackageFragmentRoot root) {
        try {
            boolean result = !JavaRuntime.newDefaultJREContainerPath()
                    .isPrefixOf(root.getRawClasspathEntry().getPath());
            result &= (root.isArchive() || root.isExternal());
            return result;
        } catch (JavaModelException ex) {
            if (!ex.isDoesNotExist())
                log.error(ex.getMessage(), ex);
            return false;
        }
    }

    @Override
    public boolean removeStorage(IProgressMonitor monitor, ToBeBuilt toBeBuilt, IStorage storage) {
        if (!isHandled(storage))
            return true;
        URI uri = getUri(storage);
        if (uri != null) {
            toBeBuilt.getToBeDeleted().add(uri);
        } else {
            if (storage instanceof IFile && JavaCore.isJavaLikeFileName(storage.getFullPath().lastSegment())) {
                IJavaElement element = JavaCore.create(((IFile) storage).getParent());
                String fileName = storage.getFullPath().lastSegment();
                String typeName = fileName.substring(0, fileName.lastIndexOf('.'));
                if (element instanceof IPackageFragmentRoot) {
                    queueJavaChange(typeName);
                } else if (element instanceof IPackageFragment) {
                    IPackageFragment packageFragment = (IPackageFragment) element;
                    queueJavaChange(packageFragment.getElementName() + "." + typeName);
                }
            }
        }
        return true;
    }

    protected void queueJavaChange(String typeName) {
        URI typeURI = typeURIHelper.createResourceURIForFQN(typeName);
        TypeResourceDescription oldDescription = new TypeResourceDescription(typeURI,
                Collections.<IEObjectDescription>emptyList());
        Delta delta = new ChangedResourceDescriptionDelta(oldDescription, null);
        queuedBuildData.queueChanges(Collections.singleton(delta));
    }

    @Override
    protected boolean isHandled(IStorage resource) {
        return (resource instanceof IJarEntryResource) || super.isHandled(resource);
    }

    /**
     * Ignores Java output folders when traversing a project.
     * 
     * @return <code>false</code> if the folder is a java output folder. Otherwise <code>true</code>.
     */
    @Override
    protected boolean isHandled(IFolder folder) {
        boolean result = super.isHandled(folder) && !jdtHelper.isFromOutputPath(folder);
        return result;
    }
}