org.eclipse.xtext.builder.impl.javasupport.JdtToBeBuiltComputer.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.xtext.builder.impl.javasupport.JdtToBeBuiltComputer.java

Source

/*******************************************************************************
 * Copyright (c) 2010 itemis AG (http://www.itemis.eu) 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
 *******************************************************************************/
package org.eclipse.xtext.builder.impl.javasupport;

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

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;
import org.eclipse.core.resources.IWorkspace.ProjectOrder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
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.IToBeBuiltComputerContribution;
import org.eclipse.xtext.builder.impl.QueuedBuildData;
import org.eclipse.xtext.builder.impl.ToBeBuilt;
import org.eclipse.xtext.common.types.access.impl.URIHelperConstants;
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.IStorage2UriMapperJdtExtensions;
import org.eclipse.xtext.ui.resource.UriValidator;
import org.eclipse.xtext.ui.util.IJdtHelper;

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

public class JdtToBeBuiltComputer implements IToBeBuiltComputerContribution {

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

    @Inject
    private QueuedBuildData queuedBuildData;

    @Inject
    private IWorkspace workspace;

    @Inject
    private ModificationStampCache modificationStampCache;

    @Inject
    private IJdtHelper jdtHelper;

    @Inject
    private UriValidator uriValidator;

    @Inject
    private IStorage2UriMapperJdtExtensions jdtUriMapperExtension;

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

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

    @Override
    public void updateProject(ToBeBuilt toBeBuilt, IProject project, IProgressMonitor monitor)
            throws CoreException {
        SubMonitor progress = SubMonitor.convert(monitor, 2);
        if (progress.isCanceled()) {
            throw new OperationCanceledException();
        }
        if (!project.isAccessible())
            return;
        IJavaProject javaProject = JavaCore.create(project);
        if (javaProject.exists()) {
            IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
            progress.setWorkRemaining(roots.length);
            final Map<String, Long> updated = Maps.newHashMap();
            ProjectOrder orderedProjects = workspace.computeProjectOrder(workspace.getRoot().getProjects());
            for (final IPackageFragmentRoot root : roots) {
                if (progress.isCanceled())
                    throw new OperationCanceledException();
                if (shouldHandle(root) && !isBuiltByUpstream(root, project, orderedProjects.projects)) {
                    Map<URI, IStorage> rootData = jdtUriMapperExtension.getAllEntries(root);
                    for (Map.Entry<URI, IStorage> e : rootData.entrySet())
                        if (uriValidator.canBuild(e.getKey(), e.getValue())) {
                            toBeBuilt.getToBeDeleted().add(e.getKey());
                            toBeBuilt.getToBeUpdated().add(e.getKey());
                        }
                }
                progress.worked(1);
            }
            synchronized (modificationStampCache) {
                modificationStampCache.projectToModificationStamp.putAll(updated);
            }
        }
    }

    protected boolean isBuiltByUpstream(IPackageFragmentRoot root, IProject project,
            IProject[] projectsInCorrectBuildOrder) {
        for (IProject p : projectsInCorrectBuildOrder) {
            if (p.equals(project))
                return false;
            if (XtextProjectHelper.hasNature(p) && XtextProjectHelper.hasBuilder(p)) {
                IJavaProject javaProject = JavaCore.create(p);
                if (javaProject.exists()) {
                    if (javaProject.isOnClasspath(root)) {
                        if (log.isTraceEnabled())
                            log.trace("Build of project '" + project.getName()
                                    + "' skips indexing classpath entry '" + root.getPath()
                                    + "' because it already indexed by " + javaProject.getElementName());
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 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(ToBeBuilt toBeBuilt, IStorage storage, IProgressMonitor monitor) {
        if (storage instanceof IFile && JavaCore.isJavaLikeFileName(storage.getName())) {
            IJavaElement element = JavaCore.create(((IFile) storage).getParent());
            String fileName = storage.getName();
            String typeName = fileName.substring(0, fileName.lastIndexOf('.'));
            if (element instanceof IPackageFragmentRoot) {
                queueJavaChange(typeName);
                return true;
            } else if (element instanceof IPackageFragment) {
                IPackageFragment packageFragment = (IPackageFragment) element;
                queueJavaChange(packageFragment.getElementName() + "." + typeName);
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean updateStorage(ToBeBuilt toBeBuilt, IStorage storage, IProgressMonitor monitor) {
        // nothing to do
        // structural java changes will be queued in a fine grained fashion by the JavaChangeQueueFiller
        return false;
    }

    protected void queueJavaChange(String typeName) {
        URI typeURI = URIHelperConstants.OBJECTS_URI.appendSegment(typeName);
        TypeResourceDescription oldDescription = new TypeResourceDescription(typeURI,
                Collections.<IEObjectDescription>emptyList());
        Delta delta = new ChangedResourceDescriptionDelta(oldDescription, null);
        queuedBuildData.queueChange(delta);
    }

    @Override
    public boolean isPossiblyHandled(IStorage resource) {
        return resource instanceof IJarEntryResource;
    }

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