org.jboss.tools.cdi.core.CDICoreBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.cdi.core.CDICoreBuilder.java

Source

/******************************************************************************* 
 * Copyright (c) 2007 Red Hat, Inc. 
 * Distributed under license by Red Hat, Inc. All rights reserved. 
 * This program is 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: 
 * Red Hat, Inc. - initial API and implementation 
 ******************************************************************************/
package org.jboss.tools.cdi.core;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageDeclaration;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.jboss.tools.cdi.core.extension.IDefinitionContextExtension;
import org.jboss.tools.cdi.core.extension.feature.IBuildParticipant2Feature;
import org.jboss.tools.cdi.core.extension.feature.IBuildParticipantFeature;
import org.jboss.tools.cdi.internal.core.impl.definition.AnnotationHelper;
import org.jboss.tools.cdi.internal.core.impl.definition.Dependencies;
import org.jboss.tools.cdi.internal.core.scanner.CDIBuilderDelegate;
import org.jboss.tools.cdi.internal.core.scanner.FileSet;
import org.jboss.tools.cdi.internal.core.scanner.lib.JarSet;
import org.jboss.tools.common.EclipseUtil;
import org.jboss.tools.common.model.XModelObject;
import org.jboss.tools.common.model.plugin.ModelPlugin;
import org.jboss.tools.common.model.project.ProjectHome;
import org.jboss.tools.common.model.util.EclipseJavaUtil;
import org.jboss.tools.common.model.util.EclipseResourceUtil;
import org.jboss.tools.common.util.UniquePaths;
import org.jboss.tools.common.web.WebUtils;

public class CDICoreBuilder extends IncrementalProjectBuilder {
    public static String BUILDER_ID = "org.jboss.tools.cdi.core.cdibuilder";

    static Set<ICDIBuilderDelegate> delegates = null;

    static Set<ICDIBuilderDelegate> getDelegates() {
        if (delegates == null) {
            delegates = new HashSet<ICDIBuilderDelegate>();
            //TODO populate; extension point will be used
            delegates.add(new CDIBuilderDelegate()); //default
        }
        return delegates;
    }

    ICDIBuilderDelegate builderDelegate;

    CDIResourceVisitor resourceVisitor = null;

    Set<IBuildParticipantFeature> buildParticipants = null;
    Set<IBuildParticipant2Feature> buildParticipants2 = null;

    /**
     * Set only for instance created to initially load cdi model.
     */
    CDICoreNature cdi;

    public CDICoreBuilder() {
    }

    public CDICoreBuilder(CDICoreNature cdi) throws CoreException {
        this.cdi = cdi;
        build(IncrementalProjectBuilder.FULL_BUILD, null, new NullProgressMonitor());
    }

    CDICoreNature getCDICoreNature() {
        if (cdi != null) {
            return cdi;
        }
        IProject p = getProject();
        if (p == null)
            return null;
        return CDICorePlugin.getCDI(p, false);
    }

    IProject getCurrentProject() {
        return cdi != null ? cdi.getProject() : getProject();
    }

    CDIResourceVisitor getResourceVisitor() {
        if (resourceVisitor == null) {
            resourceVisitor = new CDIResourceVisitor();
        }
        return resourceVisitor;
    }

    private void findDelegate() {
        Set<ICDIBuilderDelegate> ds = getDelegates();
        int relevance = 0;
        for (ICDIBuilderDelegate d : ds) {
            int r = d.computeRelevance(getCurrentProject());
            if (r > relevance) {
                builderDelegate = d;
                relevance = r;
            }
        }
    }

    public ICDIBuilderDelegate getDelegate() {
        return builderDelegate;
    }

    protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {

        resourceVisitor = null;
        findDelegate();
        if (getDelegate() == null) {
            return null;
        }
        CDICoreNature n = getCDICoreNature();
        if (n == null) {
            return null;
        }

        if (n.hasNoStorage()) {
            kind = FULL_BUILD;
        }

        n.postponeFiring();

        long begin = System.currentTimeMillis();

        try {
            n.resolveStorage(kind != FULL_BUILD);

            if (n.getDelegate() == null
                    || n.getDelegate().getClass() != getDelegate().getProjectImplementationClass()) {
                if (n.getDelegate() != null) {
                    n.clean();
                    n.postponeFiring();
                }
                kind = FULL_BUILD;
                try {
                    ICDIProject delegate = (ICDIProject) getDelegate().getProjectImplementationClass()
                            .newInstance();
                    n.setCDIProject(delegate);
                } catch (IllegalAccessException e1) {
                    CDICorePlugin.getDefault().logError(e1);
                } catch (InstantiationException e2) {
                    CDICorePlugin.getDefault().logError(e2);
                }
            }

            n.cleanTypeFactory();

            if (kind == FULL_BUILD)
                n.getClassPath().reset();

            //1. Check class path.
            boolean isClassPathUpdated = n.getClassPath().update();

            JarSet newJars = new JarSet();
            if (isClassPathUpdated || kind == FULL_BUILD) {
                //2. Update class path. Removed paths will be cached to be applied to working copy of context. 
                n.getClassPath().setSrcs(getResourceVisitor().srcs);
                newJars = n.getClassPath().process();
            }
            if (isClassPathUpdated || buildParticipants == null) {
                //3. Install extensions. That should be done before constructing working copy of context.
                buildParticipants = n.getExtensionManager().getBuildParticipantFeatures();
                buildParticipants2 = new HashSet<IBuildParticipant2Feature>();
                Set<IDefinitionContextExtension> es = new HashSet<IDefinitionContextExtension>();
                for (IBuildParticipantFeature p : buildParticipants) {
                    IDefinitionContextExtension e = p.getContext();
                    if (e != null)
                        es.add(e);
                    if (p instanceof IBuildParticipant2Feature) {
                        buildParticipants2.add((IBuildParticipant2Feature) p);
                    }
                }
                n.getDefinitions().setExtensions(es);
            }

            //4. Create working copy of context.
            n.getDefinitions().newWorkingCopy(kind == FULL_BUILD);

            //5. Modify working copy of context.
            //5.1 Apply Removed paths.
            if (isClassPathUpdated) {
                n.getClassPath().applyRemovedPaths();
            }

            for (IBuildParticipantFeature p : buildParticipants)
                p.beginVisiting();

            //5.2 Discover sources and build definitions.
            if (isClassPathUpdated || kind == FULL_BUILD) {
                buildJars(newJars);

                n.getClassPath().validateProjectDependencies();

                kind = FULL_BUILD;
            } else if (n.getClassPath().hasToUpdateProjectDependencies()) {
                n.getClassPath().validateProjectDependencies();
            }

            if (kind == FULL_BUILD) {
                fullBuild(monitor);
            } else {
                IResourceDelta delta = getDelta(getCurrentProject());
                if (delta == null) {
                    fullBuild(monitor);
                } else {
                    incrementalBuild(delta, monitor);
                }
            }
            for (IBuildParticipantFeature p : buildParticipants)
                p.buildDefinitions();

            // 6. Save created definitions to project context and build beans.
            getCDICoreNature().getDefinitions().applyWorkingCopy();

            long end = System.currentTimeMillis();
            n.fullBuildTime += end - begin;
            try {
                n.store();
            } catch (IOException e) {
                CDICorePlugin.getDefault().logError(e); //$NON-NLS-1$
            }

            //         n.postBuild();

        } finally {
            n.fireChanges();
        }

        resourceVisitor = null;

        return null;
    }

    protected void fullBuild(final IProgressMonitor monitor) throws CoreException {
        try {
            CDIResourceVisitor rv = getResourceVisitor();
            rv.incremental = false;
            getCurrentProject().accept(rv);
            FileSet fs = rv.fileSet;
            invokeBuilderDelegates(fs, getCDICoreNature());

        } catch (CoreException e) {
            CDICorePlugin.getDefault().logError(e);
        }
    }

    protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException {
        CDIResourceVisitor rv = getResourceVisitor();
        rv.incremental = true;
        delta.accept(new SampleDeltaVisitor());
        FileSet fs = rv.fileSet;
        invokeBuilderDelegates(fs, getCDICoreNature());
    }

    protected void buildJars(JarSet newJars) throws CoreException {
        IJavaProject jp = EclipseResourceUtil.getJavaProject(getCDICoreNature().getProject());
        if (jp == null)
            return;
        FileSet fileSet = new FileSet();

        for (String jar : newJars.getBeanModules().keySet()) {
            Path path = new Path(jar);
            IPackageFragmentRoot root = jp.getPackageFragmentRoot(jar);
            if (root == null)
                continue;
            if (!root.exists()) {
                IFile f = EclipseResourceUtil.getFile(jar);
                if (f != null && f.exists()) {
                    root = jp.getPackageFragmentRoot(f);
                } else {
                    f = EclipseResourceUtil.getFile(jar + "/META-INF/beans.xml");
                    if (f != null && f.exists()) {
                        root = jp.getPackageFragmentRoot(f.getParent().getParent());
                    }
                }
            }
            if (root == null || !root.exists())
                continue;
            IJavaElement[] es = root.getChildren();
            for (IJavaElement e : es) {
                if (e instanceof IPackageFragment) {
                    IPackageFragment pf = (IPackageFragment) e;
                    IClassFile[] cs = pf.getClassFiles();
                    for (IClassFile c : cs) {
                        fileSet.add(path, c.getType());
                    }
                }
            }
            XModelObject beansXML = newJars.getBeanModules().get(jar);
            fileSet.setBeanXML(path, beansXML);

            for (IBuildParticipantFeature p : buildParticipants)
                p.visitJar(path, root, beansXML);
        }
        if (!buildParticipants2.isEmpty()) {
            for (String jar : newJars.getFileSystems().keySet()) {
                Path path = new Path(jar);
                XModelObject fs = newJars.getFileSystems().get(jar);
                for (IBuildParticipant2Feature p : buildParticipants2)
                    p.visitJar(path, fs);
            }
        }
        addBasicTypes(fileSet);
        invokeBuilderDelegates(fileSet, getCDICoreNature());
    }

    void invokeBuilderDelegates(FileSet fileSet, CDICoreNature n) {
        builderDelegate.build(fileSet, n);
        for (IBuildParticipantFeature p : buildParticipants)
            p.buildDefinitions(fileSet);
    }

    void addBasicTypes(FileSet fs) throws CoreException {
        IJavaProject jp = EclipseResourceUtil.getJavaProject(getCurrentProject());
        if (jp == null)
            return;
        for (String s : AnnotationHelper.SCOPE_ANNOTATION_TYPES) {
            IType type = EclipseJavaUtil.findType(jp, s);
            if (type != null)
                fs.add(type.getPath(), type);
        }
        for (String s : AnnotationHelper.QUALIFIER_ANNOTATION_TYPES) {
            IType type = EclipseJavaUtil.findType(jp, s);
            if (type != null)
                fs.add(type.getPath(), type);
        }
        for (String s : AnnotationHelper.STEREOTYPE_ANNOTATION_TYPES) {
            IType type = EclipseJavaUtil.findType(jp, s);
            if (type != null)
                fs.add(type.getPath(), type);
        }
    }

    protected void clean(IProgressMonitor monitor) throws CoreException {
        CDICoreNature n = getCDICoreNature();
        if (n != null)
            n.clean();
    }

    /**
     * Returns files directly dependent on path which are not included into visited set. 
     * 
     * @param path
     * @param visited
     * @return
     */
    Set<IFile> getDependentFiles(IPath path, Set<IPath> visited) {
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        Dependencies d = getCDICoreNature().getDefinitions().getWorkingCopy().getDependencies();
        Set<IFile> result = new HashSet<IFile>();

        // we do not need to recurse: that will be done by visitor.
        Set<IPath> ps = d.getDirectDependencies(path);
        if (ps != null)
            for (IPath p : ps) {
                if (visited.contains(p))
                    continue;
                IFile f = root.getFile(p);
                if (f.exists()) {
                    result.add(f);
                }
            }

        return result;
    }

    class SampleDeltaVisitor implements IResourceDeltaVisitor {
        /*
         * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
         */
        public boolean visit(IResourceDelta delta) throws CoreException {
            IResource resource = delta.getResource();
            switch (delta.getKind()) {
            case IResourceDelta.ADDED:
                return getResourceVisitor().visit(resource);
            case IResourceDelta.REMOVED:
                CDICoreNature p = getCDICoreNature();
                CDIResourceVisitor v = getResourceVisitor();
                Set<IFile> fs = getDependentFiles(resource.getFullPath(), v.visited);
                for (IFile f : fs) {
                    v.visit(f);
                }
                if (p != null) {
                    p.getDefinitions().getWorkingCopy().clean(resource.getFullPath());
                }
                break;
            case IResourceDelta.CHANGED:
                return getResourceVisitor().visit(resource);
            }
            //return true to continue visiting children.
            return true;
        }
    }

    class CDIResourceVisitor implements IResourceVisitor {
        boolean incremental = false;
        FileSet fileSet = new FileSet();
        IPath[] outs = new IPath[0];
        IPath[] srcs = new IPath[0];
        IPath[] webinfs = new IPath[0];
        Set<IPath> visited = new HashSet<IPath>();

        CDIResourceVisitor() {
            webinfs = WebUtils.getWebInfPaths(getCurrentProject());
            getJavaSourceRoots(getCurrentProject());
        }

        void getJavaSourceRoots(IProject project) {
            IJavaProject javaProject = EclipseResourceUtil.getJavaProject(project);
            if (javaProject == null)
                return;
            List<IPath> ps = new ArrayList<IPath>();
            List<IPath> os = new ArrayList<IPath>();
            try {
                IPath output = javaProject.getOutputLocation();
                if (output != null)
                    os.add(output);
                IClasspathEntry[] es = javaProject.getResolvedClasspath(true);
                for (int i = 0; i < es.length; i++) {
                    if (es[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                        IResource findMember = ResourcesPlugin.getWorkspace().getRoot().findMember(es[i].getPath());
                        if (findMember != null && findMember.exists()) {
                            ps.add(findMember.getFullPath());
                        }
                        IPath out = es[i].getOutputLocation();
                        if (out != null && !os.contains(out)) {
                            os.add(out);
                        }
                    }
                }
                srcs = ps.toArray(new IPath[ps.size()]);
                outs = os.toArray(new IPath[os.size()]);
            } catch (CoreException ce) {
                CDICorePlugin.getDefault().logError("Error while locating java source roots for " + project, ce);
            }
        }

        public boolean visit(IResource resource) throws CoreException {
            IPath path = resource.getFullPath();
            path = UniquePaths.getInstance().intern(path);
            if (resource instanceof IFile) {
                if (visited.contains(path)) {
                    return false;
                }
                visited.add(path);
                IFile f = (IFile) resource;
                for (int i = 0; i < outs.length; i++) {
                    if (outs[i].isPrefixOf(path)) {
                        return false;
                    }
                }
                for (int i = 0; i < srcs.length; i++) {
                    if (srcs[i].isPrefixOf(path)) {
                        if (f.getName().endsWith(".java")) {
                            ICompilationUnit unit = EclipseUtil.getCompilationUnit(f);
                            if (unit != null) {
                                if (f.getName().equals("package-info.java")) {
                                    IPackageDeclaration[] pkg = unit.getPackageDeclarations();
                                    if (pkg != null && pkg.length > 0) {
                                        fileSet.add(f.getFullPath(), pkg[0]);
                                        if (incremental) {
                                            IResource[] ms = resource.getParent().members();
                                            for (IResource m : ms) {
                                                if (m instanceof IFile
                                                        && !m.getName().equals("package-info.java")) {
                                                    visit(m);
                                                }
                                            }
                                        }
                                    }
                                } else {
                                    IType[] ts = unit.getTypes();
                                    fileSet.add(f.getFullPath(), ts);
                                }
                            }
                        } else if (path.segmentCount() == srcs[i].segmentCount() + 2
                                && "META-INF".equals(path.segments()[path.segmentCount() - 2])) {
                            addBeansXML(f, fileSet);
                        }
                        for (IBuildParticipantFeature p : buildParticipants)
                            p.visit(f, srcs[i], null);
                        Set<IFile> ds = getDependentFiles(path, visited);
                        if (ds != null)
                            for (IFile d : ds)
                                visit(d);
                        return false;
                    }
                }
                for (IPath webinf : webinfs) {
                    if (webinf.isPrefixOf(path)) {
                        if (webinf.segmentCount() == path.segmentCount() - 1) {
                            addBeansXML(f, fileSet);
                        }
                        for (IBuildParticipantFeature p : buildParticipants)
                            p.visit(f, null, webinf);
                    }
                }

                Set<IFile> ds = getDependentFiles(path, visited);
                if (ds != null)
                    for (IFile d : ds)
                        visit(d);
            }

            if (resource instanceof IFolder) {
                for (IPath out : outs) {
                    if (out.isPrefixOf(path)) {
                        return false;
                    }
                }
                for (IPath src : srcs) {
                    if (src.isPrefixOf(path) || path.isPrefixOf(src)) {
                        return true;
                    }
                }
                for (IPath webinf : webinfs) {
                    if (webinf.isPrefixOf(path) || path.isPrefixOf(webinf)) {
                        return true;
                    }
                }
                if (resource == resource.getProject()) {
                    return true;
                }
                return false;
            }
            //return true to continue visiting children.
            return true;
        }

    }

    private void addBeansXML(IFile f, FileSet fileSet) {
        if (f.getName().equals("beans.xml")) {
            XModelObject beansXML = EclipseResourceUtil.getObjectByResource(f);
            if (beansXML == null) {
                beansXML = EclipseResourceUtil.createObjectForResource(f);
            }
            if (beansXML != null) {
                fileSet.setBeanXML(f.getFullPath(), beansXML);
            }
        }
    }

}