org.jboss.tools.jsf.jsf2.bean.build.JSF2ProjectBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.jsf.jsf2.bean.build.JSF2ProjectBuilder.java

Source

/******************************************************************************* 
 * Copyright (c) 2011 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.jsf.jsf2.bean.build;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
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.IncrementalProjectBuilder;
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.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.EclipseResourceUtil;
import org.jboss.tools.common.web.WebUtils;
import org.jboss.tools.jsf.JSFModelPlugin;
import org.jboss.tools.jsf.jsf2.bean.model.JSF2ProjectFactory;
import org.jboss.tools.jsf.jsf2.bean.model.impl.DefinitionContext;
import org.jboss.tools.jsf.jsf2.bean.model.impl.FacesConfigDefinition;
import org.jboss.tools.jsf.jsf2.bean.model.impl.JSF2Project;
import org.jboss.tools.jsf.jsf2.bean.model.impl.TypeDefinition;
import org.jboss.tools.jsf.jsf2.bean.scanner.FileSet;
import org.jboss.tools.jst.web.kb.internal.IIncrementalProjectBuilderExtension;

public class JSF2ProjectBuilder extends IncrementalProjectBuilder implements IIncrementalProjectBuilderExtension {

    JSF2ResourceVisitor resourceVisitor = null;

    /**
     * Set only for instance created to initially load jsf2 model.
     */
    JSF2Project jsf;

    public JSF2ProjectBuilder() {
    }

    public JSF2ProjectBuilder(JSF2Project jsf) throws CoreException {
        this.jsf = jsf;
        build(IncrementalProjectBuilder.FULL_BUILD, null, new NullProgressMonitor());
    }

    protected JSF2Project getJSF2Project() {
        if (jsf != null) {
            return jsf;
        }
        IProject p = getProject();
        if (p == null)
            return null;
        return (JSF2Project) JSF2ProjectFactory.getJSF2Project(p, false);
    }

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

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

    @Override
    public IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException {
        resourceVisitor = null;

        JSF2Project n = getJSF2Project();
        if (n == null) {
            return null;
        }

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

        n.postponeFiring();

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

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

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

            Map<String, XModelObject> newJars = new HashMap<String, XModelObject>();
            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();

            }
            int i = 0;

            //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();
            }

            //5.2 Discover sources and build definitions.
            if (isClassPathUpdated) {
                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);
                }
            }

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

            try {
                n.store();
            } catch (IOException e) {
                JSFModelPlugin.getDefault().logError(e); //$NON-NLS-1$
            }
        } finally {
            n.fireChanges();
        }

        return null;
    }

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

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

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

    protected void buildJars(Map<String, XModelObject> newJars) throws CoreException {
        IJavaProject jp = EclipseResourceUtil.getJavaProject(getJSF2Project().getProject());
        if (jp == null)
            return;
        FileSet fileSet = new FileSet();

        for (String jar : newJars.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/web-fragment.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());
                    }
                }
            }
        }
        build(fileSet, getJSF2Project());
    }

    void build(FileSet fs, JSF2Project project) {
        DefinitionContext context = getJSF2Project().getDefinitions().getWorkingCopy();
        Map<IPath, Set<IType>> cs = fs.getClasses();
        for (IPath f : cs.keySet()) {
            Set<IType> ts = cs.get(f);
            for (IType type : ts) {
                TypeDefinition def = new TypeDefinition();
                def.setType(type, context, TypeDefinition.FLAG_ALL_MEMBERS);
                context.addType(f, type.getFullyQualifiedName(), def);
            }
        }
        IFile facesConfig = fs.getFacesConfig();
        if (facesConfig != null) {
            FacesConfigDefinition def = new FacesConfigDefinition();
            def.setPath(facesConfig.getFullPath());
            XModelObject o = EclipseResourceUtil.createObjectForResource(facesConfig);
            if (o != null) {
                def.setObject(o);
                context.setFacesConfig(def);
            }
        }
    }

    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:
                JSF2Project p = getJSF2Project();
                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 JSF2ResourceVisitor 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>();

        public JSF2ResourceVisitor() {
            getJavaSourceRoots(getCurrentProject());
            webinfs = WebUtils.getWebInfPaths(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 = ModelPlugin.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[0]);
                outs = os.toArray(new IPath[0]);
            } catch (CoreException ce) {
                JSFModelPlugin.getDefault().logError("Error while locating java source roots for " + project, ce);
            }
        }

        @Override
        public boolean visit(IResource resource) throws CoreException {
            IPath path = resource.getFullPath();
            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);
                                }
                            }
                        }
                        Set<IFile> ds = getDependentFiles(path, visited);
                        if (ds != null)
                            for (IFile d : ds)
                                visit(d);
                        return false;
                    }
                }
                for (int i = 0; i < webinfs.length; i++) {
                    if (webinfs[i].isPrefixOf(path) && f.getName().equals("faces-config.xml")
                            && path.removeLastSegments(1).equals(webinfs[i])) {
                        fileSet.setFacesConfig(f);
                    }
                }
                Set<IFile> ds = getDependentFiles(path, visited);
                if (ds != null)
                    for (IFile d : ds)
                        visit(d);
            }

            if (resource instanceof IFolder) {
                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) || path.isPrefixOf(srcs[i])) {
                        return true;
                    }
                }
                if (resource == resource.getProject()) {
                    return true;
                }
                for (IPath webinf : webinfs) {
                    if (webinf.isPrefixOf(path) || path.isPrefixOf(webinf)) {
                        return true;
                    }
                }
                return false;
            }
            //return true to continue visiting children.
            return true;
        }

    }

    //In case if we will need that
    Set<IFile> getDependentFiles(IPath path, Set<IPath> visited) {
        return null;
    }

}