org.apache.felix.sigil.eclipse.internal.builders.SigilIncrementalProjectBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.felix.sigil.eclipse.internal.builders.SigilIncrementalProjectBuilder.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.felix.sigil.eclipse.internal.builders;

import java.io.File;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.felix.sigil.common.bnd.BundleBuilder;
import org.apache.felix.sigil.common.config.IBldProject;
import org.apache.felix.sigil.eclipse.SigilCore;
import org.apache.felix.sigil.eclipse.model.project.ISigilProjectModel;
import org.apache.felix.sigil.eclipse.model.util.JavaHelper;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
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.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.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaModelMarker;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.MessageConsoleStream;

public class SigilIncrementalProjectBuilder extends IncrementalProjectBuilder {
    @Override
    protected IProject[] build(int kind, @SuppressWarnings("unchecked") Map args, IProgressMonitor monitor)
            throws CoreException {
        IProject project = getProject();

        if (checkOk(project)) {
            switch (kind) {
            case CLEAN_BUILD:
            case FULL_BUILD:
                fullBuild(project, monitor);
                break;
            case AUTO_BUILD:
            case INCREMENTAL_BUILD:
                autoBuild(project, monitor);
                break;
            }
        }

        return null;
    }

    /**
     * @param install
     * @param project
     * @param monitor
     * @throws CoreException 
     */
    private void autoBuild(IProject project, IProgressMonitor monitor) throws CoreException {
        IResourceDelta delta = getDelta(project);
        final boolean[] changed = new boolean[1];
        ISigilProjectModel sigil = SigilCore.create(project);
        final IPath bldRoot = sigil.findBundleLocation().removeLastSegments(1);

        delta.accept(new IResourceDeltaVisitor() {
            public boolean visit(IResourceDelta delta) throws CoreException {
                if (!changed[0]) {
                    IResource res = delta.getResource();
                    if (res.getType() == IResource.FILE) {
                        changed[0] = !bldRoot.isPrefixOf(res.getLocation());
                    }
                }
                return !changed[0];
            }
        });

        if (changed[0]) {
            doBuild(project, monitor);
        }
    }

    /**
     * @param install
     * @param project
     * @param monitor
     * @throws CoreException 
     */
    private void fullBuild(IProject project, IProgressMonitor monitor) throws CoreException {
        doBuild(project, monitor);
    }

    private boolean checkOk(IProject project) throws CoreException {
        IMarker[] markers = project.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true,
                IResource.DEPTH_INFINITE);

        for (IMarker m : markers) {
            Integer s = (Integer) m.getAttribute(IMarker.SEVERITY);
            if (s != null && s.equals(IMarker.SEVERITY_ERROR)) {
                SigilCore.log("Skipping " + project.getName() + " build due to unresolved errors");
                return false;
            }
        }

        return true;
    }

    private void doBuild(IProject project, IProgressMonitor monitor) throws CoreException {
        ISigilProjectModel sigil = SigilCore.create(project);
        IBldProject bld = sigil.getBldProject();

        File[] classpath = buildClasspath(sigil, monitor);

        String destPattern = buildDestPattern(sigil);

        Properties env = new Properties();

        BundleBuilder bb = new BundleBuilder(bld, classpath, destPattern, env);

        for (IBldProject.IBldBundle bundle : bld.getBundles()) {
            String id = bundle.getId();
            loginfo("creating bundle: " + id);
            int nWarn = 0;
            int nErr = 0;
            String msg = "";

            try {
                boolean modified = bb.createBundle(bundle, false, new BundleBuilder.Log() {
                    public void warn(String msg) {
                        logwarn(msg);
                    }

                    public void verbose(String msg) {
                        loginfo(msg);
                    }
                });
                nWarn = bb.warnings().size();
                if (!modified) {
                    msg = " (not modified)";
                }
            } catch (Exception e) {
                List<String> errors = bb.errors();
                if (errors != null) {
                    nErr = errors.size();
                    for (String err : errors) {
                        logerror(err);
                    }
                }
                // FELIX-1690 - error is already logged no need to throw error as this
                // results in noisy error dialog box
                //throw SigilCore.newCoreException( "Failed to create: " + id + ": " + e, e );
            } finally {
                loginfo(id + ": " + count(nErr, "error") + ", " + count(nWarn, "warning") + msg);
            }
        }
    }

    private static void loginfo(String message) {
        log("INFO: " + message);
    }

    private static void logwarn(String message) {
        log("WARN: " + message);
    }

    private static void logerror(String message) {
        log("ERROR: " + message);
    }

    private static void log(final String message) {
        // do this in background to avoid deadlock with ui 
        Job job = new Job("log") {
            @Override
            protected IStatus run(IProgressMonitor arg0) {
                BuildConsole console = findConsole();
                MessageConsoleStream stream = console.getMessageStream();
                stream.println(message);
                return Status.OK_STATUS;
            }
        };
        job.schedule();
    }

    private static BuildConsole findConsole() {
        BuildConsole console = null;

        IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();

        for (IConsole c : manager.getConsoles()) {
            if (c instanceof BuildConsole) {
                console = (BuildConsole) c;
                break;
            }
        }

        if (console == null) {
            console = new BuildConsole();
            manager.addConsoles(new IConsole[] { console });
        }

        return console;
    }

    private String buildDestPattern(ISigilProjectModel sigil) throws CoreException {
        IPath loc = sigil.findBundleLocation().removeLastSegments(1);

        loc.toFile().mkdirs();

        return loc.toOSString() + File.separator + "[name].jar";
    }

    private File[] buildClasspath(ISigilProjectModel sigil, IProgressMonitor monitor) throws CoreException {
        LinkedList<File> files = new LinkedList<File>();
        if (sigil.getBundle().getClasspathEntrys().isEmpty()) {
            IClasspathEntry[] entries = sigil.getJavaModel().getResolvedClasspath(true);
            for (IClasspathEntry cp : entries) {
                convert(cp, sigil, files);
            }
        } else {
            buildLocalClasspath(sigil, files);
            buildExternalClasspath(sigil, files, monitor);
        }
        return files.toArray(new File[files.size()]);
    }

    private void buildExternalClasspath(ISigilProjectModel sigil, List<File> files, IProgressMonitor monitor)
            throws CoreException {
        Collection<IClasspathEntry> entries = sigil.findExternalClasspath(monitor);

        for (IClasspathEntry cp : entries) {
            convert(cp, sigil, files);
        }
    }

    private void buildLocalClasspath(ISigilProjectModel sigil, List<File> files) throws CoreException {
        Collection<IClasspathEntry> entries = JavaHelper.findClasspathEntries(sigil.getBundle());
        for (IClasspathEntry cp : entries) {
            convert(cp, sigil, files);
        }
    }

    private void convert(IClasspathEntry cp, ISigilProjectModel sigil, List<File> files) throws CoreException {
        switch (cp.getEntryKind()) {
        case IClasspathEntry.CPE_PROJECT: {
            convertProject(cp, files);
            break;
        }
        case IClasspathEntry.CPE_SOURCE: {
            convertSource(sigil, cp, files);
            break;
        }
        case IClasspathEntry.CPE_LIBRARY: {
            convertLibrary(sigil, cp, files);
            break;
        }
        case IClasspathEntry.CPE_VARIABLE:
            convertVariable(cp, files);
            break;
        }
    }

    private void convertVariable(IClasspathEntry cp, List<File> files) {
        cp = JavaCore.getResolvedClasspathEntry(cp);
        if (cp != null) {
            IPath p = cp.getPath();
            files.add(p.toFile());
        }
    }

    private void convertLibrary(ISigilProjectModel sigil, IClasspathEntry cp, List<File> files) {
        IPath p = cp.getPath();

        IProject project = sigil.getProject().getWorkspace().getRoot().getProject(p.segment(0));
        if (project.exists()) {
            p = project.getLocation().append(p.removeFirstSegments(1));
        }

        files.add(p.toFile());
    }

    private void convertSource(ISigilProjectModel sigil, IClasspathEntry cp, List<File> files)
            throws JavaModelException {
        IPath path = cp.getOutputLocation() == null ? sigil.getJavaModel().getOutputLocation()
                : cp.getOutputLocation();
        IFolder buildFolder = sigil.getProject().getFolder(path.removeFirstSegments(1));
        if (buildFolder.exists()) {
            files.add(buildFolder.getLocation().toFile());
        }
    }

    private void convertProject(IClasspathEntry cp, List<File> files) throws CoreException {
        IProject p = findProject(cp.getPath());
        ISigilProjectModel project = SigilCore.create(p);
        if (project.getBundle().getClasspathEntrys().isEmpty()) {
            // ew this is pretty messy - if a dependent bundle specifies it's dependencies
            // via package statements vs source directories then we need to add
            // the classpath path of that bundle
            for (IClasspathEntry rp : project.getJavaModel().getResolvedClasspath(true)) {
                convert(rp, project, files);
            }
        } else {
            for (String scp : project.getBundle().getClasspathEntrys()) {
                IClasspathEntry jcp = project.getJavaModel().decodeClasspathEntry(scp);
                convert(jcp, project, files);
            }
        }
    }

    private IProject findProject(IPath path) throws CoreException {
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        for (IProject p : root.getProjects()) {
            IPath projectPath = p.getFullPath();
            if (projectPath.equals(path)) {
                return p;
            }
        }

        throw SigilCore.newCoreException("No such project " + path, null);
    }

    private String count(int count, String msg) {
        return count + " " + msg + (count == 1 ? "" : "s");
    }
}