org.ops4j.pax.construct.lifecycle.EclipseOSGiMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.ops4j.pax.construct.lifecycle.EclipseOSGiMojo.java

Source

package org.ops4j.pax.construct.lifecycle;

/*
 * Copyright 2007 Stuart McCulloch
 *
 * Licensed 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.
 */

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.regex.Pattern;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.eclipse.EclipsePlugin;
import org.apache.maven.plugin.eclipse.EclipseSourceDir;
import org.apache.maven.plugin.eclipse.writers.EclipseClasspathWriter;
import org.apache.maven.plugin.eclipse.writers.EclipseProjectWriter;
import org.apache.maven.plugin.eclipse.writers.EclipseSettingsWriter;
import org.apache.maven.plugin.eclipse.writers.EclipseWriterConfig;
import org.apache.maven.plugin.ide.IdeDependency;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.apache.maven.project.path.PathTranslator;
import org.apache.maven.shared.osgi.Maven2OsgiConverter;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
import org.codehaus.plexus.util.xml.Xpp3DomWriter;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.ops4j.pax.construct.util.DirUtils;
import org.ops4j.pax.construct.util.DirUtils.EntryFilter;
import org.ops4j.pax.construct.util.PomUtils;
import org.ops4j.pax.construct.util.ReflectMojo;
import org.ops4j.pax.construct.util.StreamFactory;

/**
 * Extends <a href="http://maven.apache.org/plugins/maven-eclipse-plugin/eclipse-mojo.html">EclipsePlugin</a> to
 * provide customized Eclipse project files for Pax-Construct projects.<br/>Inherited parameters can still be used, but
 * unfortunately don't appear in the generated docs.
 * 
 * @extendsPlugin eclipse
 * @goal eclipse
 * @phase package
 * 
 * @execute phase="none"
 */
public class EclipseOSGiMojo extends EclipsePlugin {
    /**
     * Component factory for Maven projects
     * 
     * @component
     */
    private MavenProjectBuilder m_mavenProjectBuilder;

    /**
     * Component to convert between Maven and OSGi versions
     * 
     * @component
     */
    private Maven2OsgiConverter m_maven2OsgiConverter;

    /**
     * Project path translation (needed for backwards compatibility)
     * 
     * @component
     */
    private PathTranslator m_pathTranslator;

    /**
     * Switch to turn on/off fixing of dependency entries in the classpath file.
     *
     * @parameter expression="${fixDependencies}" default-value="EXTERNAL"
     */
    private String fixDependencies;

    /**
     * Provide access to the private fields of the Eclipse mojo
     */
    private ReflectMojo m_eclipseMojo;

    /**
     * The main project when generating Eclipse project files for imported bundles
     */
    private MavenProject m_provisionProject;

    /**
     * IDE dependencies that might be embedded inside the bundle
     */
    private List m_embeddableDependencies;

    /**
     * {@inheritDoc}
     */
    public boolean setup() throws MojoExecutionException {
        // we don't fork eclipse goal
        setExecutedProject(project);

        if (null != m_provisionProject) {
            enablePDE(); // imported OSGi bundle
        } else if (PomUtils.isBundleProject(executedProject)) {
            enablePDE(); // compiled OSGi bundle

            setUseProjectReferences(false);
        } else if (ProvisionMojo.isProvisioningPom(executedProject)) {
            try {
                /*
                 * unpack imported bundles and generate Eclipse files one-by-one
                 */
                setupImportedBundles();
            } catch (InvalidDependencyVersionException e) {
                getLog().warn("Unable to generate Eclipse files for project " + executedProject.getId());
            }

            /*
             * don't create Eclipse files for the provisioning POM itself!
             */
            return false;
        }

        // default to normal behaviour
        return super.setup();
    }

    /**
     * Enable PDE support
     */
    private void enablePDE() {
        if (null == m_eclipseMojo) {
            // by default enable creation of PDE project files for OSGi
            m_eclipseMojo = new ReflectMojo(this, EclipsePlugin.class);
        }

        m_eclipseMojo.setField("pde", Boolean.TRUE);
        setWtpversion("none");

        List containers = getClasspathContainers();
        if (null != containers && !containers.contains(REQUIRED_PLUGINS_CONTAINER)) {
            containers.add(REQUIRED_PLUGINS_CONTAINER);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void writeConfiguration(IdeDependency[] deps) throws MojoExecutionException {
        if (!isPdeProject()) {
            // non-OSGi project
            super.writeConfiguration(deps);
        } else {
            m_embeddableDependencies = new ArrayList();

            if (null == m_provisionProject) {
                // compiled OSGi bundle / wrapper
                writeBundleConfiguration(deps);
            } else {
                // imported (external) OSGi bundle
                writeImportedConfiguration();
            }
        }
    }

    /**
     * Customize Eclipse project files for Pax-Construct generated bundles
     * 
     * @param deps resolved project dependencies, potentially with sources and javadocs
     * @throws MojoExecutionException
     */
    private void writeBundleConfiguration(IdeDependency[] deps) throws MojoExecutionException {
        for (int i = 0; i < deps.length; i++) {
            if (deps[i].isAddedToClasspath()) {
                // cache here so we can attach sources to embedded entries
                if (!deps[i].isTestDependency() && !deps[i].isProvided()) {
                    m_embeddableDependencies.add(deps[i]);
                }

                /*
                 * Change potential test dependencies to be non-OSGi otherwise they won't appear as Required Libraries.
                 * We include provided dependencies here because PDE might not add them as Plug-in Dependencies, it all
                 * depends on the manifest (which won't necessarily import packages used during testing)
                 */
                deps[i] = fixOSGiTestDependency(deps[i]);
            }
        }

        EclipseWriterConfig config = createEclipseWriterConfig(deps);

        config.setEclipseProjectName(getEclipseProjectName(executedProject, true));

        new EclipseSettingsWriter().init(getLog(), config).write();
        new EclipseClasspathWriter().init(getLog(), config).write();
        new EclipseProjectWriter().init(getLog(), config).write();

        /*
         * copy bundle manifest to where PDE expects it, but tweak it to fix embedded paths
         */
        refactorForEclipse(getBundleFile(executedProject));

        writeAdditionalConfig();
    }

    /**
     * @param bundleProject bundle project
     * @return recently built bundle
     */
    private File getBundleFile(MavenProject bundleProject) {
        Artifact artifact = bundleProject.getArtifact();
        File bundleFile = artifact.getFile();

        if (null == bundleFile || !bundleFile.exists()) {
            // no file attached in this cycle, so check local build
            String name = bundleProject.getBuild().getFinalName() + ".jar";
            bundleFile = new File(bundleProject.getBuild().getDirectory(), name);
        }

        if (!bundleFile.exists()) {
            // last chance: see if it is already has been installed locally
            PomUtils.getFile(artifact, artifactResolver, localRepository);
            bundleFile = artifact.getFile();
        }

        return bundleFile;
    }

    /**
     * The maven-eclipse-plugin has a bug where test dependencies that are also OSGi bundles are excluded from the
     * .classpath because they are expected to be on the Bundle-ClassPath. However, this is not a valid assumption
     * because the Maven test-cases and their dependencies do not necessarily end-up packaged inside the bundle.
     * 
     * @param dependency an IDE test dependency
     * @return fixed IDE test dependency
     */
    private IdeDependency fixOSGiTestDependency(IdeDependency dependency) {
        if ("FALSE".equalsIgnoreCase(fixDependencies)) {
            return dependency;
        }

        // by default, don't fix dependencies pointing to local projects found in the same tree
        if ("EXTERNAL".equalsIgnoreCase(fixDependencies) && isReactorDependency(dependency)) {
            return dependency;
        }

        // previous behaviour in 1.3 was exhaustive search of the poms in the local file-system
        if ("CUSTOM".equalsIgnoreCase(fixDependencies)) {
            String id = dependency.getGroupId() + ':' + dependency.getArtifactId();
            File baseDir = executedProject.getBasedir();

            if (DirUtils.findPom(baseDir, id) != null) {
                return dependency;
            }
        }

        // unfortunately there's no setIsOsgiBundle() method, so we have to replace the whole dependency...
        IdeDependency testDependency = new IdeDependency(dependency.getGroupId(), dependency.getArtifactId(),
                dependency.getVersion(), dependency.getClassifier(), dependency.isReferencedProject(), true, false,
                false, dependency.isAddedToClasspath(), dependency.getFile(), dependency.getType(), false, null, 0,
                dependency.getEclipseProjectName());

        testDependency.setSourceAttachment(dependency.getSourceAttachment());
        testDependency.setJavadocAttachment(dependency.getJavadocAttachment());

        return testDependency;
    }

    private boolean isReactorDependency(IdeDependency dependency) {
        // check current reactor...
        if (reactorProjects != null) {
            for (Iterator i = reactorProjects.iterator(); i.hasNext();) {
                MavenProject reactorProject = (MavenProject) i.next();

                if (reactorProject.getGroupId().equals(dependency.getGroupId())
                        && reactorProject.getArtifactId().equals(dependency.getArtifactId())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Provide better naming for Pax-Construct generated OSGi bundles
     * 
     * @param project current Maven project
     * @param addVersion when true, add the project version to the name
     * @return an Eclipse friendly name for the bundle
     */
    private static String getEclipseProjectName(MavenProject project, boolean addVersion) {
        String projectName = project.getProperties().getProperty("bundle.symbolicName");
        if (null == projectName) {
            // fall back to standard "groupId.artifactId" but try to eliminate duplicate segments
            projectName = PomUtils.getCompoundId(project.getGroupId(), project.getArtifactId());
        }

        if (addVersion) {
            // check for wrapper version, which reflects the version of the wrapped contents
            String projectVersion = project.getProperties().getProperty("wrapped.version");
            if (null == projectVersion) {
                projectVersion = project.getVersion();
            }

            return projectName + " [" + projectVersion + ']';
        }

        return projectName;
    }

    /**
     * Select files for unpacking that don't exist locally under target/classes
     */
    private static class IncludedContentFilter implements EntryFilter {
        private final File m_outputDir;

        /**
         * @param outputDir build output directory
         */
        public IncludedContentFilter(File outputDir) {
            m_outputDir = outputDir;
        }

        /**
         * {@inheritDoc}
         */
        public boolean accept(String name) {
            // always select metadata folders as we may need to refactor them
            if (name.startsWith("META-INF") || name.startsWith("OSGI-INF")) {
                return true;
            }
            // also select any embedded jars
            else if (name.endsWith(".jar")) {
                return true;
            }

            // do we already have this file locally?
            return new File(m_outputDir, name).exists() == false;
        }
    }

    /**
     * Copy OSGi metadata to where Eclipse PDE expects it, but adjust the Bundle-ClassPath so Eclipse can find any
     * embedded jars or directories in the unpacked bundle contents under the temporary directory
     * 
     * @param bundleFile the packaged bundle
     */
    private void refactorForEclipse(File bundleFile) {
        // temporary location in the output folder
        String tempPath = "target/pax-eclipse";
        boolean refactorManifest = false;

        // make relative to the provisioning POM
        File baseDir = executedProject.getBasedir();
        File unpackDir = new File(baseDir, tempPath);

        if (bundleFile == null || !bundleFile.exists()) {
            getLog().warn("Bundle has not been built, reverting to basic behaviour");
        } else {
            DirUtils.unpackBundle(bundleFile, unpackDir, new IncludedContentFilter(getBuildOutputDirectory()));

            moveMetadata(unpackDir, "META-INF", baseDir);
            moveMetadata(unpackDir, "OSGI-INF", baseDir);

            // test to see if it's empty
            unpackDir.delete();

            refactorManifest = unpackDir.exists();
        }

        File manifestFile = new File(baseDir, "META-INF/MANIFEST.MF");

        Manifest manifest = getBundleManifest(manifestFile);
        Attributes mainAttributes = manifest.getMainAttributes();

        if (mainAttributes.getValue("Bundle-SymbolicName") == null) {
            // Eclipse mis-behaves if the bundle has no symbolic name :(
            String name = getEclipseProjectName(executedProject, false);
            mainAttributes.putValue("Bundle-SymbolicName", name.replace('-', '_'));
        }

        String bundleClassPath = mainAttributes.getValue("Bundle-ClassPath");

        /*
         * refactor Bundle-ClassPath to help Eclipse find the unpacked contents
         */
        if (refactorManifest) {
            bundleClassPath = ".," + DirUtils.rebasePaths(bundleClassPath, tempPath, ',');
            mainAttributes.putValue("Bundle-ClassPath", bundleClassPath);

            // add the embedded entries back to the Eclipse classpath
            addEmbeddedEntriesToEclipseClassPath(tempPath, bundleClassPath);
        }

        try {
            manifestFile.getParentFile().mkdirs();
            FileOutputStream out = new FileOutputStream(manifestFile);
            manifest.write(out);
            IOUtil.close(out);
        } catch (IOException e) {
            getLog().warn("Unable to update Eclipse manifest: " + manifestFile);
        }

        createBuildProperties(baseDir, tempPath);
    }

    /**
     * Create simple build.properties file so the export functionality from Eclipse/PDE works
     * 
     * @param baseDir project base directory
     * @param unpackPath path where the additional bundle contents were unpacked
     */
    private void createBuildProperties(File baseDir, String unpackPath) {
        File buildPropertiesFile = new File(baseDir, "build.properties");
        if (!buildPropertiesFile.exists()) {
            BufferedWriter writer = null;
            try {
                writer = new BufferedWriter(new FileWriter(buildPropertiesFile));

                /* compiled/wrapped bundle */
                if (null != unpackPath) {
                    File sourceDir = new File(baseDir, "src/main/java");
                    if (sourceDir.exists()) {
                        writer.write("source.. = src/main/java/,src/main/resources/");
                        writer.newLine();
                    }

                    writer.write("output.. = target/classes/");
                    writer.newLine();
                    writer.write("bin.includes = META-INF/,.");
                    if (new File(baseDir, unpackPath).exists()) {
                        writer.write(',' + unpackPath + '/');
                    }
                    writer.newLine();
                }
                /* imported bundle */
                else {
                    File bundleFile = executedProject.getArtifact().getFile();
                    if (null != bundleFile && bundleFile.isFile()) {
                        writer.write("install.location = " + bundleFile.toURI());
                        writer.newLine();
                    }
                    writer.write("source.. = .");
                    writer.newLine();
                    writer.write("output.. = .");
                    writer.newLine();
                    writer.write("bin.includes = META-INF/,.");
                    writer.newLine();
                }
            } catch (IOException e) {
                getLog().warn("Unable to create build.properties file");
            } finally {
                IOUtil.close(writer);
            }
        }
    }

    /**
     * @param manifestFile path to the local bundle manifest
     * @return the bundle manifest, or sane defaults if the manifest couldn't be opened
     */
    private Manifest getBundleManifest(File manifestFile) {
        Manifest manifest = new Manifest();

        try {
            FileInputStream in = new FileInputStream(manifestFile);
            manifest.read(in);
            IOUtil.close(in);
        } catch (IOException e) {
            Attributes mainAttributes = manifest.getMainAttributes();

            String osgiVersion = m_maven2OsgiConverter.getVersion(project.getVersion());

            // standard OSGi entries
            mainAttributes.putValue("Manifest-Version", "1");
            mainAttributes.putValue("Bundle-ManifestVersion", "2");
            mainAttributes.putValue("Bundle-Name", project.getName());
            mainAttributes.putValue("Bundle-Version", osgiVersion);

            // some basic OSGi dependencies, to help people get their code compiling...
            mainAttributes.putValue("Import-Package", "org.osgi.framework,org.osgi.util.tracker");
        }

        return manifest;
    }

    /**
     * @param fromDir source directory
     * @param metadata metadata folder
     * @param toDir target directory
     */
    private void moveMetadata(File fromDir, String metadata, File toDir) {
        File metadataDir = new File(fromDir, metadata);
        if (metadataDir.exists()) {
            try {
                FileUtils.copyDirectoryStructure(metadataDir, new File(toDir, metadata));
                FileUtils.deleteDirectory(metadataDir);
            } catch (IOException e) {
                getLog().warn("Unable to copy " + metadata + " contents to base directory");
            }
        }
    }

    /**
     * Add any embedded Bundle-ClassPath entries to the Eclipse classpath and re-attach sources/javadocs
     * 
     * @param bundleLocation relative path to the unpacked bundle
     * @param bundleClassPath the refactored Bundle-ClassPath
     */
    private void addEmbeddedEntriesToEclipseClassPath(String bundleLocation, String bundleClassPath) {
        String[] classPath = bundleClassPath.split(",");
        File basedir = executedProject.getBasedir();

        try {
            File classPathFile = new File(basedir, ".classpath");
            Reader reader = StreamFactory.newXmlReader(classPathFile);
            Xpp3Dom classPathXML = Xpp3DomBuilder.build(reader);
            IOUtil.close(reader);

            for (int i = 0; i < classPath.length; i++) {
                String binaryPath = classPath[i].trim();

                if (!".".equals(binaryPath) && new File(basedir, binaryPath).exists()) {
                    // embedded jar/directory needs to be a 'lib' entry
                    Xpp3Dom classPathEntry = new Xpp3Dom("classpathentry");
                    classPathEntry.setAttribute("exported", "true");
                    classPathEntry.setAttribute("kind", "lib");
                    classPathEntry.setAttribute("path", binaryPath);

                    // find attached sources using the previously cached IDE dependencies
                    File sourcePath = findAttachedSource(bundleLocation, binaryPath);
                    if (sourcePath != null) {
                        classPathEntry.setAttribute("sourcepath", sourcePath.getPath());
                    }

                    classPathXML.addChild(classPathEntry);
                }
            }

            Writer writer = StreamFactory.newXmlWriter(classPathFile);
            Xpp3DomWriter.write(new PrettyPrintXMLWriter(writer), classPathXML);
            IOUtil.close(writer);
        } catch (IOException e) {
            getLog().warn("Unable to find Eclipse .classpath file");
        } catch (XmlPullParserException e) {
            getLog().warn("Unable to parse Eclipse .classpath file");
        }
    }

    /**
     * Search cached IDE dependencies for an entry matching the given classpath element
     * 
     * @param bundleLocation relative path to the unpacked bundle
     * @param classPathEntry classpath element
     * @return path to the attached sources
     */
    private File findAttachedSource(String bundleLocation, String classPathEntry) {
        for (Iterator i = m_embeddableDependencies.iterator(); i.hasNext();) {
            IdeDependency dependency = (IdeDependency) i.next();

            // equivalent to '.' - source is first in list
            if (bundleLocation.equals(classPathEntry)) {
                return dependency.getSourceAttachment();
            } else if (Pattern.matches("^.*[/\\\\]" + dependency.getArtifactId() + "[-.][^/\\\\]*$",
                    classPathEntry)) {
                return dependency.getSourceAttachment();
            }
        }

        return null;
    }

    /**
     * Unpack each imported bundle in turn and generate the relevant Eclipse project files
     * 
     * @throws InvalidDependencyVersionException
     * @throws MojoExecutionException
     */
    private void setupImportedBundles() throws InvalidDependencyVersionException, MojoExecutionException {
        // don't process dependencies of imported bundles
        m_provisionProject = getExecutedProject();
        setResolveDependencies(false);

        Set artifacts = m_provisionProject.createArtifacts(artifactFactory, null, null);
        for (Iterator i = artifacts.iterator(); i.hasNext();) {
            Artifact artifact = (Artifact) i.next();

            // store project locally underneath the provisioning POM's directory
            File groupDir = new File(m_provisionProject.getBasedir(), "target/" + artifact.getGroupId());
            File baseDir = new File(groupDir, artifact.getArtifactId() + '-' + artifact.getVersion());

            // download and unpack the bundle
            if (!PomUtils.downloadFile(artifact, artifactResolver, remoteArtifactRepositories, localRepository)) {
                getLog().warn("Skipping missing bundle " + artifact);
                continue;
            }

            DirUtils.unpackBundle(artifact.getFile(), baseDir, null);

            // download the bundle POM and store locally
            MavenProject dependencyProject = writeProjectPom(baseDir, artifact);
            if (null == dependencyProject) {
                getLog().warn("Skipping missing bundle " + artifact);
                continue;
            }

            dependencyProject.setArtifact(artifact);

            setExecutedProject(dependencyProject);
            setProject(dependencyProject);

            // trick Eclipse plugin to do the right thing
            setBuildOutputDirectory(new File(baseDir, ".ignore"));
            setEclipseProjectDir(baseDir);

            try {
                // call the Eclipse plugin
                getLog().info("Generating Eclipse project for bundle " + artifact);
                execute();
            } catch (MojoFailureException e) {
                getLog().warn("Problem generating Eclipse files for artifact " + artifact);
            }
        }
    }

    /**
     * Download and save the Maven POM for the given artifact
     * 
     * @param baseDir base directory
     * @param artifact Maven artifact
     * @return the downloaded project
     */
    private MavenProject writeProjectPom(File baseDir, Artifact artifact) {
        MavenProject pom = null;

        String groupId = artifact.getGroupId();
        String artifactId = artifact.getArtifactId();
        String version = artifact.getVersion();

        Artifact pomArtifact = artifactFactory.createProjectArtifact(groupId, artifactId, version);

        try {
            pom = m_mavenProjectBuilder.buildFromRepository(pomArtifact, remoteArtifactRepositories,
                    localRepository);

            // need this when using Maven 2.1 which doesn't do any alignment
            m_pathTranslator.alignToBaseDirectory(pom.getModel(), baseDir);

            File pomFile = new File(baseDir, "pom.xml");

            Writer writer = StreamFactory.newXmlWriter(pomFile);
            pom.writeModel(writer);
            pom.setFile(pomFile);
            IOUtil.close(writer);
        } catch (ProjectBuildingException e) {
            getLog().warn("Unable to build POM for artifact " + pomArtifact);
        } catch (IOException e) {
            getLog().warn("Unable to write POM for artifact " + pomArtifact);
        }

        return pom;
    }

    /**
     * Customize Eclipse project files for imported (unpacked) bundles
     * 
     * @throws MojoExecutionException
     */
    private void writeImportedConfiguration() throws MojoExecutionException {
        EclipseWriterConfig config = createEclipseWriterConfig(new IdeDependency[0]);
        config.setEclipseProjectName(getEclipseProjectName(executedProject, true));
        config.setClasspathContainers(Collections.EMPTY_LIST);
        config.setSourceDirs(new EclipseSourceDir[0]);

        // not compiling, so just need project and classpath files
        new EclipseClasspathWriter().init(getLog(), config).write();
        new EclipseProjectWriter().init(getLog(), config).write();

        Artifact sourceArtifact = artifactFactory.createArtifactWithClassifier(executedProject.getGroupId(),
                executedProject.getArtifactId(), executedProject.getVersion(), "java-source", "sources");

        if (downloadSources) {
            PomUtils.downloadFile(sourceArtifact, artifactResolver, remoteArtifactRepositories, localRepository);
        } else {
            // check to see if we already have the source downloaded...
            PomUtils.getFile(sourceArtifact, artifactResolver, localRepository);
        }

        // set PDE classpath to point to unpacked bundle
        attachImportedContent(sourceArtifact.getFile());

        String baseDir = executedProject.getBasedir().getPath();
        File manifestFile = new File(baseDir, "META-INF/MANIFEST.MF");

        Manifest manifest = getBundleManifest(manifestFile);
        Attributes mainAttributes = manifest.getMainAttributes();

        String bundleClassPath = mainAttributes.getValue("Bundle-ClassPath");
        if (null != bundleClassPath) {
            // add any embedded entries to the default Eclipse classpath
            addEmbeddedEntriesToEclipseClassPath(baseDir, bundleClassPath);
        }

        createBuildProperties(new File(baseDir), null);
    }

    /**
     * Add a classpath entry for the unpacked imported bundle and attach it to the given source
     * 
     * @param sources attached bundle sources
     */
    private void attachImportedContent(File sources) {
        try {
            File classPathFile = new File(executedProject.getBasedir(), ".classpath");
            Reader reader = StreamFactory.newXmlReader(classPathFile);
            Xpp3Dom classPathXML = Xpp3DomBuilder.build(reader);
            IOUtil.close(reader);

            Xpp3Dom classPathEntry = new Xpp3Dom("classpathentry");
            classPathEntry.setAttribute("exported", "true");
            classPathEntry.setAttribute("kind", "lib");
            classPathEntry.setAttribute("path", ".");
            if (sources != null && sources.exists()) {
                classPathEntry.setAttribute("sourcepath", sources.getPath());
            }
            classPathXML.addChild(classPathEntry);

            Writer writer = StreamFactory.newXmlWriter(classPathFile);
            Xpp3DomWriter.write(new PrettyPrintXMLWriter(writer), classPathXML);
            IOUtil.close(writer);
        } catch (IOException e) {
            getLog().warn("Unable to find Eclipse .classpath file");
        } catch (XmlPullParserException e) {
            getLog().warn("Unable to parse Eclipse .classpath file");
        }
    }
}