org.maven.ide.eclipse.embedder.BuildPathManager.java Source code

Java tutorial

Introduction

Here is the source code for org.maven.ide.eclipse.embedder.BuildPathManager.java

Source

/*
 * Licensed to the Codehaus 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.maven.ide.eclipse.embedder;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
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.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IElementChangedListener;
import org.eclipse.jdt.core.IJavaElementDelta;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.DeltaProcessingState;
import org.eclipse.jdt.internal.core.JavaElementDelta;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.ui.packageview.PackageExplorerContentProvider;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMInstallType;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.LibraryLocation;
import org.eclipse.jface.preference.IPreferenceStore;

import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.InvalidArtifactRTException;
import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.embedder.MavenEmbedder;
import org.apache.maven.embedder.MavenEmbedderException;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.ReactorManager;
import org.apache.maven.extension.ExtensionScanningException;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.Resource;
import org.apache.maven.project.InvalidProjectModelException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.validation.ModelValidationResult;

import org.maven.ide.eclipse.Maven2Plugin;
import org.maven.ide.eclipse.Messages;
import org.maven.ide.eclipse.container.Maven2ClasspathContainer;
import org.maven.ide.eclipse.index.MavenRepositoryIndexManager;
import org.maven.ide.eclipse.launch.console.Maven2Console;
import org.maven.ide.eclipse.preferences.Maven2PreferenceConstants;
import org.maven.ide.eclipse.util.Util;

public class BuildPathManager {

    public static final String CLASSPATH_COMPONENT_DEPENDENCY = "org.eclipse.jst.component.dependency";

    public static final String CLASSPATH_COMPONENT_NON_DEPENDENCY = "org.eclipse.jst.component.nondependency";

    public static final String PACKAGING_WAR = "war";

    private final MavenEmbedderManager embedderManager;

    private final Maven2Console console;

    private final MavenModelManager mavenModelManager;

    private final MavenRepositoryIndexManager indexManager;

    private final IPreferenceStore preferenceStore;

    private final RefreshJob refreshJob;

    private String jdtVersion;

    public BuildPathManager(MavenEmbedderManager embedderManager, Maven2Console console,
            MavenModelManager mavenModelManager, MavenRepositoryIndexManager indexManager,
            IPreferenceStore preferenceStore) {
        this.embedderManager = embedderManager;
        this.console = console;
        this.mavenModelManager = mavenModelManager;
        this.indexManager = indexManager;
        this.preferenceStore = preferenceStore;
        this.refreshJob = new RefreshJob(this, console);
    }

    public static IClasspathEntry getDefaultContainerEntry() {
        return JavaCore.newContainerEntry(new Path(Maven2Plugin.CONTAINER_ID));
    }

    public static ResolverConfiguration getResolverConfiguration(IJavaProject javaProject) {
        return getResolverConfiguration(getMavenContainerEntry(javaProject));
    }

    public static ResolverConfiguration getResolverConfiguration(IClasspathEntry entry) {
        if (entry == null) {
            return new ResolverConfiguration();
        }

        boolean includeModules = entry == null ? false : //
                entry.getPath().toString().indexOf("/" + Maven2Plugin.INCLUDE_MODULES) > -1;

        boolean resolveWorkspaceProjects = entry == null ? true : //
                entry.getPath().toString().indexOf("/" + Maven2Plugin.NO_WORKSPACE_PROJECTS) == -1;

        return new ResolverConfiguration(includeModules, resolveWorkspaceProjects, getActiveProfiles(entry));
    }

    public static IClasspathEntry createContainerEntry(ResolverConfiguration configuration) {
        IPath newPath = new Path(Maven2Plugin.CONTAINER_ID);
        if (configuration.shouldIncludeModules()) {
            newPath = newPath.append(Maven2Plugin.INCLUDE_MODULES);
        }
        if (!configuration.shouldResolveWorkspaceProjects()) {
            newPath = newPath.append(Maven2Plugin.NO_WORKSPACE_PROJECTS);
        }
        if (configuration.getActiveProfiles().length() > 0) {
            newPath = newPath
                    .append(Maven2Plugin.ACTIVE_PROFILES + "[" + configuration.getActiveProfiles().trim() + "]");
        }

        return JavaCore.newContainerEntry(newPath);
    }

    public static IClasspathEntry getMavenContainerEntry(IJavaProject javaProject) {
        IClasspathEntry[] classpath;
        try {
            classpath = javaProject.getRawClasspath();
        } catch (JavaModelException ex) {
            return null;
        }
        for (int i = 0; i < classpath.length; i++) {
            IClasspathEntry entry = classpath[i];
            if (isMaven2ClasspathContainer(entry.getPath())) {
                return entry;
            }
        }
        return null;
    }

    private static String getActiveProfiles(IClasspathEntry entry) {
        String path = entry.getPath().toString();
        String prefix = "/" + Maven2Plugin.ACTIVE_PROFILES + "[";
        int n = path.indexOf(prefix);
        if (n == -1) {
            return "";
        }

        return path.substring(n + prefix.length(), path.indexOf("]", n));
    }

    public void updateClasspathContainer(IProject project, IProgressMonitor monitor) throws CoreException {
        monitor.setTaskName("Updating " + project.getName());
        ClasspathContainerResolver updater = new ClasspathContainerResolver(embedderManager, mavenModelManager,
                console, preferenceStore, monitor);
        updater.resolve(project);
        setClasspathContainer(updater.getResolved(), monitor);
    }

    void setClasspathContainer(Map resolved, IProgressMonitor monitor) throws CoreException {
        monitor.setTaskName("Setting classpath containers");
        for (Iterator it = resolved.entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            IJavaProject javaProject = JavaCore.create((IProject) entry.getKey());
            IClasspathContainer container = (IClasspathContainer) entry.getValue();
            if (javaProject != null && container != null) {

                JavaCore.setClasspathContainer(container.getPath(), new IJavaProject[] { javaProject },
                        new IClasspathContainer[] { container }, monitor);

                // XXX In Eclipse 3.3, changes to resolved classpath are not announced by JDT Core
                // and PackageExplorer does not properly refresh when we update Maven
                // classpath container.
                // As a temporary workaround, send F_CLASSPATH_CHANGED notifications
                // to all PackageExplorerContentProvider instances listening to
                // java ElementChangedEvent. 
                // Note that even with this hack, build clean is sometimes necessary to
                // reconcile PackageExplorer with actual classpath
                // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=154071
                if (getJDTVersion().startsWith("3.3")) {
                    DeltaProcessingState state = JavaModelManager.getJavaModelManager().deltaState;
                    synchronized (state) {
                        IElementChangedListener[] listeners = state.elementChangedListeners;
                        for (int i = 0; i < listeners.length; i++) {
                            if (listeners[i] instanceof PackageExplorerContentProvider) {
                                JavaElementDelta delta = new JavaElementDelta(javaProject);
                                delta.changed(IJavaElementDelta.F_CLASSPATH_CHANGED);
                                listeners[i].elementChanged(
                                        new ElementChangedEvent(delta, ElementChangedEvent.POST_CHANGE));
                            }
                        }
                    }
                }
            }
        }
    }

    private synchronized String getJDTVersion() {
        if (jdtVersion == null) {
            Bundle[] bundles = Maven2Plugin.getDefault().getBundleContext().getBundles();
            for (int i = 0; i < bundles.length; i++) {
                if (JavaCore.PLUGIN_ID.equals(bundles[i].getSymbolicName())) {
                    jdtVersion = (String) bundles[i].getHeaders().get(Constants.BUNDLE_VERSION);
                    break;
                }
            }
        }
        return jdtVersion;
    }

    public void updateSourceFolders(IProject project, ResolverConfiguration configuration,
            IProgressMonitor monitor) {
        IFile pom = project.getFile(Maven2Plugin.POM_FILE_NAME);
        if (!pom.exists()) {
            return;
        }

        monitor.beginTask("Updating sources " + project.getName(), IProgressMonitor.UNKNOWN);
        long t1 = System.currentTimeMillis();
        try {
            Set sources = new LinkedHashSet();
            List entries = new ArrayList();

            MavenProject mavenProject = collectSourceEntries(project, entries, sources, configuration, monitor);

            monitor.subTask("Configuring Build Path");
            IJavaProject javaProject = JavaCore.create(project);

            if (mavenProject != null) {
                Map options = collectOptions(mavenProject);
                setOption(javaProject, options, JavaCore.COMPILER_COMPLIANCE);
                setOption(javaProject, options, JavaCore.COMPILER_SOURCE);
                setOption(javaProject, options, JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM);

                String source = (String) options.get(JavaCore.COMPILER_SOURCE);
                if (source == null) {
                    entries.add(JavaRuntime.getDefaultJREContainerEntry());
                } else {
                    entries.add(getJREContainer(source));
                }
            }

            IClasspathEntry[] currentClasspath = javaProject.getRawClasspath();
            for (int i = 0; i < currentClasspath.length; i++) {
                // Delete all non container (e.g. JRE library) entries. See MNGECLIPSE-9 
                IClasspathEntry entry = currentClasspath[i];
                if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
                    if (!JavaRuntime.JRE_CONTAINER.equals(entry.getPath().segment(0))) {
                        entries.add(entry);
                    }
                }
            }

            if (mavenProject != null) {
                String outputDirectory = toRelativeAndFixSeparator(project.getLocation().toFile(), //
                        mavenProject.getBuild().getOutputDirectory());
                IFolder outputFolder = project.getFolder(outputDirectory);
                Util.createFolder(outputFolder);
                javaProject.setRawClasspath(
                        (IClasspathEntry[]) entries.toArray(new IClasspathEntry[entries.size()]),
                        outputFolder.getFullPath(), monitor);
            } else {
                javaProject.setRawClasspath(
                        (IClasspathEntry[]) entries.toArray(new IClasspathEntry[entries.size()]), monitor);
            }

            long t2 = System.currentTimeMillis();
            console.logMessage(
                    "Updated source folders for project " + project.getName() + " " + (t2 - t1) / 1000 + "sec");

        } catch (Exception ex) {
            String msg = "Unable to update source folders " + project.getName() + "; " + ex.toString();
            console.logMessage(msg);
            Maven2Plugin.log(msg, ex);

        } finally {
            monitor.done();
        }
    }

    private void setOption(IJavaProject javaProject, Map options, String name) {
        String newValue = (String) options.get(name);
        if (newValue == null) {
            newValue = (String) JavaCore.getDefaultOptions().get(name);
        }

        String currentValue = javaProject.getOption(name, false);
        if (!newValue.equals(currentValue)) {
            javaProject.setOption(name, newValue);
        }
    }

    private IClasspathEntry getJREContainer(String version) {
        int n = VERSIONS.indexOf(version);
        if (n > -1) {
            Map jreContainers = getJREContainers();
            for (int i = n; i < VERSIONS.size(); i++) {
                IClasspathEntry entry = (IClasspathEntry) jreContainers.get(version);
                if (entry != null) {
                    console.logMessage("JRE compliant to " + version + ". " + entry);
                    return entry;
                }
            }
        }
        IClasspathEntry entry = JavaRuntime.getDefaultJREContainerEntry();
        console.logMessage("No JRE compliant to " + version + ". Using default JRE container " + entry);
        return entry;
    }

    private Map getJREContainers() {
        Map jreContainers = new HashMap();

        jreContainers.put(getJREVersion(JavaRuntime.getDefaultVMInstall()),
                JavaRuntime.getDefaultJREContainerEntry());

        IVMInstallType[] installTypes = JavaRuntime.getVMInstallTypes();
        for (int i = 0; i < installTypes.length; i++) {
            IVMInstall[] installs = installTypes[i].getVMInstalls();
            for (int j = 0; j < installs.length; j++) {
                IVMInstall install = installs[j];
                String version = getJREVersion(install);
                if (!jreContainers.containsKey(version)) {
                    // in Eclipse 3.2 one could use JavaRuntime.newJREContainerPath(install)
                    IPath jreContainerPath = new Path(JavaRuntime.JRE_CONTAINER)
                            .append(install.getVMInstallType().getId()).append(install.getName());
                    jreContainers.put(version, JavaCore.newContainerEntry(jreContainerPath));
                }
            }
        }

        return jreContainers;
    }

    private String getJREVersion(IVMInstall install) {
        LibraryLocation[] libraryLocations = JavaRuntime.getLibraryLocations(install);
        if (libraryLocations != null) {
            for (int k = 0; k < libraryLocations.length; k++) {
                IPath path = libraryLocations[k].getSystemLibraryPath();
                String jarName = path.lastSegment();
                // TODO that won't be the case on Mac
                if ("rt.jar".equals(jarName)) {
                    try {
                        JarFile jarFile = new JarFile(path.toFile());
                        Manifest manifest = jarFile.getManifest();
                        Attributes attributes = manifest.getMainAttributes();
                        return attributes.getValue(Attributes.Name.SPECIFICATION_VERSION);
                    } catch (Exception ex) {
                        console.logError("Unable to read " + path + " " + ex.getMessage());
                    }
                }
            }
        }
        return null;
    }

    private MavenProject collectSourceEntries(IProject project, List sourceEntries, Set sources,
            ResolverConfiguration configuration, IProgressMonitor monitor) {
        if (monitor.isCanceled()) {
            throw new OperationCanceledException();
        }

        Maven2Plugin plugin = Maven2Plugin.getDefault();
        IPreferenceStore preferenceStore = plugin.getPreferenceStore();
        boolean offline = preferenceStore.getBoolean(Maven2PreferenceConstants.P_OFFLINE);
        boolean debug = preferenceStore.getBoolean(Maven2PreferenceConstants.P_DEBUG_OUTPUT);
        String globalSettings = preferenceStore.getString(Maven2PreferenceConstants.P_GLOBAL_SETTINGS_FILE);

        MavenEmbedder mavenEmbedder;
        try {
            // XXX should use project embedder with resolving from workspace?
            mavenEmbedder = EmbedderFactory.createMavenEmbedder(EmbedderFactory.createExecutionCustomizer(),
                    new PluginConsoleMavenEmbeddedLogger(console, debug), globalSettings);
        } catch (MavenEmbedderException ex) {
            console.logError("Unable to create embedder; " + ex.toString());
            return null;
        }

        IFile pomResource = project.getFile(Maven2Plugin.POM_FILE_NAME);

        monitor.setTaskName("Reading " + pomResource.getFullPath());
        if (preferenceStore.getBoolean(Maven2PreferenceConstants.P_DEBUG_OUTPUT)) {
            console.logMessage("Reading " + pomResource.getFullPath());
        }

        File pomFile = pomResource.getLocation().toFile();

        MavenProject mavenProject;
        //    try {
        //      mavenProject = mavenEmbedder.readProject(pomFile);
        //    } catch(Exception ex) {
        //      console.logError("Unable to read project " + pomResource.getFullPath() + "; " + ex.toString());
        //      return null;
        //    }

        File basedir = pomResource.getLocation().toFile().getParentFile();
        File projectBaseDir = project.getLocation().toFile();

        monitor.subTask("Generating Sources " + pomResource.getFullPath());
        try {
            console.logMessage("Generating sources " + pomResource.getFullPath());

            MavenExecutionRequest request = EmbedderFactory.createMavenExecutionRequest(mavenEmbedder, offline,
                    debug);

            request.setUseReactor(false);
            request.setRecursive(configuration.shouldIncludeModules());

            request.setBaseDirectory(pomFile.getParentFile());
            request.setGoals(Collections.singletonList("process-test-resources"));
            request.addEventMonitor(new PluginConsoleEventMonitor(console));
            request.setTransferListener(new TransferListenerAdapter(monitor, console, indexManager));
            // request.setPomFile(pomFile.getAbsolutePath());
            // request.setGoals(Arrays.asList("generate-sources,generate-resources,generate-test-sources,generate-test-resources".split(",")));
            // request.setProfiles(...);
            // request.setReactorFailureBehavior(MavenExecutionRequest.REACTOR_FAIL_AT_END);

            MavenExecutionResult result = mavenEmbedder.execute(request);

            // TODO optimize project refresh
            monitor.subTask("Refreshing");
            project.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 1));

            mavenProject = result.getProject();

            ReactorManager reactorManager = result.getReactorManager();
            if (reactorManager != null && reactorManager.getSortedProjects() != null) {
                if (configuration.shouldIncludeModules()) {
                    for (Iterator it = reactorManager.getSortedProjects().iterator(); it.hasNext();) {
                        addDirs(project, sources, sourceEntries, (MavenProject) it.next(), basedir, projectBaseDir);
                    }
                } else {
                    addDirs(project, sources, sourceEntries, //
                            (MavenProject) reactorManager.getSortedProjects().iterator().next(), //
                            basedir, projectBaseDir);
                }
            }

            if (result.hasExceptions()) {
                for (Iterator it = result.getExceptions().iterator(); it.hasNext();) {
                    Exception ex = (Exception) it.next();
                    console.logError("Build error for " + pomResource.getFullPath() + "; " + ex.toString());
                }
            }

            if (mavenProject == null) {
                try {
                    mavenProject = mavenEmbedder.readProject(pomFile);
                } catch (Exception ex2) {
                    console.logError("Unable to read project " + pomResource.getFullPath() + "; " + ex2.toString());
                    return null;
                }
            }

        } catch (Exception ex) {
            String msg = "Build error for " + pomResource.getFullPath();
            console.logError(msg + "; " + ex.toString());
            Maven2Plugin.log(msg, ex);

            try {
                mavenProject = mavenEmbedder.readProject(pomFile);
            } catch (Exception ex2) {
                console.logError("Unable to read project " + pomResource.getFullPath() + "; " + ex.toString());
                return null;
            }

            addDirs(project, sources, sourceEntries, mavenProject, basedir, projectBaseDir);
        }

        return mavenProject;
    }

    private Map collectOptions(MavenProject mavenProject) {
        Map options = new HashMap();

        String source = getBuildOption(mavenProject, "maven-compiler-plugin", "source");
        if (source != null) {
            if (VERSIONS.contains(source)) {
                console.logMessage("Setting source compatibility: " + source);
                setVersion(options, JavaCore.COMPILER_SOURCE, source);
                setVersion(options, JavaCore.COMPILER_COMPLIANCE, source);
            } else {
                console.logError("Invalid compiler source " + source + ". Using default");
            }
        }

        String target = getBuildOption(mavenProject, "maven-compiler-plugin", "target");
        if (target != null) {
            if (VERSIONS.contains(target)) {
                console.logMessage("Setting target compatibility: " + source);
                setVersion(options, JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, target);
            } else {
                console.logError("Invalid compiler target " + target + ". Using default");
            }
        }

        return options;
    }

    private void addDirs(IContainer project, Set sources, List sourceEntries, MavenProject mavenProject,
            File basedir, File projectBaseDir) {
        addSourceDirs(project, sources, sourceEntries, mavenProject.getCompileSourceRoots(), basedir,
                projectBaseDir);
        addSourceDirs(project, sources, sourceEntries, mavenProject.getTestCompileSourceRoots(), basedir,
                projectBaseDir);

        addResourceDirs(project, sources, sourceEntries, mavenProject.getBuild().getResources(), basedir,
                projectBaseDir);
        addResourceDirs(project, sources, sourceEntries, mavenProject.getBuild().getTestResources(), basedir,
                projectBaseDir);

        // HACK to support xmlbeans generated classes MNGECLIPSE-374
        File generatedClassesDir = new File(mavenProject.getBuild().getDirectory(),
                "generated-classes" + File.separator + "xmlbeans");
        IResource generatedClasses = project.findMember(toRelativeAndFixSeparator(projectBaseDir, //
                generatedClassesDir.getAbsolutePath()));
        if (generatedClasses != null && generatedClasses.isAccessible()
                && generatedClasses.getType() == IResource.FOLDER) {
            sourceEntries.add(JavaCore.newLibraryEntry(generatedClasses.getFullPath(), null, null));
        }
    }

    private void addSourceDirs(IContainer project, Set sources, List sourceEntries, List sourceRoots, File basedir,
            File projectBaseDir) {
        for (Iterator it = sourceRoots.iterator(); it.hasNext();) {
            String sourceRoot = (String) it.next();
            if (new File(sourceRoot).isDirectory()) {
                IResource r = project.findMember(toRelativeAndFixSeparator(projectBaseDir, sourceRoot));
                if (r != null && sources.add(r.getFullPath().toString())) {
                    sourceEntries.add(JavaCore
                            .newSourceEntry(r.getFullPath() /*, new IPath[] { new Path( "**"+"/.svn/"+"**")} */));
                    console.logMessage("Adding source folder " + r.getFullPath());
                }
            }
        }
    }

    private void addResourceDirs(IContainer project, Set sources, List sourceEntries, List resources, File basedir,
            File projectBaseDir) {
        for (Iterator it = resources.iterator(); it.hasNext();) {
            Resource resource = (Resource) it.next();
            File resourceDirectory = new File(resource.getDirectory());
            if (resourceDirectory.exists() && resourceDirectory.isDirectory()) {
                IResource r = project
                        .findMember(toRelativeAndFixSeparator(projectBaseDir, resource.getDirectory()));
                if (r != null && sources.add(r.getFullPath().toString())) {
                    sourceEntries.add(JavaCore.newSourceEntry(r.getFullPath(), new IPath[] { new Path("**") },
                            r.getFullPath())); //, new IPath[] { new Path( "**"+"/.svn/"+"**")} ) );
                    console.logMessage("Adding resource folder " + r.getFullPath());
                }
            }
        }
    }

    private String toRelativeAndFixSeparator(File basedir, String absolutePath) {
        String relative;
        if (absolutePath.equals(basedir.getAbsolutePath())) {
            relative = ".";
        } else if (absolutePath.startsWith(basedir.getAbsolutePath())) {
            relative = absolutePath.substring(basedir.getAbsolutePath().length() + 1);
        } else {
            relative = absolutePath;
        }
        return relative.replace('\\', '/'); //$NON-NLS-1$ //$NON-NLS-2$
    }

    public void enableMavenNature(IProject project, ResolverConfiguration configuration, IProgressMonitor monitor)
            throws CoreException, JavaModelException {
        monitor.subTask("Enable Maven nature");

        ArrayList newNatures = new ArrayList();
        newNatures.add(JavaCore.NATURE_ID);
        newNatures.add(Maven2Plugin.NATURE_ID);

        IProjectDescription description = project.getDescription();
        String[] natures = description.getNatureIds();
        for (int i = 0; i < natures.length; ++i) {
            String id = natures[i];
            if (!Maven2Plugin.NATURE_ID.equals(id) && !JavaCore.NATURE_ID.equals(natures[i])) {
                newNatures.add(natures[i]);
            }
        }
        description.setNatureIds((String[]) newNatures.toArray(new String[newNatures.size()]));
        project.setDescription(description, monitor);

        IJavaProject javaProject = JavaCore.create(project);
        if (javaProject != null) {
            Set containerEntrySet = new LinkedHashSet();
            IClasspathContainer container = getMaven2ClasspathContainer(javaProject);
            if (container != null) {
                IClasspathEntry[] entries = container.getClasspathEntries();
                for (int i = 0; i < entries.length; i++) {
                    containerEntrySet.add(entries[i].getPath().toString());
                }
            }

            // remove classpath container from JavaProject
            IClasspathEntry[] entries = javaProject.getRawClasspath();
            ArrayList newEntries = new ArrayList();
            for (int i = 0; i < entries.length; i++) {
                IClasspathEntry entry = entries[i];
                if (!isMaven2ClasspathContainer(entry.getPath())
                        && !containerEntrySet.contains(entry.getPath().toString())) {
                    newEntries.add(entry);
                }
            }

            newEntries.add(createContainerEntry(configuration));

            javaProject.setRawClasspath(
                    (IClasspathEntry[]) newEntries.toArray(new IClasspathEntry[newEntries.size()]), monitor);
        }
    }

    public void disableMavenNature(IProject project, IProgressMonitor monitor) {
        monitor.subTask("Disable Maven nature");

        try {
            project.deleteMarkers(Maven2Plugin.MARKER_ID, true, IResource.DEPTH_INFINITE);

            IProjectDescription description = project.getDescription();
            String[] natures = description.getNatureIds();
            ArrayList newNatures = new ArrayList();
            for (int i = 0; i < natures.length; ++i) {
                if (!Maven2Plugin.NATURE_ID.equals(natures[i])) {
                    newNatures.add(natures[i]);
                }
            }
            description.setNatureIds((String[]) newNatures.toArray(new String[newNatures.size()]));
            project.setDescription(description, null);

            IJavaProject javaProject = JavaCore.create(project);
            if (javaProject != null) {
                // remove classpatch container from JavaProject
                IClasspathEntry[] entries = javaProject.getRawClasspath();
                ArrayList newEntries = new ArrayList();
                for (int i = 0; i < entries.length; i++) {
                    if (!isMaven2ClasspathContainer(entries[i].getPath())) {
                        newEntries.add(entries[i]);
                    }
                }
                javaProject.setRawClasspath(
                        (IClasspathEntry[]) newEntries.toArray(new IClasspathEntry[newEntries.size()]), null);
            }

        } catch (CoreException ex) {
            Maven2Plugin.log(ex);
        }
    }

    public static boolean isMaven2ClasspathContainer(IPath containerPath) {
        return containerPath != null && containerPath.segmentCount() > 0
                && Maven2Plugin.CONTAINER_ID.equals(containerPath.segment(0));
    }

    public static IClasspathContainer getMaven2ClasspathContainer(IJavaProject project) throws JavaModelException {
        IClasspathEntry[] entries = project.getRawClasspath();
        for (int i = 0; i < entries.length; i++) {
            IClasspathEntry entry = entries[i];
            if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER
                    && isMaven2ClasspathContainer(entry.getPath())) {
                return JavaCore.getClasspathContainer(entry.getPath(), project);
            }
        }
        return null;
    }

    private static String getBuildOption(MavenProject project, String artifactId, String optionName) {
        String option = getBuildOption(project.getBuild().getPlugins(), artifactId, optionName);
        if (option != null) {
            return option;
        }
        PluginManagement pluginManagement = project.getBuild().getPluginManagement();
        if (pluginManagement != null) {
            return getBuildOption(pluginManagement.getPlugins(), artifactId, optionName);
        }
        return null;
    }

    private static String getBuildOption(List plugins, String artifactId, String optionName) {
        for (Iterator it = plugins.iterator(); it.hasNext();) {
            Plugin plugin = (Plugin) it.next();
            if (artifactId.equals(plugin.getArtifactId())) {
                Xpp3Dom o = (Xpp3Dom) plugin.getConfiguration();
                if (o != null && o.getChild(optionName) != null) {
                    return o.getChild(optionName).getValue();
                }
            }
        }
        return null;
    }

    private static final List VERSIONS = Arrays.asList("1.1,1.2,1.3,1.4,1.5,1.6,1.7".split(","));

    private static void setVersion(Map options, String name, String value) {
        if (value == null) {
            return;
        }
        String current = (String) options.get(name);
        if (current == null) {
            options.put(name, value);
        } else {
            int oldIndex = VERSIONS.indexOf(current);
            int newIndex = VERSIONS.indexOf(value.trim());
            if (newIndex > oldIndex) {
                options.put(name, value);
            }
        }
    }

    static void addMarker(IResource resource, String message, int lineNumber, int severity) {
        try {
            if (resource.isAccessible()) {
                IMarker marker = resource.createMarker(Maven2Plugin.MARKER_ID);
                marker.setAttribute(IMarker.MESSAGE, message);
                marker.setAttribute(IMarker.SEVERITY, severity);
                if (lineNumber == -1) {
                    lineNumber = 1;
                }
                marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
            }
        } catch (CoreException ex) {
            Maven2Plugin.getDefault().getConsole().logError("Unable to add marker; " + ex.toString());
        }
    }

    static void deleteMarkers(IResource resource) {
        try {
            if (resource.isAccessible()) {
                resource.deleteMarkers(Maven2Plugin.MARKER_ID, false, IResource.DEPTH_ZERO);
            }
        } catch (CoreException ex) {
            Maven2Plugin.getDefault().getConsole().logError("Unable to delete marker; " + ex.toString());
        }
    }

    public IProject importProject(File pomFile, Model model, ResolverConfiguration configuration,
            IProgressMonitor monitor) throws CoreException {
        String projectName = model.getArtifactId();
        IWorkspace workspace = ResourcesPlugin.getWorkspace();

        IWorkspaceRoot root = workspace.getRoot();
        IProject project = root.getProject(projectName);
        if (project.exists()) {
            return null;
        }

        if (pomFile.getAbsolutePath().startsWith(workspace.getRoot().getLocation().toFile().getAbsolutePath())) {
            project.create(monitor);
        } else {
            IProjectDescription description = workspace.newProjectDescription(projectName);
            description.setLocation(new Path(pomFile.getParentFile().getAbsolutePath()));
            project.create(description, monitor);
        }

        if (!project.isOpen()) {
            project.open(monitor);
        }

        configureProject(project, configuration, monitor);

        return project;
    }

    public void configureProject(IProject project, ResolverConfiguration configuration, IProgressMonitor monitor)
            throws CoreException {
        BuildPathManager buildpathManager = Maven2Plugin.getDefault().getBuildpathManager();
        buildpathManager.enableMavenNature(project, configuration, monitor);
        buildpathManager.updateSourceFolders(project, configuration, monitor);
        //    buildpathManager.updateClasspathContainer(project, monitor);
    }

    /**
     * Schedules classpath container of the given project to be refreshed in a background job. This method returns
     * immediately.
     */
    public void scheduleUpdateClasspathContainer(IProject project) {
        refreshJob.queueRefresh(project);
    }

    /**
     * Schedules classpath containers of the given collection of projects to be refreshed in a background job. This method
     * returns immediately.
     */
    public void scheduleUpdateClasspathContainer(Collection projects) {
        refreshJob.queueRefresh(projects);
    }

    static class RefreshJob extends WorkspaceJob {

        private static final long PROCESSING_DELAY = 1000L;

        private final BuildPathManager buildPathManager;

        private final Maven2Console console;

        private final ArrayList queue = new ArrayList();

        public RefreshJob(BuildPathManager buildPathManager, Maven2Console console) {
            super("Maven classpath container refresh job");
            this.buildPathManager = buildPathManager;
            this.console = console;
        }

        public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
            while (true) {
                Set projects = new LinkedHashSet();
                synchronized (queue) {
                    projects.addAll(queue);
                    queue.clear();
                }
                if (projects.isEmpty()) {
                    break;
                }

                ClasspathContainerResolver resolver = new ClasspathContainerResolver(
                        buildPathManager.embedderManager, buildPathManager.mavenModelManager,
                        buildPathManager.console, buildPathManager.preferenceStore, monitor);

                for (Iterator it = projects.iterator(); it.hasNext();) {
                    IProject project = (IProject) it.next();
                    try {
                        resolver.resolve(project);
                    } catch (Exception e) {
                        console.logError("Unable to refresh classpath container: " + e);
                    }
                }
                buildPathManager.setClasspathContainer(resolver.getResolved(), monitor);
            }
            return Status.OK_STATUS;
        }

        public void queueRefresh(IProject project) {
            synchronized (queue) {
                queue.add(project);
            }
            schedule(PROCESSING_DELAY);
        }

        public void queueRefresh(Collection projects) {
            if (projects == null || projects.isEmpty())
                return;
            synchronized (queue) {
                queue.addAll(projects);
            }
            schedule(PROCESSING_DELAY);
        }
    }

    public static class ClasspathContainerResolver {

        private final MavenEmbedderManager embedderManager;

        private final MavenModelManager mavenModelManager;

        private final Maven2Console console;

        private final IPreferenceStore preferenceStore;

        private final IProgressMonitor monitor;

        private final Map resolved = new LinkedHashMap();

        private MavenEmbedder workspaceAwareEmbedder;

        private MavenEmbedder defaultEmbedder;

        private final Map mavenProjects = new HashMap();

        public ClasspathContainerResolver(MavenEmbedderManager embedderManager, MavenModelManager mavenModelManager,
                Maven2Console console, IPreferenceStore preferenceStore, IProgressMonitor monitor) {
            this.embedderManager = embedderManager;
            this.mavenModelManager = mavenModelManager;
            this.console = console;
            this.preferenceStore = preferenceStore;
            this.monitor = monitor;
        }

        public Map getResolved() {
            return resolved;
        }

        public void stop() {
            stopEmbedder(workspaceAwareEmbedder);
            stopEmbedder(defaultEmbedder);
        }

        private void stopEmbedder(MavenEmbedder embedder) {
            if (embedder != null) {
                try {
                    embedder.stop();
                } catch (MavenEmbedderException ex) {
                    String msg = "Unable to stop project embedder; " + ex.getMessage();
                    console.logError(msg);
                    Maven2Plugin.log(CLASSPATH_COMPONENT_DEPENDENCY, ex);
                }
            }
        }

        public void resolve(IProject project) throws JavaModelException, CoreException {
            if (monitor.isCanceled()) {
                throw new OperationCanceledException();
            }
            monitor.subTask("resolving " + project.getName());

            IJavaProject javaProject = JavaCore.create(project);
            ResolverConfiguration resolverConfiguration = getResolverConfiguration(javaProject);

            IFile pomFile = project.getFile(Maven2Plugin.POM_FILE_NAME);

            Set entries = new LinkedHashSet();
            Map moduleArtifacts = new LinkedHashMap();

            deleteMarkers(project);
            try {
                mavenModelManager.updateMavenModel(pomFile, resolverConfiguration.shouldIncludeModules(), monitor);
            } catch (CoreException ex) {
                addMarker(pomFile, ex.getMessage(), 1, IMarker.SEVERITY_ERROR);
            }

            MavenEmbedder embedder;
            if (resolverConfiguration.shouldResolveWorkspaceProjects()) {
                if (workspaceAwareEmbedder == null) {
                    workspaceAwareEmbedder = embedderManager
                            .createEmbedder(EmbedderFactory.createWorkspaceCustomizer(true));
                }
                embedder = workspaceAwareEmbedder;
            } else {
                if (defaultEmbedder == null) {
                    defaultEmbedder = embedderManager
                            .createEmbedder(EmbedderFactory.createWorkspaceCustomizer(false));
                }
                embedder = defaultEmbedder;
            }

            if (embedder != null) {
                resolveClasspathEntries(entries, moduleArtifacts, pomFile, pomFile, resolverConfiguration, monitor,
                        embedder);
            }

            IClasspathEntry containerEntry = getMavenContainerEntry(javaProject);
            if (containerEntry != null) {
                Maven2ClasspathContainer container = new Maven2ClasspathContainer(containerEntry.getPath(),
                        entries);
                resolved.put(project, container);
            } else {
                resolved.put(project, null); // TODO test me
            }

            Set dependentProjects = mavenModelManager.getDependentProjects(pomFile);
            for (Iterator it = dependentProjects.iterator(); it.hasNext();) {
                IProject p = (IProject) it.next();
                if (!resolved.containsKey(p)) {
                    resolve(p);
                }
            }
        }

        private void resolveClasspathEntries(Set entries, Map moduleArtifacts, IFile rootPomFile, IFile pomFile,
                ResolverConfiguration resolverConfiguration, IProgressMonitor monitor, MavenEmbedder embedder) {
            if (monitor.isCanceled()) {
                throw new OperationCanceledException();
            }

            if (pomFile == null || !pomFile.isAccessible()) {
                return;
            }

            monitor.subTask("reading " + pomFile.getFullPath());
            if (preferenceStore.getBoolean(Maven2PreferenceConstants.P_DEBUG_OUTPUT)) {
                console.logMessage("Reading " + pomFile.getFullPath());
            }

            deleteMarkers(pomFile);

            IProject currentProject = pomFile.getProject();
            try {
                boolean offline = preferenceStore.getBoolean(Maven2PreferenceConstants.P_OFFLINE);
                boolean downloadSources = !offline
                        & preferenceStore.getBoolean(Maven2PreferenceConstants.P_DOWNLOAD_SOURCES);
                boolean downloadJavadoc = !offline
                        & preferenceStore.getBoolean(Maven2PreferenceConstants.P_DOWNLOAD_JAVADOC);
                boolean debug = preferenceStore.getBoolean(Maven2PreferenceConstants.P_DEBUG_OUTPUT);

                MavenProject mavenProject = getMavenProject(pomFile, resolverConfiguration, monitor, embedder,
                        offline, debug);
                if (mavenProject == null) {
                    return;
                }

                // deleteMarkers(pomFile);
                // TODO use version?
                moduleArtifacts.put(mavenProject.getGroupId() + ":" + mavenProject.getArtifactId() + ":"
                        + mavenProject.getVersion(), mavenProject.getArtifact());

                // From MNGECLIPSE-105
                // If the current project is a WAR project AND it has
                // a dynamic web project nature, make sure that any workspace
                // projects that it depends on are NOT included in any way
                // in the container (neither as projects nor as artifacts).
                // The idea is that the inclusion is controlled explicitly
                // by a developer via WTP UI.
                boolean skipWorkspaceProjectsForWeb = PACKAGING_WAR.equals(mavenProject.getPackaging())
                        && hasDynamicWebProjectNature(currentProject);

                // Set artifacts = mavenProject.getArtifacts();
                // TODO merge all artifacts into a single list; may need to refine this
                List artifacts = new ArrayList();
                artifacts.addAll(mavenProject.getCompileArtifacts());
                artifacts.addAll(mavenProject.getTestArtifacts());
                artifacts.addAll(mavenProject.getRuntimeArtifacts());
                artifacts.addAll(mavenProject.getSystemArtifacts());
                // artifacts.addAll(mavenProject.getAttachedArtifacts());
                // artifacts.addAll(mavenProject.getDependencyArtifacts());

                for (Iterator it = artifacts.iterator(); it.hasNext();) {
                    if (monitor.isCanceled()) {
                        throw new OperationCanceledException();
                    }

                    Artifact a = (Artifact) it.next();

                    monitor.subTask("Processing " + a.getId());

                    // String artifactKey = a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getVersion() + ":" + a.getType();
                    String artifactKey = a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getVersion() + ":"
                            + a.getClassifier();
                    if (moduleArtifacts.containsKey(artifactKey)) {
                        continue;
                    }

                    //          ArtifactHandler artifactHandler = embedder.getArtifactHandler(a);
                    //          if(!artifactHandler.isAddedToClasspath()
                    //              || !("jar".equals(artifactHandler.getExtension()) || "zip".equals(artifactHandler.getExtension()))) {
                    //            continue;
                    //          }

                    moduleArtifacts.put(artifactKey, a);

                    ArrayList attributes = new ArrayList();

                    mavenModelManager.addProjectArtifact(pomFile, a);
                    // this is needed to projects with have modules (either inner or external)
                    mavenModelManager.addProjectArtifact(rootPomFile, a);

                    String scope = a.getScope();
                    // Check the scope & set WTP non-dependency as appropriate
                    if (Artifact.SCOPE_PROVIDED.equals(scope) || Artifact.SCOPE_TEST.equals(scope)
                            || Artifact.SCOPE_SYSTEM.equals(scope)) {
                        attributes.add(JavaCore.newClasspathAttribute(CLASSPATH_COMPONENT_NON_DEPENDENCY, ""));
                    }

                    IFile artifactPomFile = mavenModelManager.getArtifactFile(a);
                    if (artifactPomFile != null) {
                        IProject artifactProject = artifactPomFile.getProject();
                        if (artifactProject.getFullPath().equals(currentProject.getFullPath())) {
                            // This is another artifact in our current project so we should not
                            // add our own project to ourself
                            continue;
                        }

                        if (skipWorkspaceProjectsForWeb) {
                            // From MNGECLIPSE-105
                            // Leave it out so that the user can handle it the WTP way
                            continue;
                        }
                    }

                    if (resolverConfiguration.shouldResolveWorkspaceProjects()) {
                        mavenModelManager.addProjectArtifact(pomFile, a);
                        // this is needed to projects with have modules (either inner or external)
                        mavenModelManager.addProjectArtifact(rootPomFile, a);

                        if (artifactPomFile != null) {
                            IProject artifactProject = artifactPomFile.getProject();
                            entries.add(JavaCore.newProjectEntry(artifactProject.getFullPath(), false));
                            continue;
                        }
                    }

                    File artifactFile = a.getFile();
                    if (artifactFile == null) {
                        // Embedder returns unresolved artifacts when dependencies can't be downloaded 
                        try {
                            embedder.resolve(a, mavenProject.getRemoteArtifactRepositories(),
                                    embedder.getLocalRepository());
                            artifactFile = a.getFile();
                        } catch (AbstractArtifactResolutionException ex) {
                            String name = ex.getGroupId() + ":" + ex.getArtifactId() + "-" + ex.getVersion() + "-"
                                    + ex.getType();
                            console.logError("Unable resolve artifact " + name);
                        }
                    }

                    if (artifactFile != null) {
                        String artifactLocation = artifactFile.getAbsolutePath();

                        Path srcPath = materializeArtifactPath(embedder, mavenProject, a, "java-source", "sources",
                                downloadSources, monitor);

                        attributes.add(
                                JavaCore.newClasspathAttribute(Maven2Plugin.GROUP_ID_ATTRIBUTE, a.getGroupId()));
                        attributes.add(JavaCore.newClasspathAttribute(Maven2Plugin.ARTIFACT_ID_ATTRIBUTE,
                                a.getArtifactId()));
                        attributes.add(
                                JavaCore.newClasspathAttribute(Maven2Plugin.VERSION_ATTRIBUTE, a.getVersion()));

                        if (srcPath == null) { // no need to search for javadoc if we have source code
                            Path javadocPath = materializeArtifactPath(embedder, mavenProject, a, "javadoc",
                                    "javadoc", downloadJavadoc, monitor);
                            String javaDocUrl = null;
                            if (javadocPath != null) {
                                javaDocUrl = Maven2ClasspathContainer.getJavaDocUrl(javadocPath.toString());
                            } else {
                                javaDocUrl = getJavaDocUrl(artifactLocation, monitor);
                            }
                            if (javaDocUrl != null) {
                                attributes.add(JavaCore.newClasspathAttribute(
                                        IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, javaDocUrl));
                            }
                        }

                        entries.add(JavaCore.newLibraryEntry(new Path(artifactLocation), //
                                srcPath, null, new IAccessRule[0], //
                                (IClasspathAttribute[]) attributes
                                        .toArray(new IClasspathAttribute[attributes.size()]), // 
                                false /*not exported*/));
                    }
                }

                if (resolverConfiguration.shouldIncludeModules()) {
                    IContainer basedir = pomFile.getParent();

                    List modules = mavenProject.getModules();
                    for (Iterator it = modules.iterator(); it.hasNext() && !monitor.isCanceled();) {
                        if (monitor.isCanceled()) {
                            throw new OperationCanceledException();
                        }

                        String module = (String) it.next();
                        IResource memberPom = basedir.findMember(module + "/" + Maven2Plugin.POM_FILE_NAME); //$NON-NLS-1$
                        if (memberPom != null && memberPom.getType() == IResource.FILE) {
                            resolveClasspathEntries(entries, moduleArtifacts, // 
                                    rootPomFile, (IFile) memberPom, resolverConfiguration, monitor, embedder);
                        }
                    }
                }

            } catch (OperationCanceledException ex) {
                throw ex;

            } catch (InvalidArtifactRTException ex) {
                addMarker(pomFile, ex.getBaseMessage(), 1, IMarker.SEVERITY_ERROR);
                console.logError("Unable to read " + getPomName(pomFile) + "; " + ex.getBaseMessage());

            } catch (IllegalStateException ex) {
                addMarker(pomFile, ex.getMessage(), 1, IMarker.SEVERITY_ERROR);
                console.logError("Unable to read " + getPomName(pomFile) + "; " + ex.getMessage());

            } catch (Throwable ex) {
                addMarker(pomFile, ex.toString(), 1, IMarker.SEVERITY_ERROR);

                String msg = "Unable to read " + getPomName(pomFile) + "; " + ex.toString();
                console.logError(msg);
                Maven2Plugin.log(msg, ex);

            } finally {
                monitor.done();

            }
        }

        private MavenProject getMavenProject(IFile pomFile, ResolverConfiguration resolverConfiguration,
                IProgressMonitor monitor, MavenEmbedder embedder, boolean offline, boolean debug) {
            //      MavenProject mavenProject = (MavenProject) mavenProjects.get(pomFile);
            //      if(mavenProject==null) {
            MavenExecutionResult result = mavenModelManager.readMavenProject(pomFile.getLocation().toFile(),
                    monitor, offline, debug, resolverConfiguration, embedder);
            MavenProject mavenProject = getMavenProject(pomFile, result);
            // mavenProjects.put(pomFile, mavenProject);
            //      }
            return mavenProject;
        }

        private String getJavaDocUrl(String artifactLocation, IProgressMonitor monitor) throws CoreException {
            // guess the javadoc url from the project url in the artifact's pom.xml
            File file = new File(artifactLocation.substring(0, artifactLocation.length() - 4) + ".pom");
            if (file.exists()) {
                Model model = mavenModelManager.readMavenModel(file);
                String url = model.getUrl();
                if (url != null) {
                    url = url.trim();
                    if (url.length() > 0) {
                        if (!url.endsWith("/"))
                            url += "/";
                        return url + "apidocs/"; // assuming project is using maven-generated site
                    }
                }
            }
            return null;
        }

        // type = "java-source"
        private Path materializeArtifactPath(MavenEmbedder embedder, MavenProject mavenProject, Artifact a,
                String type, String suffix, boolean download, IProgressMonitor monitor) throws Exception {
            File artifactFile = a.getFile();
            if (artifactFile == null) {
                console.logError("Missing artifact file for " + a.getId());
                return null;
            }

            String artifactLocation = artifactFile.getAbsolutePath();

            // XXX MNGECLIPSE-205
            File file;
            if ("java-source".equals(type) && "tests".equals(a.getArtifactHandler().getClassifier())) {
                suffix = "test-sources";
                file = new File(artifactLocation.substring(0, artifactLocation.length() - "-tests.jar".length())
                        + "-" + suffix + ".jar");
            } else {
                // artifactLocation ends on '.jar' or '.zip'
                file = new File(artifactLocation.substring(0, artifactLocation.length() - ".jar".length()) + "-"
                        + suffix + ".jar");
            }

            if (file.exists()) {
                // workaround to not download already existing archive
                return new Path(file.getAbsolutePath());
            }

            if (download) {
                monitor.beginTask("Resolving " + type + " " + a.getId(), IProgressMonitor.UNKNOWN);
                try {
                    // TODO need to take into account issue with the "test-sources"
                    Artifact f = embedder.createArtifactWithClassifier(a.getGroupId(), a.getArtifactId(),
                            a.getVersion(), type, suffix);
                    if (f != null) {
                        embedder.resolve(f, mavenProject.getRemoteArtifactRepositories(),
                                embedder.getLocalRepository());
                        return new Path(f.getFile().getAbsolutePath());
                    }
                } catch (AbstractArtifactResolutionException ex) {
                    String name = ex.getGroupId() + ":" + ex.getArtifactId() + "-" + ex.getVersion() + "."
                            + ex.getType();
                    console.logError("Unable to download " + type + " for artifact " + name);
                    if (!"java-source".equals(type) && !"javadoc".equals(type)) {
                        console.logError("Error: " + ex.getOriginalMessage());
                    }
                } finally {
                    monitor.done();
                }
            }
            return null;
        }

        private MavenProject getMavenProject(IFile pomFile, MavenExecutionResult result) {
            addErrorMarkers(pomFile, result);

            if (!result.hasExceptions()) {
                return result.getProject();
            }

            for (Iterator it = result.getExceptions().iterator(); it.hasNext();) {
                Exception ex = (Exception) it.next();
                if (ex instanceof ExtensionScanningException) {
                    if (ex.getCause() instanceof ProjectBuildingException) {
                        handleProjectBuildingException(pomFile, (ProjectBuildingException) ex.getCause());
                    } else {
                        handleBuildException(pomFile, ex);
                    }

                } else if (ex instanceof ProjectBuildingException) {
                    handleProjectBuildingException(pomFile, (ProjectBuildingException) ex);

                } else if (ex instanceof AbstractArtifactResolutionException) {
                    // String msg = ex.getMessage().replaceAll("----------", "").replaceAll("\r\n\r\n", "\n").replaceAll("\n\n", "\n");
                    // addMarker(pomFile, msg, 1, IMarker.SEVERITY_ERROR);
                    // console.logError(msg);

                    AbstractArtifactResolutionException rex = (AbstractArtifactResolutionException) ex;
                    String errorMessage = getArtifactId(rex) + " " + getErrorMessage(ex);
                    addMarker(pomFile, errorMessage, 1, IMarker.SEVERITY_ERROR);
                    console.logError(errorMessage);

                    try {
                        // TODO
                        File file = pomFile.getLocation().toFile();
                        return embedderManager.getWorkspaceEmbedder().readProject(file);

                    } catch (ProjectBuildingException ex2) {
                        handleProjectBuildingException(pomFile, ex2);
                    } catch (Exception ex2) {
                        handleBuildException(pomFile, ex2);
                    }

                } else {
                    handleBuildException(pomFile, ex);
                }
            }
            return null;
        }

        private void addErrorMarkers(IFile pomFile, MavenExecutionResult result) {
            ArtifactResolutionResult resolutionResult = result.getArtifactResolutionResult();
            if (resolutionResult != null) {
                // List missingArtifacts = resolutionResult.getMissingArtifacts();
                addErrorMarkers(pomFile, "Metadata resolution error",
                        resolutionResult.getMetadataResolutionExceptions());
                addErrorMarkers(pomFile, "Artifact error", resolutionResult.getErrorArtifactExceptions());
                addErrorMarkers(pomFile, "Version range violation", resolutionResult.getVersionRangeViolations());
                addErrorMarkers(pomFile, "Curcular dependency error",
                        resolutionResult.getCircularDependencyExceptions());
            }
        }

        private void addErrorMarkers(IFile pomFile, String msg, List exceptions) {
            if (exceptions != null) {
                for (Iterator it = exceptions.iterator(); it.hasNext();) {
                    Exception ex = (Exception) it.next();
                    if (ex instanceof AbstractArtifactResolutionException) {
                        AbstractArtifactResolutionException rex = (AbstractArtifactResolutionException) ex;
                        String errorMessage = getArtifactId(rex) + " " + getErrorMessage(ex);
                        addMarker(pomFile, errorMessage, 1, IMarker.SEVERITY_ERROR);
                        console.logError(errorMessage);

                    } else {
                        addMarker(pomFile, ex.getMessage(), 1, IMarker.SEVERITY_ERROR);
                        console.logError(msg + "; " + ex.toString());
                    }
                }
            }
        }

        private String getArtifactId(AbstractArtifactResolutionException rex) {
            String id = rex.getGroupId() + ":" + rex.getArtifactId() + ":" + rex.getVersion();
            if (rex.getClassifier() != null) {
                id += ":" + rex.getClassifier();
            }
            if (rex.getType() != null) {
                id += ":" + rex.getType();
            }
            return id;
        }

        private String getErrorMessage(Exception ex) {
            Throwable lastCause = ex;
            Throwable cause = lastCause.getCause();

            String msg = lastCause.getMessage();
            while (cause != null && cause != lastCause) {
                msg = cause.getMessage();
                //        if(lastCause instanceof ResourceDoesNotExistException) {
                //          msg = ((ResourceDoesNotExistException) lastCause).getLocalizedMessage();
                //        } else {
                //        }
                lastCause = cause;
                cause = cause.getCause();
            }

            return msg;
        }

        private void handleBuildException(IFile pomFile, Exception ex) {
            String msg = Messages.getString("plugin.markerBuildError") + ex.getMessage();
            addMarker(pomFile, msg, 1, IMarker.SEVERITY_ERROR); //$NON-NLS-1$
            console.logError(msg);
        }

        private void handleProjectBuildingException(IFile pomFile, ProjectBuildingException ex) {
            Throwable cause = ex.getCause();
            if (cause instanceof XmlPullParserException) {
                XmlPullParserException pex = (XmlPullParserException) cause;
                console.logError(Messages.getString("plugin.markerParsingError") + getPomName(pomFile) + "; "
                        + pex.getMessage());
                addMarker(pomFile, pex.getMessage(), pex.getLineNumber(), IMarker.SEVERITY_ERROR); //$NON-NLS-1$

            } else if (ex instanceof InvalidProjectModelException) {
                InvalidProjectModelException mex = (InvalidProjectModelException) ex;
                ModelValidationResult validationResult = mex.getValidationResult();
                String msg = Messages.getString("plugin.markerBuildError") + mex.getMessage();
                console.logError(msg);
                if (validationResult == null) {
                    addMarker(pomFile, msg, 1, IMarker.SEVERITY_ERROR); //$NON-NLS-1$
                } else {
                    for (Iterator it = validationResult.getMessages().iterator(); it.hasNext();) {
                        String message = (String) it.next();
                        addMarker(pomFile, message, 1, IMarker.SEVERITY_ERROR); //$NON-NLS-1$
                        console.logError("  " + message);
                    }
                }

            } else {
                handleBuildException(pomFile, ex);
            }
        }

        private String getPomName(IFile pomFile) {
            return pomFile.getProject().getName() + "/" + pomFile.getProjectRelativePath();
        }

        private boolean hasDynamicWebProjectNature(IProject project) {
            try {
                if (project.hasNature("org.eclipse.wst.common.modulecore.ModuleCoreNature")
                        || project.hasNature("org.eclipse.wst.common.project.facet.core.nature")) {
                    return true;
                }
            } catch (Exception e) {
                console.logError("Unable to inspect nature: " + e);
            }
            return false;
        }

    }

}