move nb-repository-plugin to his directory
diff --git a/.gitignore b/.gitignore
index 53f4905..0fac148 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
+
 /target/
-/nbactions.xml
\ No newline at end of file
+/nbactions.xml
+
diff --git a/README.md b/nb-repository-plugin/README.md
similarity index 100%
rename from README.md
rename to nb-repository-plugin/README.md
diff --git a/pom.xml b/nb-repository-plugin/pom.xml
similarity index 100%
rename from pom.xml
rename to nb-repository-plugin/pom.xml
diff --git a/src/it/folder/pom.xml b/nb-repository-plugin/src/it/folder/pom.xml
similarity index 100%
rename from src/it/folder/pom.xml
rename to nb-repository-plugin/src/it/folder/pom.xml
diff --git a/src/it/pom.xml b/nb-repository-plugin/src/it/pom.xml
similarity index 100%
rename from src/it/pom.xml
rename to nb-repository-plugin/src/it/pom.xml
diff --git a/src/it/settings.xml b/nb-repository-plugin/src/it/settings.xml
similarity index 100%
copy from src/it/settings.xml
copy to nb-repository-plugin/src/it/settings.xml
diff --git a/src/main/java/org/codehaus/mojo/nbm/repository/DownloadIndexMojo.java b/nb-repository-plugin/src/main/java/org/codehaus/mojo/nbm/repository/DownloadIndexMojo.java
similarity index 100%
rename from src/main/java/org/codehaus/mojo/nbm/repository/DownloadIndexMojo.java
rename to nb-repository-plugin/src/main/java/org/codehaus/mojo/nbm/repository/DownloadIndexMojo.java
diff --git a/src/main/java/org/codehaus/mojo/nbm/repository/PopulateRepositoryMojo.java b/nb-repository-plugin/src/main/java/org/codehaus/mojo/nbm/repository/PopulateRepositoryMojo.java
similarity index 100%
rename from src/main/java/org/codehaus/mojo/nbm/repository/PopulateRepositoryMojo.java
rename to nb-repository-plugin/src/main/java/org/codehaus/mojo/nbm/repository/PopulateRepositoryMojo.java
diff --git a/src/site/apt/index.apt b/nb-repository-plugin/src/site/apt/index.apt
similarity index 100%
rename from src/site/apt/index.apt
rename to nb-repository-plugin/src/site/apt/index.apt
diff --git a/src/site/apt/repository.apt b/nb-repository-plugin/src/site/apt/repository.apt
similarity index 100%
rename from src/site/apt/repository.apt
rename to nb-repository-plugin/src/site/apt/repository.apt
diff --git a/src/site/site.xml b/nb-repository-plugin/src/site/site.xml
similarity index 100%
rename from src/site/site.xml
rename to nb-repository-plugin/src/site/site.xml
diff --git a/src/test/java/org/codehaus/mojo/nbm/repository/PopulateRepositoryMojoTest.java b/nb-repository-plugin/src/test/java/org/codehaus/mojo/nbm/repository/PopulateRepositoryMojoTest.java
similarity index 100%
rename from src/test/java/org/codehaus/mojo/nbm/repository/PopulateRepositoryMojoTest.java
rename to nb-repository-plugin/src/test/java/org/codehaus/mojo/nbm/repository/PopulateRepositoryMojoTest.java
diff --git a/src/test/resources/PopulateMojoTest.xml b/nb-repository-plugin/src/test/resources/PopulateMojoTest.xml
similarity index 100%
rename from src/test/resources/PopulateMojoTest.xml
rename to nb-repository-plugin/src/test/resources/PopulateMojoTest.xml
diff --git a/nbm-maven-harness/pom.xml b/nbm-maven-harness/pom.xml
new file mode 100644
index 0000000..ef0dada
--- /dev/null
+++ b/nbm-maven-harness/pom.xml
@@ -0,0 +1,222 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>mojo-parent</artifactId>
+        <version>37</version>
+    </parent>
+    <artifactId>nbm-maven-harness</artifactId>
+    <version>8.3-SNAPSHOT</version>
+    <name>NBM Harness for Maven</name>
+    <licenses>
+        <license>
+            <name>CDDL + GPL 2 with Classpath Exception</name>
+            <url>http://netbeans.org/cddl-gplv2.html</url>
+        </license>
+    </licenses>
+    <scm>
+        <connection>scm:git:https://github.com/mojohaus/nbm-maven-harness.git</connection>
+        <developerConnection>scm:git:ssh://git@github.com/mojohaus/nbm-maven-harness.git</developerConnection>
+        <url>https://github.com/mojohaus/nbm-maven-harness/tree/${project.scm.tag}</url>
+        <tag>master</tag>
+    </scm>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>2.4</version>
+                <executions>
+                    <execution>
+                        <phase>generate-resources</phase>
+                        <id>unpack-harness</id>
+                        <goals>
+                            <goal>get</goal>
+                        </goals>
+                        <configuration>
+                            <artifact>org.netbeans.modules:org-netbeans-modules-apisupport-harness:${netbeans.version}:nbm</artifact>
+                            <transitive>false</transitive>
+                            <remoteRepositories>${netbeans.repo}</remoteRepositories>
+                            <destination>${project.build.directory}/harness.nbm</destination>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <phase>generate-resources</phase>
+                        <id>unpack-installer</id>
+                        <goals>
+                            <goal>get</goal>
+                        </goals>
+                        <configuration>
+                            <artifact>org.netbeans.modules:org-netbeans-libs-nbi-ant:${netbeans.version}:nbm</artifact>
+                            <transitive>false</transitive>
+                            <remoteRepositories>${netbeans.repo}</remoteRepositories>
+                            <destination>${project.build.directory}/nbi-ant.nbm</destination>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <phase>generate-resources</phase>
+                        <id>unpack-installer-engine</id>
+                        <goals>
+                            <goal>get</goal>
+                        </goals>
+                        <configuration>
+                            <artifact>org.netbeans.modules:org-netbeans-libs-nbi-engine:${netbeans.version}:nbm</artifact>
+                            <transitive>false</transitive>
+                            <remoteRepositories>${netbeans.repo}</remoteRepositories>
+                            <destination>${project.build.directory}/nbi-engine.nbm</destination>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>1.6</version>
+                <executions>
+                    <execution>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                        <configuration>
+                            <target>
+                                <unzip src="${project.build.directory}/harness.nbm" dest="${project.build.directory}/classes">
+                                    <patternset>
+                                        <include name="netbeans/etc/app.conf" />
+                                        <include name="netbeans/etc/applicationIcon.icns*" />
+                                        <include name="netbeans/launchers/app*" />
+                                    </patternset>
+                                    <mapper type="glob" from="netbeans/*" to="harness/*" />
+                                </unzip>
+                                <unzip src="${project.build.directory}/harness.nbm" dest="${project.build.directory}">
+                                    <patternset>
+                                        <include name="netbeans/tasks.jar.pack.gz" />
+                                        <include name="netbeans/jnlp/jnlp-launcher.jar.pack.gz" />
+                                    </patternset>
+                                    <flattenmapper />
+                                </unzip>
+                                <exec executable="unpack200" failonerror="true">
+                                    <arg file="${project.build.directory}/tasks.jar.pack.gz" />
+                                    <arg file="${project.build.directory}/tasks.jar" />
+                                </exec>
+                                <mkdir dir="${project.build.directory}/classes/harness/jnlp" />
+                                <exec executable="unpack200" failonerror="true">
+                                    <arg file="${project.build.directory}/jnlp-launcher.jar.pack.gz" />
+                                    <arg file="${project.build.directory}/classes/harness/jnlp/jnlp-launcher.jar" />
+                                </exec>
+                                <unzip src="${project.build.directory}/tasks.jar" dest="${project.build.directory}/classes" />
+                                <unzip src="${project.build.directory}/nbi-ant.nbm" dest="${project.build.directory}/classes">
+                                    <patternset>
+                                        <include name="netbeans/modules/" />
+                                        <include name="netbeans/nbi/" />
+                                    </patternset>
+                                    <mapper type="glob" from="netbeans/*" to="harness/*" />
+                                </unzip>
+                                <unzip src="${project.build.directory}/nbi-engine.nbm" dest="${project.build.directory}/classes">
+                                    <patternset>
+                                        <include name="netbeans/modules/" />
+                                    </patternset>
+                                    <mapper type="glob" from="netbeans/*" to="harness/*" />
+                                </unzip>
+                                <exec executable="unpack200" failonerror="true">
+                                    <arg file="${project.build.directory}/classes/harness/modules/org-netbeans-libs-nbi-ant.jar.pack.gz" />
+                                    <arg file="${project.build.directory}/classes/harness/modules/org-netbeans-libs-nbi-ant.jar" />
+                                </exec>
+                                <exec executable="unpack200" failonerror="true">
+                                    <arg file="${project.build.directory}/classes/harness/modules/org-netbeans-libs-nbi-engine.jar.pack.gz" />
+                                    <arg file="${project.build.directory}/classes/harness/modules/org-netbeans-libs-nbi-engine.jar" />
+                                </exec>
+                                <exec executable="unpack200" failonerror="true">
+                                    <arg file="${project.build.directory}/classes/harness/modules/ext/nbi-engine.jar.pack.gz" />
+                                    <arg file="${project.build.directory}/classes/harness/modules/ext/nbi-engine.jar" />
+                                </exec>
+                                <exec executable="unpack200" failonerror="true">
+                                    <arg file="${project.build.directory}/classes/harness/modules/ext/nbi-registries-management.jar.pack.gz" />
+                                    <arg file="${project.build.directory}/classes/harness/modules/ext/nbi-registries-management.jar" />
+                                </exec>
+                                <exec executable="unpack200" failonerror="true">
+                                    <arg file="${project.build.directory}/classes/harness/modules/ext/nbi-ant-tasks.jar.pack.gz" />
+                                    <arg file="${project.build.directory}/classes/harness/modules/ext/nbi-ant-tasks.jar" />
+                                </exec>
+                                <delete>
+                                    <fileset dir="${project.build.directory}/classes/harness/modules" includes="**/*.pack.gz" />
+                                </delete>
+                                <!-- patch product.xml - unable to delete temp files after build finishes -->
+                                <replace file="${project.build.directory}/classes/harness/nbi/.common/product.xml">
+                                    <replacetoken expandProperties="false"><![CDATA[<delete dir="${current.temp.dir}>"]]></replacetoken>
+                                    <replacevalue expandProperties="false"><![CDATA[<delete dir="${current.temp.dir}" deleteonexit="true">]]></replacevalue>
+                                </replace>
+                                <!-- patch replace exec with ant task in common.xml -->
+                                <replaceregexp file="${project.build.directory}/classes/harness/nbi/.common/common.xml" match="exec executable=.{3}ant.executable(.+?)/exec" replace="@EXEC@" flags="s" />
+                                <replace file="${project.build.directory}/classes/harness/nbi/.common/common.xml" failOnNoReplacements="true">
+                                    <replacetoken expandProperties="false">@EXEC@</replacetoken>
+                                    <replacevalue expandProperties="false"><![CDATA[ant inheritrefs="false" 
+                dir="${cvs.dir}/${nbproject.path}">
+                  <target name="clean" />
+                  <property name="ignore.native" value="true" />
+                  <property name="no.dependencies" value="true" />
+                  <property name="dont.build.custom.tasks" value="true" /> 
+                  <property name="custom.tasks.cls" value="${custom.tasks.cls}" />
+            </ant]]></replacevalue>
+                                </replace>
+                                <replaceregexp file="${project.build.directory}/classes/harness/nbi/.common/common.xml" match="exec executable=.{3}ant.executable(.+?)/exec" replace="@EXEC@" flags="s" />
+                                <replace file="${project.build.directory}/classes/harness/nbi/.common/common.xml" failOnNoReplacements="true">
+                                    <replacetoken expandProperties="false">@EXEC@</replacetoken>
+                                    <replacevalue expandProperties="false"><![CDATA[condition property="nb.jdk.home.value"
+                   value="${@java.home@}/.."
+                   else="${@java.home@}">
+                <not>
+                    <equals arg1="Apple Inc." arg2="${java.vendor}" />
+                </not>
+        </condition>
+        <condition property="custom.parameter.name" value="reference.NBI_Engine.jar">
+            <contains string="${nb.custom.parameter}" substring="reference.NBI_Engine.jar" />
+        </condition>
+        <condition property="custom.parameter.value" value="${core.engine.dist.file}">
+            <contains string="${nb.custom.parameter}" substring="reference.NBI_Engine.jar" />
+        </condition>
+        <condition property="custom.parameter.name" value="javac.classpath">
+            <contains string="${nb.custom.parameter}" substring="javac.classpath" />
+        </condition>
+        <condition property="custom.parameter.value" value="${engine.dist.file}">
+            <contains string="${nb.custom.parameter}" substring="javac.classpath" />
+        </condition>
+        <echoproperties />
+        <ant inheritRefs="false" dir="${cvs.dir}/${nbproject.path}" > 
+                  <target name="clean" />
+                  <target name="compile" />
+                  <property name="platforms.JDK_1.5.home" value="${nb.jdk.home.value}" />
+                  <property name="ignore.native" value="true" />
+                  <property name="no.dependencies" value="true" />
+                  <property name="dont.build.custom.tasks" value="true" /> 
+                  <property name="custom.tasks.cls" value="${custom.tasks.cls}" />
+                  <property name="${custom.parameter.name}" value="${custom.parameter.value}" />
+        </ant]]></replacevalue>
+                                </replace>
+                                <replace file="${project.build.directory}/classes/harness/nbi/.common/common.xml" failOnNoReplacements="true" token="@java.home@" value="java.home" />
+                            </target>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <!-- No real effect on the build, but prevents NB IDE from thinking src/main/java should be considered in preference to the JAR: -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>1.5</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    <properties>
+        <netbeans.repo>netbeans::default::http://bits.netbeans.org/nexus/content/groups/netbeans/</netbeans.repo>
+        <netbeans.version>RELEASE82</netbeans.version>
+    </properties>
+</project>
diff --git a/nbm-maven-harness/src/main/java/Dummy.java b/nbm-maven-harness/src/main/java/Dummy.java
new file mode 100644
index 0000000..6e291bf
--- /dev/null
+++ b/nbm-maven-harness/src/main/java/Dummy.java
@@ -0,0 +1,7 @@
+/**
+ * dummy class to keep central maven repository happy.
+ * @author mkleint
+ */
+public class Dummy {
+
+}
diff --git a/nbm-maven-harness/src/main/java/dummy.txt b/nbm-maven-harness/src/main/java/dummy.txt
new file mode 100644
index 0000000..d4fd10c
--- /dev/null
+++ b/nbm-maven-harness/src/main/java/dummy.txt
@@ -0,0 +1,2 @@
+This jar doesn't have sources or javadoc.
+It contains a multitude of resources from the netbeans IDE, used by the nbm-maven-plugin.
diff --git a/nbm-maven-plugin/README.md b/nbm-maven-plugin/README.md
new file mode 100644
index 0000000..478b4a4
--- /dev/null
+++ b/nbm-maven-plugin/README.md
@@ -0,0 +1,194 @@
+# NetBeans Module Maven plugin
+
+[ ![Codeship Status for mojohaus/nbm-maven-plugin](https://codeship.com/projects/827d5e10-2da6-0133-ca32-7e50f7676400/status?branch=master)](https://codeship.com/projects/98910)
+
+This Apache Maven plugin is able to create NetBeans module(plugin) artifacts. It registers a new packaging type `nbm`. Any project with this packaging will be automatically turned into a NetBeans module project. Additionally it allows to create clusters of modules, generate an autoupdate site content or build and assemble an application on top of NetBeans platform.
+
+Note: The `nbm:populate-repository` goal has been moved to it's own plugin at [nb-repository-plugin](https://github.com/mojohaus/nb-repository-plugin/).
+
+To get access to a repository with NetBeans.org module artifacts and metadata, add [http://bits.netbeans.org/maven2/](http://bits.netbeans.org/maven2/) repository to your project POM or the repository manager you are using. The repository hosts binaries of NetBeans 6.5 and later.
+
+Also see: [Maven NBM development FAQs](http://wiki.netbeans.org/NetBeansDeveloperFAQ#Mavenized_Builds)
+
+Sample pom.xml excerpts for creation of a NetBeans module:
+```xml
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>example-netbeans-module</artifactId>
+  <groupId>org.mycompany.myproject</groupId>
+  <!--here is the packaging and lifecycle defined-->
+  <packaging>nbm</packaging>
+
+  <!-- .... -->
+  <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+                <version>3.8.1</version>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin> <!-- required since nbm-plugin 3.0-->
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.0.2</version>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+  </build>
+
+ <!-- .... -->
+    <!-- this section is important only to access the binaries of NetBeans that you use as dependencies -->
+    <repositories>
+        <repository>
+            <id>netbeans</id>
+            <name>repository hosting netbeans.org api artifacts</name>
+            <url>http://bits.netbeans.org/maven2/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+```    
+To build the project then, just type
+```
+mvn install
+```
+## Maven Dependency vs. NetBeans runtime dependency
+There are important differences between Maven's dependency mechanism and NetBeans runtime dependencies. Maven's dependencies are transitive, so at compile time you get not only direct dependencies you declared, but also dependencies of dependencies etc. In NetBeans, the module dependencies are non-transitive by nature, you have to explicitly declare all at runtime. Additionally next to module dependencies there are also library jars attached and shipped with the module's main artifact. In the NetBeans terminology there is a special sort of modules called "library wrappers". These library wrappers add the libraries on the module's classpath and allow other modules to depend on the libraries within the IDE's runtime.
+
+The ways in which the nbm-maven-plugin tries to adress these issues has changed over time.
+
+The plugin walks the dependency tree to detect and identify module dependencies and classpath libraries.
+
+A maven dependency is turned into a NetBeans runtime dependency when:
+
+* For NetBeans module dependencies (dependency jars that have the NetBeans specific entries in META-INF/MANIFEST.MF)
+  * It's a direct dependency (non-transitive) and is a NetBeans module itself. Preferred way of declaring module dependencies.
+  * It's defined in existing (though optional and deprecated) module.xml file in dependencies section. Try to avoid this, but still useful if one wants to put an explicit dependency value on the module, or use implementation dependency.
+  * When the dependency is of type nbm. Deprecated in **3.0.x**, only helpful in older versions. Such dependencies don't include their transitive deps on compilation classpath. That should allow one to simulate the rumtime dependencies at compilation time in maven, however there's one major drawback. Not only are the nbm's module dependencies hidden, but the libraries associated with the given nbm module are also hidden. So you can end up with less stuff on classpath as opposed to more stuff with jar typed dependencies.
+* For module libraries (jars that are packed together with the module and appear on it's classpath directly, not by a dependency relationship.)
+  * It's a direct dependency and is not of provided scope.
+  * It's a transitive dependency, pulled in by a direct dependency (only non-module one - see first bullet) This is new in **3.0+**
+  * It's defined in existing (though optional) module.xml file in libraries section. Consider this deprecated in **3.0+**.
+
+The complete nbm descriptor format documentation, and example descriptors are also available. 
+
+Please note that since **3.8** version, the descriptor is deprecated and replaced by plugin configuration parameters.
+
+Additionally we perform dependency analysis in order to warn the user when runtime dependencies are wrong. So project's own classes and it's classpath libraries' classes are checked against the module dependencies (with appropriate filtering for public packages/private packages). If the classes depend on declared module dependency's private classes or on transitive module dependency's classes, the build fails. That should prevent ClassNotFoundException's later at runtime, when the NetBeans module system constructs the classpath for the module based on our metadata generated.
+
+## Using OSGi bundles in NetBeans platform based applications
+Starting with version **3.2**, it's possible for the NetBeans modules to depend on OSGi bundles. A proper module dependency section will be generated. To include the bundle in the application, add dependency on the bundle from nbm-application. There are a few prerequisites.
+
+It works only in NetBeans 6.9 and later which support the embedding of bundles at runtime
+Add `<useOSGiDependencies>true</useOSGiDependencies>` configuration entry to all the modules depending on OSGi bundles. Existing applications/modules need to check modules wrapping external libraries for library jars that are also OSGi bundles. Such modules will no longer include the OSGi bundles as part of the module NBM but will include a modular dependency reference on the bundle only. Modules depending on these old wrapper modules shall depend directly on the bundle, eventually rendering the old library wrapper module obsolete.
+in the distribution, all bundles will be included in the default cluster (extra if not configured otherwise), in **3.10 and later** the plugin will attempt to guess the cluster based on modules depending on it.
+Before version **3.10** all bundles will be autoload, thus requiring at least one depending regular module to enable them. In **3.10 and later**, developers of the OSGi bundles can influence the autoload vs regular behaviour by adding Nbm-Maven-Plugin-Autoload attribute to the bundle's manifest with "true" or "false" values. False means the module will be enabled on start, even without any other modules depending on it.
+
+## Multi module setup
+If you have a set of NetBeans modules, or are building on top of NetBeans Platform, you will make use of the additional goals provided by the plugin.
+
+If you are building a Platform-based application, use a project with `nbm-application` packaging to perform the final application assembly. This packaging type (defined in nbm-maven-plugin) should have your module projects and all dependencies of the target NetBeans Platform included as dependencies.
+
+For the NetBeans Platform/IDE modules, there are artifacts that aggregate modules in clusters. These are put in the `org.netbeans.clusters` groupId (on `bits.netbeans.org` or in your own repository). The following snippet will include the basic NetBeans platform cluster and your own module in the application. You can use standard dependency exclusion lists to cut out modules from the Platform that you don't need.
+
+```xml
+    <artifactId>application</artifactId>
+    <packaging>nbm-application</packaging>
+    <version>1.0-SNAPSHOT</version>
+    <dependencies>
+        <dependency>
+            <groupId>org.netbeans.cluster</groupId>
+            <artifactId>platform8</artifactId>
+            <version>${netbeans.version}</version>
+            <type>pom</type>
+        </dependency>
+        <dependency>
+            <groupId>com.mycompany</groupId>
+            <artifactId>module1</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+```    
+The nbm-application project/packaging defines a build lifecycle that creates a final application from the NBM files in local/remote repotories and bundles them in a ZIP file (also uploadable to the repository). In addition to that you can configure the project to generate an autoupdate site and/or webstartable binaries of the applications (typically in a deployment profile):
+
+```xml
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>extra</id>
+                        <goals>
+                            <goal>autoupdate</goal>
+                            <goal>webstart-app</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+```            
+See the `autoupdate` and `webstart-app` goals for more details.
+
+### mvn nbm:cluster
+This goal aggregates output of multiple NetBeans module projects and creates one or more clusters in the current project. So usually one runs this goal on the parent POM project, which aggregates the content of all its modules. The resulting cluster structure can later be used for running the application, creating an installer or similar. A variant of this goal is also included in the nbm-application project's default lifecycle.
+
+### mvn nbm:branding
+Branding is to used when one builds an application based on NetBeans Platform (as opposed to creating set of modules for the IDE). Branding contains all the resources that are to be changed in the platform binaries (resource bundles, images, HTML files etc.) to give the application its unique look.
+
+This goal can be attached to one of the nbm module projects that will be part of the NetBeans Platform-based application.
+
+For more detailed tutorial, check [NetBeans Platform Quick Start Using Maven tutorial](https://platform.netbeans.org/tutorials/nbm-maven-quickstart.html)
+
+The branding is included as part of a regular nbm subproject and cannot be attached to a pom packaged root project.
+
+### mvn nbm:run-ide nbm:run-platform
+These two goals do almost the same, they allow you to execute your projects content within the IDE or NetBeans platform.
+
+`nbm:run-platform` only makes sense to execute on projects with `nbm-application` packaging.
+
+For more information on plugin configuration and customization, see goal documentation.
+
+## Public packages declaration
+By default all your module's packages (and classes) and private to the given module. If you want to expose any API to other modules, you will need to declare those public packages in your `pom.xml`. This includes not only your own classes but also any other 3rd party library classes that are packaged with your module and are to be exposed for reuse by other modules.
+
+For example:
+```xml
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+                <version>3.8.1</version>
+                <extensions>true</extensions>
+                <configuration>
+                   <publicPackages>
+                       <publicPackage>org.foo.api</publicPackage>
+                       <publicPackage>org.apache.commons.*</publicPackage>
+                   </publicPackages>
+                </configuration>
+            </plugin>
+```            
+there is a package `org.foo.api` made public (but not `org.foo.api.impl` package) and any package starting with `org.apache.commons`, so both `org.apache.commons.io` and `org.apache.commons.exec` packages are exposed to the outside
+
+## Archetypes anyone?
+There are two basic archetypes:
+
+The first once creates a single project preconfigured to be a NetBeans module. Use this one if you are developing a NetBeans IDE module, or a module for a NetBeans Platform-based application.
+```
+mvn -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=nbm-archetype \
+  -DarchetypeVersion=... -DgroupId=org.kleint -DartifactId=milos -Dversion=1.0 archetype:generate
+```  
+The second one creates a parent POM project containing configuration and application branding for your NetBeans Platform-based application.
+```
+mvn -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=netbeans-platform-app-archetype \
+  -DarchetypeVersion=... -DgroupId=org.kleint -DartifactId=milos -Dversion=1.0 archetype:generate
+```  
+## IDE support
+The NetBeans IDE has Maven support. Among other features, it contains additional support for working with NetBeans module projects. The support includes file templates, important nodes in projects view, running module(s) in the IDE or Platform.
diff --git a/nbm-maven-plugin/pom.xml b/nbm-maven-plugin/pom.xml
new file mode 100644
index 0000000..468d03a
--- /dev/null
+++ b/nbm-maven-plugin/pom.xml
@@ -0,0 +1,529 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>mojo-parent</artifactId>
+        <version>40</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>nbm-maven-plugin</artifactId>
+    <version>4.2-SNAPSHOT</version>
+    <packaging>maven-plugin</packaging>
+
+    <name>NBM Maven Plugin</name>
+    <description>Maven plugin for creating NetBeans modules. It defines a custom lifecycle called "nbm". During packaging, the module JAR is enhanced with NetBeans-specific manifest entries and, along with other required files, packed into a *.nbm file, ready for distribution. Additionally the plugin provides aggregator goals to create an update site or cluster for your module projects.
+    </description>
+    <inceptionYear>2005</inceptionYear>
+    <url>https://github.com/mojohaus/nbm-maven-plugin</url>
+    <issueManagement>
+        <system>GitHub</system>
+        <url>https://github.com/mojohaus/nbm-maven-plugin/issues</url>
+    </issueManagement>
+    <prerequisites>
+        <maven>3.0.5</maven>
+    </prerequisites>
+    <licenses>
+        <license>
+            <name>Apache License 2</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+    <scm>
+        <connection>scm:git:https://github.com/mojohaus/nbm-maven-plugin.git</connection>
+        <developerConnection>scm:git:ssh://git@github.com/mojohaus/nbm-maven-plugin.git</developerConnection>
+        <url>https://github.com/mojohaus/nbm-maven-plugin/tree/${project.scm.tag}</url>
+        <tag>master</tag>
+    </scm>
+    <developers>
+        <developer>
+            <id>mkleint</id>
+            <name>Milos Kleint</name>
+            <email>mkleint@gmail.com</email>
+            <roles>
+                <role>Developer</role>
+            </roles>
+        </developer>
+        <developer>
+            <id>jglick</id>
+            <name>Jesse Glick</name>
+            <email>jglick@codehaus.org</email>
+            <roles>
+                <role>Developer</role>
+            </roles>
+        </developer>
+        <developer>
+            <id>ebarboni</id>
+            <name>Eric Barboni</name>
+            <roles>
+                <role>Developer</role>
+            </roles>
+        </developer>
+    </developers>
+    <contributors>
+        <contributor>
+            <name>Johan Andrén</name>
+            <email>protected</email>
+            <roles>
+                <role>Patch Contributor</role>
+                <role>Goal Contributor</role>
+            </roles>
+        </contributor>
+        <contributor>
+            <name>Mykola Nikishov</name>
+            <email>mn@mn.com.ua</email>
+            <roles>
+                <role>Patch Contributor</role>
+            </roles>
+        </contributor>
+        <contributor>
+            <name>Frantisek Mantlik</name>
+            <email>frantisek@mantlik.cz</email>
+            <roles>
+                <role>Goal Contributor</role>
+            </roles>
+        </contributor>
+    </contributors>
+    
+    <build>
+        <plugins>
+            <plugin>
+   <!-- TODO need to override parent version value... I suppose this will eventually end up in mojo parent pom, check regularly -->
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>3.5</version>
+                <configuration>
+                    <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+                 </configuration>
+                <executions>
+                    <execution>
+                        <id>mojo-descriptor</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>descriptor</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>help-goal</id>
+                        <goals>
+                            <goal>helpmojo</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.modello</groupId>
+                <artifactId>modello-maven-plugin</artifactId>
+                <version>1.8.3</version>
+                <executions>
+                    <execution>
+                        <id>build</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>xpp3-reader</goal>
+                            <goal>java</goal>
+                            <goal>xdoc</goal>
+                            <!--goal>xsd</goal-->
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>site</id>
+                        <phase>site-generate</phase>
+                        <goals>
+                            <goal>xdoc</goal>
+                            <!--goal>xsd</goal-->
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <models>
+                        <model>src/main/mdo/descriptor.mdo</model>
+                    </models>
+                    <version>1.0.0</version>
+                    <useJava5>true</useJava5>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>animal-sniffer-maven-plugin</artifactId>
+                <version>1.16</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                           <goal>check</goal>
+                        </goals>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java17</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-site-plugin</artifactId>
+                <version>3.6</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.shared</groupId>
+                        <artifactId>maven-shared-resources</artifactId>
+                        <version>2</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-invoker-plugin</artifactId>
+                        <version>1.10</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-project-info-reports-plugin</artifactId>
+                <version>2.9</version>
+                <reportSets>
+                    <reportSet>
+                        <reports>
+                            <report>plugins</report>
+                            <!-- <report>cim</report> -->
+                        </reports>
+                    </reportSet>
+                </reportSets>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-changes-plugin</artifactId>
+                <version>2.12.1</version>
+                <reportSets>
+                    <reportSet> 
+                        <reports>
+                            <report>github-report</report>
+                        </reports> 
+                    </reportSet>
+                </reportSets>
+                <configuration>
+                    <!-- configure github milestone ? -->
+                    <onlyMilestoneIssues>false</onlyMilestoneIssues>
+                    <onlyCurrentVersion>false</onlyCurrentVersion>
+
+                </configuration>
+   
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <version>2.17</version>
+                <reportSets>
+                    <reportSet>
+                        <reports>
+                            <report>checkstyle</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+                <configuration>
+                    <configLocation>config/maven_checks.xml</configLocation>
+                    <headerLocation>config/maven-header.txt</headerLocation>
+                </configuration>
+                            
+            </plugin>
+                        
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>3.0.0-M1</version>
+                <configuration>
+                    <quiet>true</quiet>
+                    <links>
+                        <!--<link>http://download-llnw.oracle.com/javaee/1.4/api/</link>-->
+                        <!-- unreachable site <link>http://commons.apache.org/collections/apidocs-COLLECTIONS_3_0/</link>-->
+                        <link>http://commons.apache.org/dbcp/apidocs/</link>
+                        <link>http://commons.apache.org/fileupload/apidocs/</link>
+                        <link>http://commons.apache.org/logging/apidocs/</link>
+                        <link>http://commons.apache.org/pool/apidocs/</link>
+                        <link>http://junit.sourceforge.net/javadoc/</link>
+                        <link>http://logging.apache.org/log4j/1.2/apidocs/</link>
+                        <!-- unreachable site <link>http://jakarta.apache.org/regexp/apidocs/</link> -->
+                        <link>http://velocity.apache.org/engine/releases/velocity-1.5/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${mojo.javadoc.mavenVersion}/maven-artifact/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${mojo.javadoc.mavenVersion}/maven-model/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${mojo.javadoc.mavenVersion}/maven-plugin-api/apidocs/</link>
+                        <!-- unreachable site <link>http://maven.apache.org/ref/${mojo.javadoc.mavenVersion}/maven-project/apidocs/</link>-->
+                        <!-- unreachable site <link>http://maven.apache.org/ref/${mojo.javadoc.mavenVersion}/maven-reporting/maven-reporting-api/apidocs/</link>-->
+                        <link>http://maven.apache.org/ref/${mojo.javadoc.mavenVersion}/maven-settings/apidocs/</link>
+                    </links>
+                    <tagletArtifacts>
+                        <tagletArtifact>
+                            <groupId>org.apache.maven.plugin-tools</groupId>
+                            <artifactId>maven-plugin-tools-javadoc</artifactId>
+                            <version>3.4</version>
+                        </tagletArtifact>
+                        <tagletArtifact>
+                            <groupId>org.codehaus.plexus</groupId>
+                            <artifactId>plexus-component-javadoc</artifactId>
+                            <version>1.6</version>
+                        </tagletArtifact>
+                    </tagletArtifacts>
+                </configuration>
+                <reportSets>
+                    <reportSet>
+                        <reports>
+                            <report>javadoc</report>
+                            <report>test-javadoc</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+            </plugin>
+                        
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jxr-plugin</artifactId>
+                <version>2.5</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>3.5</version>
+                <configuration>
+                    <requirements>
+                        <!--
+                        NOTE: Maven 2.x does not interpolate properties of the form project.*|pom.* so the Maven Plugin Plugin
+                        gets garbage when manually examining the config of the Maven Compiler Plugin.
+                        -->
+                        <jdk>${mojo.java.target}</jdk>
+                    </requirements>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-pmd-plugin</artifactId>
+                <version>3.8</version>
+                <configuration>
+                    <targetJdk>1.5</targetJdk>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-linkcheck-plugin</artifactId>
+                <version>1.2</version>
+                <configuration>
+                    <excludedLinks>
+                        <excludedLink>../../images/codehaus-small.png</excludedLink>
+                        <excludedLink>../../images/mojo_logo.png</excludedLink>
+                        <excludedLink>plugin-info.html</excludedLink>
+                    </excludedLinks>
+                    <!--<excludedPages>
+                        <excludedPage>dependencies.html</excludedPage> 
+                    </excludedPages>-->
+                </configuration>	       
+            </plugin>                        
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>cobertura-maven-plugin</artifactId>
+                <version>2.7</version>
+                <configuration>
+                    <instrumentation>
+                        <excludes>
+                            <exclude>**/HelpMojo.class</exclude>
+                        </excludes>
+                    </instrumentation>    
+                </configuration>
+            </plugin>
+            <plugin> 
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>taglist-maven-plugin</artifactId>
+                <version>2.4</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <version>0.12</version>
+            </plugin>
+        </plugins>
+    </reporting>
+    <profiles>
+        <profile>
+            <id>tools.jar</id>
+            <activation>
+                <file>
+                    <exists>${java.home}/../lib/tools.jar</exists>
+                </file>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>com.sun</groupId>
+                    <artifactId>tools</artifactId>
+                    <version>1.5.0</version>
+                    <scope>system</scope>
+                    <systemPath>${java.home}/../lib/tools.jar</systemPath>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>run-its</id>
+            <build>
+
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-invoker-plugin</artifactId>
+                        <version>2.0.0</version>
+                        <configuration>
+                            <debug>true</debug>
+                            <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+                            <pomIncludes>
+                                <pomInclude>*/pom.xml</pomInclude>
+                            </pomIncludes>
+                            <postBuildHookScript>verify</postBuildHookScript>
+                            <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+                            <settingsFile>src/it/settings.xml</settingsFile>
+                            <goals>
+                                <!-- default build in netbeans IDE -->
+                                <goal>clean</goal>
+                                <goal>install</goal>
+                            </goals>
+                            <filterProperties>
+                                <netbeans.version>RELEASE82</netbeans.version>
+                            </filterProperties>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>integration-test</id>
+                                <goals>
+                                    <goal>install</goal>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+
+            </build>
+        </profile>
+    </profiles>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-artifact</artifactId>
+            <version>${maven.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-compat</artifactId>
+            <version>${maven.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-plugin-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>1.9.6</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-utils</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-archiver</artifactId>
+            <version>3.5</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>plexus-component-api</artifactId>
+                    <groupId>org.codehaus.plexus</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.shared</groupId>
+            <artifactId>maven-dependency-tree</artifactId>
+            <version>2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.shared</groupId>
+            <artifactId>maven-dependency-analyzer</artifactId>
+            <version>1.10</version>
+        </dependency>
+        <!-- maven dependecy analyser version 1.8 will have the correct dependency -->
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-model</artifactId>
+            <version>${maven.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-container-default</artifactId>
+            <version>1.7.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.shared</groupId>
+            <artifactId>maven-filtering</artifactId>
+            <version>3.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <version>${maven.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-testing</groupId>
+            <artifactId>maven-plugin-testing-harness</artifactId>
+            <version>1.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>nbm-maven-harness</artifactId>
+            <version>8.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-io</artifactId>
+            <version>3.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>nb-shared</artifactId>
+            <version>1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>18.0</version>
+            <type>jar</type>
+        </dependency>
+    </dependencies>
+    <properties>
+        <mojo.java.target>1.7</mojo.java.target>
+        <maven.version>3.0.5</maven.version>
+    </properties>
+</project>
diff --git a/nbm-maven-plugin/src/it/full/application/pom.xml b/nbm-maven-plugin/src/it/full/application/pom.xml
new file mode 100644
index 0000000..5b044f5
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/application/pom.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.codehaus.mojo</groupId> 
+        <artifactId>ittest-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>ittest-app</artifactId>
+    <packaging>nbm-application</packaging>
+
+    <name>ittest-app</name>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <all.clusters>${project.build.directory}/${brandingToken}</all.clusters>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.netbeans.cluster</groupId>
+            <artifactId>platform</artifactId>
+            <version>${netbeans.version}</version>
+            <type>pom</type>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ittest-branding</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!-- NbModuleSuite functional in RELEASE70 or later: -->
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-nbjunit</artifactId>
+            <version>${netbeans.version}</version>
+            <scope>test</scope> <!-- beyond platform cluster, this often needs to be dropped down to compile/runtime, some other modules in IDE clusters depend on it -->
+        </dependency>
+        <!-- To use Jelly Tools in your functional tests, add or replace with:
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-jellytools-platform</artifactId>
+            <version>${netbeans.version}</version>
+            <scope>test</scope>
+        </dependency>
+        -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ittest-sample</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+            </plugin>
+            <!-- Permits NbModuleSuite to be run in integration-test phase: -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.12.2</version>
+                <configuration>
+                    <systemPropertyVariables>
+                        <all.clusters>${all.clusters}</all.clusters>
+                        <branding.token>${brandingToken}</branding.token>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>deployment</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>nbm-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>extra</id>
+                                <goals>
+                                    <goal>autoupdate</goal>
+                                    <goal>webstart-app</goal>
+                                    <goal>build-installers</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/nbm-maven-plugin/src/it/full/application/src/test/java/nbmmavenpluginit/ittest/ApplicationTest.java b/nbm-maven-plugin/src/it/full/application/src/test/java/nbmmavenpluginit/ittest/ApplicationTest.java
new file mode 100644
index 0000000..767fa4a
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/application/src/test/java/nbmmavenpluginit/ittest/ApplicationTest.java
@@ -0,0 +1,32 @@
+package nbmmavenpluginit.ittest;
+
+import java.util.logging.Level;
+import junit.framework.Test;
+import org.netbeans.junit.NbModuleSuite;
+import org.netbeans.junit.NbTestCase;
+
+public class ApplicationTest extends NbTestCase {
+
+    public static Test suite() {
+        return NbModuleSuite.createConfiguration(ApplicationTest.class).
+                gui(false).
+                failOnMessage(Level.WARNING). // works at least in RELEASE71
+                failOnException(Level.INFO).
+                enableClasspathModules(false). 
+                clusters(".*").
+                suite(); // RELEASE71+, else use NbModuleSuite.create(NbModuleSuite.createConfiguration(...))
+    }
+
+    public ApplicationTest(String n) {
+        super(n);
+    }
+
+    public void testApplication() {
+        // pass if there are merely no warnings/exceptions
+        /* Example of using Jelly Tools (additional test dependencies required) with gui(true):
+        new ActionNoBlock("Help|About", null).performMenu();
+        new NbDialogOperator("About").closeByButton();
+         */
+    }
+
+}
diff --git a/nbm-maven-plugin/src/it/full/branding/pom.xml b/nbm-maven-plugin/src/it/full/branding/pom.xml
new file mode 100644
index 0000000..e17602c
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/branding/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>ittest-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>ittest-branding</artifactId>
+    <packaging>nbm</packaging>
+
+    <name>ittest-branding</name>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-api-annotations-common</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>${jar.plugin.version}</version>
+                <!-- to have the jar plugin pickup the nbm generated manifest -->
+                 
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/core/core.jar/org/netbeans/core/startup/Bundle.properties
new file mode 100644
index 0000000..da1c7a2
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/core/core.jar/org/netbeans/core/startup/Bundle.properties
@@ -0,0 +1,2 @@
+currentVersion=ittest {0}
+LBL_splash_window_title=Starting ittest
diff --git a/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties
new file mode 100644
index 0000000..f47648a
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties
@@ -0,0 +1,2 @@
+CTL_MainWindow_Title=ittest {0}
+CTL_MainWindow_Title_No_Project=ittest {0}
diff --git a/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/modules/org-netbeans-core.jar/org/netbeans/core/ui/Bundle.properties b/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/modules/org-netbeans-core.jar/org/netbeans/core/ui/Bundle.properties
new file mode 100644
index 0000000..3a9dc74
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/branding/src/main/nbm-branding/modules/org-netbeans-core.jar/org/netbeans/core/ui/Bundle.properties
@@ -0,0 +1 @@
+LBL_ProductInformation=ittest
diff --git a/nbm-maven-plugin/src/it/full/branding/src/main/nbm/manifest.mf b/nbm-maven-plugin/src/it/full/branding/src/main/nbm/manifest.mf
new file mode 100644
index 0000000..fec80e2
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/branding/src/main/nbm/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+OpenIDE-Module-Localizing-Bundle: nbmmavenpluginit/ittest/branding/Bundle.properties
+AutoUpdate-Essential-Module: true
diff --git a/nbm-maven-plugin/src/it/full/branding/src/main/resources/nbmmavenpluginit/ittest/branding/Bundle.properties b/nbm-maven-plugin/src/it/full/branding/src/main/resources/nbmmavenpluginit/ittest/branding/Bundle.properties
new file mode 100644
index 0000000..e999176
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/branding/src/main/resources/nbmmavenpluginit/ittest/branding/Bundle.properties
@@ -0,0 +1,5 @@
+# Localized module labels. Defaults taken from POM (<name>, <description>, <groupId>) if unset.
+#OpenIDE-Module-Name=
+#OpenIDE-Module-Short-Description=
+#OpenIDE-Module-Long-Description=
+#OpenIDE-Module-Display-Category=
diff --git a/nbm-maven-plugin/src/it/full/ittest-sample/pom.xml b/nbm-maven-plugin/src/it/full/ittest-sample/pom.xml
new file mode 100644
index 0000000..e258bf8
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/ittest-sample/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>ittest-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>ittest-sample</artifactId>
+    <packaging>nbm</packaging>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>${jar.plugin.version}</version>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-api-annotations-common</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+    </dependencies>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+</project>
\ No newline at end of file
diff --git a/nbm-maven-plugin/src/it/full/ittest-sample/src/main/nbm/manifest.mf b/nbm-maven-plugin/src/it/full/ittest-sample/src/main/nbm/manifest.mf
new file mode 100644
index 0000000..50de95d
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/ittest-sample/src/main/nbm/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+OpenIDE-Module-Localizing-Bundle: nbmmavenpluginit/ittest/Bundle.properties
+
diff --git a/nbm-maven-plugin/src/it/full/ittest-sample/src/main/resources/nbmmavenpluginit/ittest/Bundle.properties b/nbm-maven-plugin/src/it/full/ittest-sample/src/main/resources/nbmmavenpluginit/ittest/Bundle.properties
new file mode 100644
index 0000000..d307fd9
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/ittest-sample/src/main/resources/nbmmavenpluginit/ittest/Bundle.properties
@@ -0,0 +1,6 @@
+#Localized module labels. Defaults taken from POM (<name>, <description>, <groupId>) if unset.
+#OpenIDE-Module-Name=
+#OpenIDE-Module-Short-Description=
+#OpenIDE-Module-Long-Description=
+#OpenIDE-Module-Display-Category=
+#Tue Aug 25 17:58:31 CEST 2015
diff --git a/nbm-maven-plugin/src/it/full/pom.xml b/nbm-maven-plugin/src/it/full/pom.xml
new file mode 100644
index 0000000..fd04a61
--- /dev/null
+++ b/nbm-maven-plugin/src/it/full/pom.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>nbm-maven-plugin-it-root</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>ittest-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>ittest-parent</name>
+
+   
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>nbm-maven-plugin</artifactId>
+                    <extensions>true</extensions>
+                    <configuration>
+                        <brandingToken>${brandingToken}</brandingToken>
+                        <cluster>${brandingToken}</cluster>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <!-- NetBeans 6.9+ requires JDK 6, starting NetBeans 7.4 source 1.7 is required -->
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>2.5.1</version>
+                    <configuration>
+                        <source>1.7</source>
+                        <target>1.7</target>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-jar-plugin</artifactId>
+                    <version>${jar.plugin.version}</version>
+                    <configuration>
+                        <archive>
+                            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                        </archive>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <modules>
+        <module>branding</module>
+        <module>application</module>
+        <module>ittest-sample</module>
+    </modules>
+
+    <properties>
+        <netbeans.version>@netbeans.version@</netbeans.version>
+        <brandingToken>ittest</brandingToken>
+    </properties>
+</project>
diff --git a/nbm-maven-plugin/src/it/pom.xml b/nbm-maven-plugin/src/it/pom.xml
new file mode 100644
index 0000000..410689f
--- /dev/null
+++ b/nbm-maven-plugin/src/it/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.codehaus.mojo</groupId>
+    <artifactId>nbm-maven-plugin-it-root</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <repositories>
+        <!--
+        Repository hosting NetBeans modules, especially APIs.
+        Versions are based on IDE releases, e.g.: RELEASE691
+        To create your own repository, use: nbm:populate-repository
+        -->
+        <repository>
+            <id>netbeans</id>
+            <name>NetBeans</name>
+            <url>http://bits.netbeans.org/nexus/content/groups/netbeans/</url>
+        </repository>
+    </repositories>
+    <build>
+        <pluginManagement>
+            <plugins>
+               
+                <plugin>  
+                    <groupId>@project.groupId@</groupId>
+                    <artifactId>@project.artifactId@</artifactId>  
+                    <version>@project.version@</version>
+                </plugin>
+                <!--<plugin>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>@compilerPluginVersion@</version>
+                    <configuration>
+                        <source>@testJavaVersion@</source>
+                        <target>@testJavaVersion@</target>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>@surefirePluginVersion@</version>
+                </plugin>-->
+            </plugins>
+        </pluginManagement>
+    </build>
+    <properties>
+        <jar.plugin.version>3.0.2</jar.plugin.version>
+    </properties>
+</project>
\ No newline at end of file
diff --git a/src/it/settings.xml b/nbm-maven-plugin/src/it/settings.xml
similarity index 100%
rename from src/it/settings.xml
rename to nbm-maven-plugin/src/it/settings.xml
diff --git a/nbm-maven-plugin/src/it/single/pom.xml b/nbm-maven-plugin/src/it/single/pom.xml
new file mode 100644
index 0000000..5c678c3
--- /dev/null
+++ b/nbm-maven-plugin/src/it/single/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>nbm-maven-plugin-it-root</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>nbm-maven-plugin-it-single-module</artifactId>
+    <packaging>nbm</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-util</artifactId>
+            <version>@netbeans.version@</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+                
+            <plugin>  
+                <groupId>@project.groupId@</groupId>
+                <artifactId>@project.artifactId@</artifactId>  
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>${jar.plugin.version}</version>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+     
+    </build>
+</project>
\ No newline at end of file
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/AbstractNbmMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/AbstractNbmMojo.java
new file mode 100644
index 0000000..3e0520b
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/AbstractNbmMojo.java
@@ -0,0 +1,493 @@
+/* ==========================================================================
+ * Copyright 2003-2004 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
+import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
+import org.apache.maven.shared.dependency.graph.DependencyNode;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.codehaus.mojo.nbm.model.Dependency;
+import org.codehaus.mojo.nbm.model.NetBeansModule;
+import org.codehaus.mojo.nbm.model.io.xpp3.NetBeansModuleXpp3Reader;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+import org.codehaus.plexus.util.IOUtil;
+
+public abstract class AbstractNbmMojo
+    extends org.codehaus.mojo.nbm.utils.AbstractNetbeansMojo
+{
+
+    static boolean matchesLibrary( Artifact artifact, List<String> libraries, ExamineManifest depExaminator,
+        Log log, boolean useOsgiDependencies )
+    {
+        String artId = artifact.getArtifactId();
+        String grId = artifact.getGroupId();
+        String id = grId + ":" + artId;
+        boolean explicit = libraries.remove( id );
+        if ( explicit )
+        {
+            log.debug(
+                id + " included as module library, explicitly declared in module descriptor." );
+            return explicit;
+        }
+        if ( Artifact.SCOPE_PROVIDED.equals( artifact.getScope() ) || Artifact.SCOPE_SYSTEM.equals(
+            artifact.getScope() ) )
+        {
+            log.debug(
+                id + " omitted as module library, has scope 'provided/system'" );
+            return false;
+        }
+        if ( "nbm".equals( artifact.getType() ) )
+        {
+            return false;
+        }
+        if ( depExaminator.isNetBeansModule() || ( useOsgiDependencies && depExaminator.isOsgiBundle() ) )
+        {
+            //TODO I can see how someone might want to include an osgi bundle as library, not dependency.
+            // I guess it won't matter much in 6.9+, in older versions it could be a problem.
+            return false;
+        }
+        log.debug(
+            id + " included as module library, squeezed through all the filters." );
+        return true;
+    }
+
+    static Dependency resolveNetBeansDependency( Artifact artifact, List<Dependency> deps,
+        ExamineManifest manifest, Log log )
+    {
+        String artId = artifact.getArtifactId();
+        String grId = artifact.getGroupId();
+        String id = grId + ":" + artId;
+        for ( Dependency dep : deps )
+        {
+            if ( id.equals( dep.getId() ) )
+            {
+                if ( manifest.isNetBeansModule() )
+                {
+                    return dep;
+                }
+                else
+                {
+                    if ( dep.getExplicitValue() != null )
+                    {
+                        return dep;
+                    }
+                    log.warn(
+                        id + " declared as module dependency in descriptor, but not a NetBeans module" );
+                    return null;
+                }
+            }
+        }
+        if ( "nbm".equals( artifact.getType() ) )
+        {
+            Dependency dep = new Dependency();
+            dep.setId( id );
+            dep.setType( "spec" );
+            log.debug( "Adding nbm module dependency - " + id );
+            return dep;
+        }
+        if ( manifest.isNetBeansModule() )
+        {
+            Dependency dep = new Dependency();
+            dep.setId( id );
+            dep.setType( "spec" );
+            log.debug( "Adding direct NetBeans module dependency - " + id );
+            return dep;
+        }
+        return null;
+    }
+
+    protected final NetBeansModule readModuleDescriptor( File descriptor )
+        throws MojoExecutionException
+    {
+        if ( descriptor == null )
+        {
+            throw new MojoExecutionException(
+                "The module descriptor has to be configured." );
+        }
+        if ( !descriptor.exists() )
+        {
+            throw new MojoExecutionException(
+                "The module descriptor is missing: '" + descriptor + "'." );
+        }
+        Reader r = null;
+        try
+        {
+            r = new FileReader( descriptor );
+            NetBeansModuleXpp3Reader reader = new NetBeansModuleXpp3Reader();
+            NetBeansModule module = reader.read( r );
+            return module;
+        }
+        catch ( IOException exc )
+        {
+            throw new MojoExecutionException(
+                "Error while reading module descriptor '" + descriptor + "'.",
+                exc );
+        }
+        catch ( XmlPullParserException xml )
+        {
+            throw new MojoExecutionException(
+                "Error while reading module descriptor '" + descriptor + "'.",
+                xml );
+        }
+        finally
+        {
+            IOUtil.close( r );
+        }
+    }
+
+    protected final NetBeansModule createDefaultDescriptor( MavenProject project, boolean log )
+    {
+
+        if ( log )
+        {
+            getLog().info(
+                "No Module Descriptor defined, trying to fallback to generated values:" );
+        }
+        NetBeansModule module = new NetBeansModule();
+        return module;
+    }
+
+    static List<Artifact> getLibraryArtifacts( DependencyNode treeRoot, NetBeansModule module,
+                                               List<Artifact> runtimeArtifacts,
+                                               Map<Artifact, ExamineManifest> examinerCache, Log log,
+                                               boolean useOsgiDependencies )
+        throws MojoExecutionException
+    {
+        List<Artifact> include = new ArrayList<Artifact>();
+        if ( module != null )
+        {
+            List<String> librList = new ArrayList<String>();
+            if ( module.getLibraries() != null )
+            {
+                librList.addAll( module.getLibraries() );
+            }
+            CollectLibrariesNodeVisitor visitor = new CollectLibrariesNodeVisitor( librList,
+                runtimeArtifacts, examinerCache, log, treeRoot, useOsgiDependencies );
+            treeRoot.accept( visitor );
+            include.addAll( visitor.getArtifacts() );
+        }
+        return include;
+    }
+
+    static List<ModuleWrapper> getModuleDependencyArtifacts( DependencyNode treeRoot, NetBeansModule module,
+                                                             Dependency[] customDependencies, MavenProject project,
+                                                             Map<Artifact, ExamineManifest> examinerCache,
+                                                             List<Artifact> libraryArtifacts, Log log,
+                                                             boolean useOsgiDependencies )
+        throws MojoExecutionException
+    {
+        List<Dependency> deps = new ArrayList<Dependency>();
+        if (customDependencies != null) {
+            deps.addAll( Arrays.asList( customDependencies ));
+        }
+        if (module != null && !module.getDependencies().isEmpty()) {
+            log.warn( "dependencies in module descriptor are deprecated, use the plugin's parameter moduleDependencies");
+            //we need to make sure a dependency is not twice there, module deps override the config (as is the case with other
+            //configurations)
+            for (Dependency d : module.getDependencies()) {
+                Dependency found = null;
+                for (Dependency d2 : deps) {
+                    if (d2.getId().equals(d.getId())) {
+                        found = d2;
+                        break;
+                    }
+                }
+                if (found != null) {
+                    deps.remove( found );
+                }
+                deps.add(d);
+            }
+        }
+        List<ModuleWrapper> include = new ArrayList<ModuleWrapper>();
+        
+            @SuppressWarnings( "unchecked" )
+            List<Artifact> artifacts = project.getCompileArtifacts();
+            for ( Artifact artifact : artifacts )
+            {
+                if ( libraryArtifacts.contains( artifact ) )
+                {
+                    continue;
+                }
+                ExamineManifest depExaminator = examinerCache.get( artifact );
+                if ( depExaminator == null )
+                {
+                    depExaminator = new ExamineManifest( log );
+                    depExaminator.setArtifactFile( artifact.getFile() );
+                    depExaminator.checkFile();
+                    examinerCache.put( artifact, depExaminator );
+                }
+                Dependency dep = resolveNetBeansDependency( artifact, deps, depExaminator, log );
+                if ( dep != null )
+                {
+                    ModuleWrapper wr = new ModuleWrapper();
+                    wr.dependency = dep;
+                    wr.artifact = artifact;
+                    wr.transitive = false;
+                    //only direct deps matter to us..
+                    if ( depExaminator.isNetBeansModule() && artifact.getDependencyTrail().size() > 2 )
+                    {
+                        log.debug(
+                            artifact.getId() + " omitted as NetBeans module dependency, not a direct one. Declare it in the pom for inclusion." );
+                        wr.transitive = true;
+
+                    }
+                    include.add( wr );
+                }
+                else
+                {
+                    if ( useOsgiDependencies && depExaminator.isOsgiBundle() )
+                    {
+                        ModuleWrapper wr = new ModuleWrapper();
+                        wr.osgi = true;
+                        String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
+                        for ( Dependency depe : deps )
+                        {
+                            if ( id.equals( depe.getId() ) )
+                            {
+                                wr.dependency = depe;
+                            }
+                        }
+                        boolean print = false;
+                        if ( wr.dependency == null )
+                        {
+                            Dependency depe = new Dependency();
+                            depe.setId( id );
+                            depe.setType( "spec" );
+                            wr.dependency = depe;
+                            print = true;
+                        }
+
+                        wr.artifact = artifact;
+                        wr.transitive = false;
+                        //only direct deps matter to us..
+                        if ( artifact.getDependencyTrail().size() > 2 )
+                        {
+                            log.debug(
+                                artifact.getId() + " omitted as NetBeans module OSGi dependency, not a direct one. Declare it in the pom for inclusion." );
+                            wr.transitive = true;
+
+                        }
+                        else
+                        {
+                            if ( print )
+                            {
+                                log.info( "Adding OSGi bundle dependency - " + id );
+                            }
+                        }
+
+                        include.add( wr );
+                    }
+                }
+            }
+        return include;
+    }
+
+    static class ModuleWrapper
+    {
+
+        Dependency dependency;
+
+        Artifact artifact;
+
+        boolean transitive = true;
+        
+        boolean osgi = false;
+
+    }
+
+    //copied from dependency:tree mojo
+    protected DependencyNode createDependencyTree( MavenProject project, DependencyGraphBuilder dependencyGraphBuilder,
+                                                   String scope )
+        throws MojoExecutionException
+    {
+        ArtifactFilter artifactFilter = createResolvingArtifactFilter( scope );
+        try
+        {
+            return dependencyGraphBuilder.buildDependencyGraph( project, artifactFilter );
+        }
+        catch ( DependencyGraphBuilderException exception )
+        {
+            throw new MojoExecutionException( "Cannot build project dependency tree", exception );
+        }
+
+    }
+
+    //copied from dependency:tree mojo
+    /**
+     * Gets the artifact filter to use when resolving the dependency tree.
+     *
+     * @return the artifact filter
+     */
+    private ArtifactFilter createResolvingArtifactFilter( String scope )
+    {
+        ArtifactFilter filter;
+
+        // filter scope
+        if ( scope != null )
+        {
+            getLog().debug( "+ Resolving dependency tree for scope '" + scope + "'" );
+
+            filter = new ScopeArtifactFilter( scope );
+        }
+        else
+        {
+            filter = null;
+        }
+
+        return filter;
+    }
+
+    protected final ArtifactResult turnJarToNbmFile( Artifact art, ArtifactFactory artifactFactory,
+                                                     ArtifactResolver artifactResolver, MavenProject project,
+                                                     ArtifactRepository localRepository )
+        throws MojoExecutionException
+    {
+        if ( "jar".equals( art.getType() ) || "nbm".equals( art.getType() ) )
+        {
+            //TODO, it would be nice to have a check to see if the
+            // "to-be-created" module nbm artifact is actually already in the
+            // list of dependencies (as "nbm-file") or not..
+            // that would be a timesaver
+            ExamineManifest mnf = new ExamineManifest( getLog() );
+            File jar = art.getFile();
+            if ( !jar.isFile() )
+            {
+                //MNBMODULE-210 with recent CoS changes in netbeans (7.4) jar will be file as we link open projects in the build
+                // via WorkspaceReader. That's fine here, as all we need is to know if project is osgi or nbm module.
+                // the nbm file has to be in local repository though.
+                String path = localRepository.pathOf( art );
+                File jar2 = new File(localRepository.getBasedir(), path.replace( "/", File.separator));
+                File manifest = new File(jar, "META-INF/MANIFEST.MF" );
+                
+                if (! jar2.isFile() || !manifest.isFile() ) {
+                    getLog().warn( "MNBMODULE-131: need to at least run install phase on " + jar2 );
+                    return new ArtifactResult( null, null );
+                }
+                mnf.setManifestFile( manifest );
+            } else {
+                mnf.setJarFile( jar );
+            }
+            mnf.checkFile();
+            if ( mnf.isNetBeansModule() )
+            {
+                Artifact nbmArt = artifactFactory.createDependencyArtifact(
+                    art.getGroupId(),
+                    art.getArtifactId(),
+                    art.getVersionRange(),
+                    "nbm-file",
+                    art.getClassifier(),
+                    art.getScope() );
+                try
+                {
+                    artifactResolver.resolve( nbmArt, project.getRemoteArtifactRepositories(), localRepository );
+                }
+
+                catch ( ArtifactResolutionException ex )
+                {
+                    //shall be check before actually resolving from repos?
+                    checkReactor( art, nbmArt );
+                    if ( !nbmArt.isResolved() )
+                    {
+                        throw new MojoExecutionException( "Failed to retrieve the nbm file from repository", ex );
+                    }
+                }
+                catch ( ArtifactNotFoundException ex )
+                {
+                    //shall be check before actually resolving from repos?
+                    checkReactor( art, nbmArt );
+                    if ( !nbmArt.isResolved() )
+                    {
+                        throw new MojoExecutionException( "Failed to retrieve the nbm file from repository", ex );
+                    }
+                }
+                return new ArtifactResult( nbmArt, mnf );
+            }
+            if ( mnf.isOsgiBundle() )
+            {
+                return new ArtifactResult( null, mnf );
+            }
+        }
+        return new ArtifactResult( null, null );
+    }
+
+    protected static final class ArtifactResult
+    {
+        private final Artifact converted;
+        private final ExamineManifest manifest;
+
+        ArtifactResult( Artifact conv, ExamineManifest manifest )
+        {
+            converted = conv;
+            this.manifest = manifest;
+        }
+
+        boolean hasConvertedArtifact()
+        {
+            return converted != null;
+        }
+
+        Artifact getConvertedArtifact()
+        {
+            return converted;
+        }
+
+        public boolean isOSGiBundle()
+        {
+            return manifest != null && manifest.isOsgiBundle();
+        }
+
+        public ExamineManifest getExaminedManifest()
+        {
+            return manifest;
+        }
+    }
+
+    private void checkReactor( Artifact art, Artifact nbmArt )
+    {
+        if ( art.getFile().getName().endsWith( ".jar" ) )
+        {
+            String name = art.getFile().getName();
+            name = name.substring( 0, name.length() - ".jar".length() ) + ".nbm";
+            File fl = new File( art.getFile().getParentFile(), name );
+            if ( fl.exists() )
+            {
+                nbmArt.setFile( fl );
+                nbmArt.setResolved( true );
+            }
+        }
+    }
+
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/AdaptNbVersion.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/AdaptNbVersion.java
new file mode 100644
index 0000000..f80ff9c
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/AdaptNbVersion.java
@@ -0,0 +1,105 @@
+/* ==========================================================================
+ * Copyright 2003-2004 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+
+/**
+ *  will try to convert the maven version number to a NetBeans friendly version number.
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ *
+ */
+public class AdaptNbVersion
+{
+
+    public static final String TYPE_SPECIFICATION = "spec"; //NOI18N
+    public static final String TYPE_IMPLEMENTATION = "impl"; //NOI18N
+    private static final String SNAPSHOT = "SNAPSHOT"; //NOI18N
+
+    public static String adaptVersion( String version, Object type, Date date )
+    {
+        StringTokenizer tok = new StringTokenizer( version, "." );
+        if ( SNAPSHOT.equals( version ) && TYPE_IMPLEMENTATION.equals( type ) )
+        {
+            return "0.0.0." + generateSnapshotValue( date );
+        }
+        StringBuffer toReturn = new StringBuffer();
+        while ( tok.hasMoreTokens() )
+        {
+            String token = tok.nextToken();
+            if ( TYPE_IMPLEMENTATION.equals( type ) )
+            {
+                int snapshotIndex = token.indexOf( SNAPSHOT );
+                if ( snapshotIndex > 0 )
+                {
+                    String repl = token.substring( 0, snapshotIndex ) + generateSnapshotValue( date );
+                    if ( token.length() > snapshotIndex + SNAPSHOT.length() )
+                    {
+                        repl = token.substring(
+                                snapshotIndex + SNAPSHOT.length() );
+                    }
+                    token = repl;
+                }
+            }
+            if ( TYPE_SPECIFICATION.equals( type ) )
+            {
+                // strip the trailing -RC1, -BETA5, -SNAPSHOT
+                if ( token.indexOf( '-' ) > 0 )
+                {
+                    token = token.substring( 0, token.indexOf( '-' ) );
+                } else if ( token.indexOf( '_' ) > 0 )
+                {
+                    token = token.substring( 0, token.indexOf( '_' ) );
+                }
+                try
+                {
+                    Integer intValue = Integer.valueOf( token );
+                    token = intValue.toString();
+                }
+                catch ( NumberFormatException exc )
+                {
+                    // ignore, will just not be added to the
+                    token = "";
+                }
+            }
+            if ( token.length() > 0 )
+            {
+                if ( toReturn.length() != 0 )
+                {
+                    toReturn.append( "." );
+                }
+                toReturn.append( token );
+            }
+
+        }
+        if ( toReturn.length() == 0 )
+        {
+            toReturn.append( "0.0.0" );
+        }
+        return toReturn.toString();
+    }
+
+    private static String generateSnapshotValue( Date date )
+    {
+        SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyyMMdd" );
+        dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
+        return dateFormat.format( date );
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/BrandingMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/BrandingMojo.java
new file mode 100644
index 0000000..0d06d47
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/BrandingMojo.java
@@ -0,0 +1,227 @@
+/* ==========================================================================
+ * Copyright 2007 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.jar.JarArchiver;
+import org.codehaus.plexus.util.DirectoryScanner;
+import org.codehaus.plexus.util.FileUtils;
+
+/**
+ * Package branding resources for NetBeans platform/IDE based application.
+ * The format of branding resources is the same as in
+ * NetBeans Ant-based projects.
+ * 
+ * The <code>src/main/nbm-branding</code> folder of the project is assumed to 
+ * contain the branding content. Within the directory, the following folder structure is assumed:
+ * <ul>
+ * <li>
+ * 1. pick the IDE/platform module which contents you want to brand. eg. org-openide-windows.jar
+ * </li><li>
+ * 2. locate the jar within the IDE/platform installation and it's cluster, eg. modules/org-openide-windows.jar 
+ * </li><li>
+ * 3. create the same folder structure in src/main/nbm-branding, make folder with the module's jar name as well.
+ * eg. create folder by name modules/org-openide-windows.jar
+ * </li><li>
+ * 4. within that folder place your branding modifications at the same location, as if they were withn the jar,
+ * eg. org/openide/windows/ui/Bundle.properties and place the changed bundle keys there.
+ * </li></ul>
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ *
+ *
+ */
+@Mojo(name="branding",
+        requiresProject=true,
+        threadSafe = true,
+        defaultPhase= LifecyclePhase.PACKAGE)
+public class BrandingMojo
+        extends AbstractNbmMojo
+{
+
+    /**
+     * directory where the the binary content is created.
+     */
+    @Parameter(required=true, defaultValue="${project.build.directory}/nbm")
+    protected File nbmBuildDir;
+    
+    /**
+    * output directory.
+    */
+    @Parameter(defaultValue="${project.build.directory}", required=true)
+    protected File outputDirectory;
+    
+    /**
+     * Location of the branded resources.
+     */
+    @Parameter(required=true, defaultValue="${basedir}/src/main/nbm-branding")
+    private File brandingSources;
+    /**
+     * The branding token used by the application.
+     * Required unless {@code nbmBuildDir} does not exist and the mojo is thus skipped.
+     */
+    @Parameter(property="netbeans.branding.token")
+    private String brandingToken;
+    /**
+     * cluster of the branding.
+     */
+    @Parameter(required=true, defaultValue="extra")
+    protected String cluster;
+    /**
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    @Parameter(required=true, readonly=true, property="project")
+    private MavenProject project;
+
+    public void execute()
+        throws MojoExecutionException
+    {
+        if ( !"nbm".equals( project.getPackaging() ) ) 
+        {
+            getLog().error( "The nbm:branding goal shall be used within a NetBeans module project only (packaging 'nbm')" );
+        }
+        if ( !brandingSources.isDirectory() )
+        {
+            getLog().info( "No branding to process." );
+            return;
+        }
+        if ( brandingToken == null )
+        {
+            throw new MojoExecutionException( "brandingToken must be defined for mojo:branding" );
+        }
+        try
+        {
+
+            DirectoryScanner scanner = new DirectoryScanner();
+            scanner.setIncludes( new String[]
+                    {
+                        "**/*.*"
+                    } );
+            scanner.addDefaultExcludes();
+            scanner.setBasedir( brandingSources );
+            scanner.scan();
+
+            final String clusterPathPart = "netbeans" + File.separator + cluster;
+            File outputDir = new File(outputDirectory, "branding_and_locales");
+            outputDir.mkdirs();
+            File clusterDir = new File( nbmBuildDir, clusterPathPart );
+            clusterDir.mkdirs();
+
+            // copy all files and see to it that they get the correct names
+            for ( String brandingFilePath : scanner.getIncludedFiles() )
+            {
+                File brandingFile = new File( brandingSources, brandingFilePath );
+                String[] locale = getLocale( brandingFile.getName());
+                String token = locale[1] == null ? brandingToken : brandingToken + "_" + locale[1];
+                File root = new File(outputDir, token);
+                root.mkdirs();
+                String destinationName = locale[0] + "_" + token + locale[2];
+                File brandingDestination = new File( root, brandingFilePath.replace( brandingFile.getName(), destinationName) );
+                if ( !brandingDestination.getParentFile().exists() )
+                {
+                    brandingDestination.getParentFile().mkdirs();
+                }
+                FileUtils.copyFile( brandingFile, brandingDestination );
+            }
+            for (File rootDir : outputDir.listFiles()) {
+                if (!rootDir.isDirectory()) {
+                    continue;
+                }
+                String effectiveBranding = rootDir.getName();
+                // create jar-files from each toplevel .jar directory
+                scanner.setIncludes( new String[]
+                    {
+                        "**/*.jar"
+                    } );
+                scanner.setBasedir( rootDir );
+                scanner.scan();
+                for ( String jarDirectoryPath : scanner.getIncludedDirectories() )
+                {
+                    // move nnn.jar directory to nnn.jar.tmp
+                    File jarDirectory = new File( rootDir, jarDirectoryPath );
+                    File destinationLocation = new File(clusterDir, jarDirectoryPath).getParentFile();
+                    destinationLocation.mkdirs();
+                    // jars should be placed in locales/ under the same directory the jar-directories are
+                    File destinationJar =
+                        new File( destinationLocation + File.separator + "locale"
+                            + File.separator + destinationFileName( jarDirectory.getName(), effectiveBranding ) );
+
+                    // create nnn.jar archive of contents
+                    JarArchiver archiver = new JarArchiver();
+                    archiver.setDestFile( destinationJar );
+                    archiver.addDirectory( jarDirectory );
+                    archiver.createArchive();
+                }
+            }
+
+        }
+        catch ( Exception ex )
+        {
+            throw new MojoExecutionException( "Error creating branding", ex );
+        }
+    }
+
+    static  String destinationFileName( String brandingFilePath, String branding )
+    {
+        // use first underscore in filename 
+        int lastSeparator = brandingFilePath.lastIndexOf( File.separator );
+        String infix = "_" + branding;
+
+        // no underscores, use dot
+        int lastDot = brandingFilePath.lastIndexOf( "." );
+        if (lastDot == -1 || lastDot < lastSeparator) {
+            return brandingFilePath + infix;
+        }
+        return brandingFilePath.substring( 0, lastDot ) + infix + brandingFilePath.substring( lastDot );
+    }
+    
+    //[0] prefix
+    //[1] locale
+    //[2] suffix
+    static String[] getLocale(String name) {
+        String suffix = "";
+        int dot = name.indexOf( ".");
+        if (dot > -1) { //remove file extension
+            suffix = name.substring( dot );
+            name = name.substring( 0, dot);
+        }
+        String locale = null;
+        int count = 1;
+        //iterate from back of the string, max 3 times and see if the pattern patches local pattern
+        while (count <= 3) {
+            int underscore = name.lastIndexOf( '_');
+            if (underscore > -1) {
+                String loc1 = name.substring( underscore  + 1);
+                if (loc1.length() != 2) {
+                    break;
+                } 
+                locale = loc1 + (locale == null ? "" : "_" + locale);
+                name = name.substring( 0, underscore);
+            } else {
+                break;
+            }
+            count = count + 1;
+        }
+        return new String[] {name, locale, suffix};
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/BuildInstallersMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/BuildInstallersMojo.java
new file mode 100644
index 0000000..fab8fa7
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/BuildInstallersMojo.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2012 Frantisek Mantlik <frantisek at mantlik.cz>.
+ *
+ * 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.
+ * under the License.
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.*;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Build installers for Mavenized NetBeans application.
+ * Creates installers for supported operating systems
+ * and packages each installer as a deployable artifact.
+ * <p>See a <a href="http://www.mojohaus.org/nbm-maven-plugin/buildinstexample.html">how-to</a> on customizing the installer.
+ * @author <a href="mailto:frantisek@mantlik.cz">Frantisek Mantlik</a>
+ */
+@Mojo(name="build-installers", 
+        requiresProject=true, 
+        requiresDependencyResolution=ResolutionScope.RUNTIME,
+        threadSafe = true,
+        defaultPhase=LifecyclePhase.PACKAGE )
+public class BuildInstallersMojo
+        extends AbstractNbmMojo
+{
+
+    /**
+    * output directory.
+    */
+    @Parameter(defaultValue="${project.build.directory}", required=true)
+    protected File outputDirectory;
+    /**
+    * The branding token for the application based on NetBeans platform.
+    */
+    @Parameter(property="netbeans.branding.token", required=true)
+    protected String brandingToken;
+    /**
+    * Installation directory name at the destination system
+    * Deprecated, to be removed, was never actually used.
+    */
+    @Parameter(property="netbeans.branding.token")
+    protected String installDirName;
+    /**
+    * Prefix of all generated installers files
+    */
+    @Parameter(defaultValue="${project.build.finalName}")
+    private String installersFilePrefix;
+    /**
+     * Create installer for Windows
+     */
+    @Parameter(defaultValue="true")
+    private boolean installerOsWindows;
+    /**
+     * Create installer for Solaris
+     */
+    @Parameter(defaultValue="true")
+    private boolean installerOsSolaris;
+    /**
+     * Create installer for Linux
+     */
+    @Parameter(defaultValue="true")    
+    private boolean installerOsLinux;
+    /**
+     * Create installer for MacOSx
+     */
+    @Parameter(defaultValue="true")    
+    private boolean installerOsMacosx;
+    /**
+     * Enable Pack200 compression
+     */
+    @Parameter(defaultValue="true")
+    private boolean installerPack200Enable;
+    /**
+     * License file
+     */
+    @Parameter(defaultValue="${basedir}/license.txt")
+    private File installerLicenseFile;
+    /**
+     * Custom installer template.
+     * This file, if provided, will replace default template from
+     * &lt;NetBeansInstallation&gt;/harness/nbi/stub/template.xml
+     */
+    @Parameter
+    private File templateFile;
+    /**
+     * Parameters passed to templateFile 
+     * or to installer/nbi/stub/template.xml 
+     * to customize generated installers.
+     *
+     */
+    @Parameter
+    private Map<String, String> userSettings;
+    
+    /**
+     * Name of the zip artifact used to produce installers from (without .zip extension)
+     */
+    @Parameter(defaultValue="${project.build.finalName}")
+    private String finalName;
+
+    // <editor-fold defaultstate="collapsed" desc="Component parameters">
+    /**
+     * Used for attaching the artifact in the project
+     */
+    @Component
+    private MavenProjectHelper projectHelper;
+        
+    @Parameter(readonly=true, required=true, property="basedir")
+    private File basedir;
+    /**
+    * The Maven Project.
+    */
+    @Parameter(required=true, readonly=true, property="project")    
+    private MavenProject project;    
+
+    // </editor-fold>
+    @Override
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        Project antProject = antProject();
+
+        if ( !"nbm-application".equals( project.getPackaging() ) )
+        {
+            throw new MojoExecutionException(
+                    "This goal only makes sense on project with 'nbm-application' packaging." );
+        }
+        
+        if (!installerOsLinux && !installerOsMacosx && !installerOsSolaris && !installerOsWindows) {
+            getLog().warn( "None of the Operating System Installers selected, skipping 'build-installers' goal.");
+            return;
+        }
+
+        String zipName = finalName + ".zip";
+        File zipFile = new File( outputDirectory, zipName );
+        getLog().info( String.format( "Running Build Installers action for (existing=%2$s) zip file %1$s",
+                zipFile, zipFile.exists() ) );
+
+
+        File appIconIcnsFile;
+
+        // Copy Netbeans Installer resources
+        FileUrlUtils fu = new FileUrlUtils();
+        File harnessDir = new File( outputDirectory, "installer" );
+        fu.copyResourcesRecursively( getClass().getClassLoader().getResource( "harness" ), harnessDir );
+
+        // Overwrite template file with modified version to accept branded images etc.
+        if ( templateFile != null )
+        {
+            File template = new File( harnessDir, "nbi/stub/template.xml" );
+            fu.copyFile( templateFile, template );
+        }
+
+        appIconIcnsFile = new File( harnessDir, "etc" + File.separatorChar + "applicationIcon.icns" );
+        getLog().info( "Application icon:" + appIconIcnsFile.getAbsolutePath() );
+
+        Map<String, String> props = new HashMap<String, String> ();
+
+        props.put( "suite.location", basedir.getAbsolutePath().replace( "\\", "/" ) );
+        props.put( "suite.props.app.name", brandingToken);
+        props.put( "suite.dist.zip", zipFile.getAbsolutePath().replace( "\\", "/" ) );
+        props.put( "suite.dist.directory", outputDirectory.getAbsolutePath().replace( "\\", "/" ) );
+        props.put( "installer.build.dir", new File( outputDirectory, "installerbuild" ).getAbsolutePath().replace( "\\", "/" ) );
+        
+        props.put( "installers.file.prefix", installersFilePrefix );
+
+//        props.put( "install.dir.name", installDirName );
+
+        //mkleint: this is a flawed pattern! cannot make any assumption on multimodule layout
+        String appName = project.getParent().getArtifactId().replace( ".", "" ).replace( "-", "" ).replace( "_", "" ).replaceAll( "[0-9]+", "" );
+        props.put( "suite.nbi.product.uid", appName.toLowerCase( Locale.ENGLISH ) );
+
+        props.put( "suite.props.app.title", ( project.getName() + " " + project.getVersion() ).replaceAll( "-SNAPSHOT", "" ) );
+
+        String appVersion = project.getVersion().replaceAll( "-SNAPSHOT", "" );
+        props.put( "suite.nbi.product.version.short", appVersion );
+        while ( appVersion.split( "\\." ).length < 5 )
+        {
+            appVersion += ".0";
+        }
+        props.put( "suite.nbi.product.version", appVersion );
+
+        props.put( "nbi.stub.location", new File( harnessDir, "nbi/stub" ).getAbsolutePath().replace( "\\", "/" ) );
+
+        props.put( "nbi.stub.common.location", new File( harnessDir, "nbi/.common" ).getAbsolutePath().replace( "\\", "/" ) );
+
+        props.put( "nbi.ant.tasks.jar", new File( harnessDir, "modules/ext/nbi-ant-tasks.jar" ).getAbsolutePath().replace( "\\", "/" ) );
+
+        props.put( "nbi.registries.management.jar", new File( harnessDir, "modules/ext/nbi-registries-management.jar" ).getAbsolutePath().replace( "\\", "/" ) );
+
+        props.put( "nbi.engine.jar", new File( harnessDir, "modules/ext/nbi-engine.jar" ).getAbsolutePath().replace( "\\", "/" ) );
+
+        if ( installerLicenseFile != null )
+        {
+            getLog().info( String.format( "License file is at %1s, exist = %2$s", installerLicenseFile, installerLicenseFile.exists() ) );
+            props.put( "nbi.license.file", installerLicenseFile.getAbsolutePath() ); //mkleint: no path replacement here??
+        }
+
+        List<String> platforms = new ArrayList<String>();
+
+        if ( this.installerOsLinux )
+        {
+            platforms.add( "linux" );
+            File linuxFile = new File( outputDirectory, installersFilePrefix + "-linux.sh" );
+            projectHelper.attachArtifact( project, "sh", "linux", linuxFile );
+        }
+        if ( this.installerOsSolaris )
+        {
+            platforms.add( "solaris" );
+            File solarisFile = new File( outputDirectory, installersFilePrefix + "-solaris.sh" );
+            projectHelper.attachArtifact( project, "sh", "solaris", solarisFile );
+        }
+        if ( this.installerOsWindows )
+        {
+            platforms.add( "windows" );
+            File windowsFile = new File( outputDirectory, installersFilePrefix + "-windows.exe" );
+            projectHelper.attachArtifact( project, "exe", "windows", windowsFile );
+        }
+        if ( this.installerOsMacosx )
+        {
+            platforms.add( "macosx" );
+            File macosxFile = new File( outputDirectory, installersFilePrefix + "-macosx.tgz" );
+            projectHelper.attachArtifact( project, "tgz", "macosx", macosxFile );
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for ( int i = 0; i < platforms.size(); i++ )
+        {
+            if ( i != 0 )
+            {
+                sb.append( " " );
+            }
+            sb.append( platforms.get( i ) );
+        }
+        if ( sb.length() == 0 )
+        {
+            //nothing to build
+            getLog().warn( "Nothing to build." );
+        }
+
+        props.put( "generate.installer.for.platforms", sb.toString() );
+
+        File javaHome = new File( System.getProperty( "java.home" ) );
+        if ( new File( javaHome, "lib/rt.jar" ).exists() && javaHome.getName().equals( "jre" ) ) //mkleint: does this work on mac? no rt.jar there
+        {
+            javaHome = javaHome.getParentFile();
+        }
+        props.put( "generator-jdk-location-forward-slashes", javaHome.getAbsolutePath().replace( "\\", "/" ) );
+
+        props.put( "pack200.enabled", "" + installerPack200Enable );
+
+        if ( appIconIcnsFile != null )
+        {
+            props.put( "nbi.dock.icon.file", appIconIcnsFile.getAbsolutePath() );
+        }
+
+        try
+        {
+            antProject.setUserProperty( "ant.file", new File( harnessDir, "nbi/stub/template.xml" ).getAbsolutePath().replace( "\\", "/" ) );
+            ProjectHelper helper = ProjectHelper.getProjectHelper();
+            antProject.addReference( "ant.projectHelper", helper );
+            helper.parse( antProject, new File( harnessDir, "nbi/stub/template.xml" ) );
+            for ( Map.Entry<String, String> e : props.entrySet() )
+            {
+                antProject.setProperty( e.getKey(), e.getValue() );
+            }
+            if ( userSettings != null )
+            {
+                for ( Map.Entry<String, String> e : userSettings.entrySet() )
+                {
+                    antProject.setProperty( e.getKey(), e.getValue() );
+                }
+            }
+            antProject.executeTarget( "build" );
+        }
+        catch ( Exception ex )
+        {
+            throw new MojoExecutionException( "Installers creation failed: " + ex, ex );
+        }
+    }
+
+    //mkleint: could this be replaced by something from plexus-utils?
+    private class FileUrlUtils
+    {
+
+        boolean copyFile( final File toCopy, final File destFile )
+            throws MojoExecutionException
+        {
+            try
+            {
+                return copyStream( new FileInputStream( toCopy ), new FileOutputStream( destFile ) );
+            }
+            catch ( final FileNotFoundException e )
+            {
+                throw new MojoExecutionException( "Installers creation failed: " + e, e );
+            }
+        }
+
+        boolean copyFilesRecusively( final File toCopy, final File destDir )
+            throws MojoExecutionException
+        {
+            assert destDir.isDirectory();
+
+            if ( !toCopy.isDirectory() )
+            {
+                return copyFile( toCopy, new File( destDir, toCopy.getName() ) );
+            }
+            else
+            {
+                final File newDestDir = new File( destDir, toCopy.getName() );
+                if ( !newDestDir.exists() && !newDestDir.mkdir() )
+                {
+                    return false;
+                }
+                for ( final File child : toCopy.listFiles() )
+                {
+                    if ( !copyFilesRecusively( child, newDestDir ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        boolean copyJarResourcesRecursively( final File destDir, final JarURLConnection jarConnection )
+            throws IOException, MojoExecutionException
+        {
+
+            final JarFile jarFile = jarConnection.getJarFile();
+
+            for ( final Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); )
+            {
+                final JarEntry entry = e.nextElement();
+                if ( entry.getName().startsWith( jarConnection.getEntryName() ) )
+                {
+                    final String filename = StringUtils.removePrefix( entry.getName(), //
+                            jarConnection.getEntryName() );
+
+                    final File f = new File( destDir, filename );
+                    if ( !entry.isDirectory() )
+                    {
+                        final InputStream entryInputStream = jarFile.getInputStream( entry );
+                        if ( !copyStream( entryInputStream, f ) )
+                        {
+                            return false;
+                        }
+                        entryInputStream.close();
+                    }
+                    else
+                    {
+                        if ( !ensureDirectoryExists( f ) )
+                        {
+                            throw new IOException( "Could not create directory: "
+                                    + f.getAbsolutePath() );
+                        }
+                    }
+                }
+            }
+            return true;
+        }
+
+        boolean copyResourcesRecursively( final URL originUrl, final File destination )
+            throws MojoExecutionException
+        {
+            try
+            {
+                final URLConnection urlConnection = originUrl.openConnection();
+                if ( urlConnection instanceof JarURLConnection )
+                {
+                    return copyJarResourcesRecursively( destination, (JarURLConnection) urlConnection );
+                }
+                else
+                {
+                    return copyFilesRecusively( new File( originUrl.getPath() ), destination );
+                }
+            }
+            catch ( final IOException e )
+            {
+                throw new MojoExecutionException( "Installers creation failed: " + e, e );
+            }
+        }
+
+        boolean copyStream( final InputStream is, final File f )
+            throws MojoExecutionException
+        {
+            try
+            {
+                return copyStream( is, new FileOutputStream( f ) );
+            }
+            catch ( final FileNotFoundException e )
+            {
+                throw new MojoExecutionException( "Installers creation failed: " + e, e );
+            }
+        }
+
+        boolean copyStream( final InputStream is, final OutputStream os )
+            throws MojoExecutionException
+        {
+            try
+            {
+                final byte[] buf = new byte[1024];
+
+                int len;
+                while ( ( len = is.read( buf ) ) > 0 )
+                {
+                    os.write( buf, 0, len );
+                }
+                is.close();
+                os.close();
+                return true;
+            }
+            catch ( final IOException e )
+            {
+                throw new MojoExecutionException( "Installers creation failed: " + e, e );
+            }
+        }
+
+        boolean ensureDirectoryExists( final File f )
+        {
+            return f.exists() || f.mkdir();
+        }
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CollectLibrariesNodeVisitor.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CollectLibrariesNodeVisitor.java
new file mode 100644
index 0000000..b35c7a6
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CollectLibrariesNodeVisitor.java
@@ -0,0 +1,187 @@
+/* ==========================================================================
+ * Copyright 2008 mkleint
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.shared.dependency.graph.DependencyNode;
+import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+
+/**
+ * A dependency node visitor that collects visited nodes that are known libraries or are
+ * children of known libraries
+ * @author milos kleint
+ */
+public class CollectLibrariesNodeVisitor
+    implements DependencyNodeVisitor
+{
+
+    /**
+     * The collected list of nodes.
+     */
+    private final List<Artifact> nodes;
+
+    private Map<String, Artifact> artifacts;
+
+    private Map<Artifact, ExamineManifest> examinerCache;
+
+    private List<String> explicitLibs;
+
+    private final Log log;
+
+    private MojoExecutionException throwable;
+
+    private DependencyNode root;
+
+    private Set<String> duplicates;
+
+    private Set<String> conflicts;
+
+    private Set<String> includes;
+
+    private final boolean useOsgiDependencies;
+
+    /**
+     * Creates a dependency node visitor that collects visited nodes for further processing.
+     * @param explicitLibraries list of explicit libraries
+     * @param runtimeArtifacts list of runtime artifacts
+     * @param examinerCache cache of netbeans manifest for artifacts
+     * @param log mojo logger
+     * @param root dependency to start collect with
+     * @param useOsgiDependencies whether to allow osgi dependencies or not
+     */
+    public CollectLibrariesNodeVisitor( List<String> explicitLibraries,
+        List<Artifact> runtimeArtifacts, Map<Artifact, ExamineManifest> examinerCache,
+        Log log, DependencyNode root, boolean useOsgiDependencies )
+    {
+        nodes = new ArrayList<Artifact>();
+        artifacts = new HashMap<String, Artifact>();
+        for ( Artifact a : runtimeArtifacts )
+        {
+            artifacts.put( a.getDependencyConflictId(), a );
+        }
+        this.examinerCache = examinerCache;
+        this.explicitLibs = explicitLibraries;
+        this.log = log;
+        this.root = root;
+        this.useOsgiDependencies = useOsgiDependencies;
+        duplicates = new HashSet<String>();
+        conflicts = new HashSet<String>();
+        includes = new HashSet<String>();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean visit( DependencyNode node )
+    {
+        if ( throwable != null )
+        {
+            return false;
+        }
+        if ( root == node )
+        {
+            return true;
+        }
+        try
+        {
+            Artifact artifact = node.getArtifact();
+            if ( !artifacts.containsKey( artifact.getDependencyConflictId() ) )
+            {
+                //ignore non-runtime stuff..
+                return false;
+            }
+            // somehow the transitive artifacts in the  tree are not always resolved?
+            artifact = artifacts.get( artifact.getDependencyConflictId() );
+
+            ExamineManifest depExaminator = examinerCache.get( artifact );
+            if ( depExaminator == null )
+            {
+                depExaminator = new ExamineManifest( log );
+                depExaminator.setArtifactFile( artifact.getFile() );
+                depExaminator.checkFile();
+                examinerCache.put( artifact, depExaminator );
+            }
+            if ( AbstractNbmMojo.matchesLibrary( artifact, explicitLibs, depExaminator, log, useOsgiDependencies ) )
+            {
+                if ( depExaminator.isNetBeansModule() )
+                {
+                    log.warn(
+                        "You are using a NetBeans Module as a Library (classpath extension): " + artifact.getId() );
+                }
+
+                nodes.add( artifact );
+                includes.add( artifact.getDependencyConflictId() );
+                // if a library, iterate to it's child nodes.
+                return true;
+            }
+        }
+        catch ( MojoExecutionException mojoExecutionException )
+        {
+            throwable = mojoExecutionException;
+        }
+        //don't bother iterating to childs if the current node is not a library.
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean endVisit( DependencyNode node )
+    {
+        if ( throwable != null )
+        {
+            return false;
+        }
+        if ( node == root )
+        {
+            if ( nodes.size() > 0 )
+            {
+                log.info( "Adding on module's Class-Path:" );
+                for ( Artifact inc : nodes )
+                {
+                    log.info( "    " + inc.getId() );
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets the list of collected dependency nodes.
+     * 
+     * @return the list of collected dependency nodes
+     * @throws MojoExecutionException if a throwable is set
+     */
+    public List<Artifact> getArtifacts()
+        throws MojoExecutionException
+    {
+        if ( throwable != null )
+        {
+            throw throwable;
+        }
+        return nodes;
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CollectModuleLibrariesNodeVisitor.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CollectModuleLibrariesNodeVisitor.java
new file mode 100644
index 0000000..693471a
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CollectModuleLibrariesNodeVisitor.java
@@ -0,0 +1,216 @@
+/* ==========================================================================
+ * Copyright 2008 mkleint
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.shared.dependency.graph.DependencyNode;
+import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+
+/**
+ * A dependency node visitor that collects visited nodes that are known libraries or are
+ * children of known libraries
+ * @author milos kleint
+ */
+public class CollectModuleLibrariesNodeVisitor
+    implements DependencyNodeVisitor
+{
+
+    /**
+     * The collected list of nodes.
+     */
+    private final Map<String, List<Artifact>> directNodes;
+
+    private final Map<String, List<Artifact>> transitiveNodes;
+
+    private Map<String, Artifact> artifacts;
+
+    private Map<Artifact, ExamineManifest> examinerCache;
+
+    private final Log log;
+
+    private MojoExecutionException throwable;
+
+    private DependencyNode root;
+
+    private Stack<String> currentModule = new Stack<String>();
+    private static final String LIB_ID = "!@#$%^&ROOT";
+
+    private final boolean useOSGiDependencies;
+
+    /**
+     * Creates a dependency node visitor that collects visited nodes for further processing.
+     * @param runtimeArtifacts list of runtime artifacts
+     * @param examinerCache cache of netbeans manifest for artifacts
+     * @param log mojo logger
+     * @param root dependency to start collect with
+     * @param useOSGiDependencies whether to allow osgi dependencies or not
+     */
+    public CollectModuleLibrariesNodeVisitor(
+        List<Artifact> runtimeArtifacts, Map<Artifact, ExamineManifest> examinerCache,
+        Log log, DependencyNode root, boolean useOSGiDependencies )
+    {
+        directNodes = new HashMap<String, List<Artifact>>();
+        transitiveNodes = new HashMap<String, List<Artifact>>();
+        artifacts = new HashMap<String, Artifact>();
+        for ( Artifact a : runtimeArtifacts )
+        {
+            artifacts.put( a.getDependencyConflictId(), a );
+        }
+        this.examinerCache = examinerCache;
+        this.log = log;
+        this.root = root;
+        this.useOSGiDependencies = useOSGiDependencies;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean visit( DependencyNode node )
+    {
+        if ( throwable != null )
+        {
+            return false;
+        }
+        if ( root == node )
+        {
+            return true;
+        }
+        try
+        {
+            Artifact artifact = node.getArtifact();
+            if ( !artifacts.containsKey( artifact.getDependencyConflictId() ) )
+            {
+                //ignore non-runtime stuff..
+                return false;
+            }
+            // somehow the transitive artifacts in the  tree are not always resolved?
+            artifact = artifacts.get( artifact.getDependencyConflictId() );
+
+            ExamineManifest depExaminator = examinerCache.get( artifact );
+            if ( depExaminator == null )
+            {
+                depExaminator = new ExamineManifest( log );
+                depExaminator.setArtifactFile( artifact.getFile() );
+                depExaminator.checkFile();
+                examinerCache.put( artifact, depExaminator );
+            }
+            if ( depExaminator.isNetBeansModule() || ( useOSGiDependencies && depExaminator.isOsgiBundle() ) )
+            {
+                currentModule.push( artifact.getDependencyConflictId() );
+                ArrayList<Artifact> arts = new ArrayList<Artifact>();
+                arts.add( artifact );
+                if ( currentModule.size() == 1 )
+                {
+                    directNodes.put( currentModule.peek(), arts );
+                }
+                else
+                {
+                    transitiveNodes.put( currentModule.peek(), arts );
+                }
+                return true;
+            }
+            if ( currentModule.size() > 0 )
+            {
+                ////MNBMODULE-95 we are only interested in the module owned libraries
+                if ( !currentModule.peek().startsWith( LIB_ID ) &&
+                        AbstractNbmMojo.matchesLibrary( artifact, Collections.<String>emptyList(), depExaminator, log, useOSGiDependencies ) )
+                {
+                    if ( currentModule.size() == 1 )
+                    {
+                        directNodes.get( currentModule.peek() ).add( artifact );
+                    }
+                    else
+                    {
+                        transitiveNodes.get( currentModule.peek() ).add( artifact );
+                    }
+                    // if a library, iterate to it's child nodes.
+                    return true;
+                }
+            }
+            else
+            {
+                //MNBMODULE-95 we check the non-module dependencies to see if they
+                // depend on modules/bundles. these bundles are transitive, so
+                // we add the root module as the first currentModule to keep
+                //any bundle/module underneath it as transitive
+                currentModule.push( LIB_ID + artifact.getDependencyConflictId() );
+            }
+        }
+        catch ( MojoExecutionException mojoExecutionException )
+        {
+            throwable = mojoExecutionException;
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean endVisit( DependencyNode node )
+    {
+        if ( throwable != null )
+        {
+            return false;
+        }
+        if ( !currentModule.empty()
+            && ( currentModule.peek().equals( node.getArtifact().getDependencyConflictId() )
+                            || currentModule.peek().equals( LIB_ID + node.getArtifact().getDependencyConflictId() ) ) )
+        {
+            currentModule.pop();
+        }
+        return true;
+    }
+
+    /**
+     * modules declared in the project's pom
+     * @return a map of module artifact lists, key is the dependencyConflictId
+     * @throws MojoExecutionException if an unexpected problem occurs
+     */
+    public Map<String, List<Artifact>> getDeclaredArtifacts()
+        throws MojoExecutionException
+    {
+        if ( throwable != null )
+        {
+            throw throwable;
+        }
+        return directNodes;
+    }
+
+    /**
+     * modules that were picked up transitively
+     * @return a map of module artifact lists, key is the dependencyConflictId
+     * @throws MojoExecutionException if an unexpected problem occurs
+     */
+    public Map<String, List<Artifact>> getTransitiveArtifacts()
+        throws MojoExecutionException
+    {
+        if ( throwable != null )
+        {
+            throw throwable;
+        }
+        return transitiveNodes;
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateClusterAppMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateClusterAppMojo.java
new file mode 100644
index 0000000..38a9756
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateClusterAppMojo.java
@@ -0,0 +1,1254 @@
+/* ==========================================================================
+ * Copyright Milos Kleint
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import com.google.common.collect.Sets;
+import java.io.*;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Pack200;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.CRC32;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.filters.StringInputStream;
+import org.apache.tools.ant.taskdefs.Chmod;
+import org.apache.tools.ant.types.FileSet;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.io.InputStreamFacade;
+import org.netbeans.nbbuild.MakeListOfNBM;
+
+/**
+ * Create the NetBeans module clusters/application for the 'nbm-application' packaging
+ * projects
+ *
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ */
+@Mojo(name="cluster-app", 
+        defaultPhase= LifecyclePhase.PACKAGE, 
+        requiresProject=true, 
+        threadSafe = true,
+        requiresDependencyResolution= ResolutionScope.RUNTIME )
+public class CreateClusterAppMojo
+    extends AbstractNbmMojo
+{
+
+    /**
+     * output directory where the the NetBeans application will be created.
+     */
+    @Parameter(defaultValue="${project.build.directory}", required=true)
+    private File outputDirectory;
+
+    /**
+     * The Maven Project.
+     */
+    @Parameter(required=true, readonly=true, property="project")
+    private MavenProject project;
+
+    /**
+     * The branding token for the application based on NetBeans platform.
+     */
+    @Parameter(property="netbeans.branding.token", required=true)
+    protected String brandingToken;
+
+    /**
+     * Optional path to custom etc/${brandingToken}.conf file. If not defined,
+     * a default template will be used.
+     */
+    @Parameter( property="netbeans.conf.file")
+    private File etcConfFile;
+
+    /**
+     * Optional path to custom etc/${brandingToken}.clusters file. If not defined,
+     * a default one will be generated.
+     */
+    @Parameter(property="netbeans.clusters.file")
+    private File etcClustersFile;
+
+    /**
+     * Directory which contains the executables that will be copied to
+     * the final application's bin/ directory.
+     * Please note that the name of the executables shall generally
+     * match the brandingToken parameter. Otherwise the application can be wrongly branded.
+     */
+    @Parameter(property="netbeans.bin.directory")
+    private File binDirectory;
+
+    /**
+     * If the depending NBM file doesn't contain any application cluster information,
+     * use this value as default location for such module NBMs.
+     * @since 3.2
+     */
+    @Parameter(defaultValue="extra")
+    private String defaultCluster;
+    
+    /**
+     * attempts to verify the integrity of module artifacts making sure that all dependencies are included
+     * and that all required tokens are provided
+     * @since 3.10
+     */
+    @Parameter(defaultValue = "true", property = "netbeans.verify.integrity")
+    private boolean verifyIntegrity;
+    
+    private final Collection<String> defaultPlatformTokens = Arrays.asList( new String[] {
+                    "org.openide.modules.os.Windows",
+                    "org.openide.modules.os.Unix",
+                    "org.openide.modules.os.MacOSX",
+                    "org.openide.modules.os.OS2",
+                    "org.openide.modules.os.PlainUnix",    
+                    "org.openide.modules.os.Linux",
+                    "org.openide.modules.os.Solaris",
+                    "org.openide.modules.ModuleFormat1",
+                    "org.openide.modules.ModuleFormat2",
+                    "org.openide.modules.jre.JavaFX" //MNBMODULE-234
+    });
+
+
+    // <editor-fold defaultstate="collapsed" desc="Component parameters">
+    
+    @Component
+    private ArtifactFactory artifactFactory;
+
+    @Component
+    private ArtifactResolver artifactResolver;
+
+    /**
+     * Local maven repository.
+     *
+     */
+    @Parameter(required=true, readonly=true, property="localRepository")
+    protected ArtifactRepository localRepository;
+
+// end of component params custom code folding
+// </editor-fold>
+
+    @Override
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+
+        File nbmBuildDirFile = new File( outputDirectory, brandingToken );
+        if ( !nbmBuildDirFile.exists() )
+        {
+            nbmBuildDirFile.mkdirs();
+        }
+
+        if ( "nbm-application".equals( project.getPackaging() ) )
+        {
+            Project antProject = registerNbmAntTasks();
+
+            Set<String> wrappedBundleCNBs = new HashSet<>(100);
+            Map<String, Set<String>> clusterDependencies = new HashMap<>();
+            Map<String, Set<String>> clusterModules = new HashMap<>();
+            
+            //verify integrity
+            Set<String> modulesCNBs = new HashSet<>(200);
+            Set<String> dependencyCNBs = new HashSet<>(200);
+            Map<String, Set<String>> dependencyCNBBacktraces = new HashMap<>(50);
+            Set<String> requireTokens = new HashSet<>(50);
+            Map<String, Set<String>> requireTokensBacktraces = new HashMap<>(50);
+            Set<String> provideTokens = new HashSet<>(50);
+            Set<String> osgiImports = new HashSet<>(50);
+            Map<String, Set<String>> osgiImportsBacktraces = new HashMap<>(50);
+            Set<String> osgiExports = new HashSet<>(50);
+            Set<String> osgiExportsSubs = new HashSet<>(50); //a way to deal with nb module declaring xxx.** (subpackages) declaration that is consumed by osgi imports
+            
+            List<BundleTuple> bundles = new ArrayList<>();
+
+            @SuppressWarnings( "unchecked" )
+            Set<Artifact> artifacts = project.getArtifacts();
+            for ( Artifact art : artifacts )
+            {
+                ArtifactResult res = turnJarToNbmFile( art, artifactFactory, artifactResolver, project, localRepository );
+                if ( res.hasConvertedArtifact() )
+                {
+                    art = res.getConvertedArtifact();
+                }
+
+                if ( art.getType().equals( "nbm-file" ) )
+                {
+                    try
+                    {
+                        JarFile jf = new JarFile( art.getFile() );
+                        try
+                        {
+                            String clusterName = findCluster( jf );                            
+                            ClusterTuple cluster = processCluster( clusterName, nbmBuildDirFile, art );
+                            
+                                getLog().debug( "Copying " + art.getId() + " to cluster " + clusterName );
+                                Enumeration<JarEntry> enu = jf.entries();
+
+                                // we need to trigger this ant task to generate the update_tracking file.
+                                MakeListOfNBM makeTask = (MakeListOfNBM) antProject.createTask( "genlist" );
+                                antProject.setNewProperty( "module.name", art.getFile().getName() ); // TODO
+                                antProject.setProperty( "cluster.dir", clusterName );
+                                FileSet set = makeTask.createFileSet();
+                                set.setDir( cluster.location );
+                                makeTask.setOutputfiledir( cluster.location );
+                                String[] executables = null;
+                                File classpathRoot = null;
+                                String classPath = null;
+                                while ( enu.hasMoreElements() )
+                                {
+                                    JarEntry ent = enu.nextElement();
+                                    String name = ent.getName();
+                                    //MNBMODULE-176
+                                    if (name.equals("Info/executables.list")) {
+                                        if (cluster.newer) {
+                                            InputStream is = jf.getInputStream( ent );
+                                            executables = StringUtils.split( IOUtil.toString( is, "UTF-8" ), "\n");
+                                        }
+                                    }
+                                    else if ( name.startsWith( "netbeans/" ) )
+                                    { // ignore everything else.
+                                        String path = clusterName + name.substring( "netbeans".length() );
+                                        boolean ispack200 = path.endsWith( ".jar.pack.gz" );
+                                        if ( ispack200 )
+                                        {
+                                            path = path.replace( ".jar.pack.gz", ".jar" );
+                                        }
+                                        File fl = new File( nbmBuildDirFile, path.replace( "/", File.separator ) );
+                                        String part = name.substring( "netbeans/".length() );
+                                        if ( ispack200 )
+                                        {
+                                            part = part.replace( ".jar.pack.gz", ".jar" );
+                                        }
+                                        if (cluster.newer) 
+                                        {
+                                            if ( ent.isDirectory() )
+                                            {
+                                                fl.mkdirs();
+                                            }
+                                            else if ( path.endsWith( ".external" ) ) // MNBMODULE-138
+                                            {
+                                                InputStream is = jf.getInputStream( ent );
+                                                try
+                                                {
+                                                    externalDownload( new File( fl.getParentFile(),
+                                                                                fl.getName().replaceFirst( "[.]external$",
+                                                                                                           "" ) ), is );
+                                                }
+                                                finally
+                                                {
+                                                    is.close();
+                                                }
+                                                //MNBMODULE-192
+                                                set.appendIncludes( new String[] { name.substring( "netbeans/".length(), name.length() - ".external".length() ) } );
+                                            }
+                                            else
+                                            {
+                                                set.appendIncludes( new String[] { part } );
+
+                                                fl.getParentFile().mkdirs();
+                                                fl.createNewFile();
+                                                BufferedOutputStream outstream = null;
+                                                try
+                                                {
+                                                    outstream = new BufferedOutputStream( new FileOutputStream( fl ) );
+                                                    InputStream instream = jf.getInputStream( ent );
+                                                    if ( ispack200 )
+                                                    {
+                                                        Pack200.Unpacker unp = Pack200.newUnpacker();
+                                                        JarOutputStream jos = new JarOutputStream( outstream );
+                                                        GZIPInputStream gzip = new GZIPInputStream( instream );
+                                                        try
+                                                        {
+                                                            unp.unpack( gzip, jos );
+                                                        }
+                                                        finally
+                                                        {
+                                                            jos.close();
+                                                        }
+                                                    }
+                                                    else
+                                                    {
+                                                        IOUtil.copy( instream, outstream );
+                                                    }
+                                                }
+                                                finally
+                                                {
+                                                    IOUtil.close( outstream );
+                                                }
+                                            }
+                                        }
+                                            
+                                            //TODO examine netbeans/config/Modules to see if the module is autoload/eager
+                                            // in verifyIntegrity these could be handled more gracefully than regular modules.
+                                            //eager is simpler, does not need to have module dependencies satisfied.
+                                            //autoload needs checking if any of the other modules declares a dependency on it. if not, also safe to ignore?
+                                            
+                                            
+                                            // now figure which one of the jars is the module jar..
+                                            if ( part.matches("(modules|core|lib)/[^/]+[.]jar") )
+                                            {
+                                                ExamineManifest ex = new ExamineManifest( getLog() );
+                                                ex.setJarFile( fl );
+                                                ex.setPopulateDependencies( true );
+                                                ex.checkFile();
+                                                if ( ex.isNetBeansModule() )
+                                                {
+                                                    makeTask.setModule( part );
+                                                    addToMap(clusterDependencies, clusterName, ex.getDependencyTokens());
+                                                    addToMap(clusterModules, clusterName, Collections.singletonList( ex.getModule() ));
+                                                    if (ex.getClasspath().length() > 0) { //MNBMODULE-220
+                                                        classPath = ex.getClasspath();
+                                                        classpathRoot = fl.getParentFile();
+                                                    }
+                                                }
+                                                if (verifyIntegrity) {
+                                                    dependencyCNBs.addAll(ex.getDependencyTokens());
+                                                    modulesCNBs.add(ex.getModule());
+                                                    for (String d : ex.getDependencyTokens()) {
+                                                        addToMap(dependencyCNBBacktraces, d, Collections.singletonList( ex.getModule() ));
+                                                    }
+                                                    if (ex.isNetBeansModule()) {
+                                                        requireTokens.addAll(ex.getNetBeansRequiresTokens());
+                                                        for (String r : ex.getNetBeansRequiresTokens()) {
+                                                            addToMap( requireTokensBacktraces, r, Collections.singletonList( ex.getModule()));
+                                                        }
+                                                        provideTokens.addAll(ex.getNetBeansProvidesTokens());
+                                                        for (String pack : ex.getPackages()) {
+                                                            if (pack.endsWith( ".**")) {
+                                                                //what to do with subpackages?
+                                                                pack = pack.substring( 0, pack.length() - ".**".length());
+                                                                osgiExportsSubs.add( pack );
+                                                            } else if (pack.endsWith( ".*")) {
+                                                                pack = pack.substring( 0, pack.length() - ".*".length());
+                                                                osgiExports.add(pack);                                                            
+                                                            }
+                                                        }
+                                                        
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                    if (classPath != null) { //MNBMODULE-220 collect wrappedbundleCNBs, later useful in assignClustersToBundles(), these get removed from list of bundles.
+                                        String[] paths = StringUtils.split( classPath, " ");
+                                        for (String path : paths) {
+                                            path = path.trim();
+                                            File classpathFile = new File(classpathRoot, path);
+                                            if (path.equals("${java.home}/lib/ext/jfxrt.jar")) { //MNBMODULE-228
+                                                String jhm = System.getProperty("java.home");
+                                                classpathFile = new File(new File(new File(new File(jhm), "lib"), "ext"), "jfxrt.jar");
+                                                if (!classpathFile.exists()) {
+                                                    File jdk7 = new File(new File(new File(jhm), "lib"), "jfxrt.jar");
+                                                    if (jdk7.exists()) {
+                                                        classpathFile = jdk7;
+                                                    }
+                                                }
+                                            }
+                                            if (!classpathFile.isFile()) {
+                                                getLog().warn( "Could not resolve Class-Path item in " + art.getId() + ", path is:" + path +  ", skipping");
+                                                continue; //try to guard against future failures
+                                            } 
+                                            ExamineManifest ex = new ExamineManifest( getLog() );
+                                            ex.setJarFile( classpathFile );
+                                            //ex.setPopulateDependencies( true );
+                                            ex.checkFile();
+                                            if (ex.isOsgiBundle()) {
+                                                wrappedBundleCNBs.add( ex.getModule() );
+                                            }
+                                        }
+                                    }
+                            if ( cluster.newer )
+                            {
+                                try
+                                {
+                                    makeTask.execute();
+                                }
+                                catch ( BuildException e )
+                                {
+                                    getLog().error( "Cannot Generate update_tracking XML file from " + art.getFile() );
+                                    throw new MojoExecutionException( e.getMessage(), e );
+                                }
+
+                                if ( executables != null )
+                                {
+                                    //MNBMODULE-176
+                                    for ( String exec : executables )
+                                    {
+                                        exec = exec.replace( "/", File.separator );
+                                        File execFile = new File( cluster.location, exec );
+                                        if ( execFile.exists() )
+                                        {
+                                            execFile.setExecutable( true, false );
+                                        }
+                                    }
+                                }
+                            }
+                            
+                        }
+                        finally
+                        {
+                            jf.close();
+                        }
+                    }
+                    catch ( IOException ex )
+                    {
+                        getLog().error( art.getFile().getAbsolutePath(), ex );
+                    }
+                }
+                if ( res.isOSGiBundle() )
+                {
+                    ExamineManifest ex = res.getExaminedManifest();
+                    bundles.add( new BundleTuple( art,  ex) );
+                    if (verifyIntegrity) {
+                        dependencyCNBs.addAll(ex.getDependencyTokens());
+                        for ( String d : ex.getDependencyTokens() )
+                        {
+                            addToMap( dependencyCNBBacktraces, d, Collections.singletonList( ex.getModule() ) );
+                        }
+                        modulesCNBs.add(ex.getModule());
+                        osgiImports.addAll( ex.getOsgiImports());
+                        for ( String d : ex.getOsgiImports() )
+                        {
+                            addToMap( osgiImportsBacktraces, d, Collections.singletonList( ex.getModule() ) );
+                        }
+                        
+                        osgiExports.addAll( ex.getOsgiExports());
+                    }
+                } 
+            }
+            
+            if (verifyIntegrity) {
+                if (getLog().isDebugEnabled()) {
+                    getLog().debug( "All found codenamebases:" + Arrays.toString( modulesCNBs.toArray()) );
+                    getLog().debug( "All found OSGI exports:" + Arrays.toString( osgiExports.toArray()) );
+                    getLog().debug( "All found provided tokens:" + Arrays.toString( provideTokens.toArray()) );
+                }
+                dependencyCNBs.removeAll( modulesCNBs );
+                if (modulesCNBs.contains( "org.netbeans.modules.netbinox")) {
+                    dependencyCNBs.remove( "org.eclipse.osgi"); //this is special.
+                }
+                osgiImports.removeAll( osgiExports );
+                Iterator<String> it = osgiImports.iterator();
+                while (it.hasNext()) {
+                    String s = it.next();
+                    if (s.startsWith( "java.") || s.startsWith( "javax.") || s.startsWith( "sun.") || s.startsWith( "org.xml.sax") || s.startsWith( "org.w3c.dom") || s.startsWith( "org.ietf.jgss")) {
+                        it.remove();
+                        continue;
+                    }
+                    for (String sub : osgiExportsSubs) {
+                        if (s.startsWith( sub )) {
+                            it.remove();
+                            break;
+                        }
+                    }
+                }
+                requireTokens.removeAll( provideTokens );
+                requireTokens.removeAll( defaultPlatformTokens );
+                if (!dependencyCNBs.isEmpty() || !osgiImports.isEmpty() ||!requireTokens.isEmpty()) {
+                    if (!dependencyCNBs.isEmpty()) {
+                        getLog().error( "Some included modules/bundles depend on these codenamebases but they are not included. The application will fail starting up. The missing codenamebases are:" );
+                        for (String s : dependencyCNBs) {
+                            Set<String> back = dependencyCNBBacktraces.get( s );
+                            getLog().error("   " + s + (back != null ? "          ref: " + Arrays.toString( back.toArray()) : ""));
+                        }
+                    }
+                    if (!osgiImports.isEmpty()) {
+                        getLog().error("Some OSGi imports are not satisfied by included bundles' exports. The application will fail starting up. The missing imports are:");
+                        for (String s : osgiImports) {
+                            Set<String> back = osgiImportsBacktraces.get( s );
+                            getLog().error("   " + s + (back != null ? "          ref: " + Arrays.toString( back.toArray()) : ""));
+                        }
+                    }
+                     if (!requireTokens.isEmpty()) {
+                        getLog().error("Some tokens required by included modules are not provided by included modules. The application will fail starting up. The missing tokens are:");
+                        for (String s : requireTokens) {
+                            Set<String> back = requireTokensBacktraces.get( s );
+                            getLog().error("   " + s + (back != null ? "          ref: " + Arrays.toString( back.toArray()) : ""));
+                        }
+                    }
+                    throw new MojoFailureException("See above for consistency validation check failures. Either fix those by adding the relevant dependencies to the application or disable the check by setting the verifyIntegrity parameter to false or by running with -Dnetbeans.verify.integrity=false cmd line parameter.");
+                } else {
+                    getLog().info( "Integrity verification passed.");
+                }
+            } else {
+                getLog().info( "Integrity verification skipped.");
+            }
+            
+            //attempt to sort clusters based on the dependencies and cluster content.
+            Map<String, Set<String>> cluster2depClusters = computeClusterOrdering( clusterDependencies, clusterModules );
+            clusterModules.clear();
+        
+            //now assign the cluster to bundles based on dependencies..
+            assignClustersToBundles( bundles, wrappedBundleCNBs, clusterDependencies, cluster2depClusters, getLog() );
+            
+            
+            for (BundleTuple ent : bundles) {
+                Artifact art = ent.artifact;
+                final ExamineManifest ex = ent.manifest;
+                
+                String clstr = ent.cluster;
+                if (clstr == null) {
+                    clstr = defaultCluster;
+                }
+                
+                ClusterTuple cluster = processCluster( clstr, nbmBuildDirFile, art );
+                if ( cluster.newer )
+                {
+                    getLog().info( "Copying " + art.getId() + " to cluster " + clstr );
+                    File modules = new File( cluster.location, "modules" );
+                    modules.mkdirs();
+                    File config = new File( cluster.location, "config" );
+                    File confModules = new File( config, "Modules" );
+                    confModules.mkdirs();
+                    File updateTracking = new File( cluster.location, "update_tracking" );
+                    updateTracking.mkdirs();
+                    final String cnb = ex.getModule();
+                    final String cnbDashed = cnb.replace( ".", "-" );
+                    final File moduleArt = new File( modules, cnbDashed + ".jar" ); //do we need the file in some canotical name pattern?
+                    final String specVer = ex.getSpecVersion();
+                    try
+                    {
+                        FileUtils.copyFile( art.getFile(), moduleArt );
+                        final File moduleConf = new File( confModules, cnbDashed + ".xml" );
+                        FileUtils.copyStreamToFile( new InputStreamFacade() {
+                            @Override
+                            public InputStream getInputStream() throws IOException
+                            {
+                                return new StringInputStream( createBundleConfigFile( cnb, ex.isBundleAutoload() ), "UTF-8" );
+                            }
+                        }, moduleConf );
+                        FileUtils.copyStreamToFile( new InputStreamFacade() {
+                            @Override
+                            public InputStream getInputStream() throws IOException
+                            {
+                                return new StringInputStream( createBundleUpdateTracking( cnb, moduleArt, moduleConf, specVer ), "UTF-8" );
+                            }
+                        }, new File( updateTracking, cnbDashed + ".xml" ) );
+                    }
+                    catch ( IOException exc )
+                    {
+                        getLog().error( exc );
+                    }
+                }
+            }
+
+            getLog().info(
+                "Created NetBeans module cluster(s) at " + nbmBuildDirFile.getAbsoluteFile() );
+
+        }
+        else
+        {
+            throw new MojoExecutionException(
+                "This goal only makes sense on project with nbm-application packaging" );
+        }
+        //in 6.1 the rebuilt modules will be cached if the timestamp is not touched.
+        File[] files = nbmBuildDirFile.listFiles();
+        for ( File file : files )
+        {
+            if ( file.isDirectory() )
+            {
+                File stamp = new File( file, ".lastModified" );
+                if ( !stamp.exists() )
+                {
+                    try
+                    {
+                        stamp.createNewFile();
+                    }
+                    catch ( IOException ex )
+                    {
+                        ex.printStackTrace();
+                    }
+                }
+                stamp.setLastModified( new Date().getTime() );
+            }
+        }
+        try
+        {
+            createBinEtcDir( nbmBuildDirFile, brandingToken );
+        }
+        catch ( IOException ex )
+        {
+            throw new MojoExecutionException(
+                "Cannot process etc folder content creation.", ex );
+        }
+    }
+    private final static Pattern patt = Pattern.compile(
+        ".*targetcluster=\"([a-zA-Z0-9_\\.\\-]+)\".*", Pattern.DOTALL );
+
+    private String findCluster( JarFile jf )
+        throws MojoFailureException, IOException
+    {
+        ZipEntry entry = jf.getEntry( "Info/info.xml" );
+        InputStream ins = jf.getInputStream( entry );
+        String str = IOUtil.toString( ins, "UTF8" );
+        Matcher m = patt.matcher( str );
+        if ( !m.matches() )
+        {
+            getLog().info( "Cannot find cluster for " + jf.getName() + " Falling back to default value - '"
+                               + defaultCluster + "'." );
+            return defaultCluster;
+        }
+        else
+        {
+            return m.group( 1 );
+        }
+    }
+
+    /**
+     * 
+     * @param buildDir Directory where the platform bundle is built
+     * @param brandingToken
+     * 
+     * @throws java.io.IOException
+     */
+    private void createBinEtcDir( File buildDir, String brandingToken )
+        throws IOException, MojoExecutionException
+    {
+        File etcDir = new File( buildDir + File.separator + "etc" );
+        etcDir.mkdir();
+
+        // create app.clusters which contains a list of clusters to include in the application
+
+        File clusterConf = new File( etcDir + File.separator + brandingToken + ".clusters" );
+        String clustersString;
+        if ( etcClustersFile != null )
+        {
+            clustersString = FileUtils.fileRead( etcClustersFile, "UTF-8" );
+        }
+        else
+        {
+            clusterConf.createNewFile();
+            StringBuilder buffer = new StringBuilder();
+            File[] clusters = buildDir.listFiles( new FileFilter()
+            {
+
+                @Override
+                public boolean accept( File pathname )
+                {
+                    return new File( pathname, ".lastModified" ).exists();
+                }
+            } );
+            for ( File cluster : clusters )
+            {
+                buffer.append( cluster.getName() );
+                buffer.append( "\n" );
+            }
+            clustersString = buffer.toString();
+        }
+
+        FileUtils.fileWrite( clusterConf.getAbsolutePath(), clustersString );
+
+        File confFile = etcConfFile;
+        String str;
+        if ( confFile == null )
+        {
+            File harnessDir = new File( buildDir, "harness" );
+            // app.conf contains default options and other settings
+            confFile = new File(
+                    harnessDir.getAbsolutePath() + File.separator + "etc" + File.separator + "app.conf" );
+            if ( confFile.exists() )
+            {
+                str = FileUtils.fileRead( confFile, "UTF-8" );
+            }
+            else 
+            {
+                getLog().debug( "Using fallback app.conf shipping with the nbm-maven-plugin." );
+                InputStream instream = null;
+                try
+                {
+                    instream = getClass().getClassLoader().getResourceAsStream( "harness/etc/app.conf" );
+                    str = IOUtil.toString( instream, "UTF-8" );
+                }
+                finally
+                {
+                    IOUtil.close( instream );
+                }
+            }
+        }
+        else
+        {
+            str = FileUtils.fileRead( confFile, "UTF-8" );
+        }
+        File confDestFile = new File(
+            etcDir.getAbsolutePath() + File.separator + brandingToken + ".conf" );
+
+        str = str.replace( "${branding.token}", brandingToken );
+        FileUtils.fileWrite( confDestFile.getAbsolutePath(), "UTF-8", str );
+
+        File destBinDir = new File( buildDir + File.separator + "bin" );
+        destBinDir.mkdir();
+
+        File binDir;
+        File destExeW = new File( destBinDir, brandingToken + "_w.exe" );
+        File destExe = new File( destBinDir, brandingToken + ".exe" );
+        File destExe64 = new File( destBinDir, brandingToken + "64.exe" );
+        File destSh = new File( destBinDir, brandingToken );
+
+        if ( binDirectory != null )
+        {
+            //we have custom launchers.
+            binDir = binDirectory;
+            File[] fls = binDir.listFiles();
+            if ( fls == null )
+            {
+                throw new MojoExecutionException( "Parameter 'binDirectory' has to point to an existing folder." );
+            }
+            for ( File fl : fls )
+            {
+                String name = fl.getName();
+                File dest = null;
+                if ( name.endsWith( "_w.exe" ) ) 
+                {
+                    dest = destExeW;
+                }
+                else if ( name.endsWith( "64.exe" ) )
+                {
+                    dest = destExe64;
+                }
+                else if ( name.endsWith( ".exe" ) )
+                {
+                    dest = destExe;
+                }
+                else if ( !name.contains( "." ) || name.endsWith( ".sh" ) )
+                {
+                    dest = destSh;
+                }
+                if ( dest != null  && fl.exists() ) //in 6.7 the _w.exe file is no more.
+                {
+                    FileUtils.copyFile( fl, dest );
+                }
+                else
+                {
+                    //warn about file not being copied
+                }
+            }
+        }
+        else
+        {
+            File harnessDir = new File( buildDir, "harness" );
+            //we have org-netbeans-modules-apisupport-harness in target area, just use it's own launchers.
+            binDir = new File(
+                    harnessDir.getAbsolutePath() + File.separator + "launchers" );
+            if ( binDir.exists() )
+            {
+                File exe = new File( binDir, "app.exe" );
+                FileUtils.copyFile( exe, destExe );
+                File exe64 = new File( binDir, "app64.exe" );
+                if ( exe64.isFile() )
+                {
+                    FileUtils.copyFile( exe64, destExe64 );
+                }
+                File exew = new File( binDir, "app_w.exe" );
+                if ( exew.exists() ) //in 6.7 the _w.exe file is no more.
+                {
+                    FileUtils.copyFile( exew, destExeW );
+                }
+                File sh = new File( binDir, "app.sh" );
+                FileUtils.copyFile( sh, destSh );
+            }
+            else
+            {
+                File nbm = getHarnessNbm();
+                try (ZipFile zip = new ZipFile( nbm )) {
+                    getLog().debug( "Using fallback executables from downloaded org-netbeans-modules-apisupport-harness nbm file." );
+                    writeFromZip(zip, "netbeans/launchers/app.sh",  destSh, true );
+                    writeFromZip(zip, "netbeans/launchers/app.exe",  destExe, true );
+                    writeFromZip(zip, "netbeans/launchers/app64.exe",  destExe64, false );
+                    writeFromZip(zip, "netbeans/launchers/app_w.exe",  destExeW, false );
+                }
+            }
+        }
+
+        Project antProject = antProject();
+
+        Chmod chmod = (Chmod) antProject.createTask( "chmod" );
+        FileSet fs = new FileSet();
+        fs.setDir( destBinDir );
+        fs.setIncludes( "*" );
+        chmod.addFileset( fs );
+        chmod.setPerm( "755" );
+        chmod.execute();
+    }
+
+    private void writeFile( String path, File destSh )
+        throws IOException
+    {
+        InputStream instream = null;
+        OutputStream output = null;
+        try
+        {
+            instream = getClass().getClassLoader().getResourceAsStream( path );
+            if ( instream == null )
+            {
+                throw new FileNotFoundException( path );
+            }
+            destSh.createNewFile();
+            output = new BufferedOutputStream( new FileOutputStream( destSh ) );
+            IOUtil.copy( instream, output );
+        }
+        finally
+        {
+            IOUtil.close( instream );
+            IOUtil.close( output );
+        }
+    }
+
+    private ClusterTuple processCluster( String cluster, File nbmBuildDirFile, Artifact art )
+    {
+        File clusterFile = new File( nbmBuildDirFile, cluster );
+        boolean newer = false;
+        if ( !clusterFile.exists() )
+        {
+            clusterFile.mkdir();
+            newer = true;
+        }
+        else
+        {
+            File stamp = new File( clusterFile, ".lastModified" );
+            if ( stamp.lastModified() < art.getFile().lastModified() )
+            {
+                newer = true;
+            }
+        }
+        return new ClusterTuple( clusterFile, newer );
+    }
+
+    private void externalDownload( File f, InputStream is )
+        throws IOException
+    {
+        // Cf. org.netbeans.nbbuild.AutoUpdate
+        BufferedReader r = new BufferedReader( new InputStreamReader( is, "UTF-8" ) );
+        long crc = -1;
+        long size = -1;
+        boolean found = false;
+        String line;
+        while ( ( line = r.readLine() ) != null )
+        {
+            if ( line.startsWith( "CRC:" ) )
+            {
+                crc = Long.parseLong( line.substring( 4 ).trim() );
+            }
+            else if ( line.startsWith( "URL:m2:/" ) )
+            {
+                if ( ! found )
+                {
+                    String[] coords = line.substring( 8 ).trim().split( ":" );
+                    Artifact artifact;
+                    if ( coords.length == 4 )
+                    {
+                        artifact = artifactFactory.createArtifact( coords[0], coords[1], coords[2], null, coords[3] );
+                    }
+                    else
+                    {
+                        artifact = artifactFactory.createArtifactWithClassifier( coords[0], coords[1], coords[2], coords[3], coords[4] );
+                    }
+                    try
+                    {
+                        artifactResolver.resolve( artifact, project.getRemoteArtifactRepositories(), localRepository );
+                        FileUtils.copyFile( artifact.getFile(), f );
+                        found = true;
+                    }
+                    catch ( AbstractArtifactResolutionException x )
+                    {
+                        getLog().warn( "Cannot find " + line.substring( 8 ), x );
+                    }
+                }
+            }
+            else if ( line.startsWith( "URL:" ) )
+            {
+                if ( ! found )
+                {
+                    String url = line.substring( 4 ).trim();
+                    try
+                    {
+                        // XXX use Wagon API instead
+                        FileUtils.copyURLToFile( new URL( url ), f );
+                        found = true;
+                    }
+                    catch ( IOException x )
+                    {
+                        getLog().warn( "Cannot download " + url, x );
+                    }
+                }
+            }
+            else if ( line.startsWith( "SIZE:" ) )
+            {
+                size = Long.parseLong( line.substring( 5 ).trim() );
+            }
+            else
+            {
+                getLog().warn( "Unrecognized line: " + line );
+            }
+        }
+        if ( ! found )
+        {
+            throw new IOException( "Could not download " + f );
+        }
+        if ( crc != -1 && crc != crcForFile( f ).getValue() )
+        {
+            throw new IOException( "CRC-32 of " + f + " does not match declared " + crc );
+        }
+        if ( size != -1 && size != f.length() )
+        {
+            throw new IOException( "Size of " + f + " does not match declared " + size );
+        }
+    }
+
+    private File getHarnessNbm() throws MojoExecutionException
+    {
+        @SuppressWarnings( "unchecked" )
+        Set<Artifact> artifacts = project.getArtifacts();
+        String version = null;
+        for (Artifact a : artifacts) {
+            if ("org.netbeans.modules".equals(a.getGroupId()) && "org-netbeans-bootstrap".equals(a.getArtifactId())) {
+                version = a.getBaseVersion(); //base version in non-snapshot should equals version, in snapshots to X-SNAPSHOT, not timestamp
+                break;
+            }
+        }
+        if (version == null) {
+            throw new MojoExecutionException( "We could not find org-netbeans-bootstrap among the modules in the application. Launchers could not be found.");
+        }
+        Artifact nbmArt = artifactFactory.createArtifact(
+            "org.netbeans.modules",
+            "org-netbeans-modules-apisupport-harness",
+            version,
+            "compile",
+            "nbm-file");
+        try
+        {
+            artifactResolver.resolve( nbmArt, project.getRemoteArtifactRepositories(), localRepository );
+        }
+
+        catch ( ArtifactResolutionException | ArtifactNotFoundException ex )
+        {
+            throw new MojoExecutionException( "Failed to retrieve the nbm file from repository", ex );
+        }
+        return nbmArt.getFile();
+    }
+
+    private void writeFromZip( final ZipFile zip, String zipPath, File destFile, boolean mandatory ) throws MojoExecutionException, IOException
+    {
+        final ZipEntry path = zip.getEntry( zipPath );
+        if (path == null) {
+            if (mandatory) {
+                throw new MojoExecutionException( zipPath + " not found in " + zip.getName());
+            }
+            getLog().debug(zipPath + " is not present in " + zip.getName());
+            return;
+        }
+        FileUtils.copyStreamToFile( new InputStreamFacade() {
+            
+            @Override
+            public InputStream getInputStream() throws IOException
+            {
+                return zip.getInputStream( path );
+            }
+        }, destFile);
+    }
+
+    private static void addToMap( Map<String, Set<String>> map, String clusterName, List<String> newValues )
+    {
+        Set<String> lst = map.get( clusterName );
+        if ( lst == null )
+        {
+            lst = new HashSet<>();
+            map.put( clusterName, lst );
+        }
+        if ( newValues != null )
+        {
+            lst.addAll( newValues );
+        }
+    }
+    
+    private static List<String> findByDependencies( Map<String, Set<String>> clusterDependencies, String spec)
+    {
+        List<String> toRet = new ArrayList<>();
+        for ( Map.Entry<String, Set<String>> entry : clusterDependencies.entrySet() )
+        {
+            if ( entry.getValue().contains( spec ) )
+            {
+                toRet.add(entry.getKey());
+            }
+        }
+        return toRet;
+    }
+
+    //the basic idea is that bundle's cluster can be determined by who depends on it.
+    //simplest case is when a module depends on it. If there are more, we need to pick one that is "lower in the stack, that's what cluster2depClusters is for.
+    //the rest needs to be determined in more sofisticated manner.
+    //start from bundles with known cluster and see what other bundles they depend on. stamp all these with the same cluster. do it recursively.
+    //At the end process the remaining bundles in reverse order. Check if *they* depend on a bundle with known cluster and so on..
+    //A few unsolved cases:
+    // - we never update the cluster information once a match was found, but there is a possibility that later in the processing the cluster could be "lowered".
+    // - 2 or more modules from unrelated clusters we cannot easily decide, most likely should be in common denominator cluster but our cluster2depClusters map is not transitive, only lists direct dependencies
+    static void assignClustersToBundles( List<BundleTuple> bundles, Set<String> wrappedBundleCNBs, Map<String, Set<String>> clusterDependencies, Map<String, Set<String>> cluster2depClusters, Log log)
+    {
+        List<BundleTuple> toProcess = new ArrayList<>();
+        List<BundleTuple> known = new ArrayList<>();
+        for ( Iterator<BundleTuple> it = bundles.iterator(); it.hasNext(); )
+        {
+            BundleTuple ent = it.next();
+            Artifact art = ent.artifact;
+            ExamineManifest ex = ent.manifest;
+            String spec = ex.getModule();
+            //null check for tests
+            //have a way to force inclusion of osgi items. Direct dependency is never wrapped by modules.
+            if ( art != null && art.getDependencyTrail().size() > 2 && wrappedBundleCNBs.contains( spec ) )
+            {
+                // we already have this one as a wrapped module.
+                log.debug( "Not including bundle " + art.getDependencyConflictId()
+                                    + ". It is already included in a NetBeans module" );
+                it.remove();
+                continue;
+            }
+            List<String> depclusters = findByDependencies(clusterDependencies, spec);
+            if (depclusters.size() == 1) {
+                ent.cluster = depclusters.get( 0 );
+                known.add( ent );
+            } else if (depclusters.isEmpty()) {
+                toProcess.add(ent);
+            } else {
+                //more results.. from 2 dependent clusters pick the one that is lower in the stack.
+                for ( Iterator<String> it2 = depclusters.iterator(); it2.hasNext(); )
+                {
+                    String s = it2.next();
+                    Set<String> depsCs = cluster2depClusters.get( s );
+                    boolean removeS = false;
+                    for (String sDep : depclusters) {
+                        if (s.equals( sDep) ) {
+                            continue;
+                        }
+                        if (depsCs != null && depsCs.contains( sDep ) ) {
+                            removeS = true;
+                        }
+                    }
+                    if (removeS) {
+                        it2.remove();
+                    }
+                }
+                ent.cluster = depclusters.get( 0 ); //TODO still some free room there, what if they don't directly depend on each other but still are related
+                known.add (ent);
+            }
+        }
+        if (!toProcess.isEmpty())
+        {
+            walkKnownBundleDependenciesDown(known, toProcess);
+        }
+        if (!toProcess.isEmpty())
+        {
+            walkKnownBundleDependenciesUp(known, toProcess);
+        }
+    }
+
+    private static void walkKnownBundleDependenciesDown( List<BundleTuple> known, List<BundleTuple> toProcess )
+    {
+        boolean atLeastOneWasFound = false;
+        for ( Iterator<BundleTuple> it = toProcess.iterator(); it.hasNext(); )
+        {
+            BundleTuple bundleTuple = it.next();
+            boolean found = false;
+            for ( BundleTuple knownBT : known)
+            {
+                Sets.SetView<String> is = Sets.intersection(bundleTuple.manifest.getOsgiExports() , knownBT.manifest.getOsgiImports() );
+                if (!is.isEmpty()) {
+                    found = true;
+                    bundleTuple.cluster = knownBT.cluster;
+                    break;
+                }
+                //dependencyTokens are requireBundle - matches the module property
+                is = Sets.intersection(Collections.singleton( bundleTuple.manifest.getModule()), new HashSet(knownBT.manifest.getDependencyTokens()) );
+                if (!is.isEmpty()) {
+                    found = true;
+                    bundleTuple.cluster = knownBT.cluster;
+                    break;
+                }
+                
+            }
+            if (found) {
+                atLeastOneWasFound = true;
+                it.remove();
+                known.add(bundleTuple);
+            }
+            
+        }
+        if (!toProcess.isEmpty() && atLeastOneWasFound) {
+            walkKnownBundleDependenciesDown( known, toProcess );
+        }
+    }
+
+    private static void walkKnownBundleDependenciesUp( List<BundleTuple> known, List<BundleTuple> toProcess )
+    {
+        boolean atLeastOneWasFound = false;
+        for ( Iterator<BundleTuple> it = toProcess.iterator(); it.hasNext(); )
+        {
+            BundleTuple bundleTuple = it.next();
+            boolean found = false;
+            for ( BundleTuple knownBT : known)
+            {
+                Sets.SetView<String> is = Sets.intersection(bundleTuple.manifest.getOsgiImports() , knownBT.manifest.getOsgiExports() );
+                if (!is.isEmpty()) {
+                    found = true;
+                    bundleTuple.cluster = knownBT.cluster;
+                    break;
+                }
+                //dependencyTokens are requireBundle - matches the module property
+                is = Sets.intersection(Collections.singleton( knownBT.manifest.getModule()), new HashSet(bundleTuple.manifest.getDependencyTokens()) );
+                if (!is.isEmpty()) {
+                    found = true;
+                    bundleTuple.cluster = knownBT.cluster;
+                    break;
+                }
+                
+            }
+            if (found) {
+                atLeastOneWasFound = true;
+                it.remove();
+                known.add(bundleTuple);
+            }
+            
+        }
+        if (!toProcess.isEmpty() && atLeastOneWasFound) {
+            walkKnownBundleDependenciesDown( known, toProcess );
+        }
+        if (!toProcess.isEmpty() && atLeastOneWasFound) {
+            walkKnownBundleDependenciesUp( known, toProcess );
+        }
+    }
+
+    //static and default for tests..
+    static Map<String, Set<String>> computeClusterOrdering( Map<String, Set<String>> clusterDependencies, Map<String, Set<String>> clusterModules )
+    {
+        Map<String, Set<String>> cluster2depClusters = new HashMap<>();
+        for ( Map.Entry<String, Set<String>> entry : clusterDependencies.entrySet() )
+        {
+            String cluster = entry.getKey();
+            Set<String> deps = entry.getValue();
+            for (Map.Entry<String, Set<String>> subEnt : clusterModules.entrySet()) {
+                if (subEnt.getKey().equals( cluster) ) {
+                    continue;
+                }
+                Sets.SetView<String> is = Sets.intersection(subEnt.getValue(), deps );
+                if (!is.isEmpty()) {
+                    addToMap( cluster2depClusters, cluster, Collections.singletonList( subEnt.getKey() ) );
+                }
+            }
+        }
+        return cluster2depClusters;
+    }
+    
+    static class BundleTuple {
+        final Artifact artifact;
+        final ExamineManifest manifest;
+        String cluster;
+
+        BundleTuple( Artifact artifact, ExamineManifest manifest )
+        {
+            this.artifact = artifact;
+            this.manifest = manifest;
+        }
+        
+    }
+
+    private static class ClusterTuple
+    {
+        final File location;
+        final boolean newer;
+
+        private ClusterTuple( File clusterFile, boolean newer )
+        {
+            location = clusterFile;
+            this.newer = newer;
+        }
+    }
+
+    static String createBundleConfigFile( String cnb, boolean autoload)
+    {
+        return
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+"<!DOCTYPE module PUBLIC \"-//NetBeans//DTD Module Status 1.0//EN\"\n" +
+"                        \"http://www.netbeans.org/dtds/module-status-1_0.dtd\">\n" +
+"<module name=\"" + cnb +"\">\n" +
+"    <param name=\"autoload\">" + autoload + "</param>\n" +
+"    <param name=\"eager\">false</param>\n" + (autoload ? "" : "    <param name=\"enabled\">true</param>\n") +
+"    <param name=\"jar\">modules/" + cnb.replace( ".", "-") + ".jar</param>\n" +
+"    <param name=\"reloadable\">false</param>\n" +
+"</module>\n";
+    }
+
+    static String createBundleUpdateTracking( String cnb, File moduleArt, File moduleConf, String specVersion )
+        throws FileNotFoundException, IOException
+    {
+
+        return
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+"<module codename=\"" + cnb + "\">\n" +
+"    <module_version install_time=\"" + System.currentTimeMillis() + "\" last=\"true\" origin=\"installer\" specification_version=\"" + specVersion + "\">\n" +
+"        <file crc=\"" + crcForFile( moduleConf ).getValue() + "\" name=\"config/Modules/" + cnb.replace( ".", "-" ) + ".xml\"/>\n" +
+"        <file crc=\"" + crcForFile( moduleArt ).getValue() + "\" name=\"modules/" + cnb.replace( ".", "-" ) + ".jar\"/>\n" +
+"    </module_version>\n" +
+"</module>";
+
+    }
+
+    static CRC32 crcForFile( File inFile )
+        throws FileNotFoundException, IOException
+    {
+        CRC32 crc = new CRC32();
+        try (InputStream inFileStream = new FileInputStream( inFile )) {
+            byte[] array = new byte[(int) inFile.length()];
+            int len = inFileStream.read( array );
+            if ( len != array.length )
+            {
+                throw new IOException( "Cannot fully read " + inFile );
+            }
+            crc.update( array );
+        }
+        return crc;
+    }
+
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateClusterMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateClusterMojo.java
new file mode 100644
index 0000000..89e5e40
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateClusterMojo.java
@@ -0,0 +1,200 @@
+/* ==========================================================================
+ * Copyright 2003-2004 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.List;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.filters.StringInputStream;
+import org.apache.tools.ant.taskdefs.Copy;
+import org.apache.tools.ant.types.FileSet;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.io.InputStreamFacade;
+
+/**
+ * Create the NetBeans module clusters from reactor.
+ * Semi-deprecated; used only for standalone modules and "suites".
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ */
+@Mojo(name="cluster",aggregator=true, requiresDependencyResolution= ResolutionScope.RUNTIME )
+public class CreateClusterMojo
+        extends AbstractNbmMojo
+{
+
+    /**
+     * directory where the the NetBeans cluster will be created.
+     */
+    @Parameter(defaultValue="${project.build.directory}/netbeans_clusters", required=true)
+    protected File nbmBuildDir;
+
+    /**
+     * default cluster value for reactor projects without cluster information,
+     * typically OSGi bundles
+     * @since 3.2
+     */
+    @Parameter(defaultValue="extra")
+    private String defaultCluster;
+    /**
+     * If the executed project is a reactor project, this will contains the full list of projects in the reactor.
+     */
+    @Parameter(required=true, readonly=true, property="reactorProjects")
+    private List<MavenProject> reactorProjects;
+
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        Project antProject = registerNbmAntTasks();
+
+        if ( !nbmBuildDir.exists() )
+        {
+            nbmBuildDir.mkdirs();
+        }
+
+        if ( reactorProjects != null && reactorProjects.size() > 0 )
+        {
+            for ( MavenProject proj : reactorProjects )
+            {
+                //TODO how to figure where the the buildDir/nbm directory is
+                File nbmDir = new File( proj.getBasedir(),
+                        "target" + File.separator + "nbm" + File.separator + "netbeans" );
+                if ( nbmDir.exists() )
+                {
+                    Copy copyTask = (Copy) antProject.createTask( "copy" );
+                    copyTask.setTodir( nbmBuildDir );
+                    copyTask.setOverwrite( true );
+                    FileSet set = new FileSet();
+                    set.setDir( nbmDir );
+                    set.createInclude().setName( "**" );
+                    copyTask.addFileset( set );
+
+                    try
+                    {
+                        copyTask.execute();
+                    }
+                    catch ( BuildException ex )
+                    {
+                        getLog().error( "Cannot merge modules into cluster" );
+                        throw new MojoExecutionException(
+                                "Cannot merge modules into cluster", ex );
+                    }
+                }
+                else
+                {
+                    if ( "nbm".equals( proj.getPackaging() ) )
+                    {
+                        String error =
+                            "The NetBeans binary directory structure for "
+                                + proj.getId()
+                                + " is not created yet."
+                                + "\n Please execute 'mvn install nbm:cluster' to build all relevant projects in the reactor.";
+                        throw new MojoFailureException( error );
+                    }
+                    if ( "bundle".equals( proj.getPackaging() ) )
+                    {
+                        Artifact art = proj.getArtifact();
+                        final ExamineManifest mnf = new ExamineManifest( getLog() );
+
+                        File jar = new File( proj.getBuild().getDirectory(), proj.getBuild().getFinalName() + ".jar" );
+                        if ( !jar.exists() )
+                        {
+                            getLog().error( "Skipping " + proj.getId()
+                                                + ". Cannot find the main artifact in output directory." );
+                            continue;
+                        }
+                        mnf.setJarFile( jar );
+                        mnf.checkFile();
+
+                        File cluster = new File( nbmBuildDir, defaultCluster );
+                        getLog().debug( "Copying " + art.getId() + " to cluster " + defaultCluster );
+                        File modules = new File( cluster, "modules" );
+                        modules.mkdirs();
+                        File config = new File( cluster, "config" );
+                        File confModules = new File( config, "Modules" );
+                        confModules.mkdirs();
+                        File updateTracting = new File( cluster, "update_tracking" );
+                        updateTracting.mkdirs();
+
+                        final String cnb = mnf.getModule();
+                        final String cnbDashed = cnb.replace( ".", "-" );
+                        final File moduleArt = new File( modules, cnbDashed + ".jar" ); //do we need the file in some canotical name pattern?
+                        final String specVer = mnf.getSpecVersion();
+                        try
+                        {
+                            FileUtils.copyFile( jar, moduleArt );
+                            final File moduleConf = new File( confModules, cnbDashed + ".xml" );
+                            FileUtils.copyStreamToFile( new InputStreamFacade() {
+                                public InputStream getInputStream() throws IOException
+                                {
+                                    return new StringInputStream( CreateClusterAppMojo.createBundleConfigFile( cnb, mnf.isBundleAutoload() ), "UTF-8" );
+                                }
+                            }, moduleConf );
+                            FileUtils.copyStreamToFile( new InputStreamFacade() {
+                                public InputStream getInputStream() throws IOException
+                                {
+                                    return new StringInputStream( CreateClusterAppMojo.createBundleUpdateTracking( cnb, moduleArt, moduleConf, specVer ), "UTF-8" );
+                                }
+                            }, new File( updateTracting, cnbDashed + ".xml" ) );
+                        }
+                        catch ( IOException exc )
+                        {
+                            getLog().error( exc );
+                        }
+
+                    }
+                }
+            }
+            //in 6.1 the rebuilt modules will be cached if the timestamp is not touched.
+            File[] files = nbmBuildDir.listFiles();
+            for ( int i = 0; i < files.length; i++ )
+            {
+                if ( files[i].isDirectory() )
+                {
+                    File stamp = new File( files[i], ".lastModified" );
+                    if ( !stamp.exists() )
+                    {
+                        try
+                        {
+                            stamp.createNewFile();
+                        }
+                        catch ( IOException ex )
+                        {
+                            ex.printStackTrace();
+                        }
+                    }
+                    stamp.setLastModified( new Date().getTime() );
+                }
+            }
+            getLog().info( "Created NetBeans module cluster(s) at " + nbmBuildDir );
+        }
+        else
+        {
+            throw new MojoExecutionException( "This goal only makes sense on reactor projects." );
+        }
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateNbmMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateNbmMojo.java
new file mode 100644
index 0000000..9281be3
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateNbmMojo.java
@@ -0,0 +1,406 @@
+/* ==========================================================================
+ * Copyright 2003-2004 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.Developer;
+import org.apache.maven.model.License;
+import org.apache.maven.model.Organization;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import org.codehaus.plexus.PlexusConstants;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.context.Context;
+import org.codehaus.plexus.context.ContextException;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
+import org.netbeans.nbbuild.MakeNBM;
+import org.netbeans.nbbuild.MakeNBM.Blurb;
+import org.netbeans.nbbuild.MakeNBM.Signature;
+
+/**
+ * Create the NetBeans module artifact (nbm file), part of "nbm" lifecycle/packaging.
+ * 
+ *
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ */
+@Mojo(name="nbm", 
+        requiresProject=true, 
+        threadSafe = true,
+        requiresDependencyResolution= ResolutionScope.RUNTIME, 
+        defaultPhase= LifecyclePhase.PACKAGE )
+public class CreateNbmMojo
+        extends CreateNetBeansFileStructure
+        implements Contextualizable
+{
+
+    /**
+     * keystore location for signing the nbm file
+     */
+    @Parameter(property="keystore")
+    private String keystore;
+    /**
+     * keystore password
+     */
+    @Parameter(property="keystorepass")
+    private String keystorepassword;
+    /**
+     * keystore alias
+     */
+    @Parameter(property="keystorealias")
+    private String keystorealias;
+
+    /**
+     * Boolean parameter denoting if creation of NBM file shall be skipped or not.
+     * If skipped, just the expanded directory for cluster is created
+     * @since 3.0
+     */
+    @Parameter(defaultValue="false", property="maven.nbm.skip")
+    private boolean skipNbm;
+    
+    /**
+     * if true, upon installing the NBM the platform app/IDE restart is requested. Not necessary in most cases.
+     * @since 3.8
+     */
+    @Parameter(defaultValue="false")
+    private boolean requiresRestart;
+    
+    /**
+     * Get homepage URL of the module. Is accessible from NetBeans
+     * UI upon installation, should point to place with additional
+     * information about the functionality. 
+     * @since 3.8
+     */
+    @Parameter(defaultValue="${project.url}")
+    private String homePageUrl;
+    
+    /**
+     * Author of the module. Shown in the Module manager UI.
+     * @since 3.8
+     */
+    @Parameter(defaultValue="${project.organization.name}")
+    private String author;
+    
+    /**
+     * Distribution base URL for the NBM at runtime deployment time.
+     * Note: Usefulness of the parameter is questionable, it doesn't allow for mirrors and
+     * usually when downloading the nbm, one already knows the location anyway.
+     * Please note that the netbeans.org Ant scripts put a dummy url here.
+     * The actual correct value used when constructing update site is
+     * explicitly set there. The general assumption there is that all modules from one update
+     * center come from one base URL. Also see <code>distBase</code> parameter in auto-update mojo.
+     * <p/>
+     * The value is either a direct http protocol based URL that points to
+     * the location under which nbm file will be located, or
+     * <p/>
+     * it allows to create an update site based on maven repository content.
+     * The later created autoupdate site document can use this information and
+     * compose the application from one or multiple maven repositories.
+     * <br/>
+     * Format: id::layout::url same as in maven-deploy-plugin
+     * <br/>
+     * with the 'default' and 'legacy' layouts. (maven2 vs maven1 layout)
+     * <br/>
+     * If the value doesn't contain :: characters,
+     * it's assumed to be the flat structure and the value is just the URL.
+     * 
+     */
+    @Parameter(property="maven.nbm.distributionURL")
+    private String distributionUrl;
+    
+    /**
+     * name of the license applicable to the NBM. The value should be equal across modules with the same license. If the user already agreed to the
+     * same license before, he/she won't be asked again to agree and for multiple one installed at the same time, just one license agreement is shown.
+     * When defined, <code>licenseFile</code> needs to be defined as well.
+     * @since 3.8
+     */
+    @Parameter
+    private String licenseName;
+    
+    /**
+     * path to the license agreement file that will be shown when installing the module. When defined, <code>licenseName</code> needs to be defined as well.
+     * @since 3.8
+     */
+    @Parameter
+    private File licenseFile;
+    
+
+    // <editor-fold defaultstate="collapsed" desc="Component parameters">
+
+    /**
+     * Contextualized.
+     */
+    private PlexusContainer container;
+
+    @Component
+    private ArtifactFactory artifactFactory;
+    /**
+     * Used for attaching the artifact in the project
+     */
+    @Component
+    private MavenProjectHelper projectHelper;
+
+    // end of component params custom code folding
+    // </editor-fold>
+    
+    private final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat ("yyyy/MM/dd");
+
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        if ( skipNbm )
+        {
+            getLog().info( "Skipping generation of NBM file." );
+            return;
+        }
+
+        if ( "pom".equals( project.getPackaging() ) )
+        {
+            getLog().info(
+                    "Skipping " + project.getId() + ", no nbm:nbm execution for 'pom' packaging" );
+            return;
+        }
+        super.execute();
+
+
+        // 3. generate nbm
+        File nbmFile = new File( nbmBuildDir, finalName + ".nbm" );
+        MakeNBM nbmTask = (MakeNBM) antProject.createTask( "makenbm" );
+        nbmTask.setFile( nbmFile );
+        nbmTask.setProductDir( clusterDir );
+
+        nbmTask.setModule( "modules" + File.separator + moduleJarName + ".jar" );
+        boolean reqRestart = requiresRestart;
+        if (!reqRestart && module.isRequiresRestart()) {
+            reqRestart = module.isRequiresRestart();
+            getLog().warn( "Module descriptor's requiresRestart field is deprecated, use plugin's configuration in pom.xml");
+        }
+        nbmTask.setNeedsrestart( Boolean.toString( reqRestart ) );
+        String moduleAuthor = author;
+        if (module.getAuthor() != null) {
+            moduleAuthor = module.getAuthor();
+            getLog().warn( "Module descriptor's requiresRestart field is deprecated, use plugin's configuration in pom.xml");
+        }
+        nbmTask.setModuleauthor( moduleAuthor );
+        if ( keystore != null && keystorealias != null && keystorepassword != null )
+        {
+            File ks = new File( keystore );
+            if ( !ks.exists() )
+            {
+                getLog().warn( "Cannot find keystore file at " + ks.getAbsolutePath() );
+            }
+            else
+            {
+                Signature sig = nbmTask.createSignature();
+                sig.setKeystore( ks );
+                sig.setAlias( keystorealias );
+                sig.setStorepass( keystorepassword );
+                getLog().debug( "Setup the Ant task to sign the NBM file." );
+            }
+        }
+        else if ( keystore != null || keystorepassword != null || keystorealias != null )
+        {
+            getLog().warn(
+                    "If you want to sign the nbm file, you need to define all three keystore related parameters." );
+        }
+        String licName = licenseName;
+        File licFile = licenseFile;
+        if (module.getLicenseName() != null) {
+            licName = module.getLicenseName();
+            getLog().warn( "Module descriptor's licenseName field is deprecated, use plugin's configuration in pom.xml");
+        }
+        if (module.getLicenseFile() != null) {
+            File lf = new File( project.getBasedir(), module.getLicenseFile() );
+            licFile = lf;
+            getLog().warn( "Module descriptor's licenseFile field is deprecated, use plugin's configuration in pom.xml");
+            
+        }
+        if ( licName != null && licFile != null )
+        {
+            if ( !licFile.exists() || !licFile.isFile() )
+            {
+                getLog().warn( "Cannot find license file at " + licFile.getAbsolutePath() );
+            }
+            else
+            {
+                Blurb lb = nbmTask.createLicense();
+                lb.setFile( licFile );
+                lb.addText( licName );
+            }
+        }
+        else if ( licName != null || licFile != null )
+        {
+            getLog().warn(
+                    "To set license for the nbm, you need to specify both licenseName and licenseFile parameters." );
+        }
+        else
+        {
+            Blurb lb = nbmTask.createLicense();
+            lb.addText( createDefaultLicenseHeader() );
+            lb.addText( createDefaultLicenseText() );
+        }
+        String hpUrl = homePageUrl;
+        if (module.getHomepageUrl() != null) {
+            getLog().warn( "Module descriptor's homePageUrl field is deprecated, use plugin's configuration in pom.xml");
+            hpUrl = module.getHomepageUrl();
+        }
+        if ( hpUrl != null )
+        {
+            nbmTask.setHomepage( hpUrl );
+        }
+        String distribUrl = distributionUrl;
+        if (module.getDistributionUrl() != null) {
+            distribUrl = module.getDistributionUrl();
+            getLog().warn( "Module descriptor's distributionUrl field is deprecated, use plugin's configuration in pom.xml");
+        }
+        if ( distribUrl != null )
+        {
+            ArtifactRepository distRepository = CreateUpdateSiteMojo.getDeploymentRepository(
+                    distribUrl, container, getLog() );
+            String dist = null;
+            if ( distRepository == null )
+            {
+                if ( !distribUrl.contains( "::" ) )
+                {
+                    dist =
+                        distribUrl + ( distribUrl.endsWith( "/" ) ? "" : "/" )
+                            + nbmFile.getName();
+                }
+            }
+            else
+            {
+                Artifact art = artifactFactory.createArtifact(
+                        project.getGroupId(), project.getArtifactId(),
+                        project.getVersion(), null, "nbm-file" );
+
+                dist =
+                    distRepository.getUrl() + ( distRepository.getUrl().endsWith( "/" ) ? "" : "/" )
+                        + distRepository.pathOf( art );
+
+            }
+            nbmTask.setDistribution( dist );
+        }
+        else
+        {
+            nbmTask.setDistribution( nbmFile.getName() );
+        }
+        if ( ! "extra".equals( cluster ) )
+        {
+            nbmTask.setTargetcluster( cluster );
+        }
+        //MNBMODULE-217 avoid using the static DATE_FORMAT variable in MavenNBM.java (in ant harness)
+        nbmTask.setReleasedate( DATE_FORMAT.format(new Date(System.currentTimeMillis())) );
+        try
+        {
+            nbmTask.execute();
+        }
+        catch ( BuildException e )
+        {
+            throw new MojoExecutionException( "Cannot Generate nbm file:" + e.getMessage(), e );
+        }
+        try
+        {
+            File nbmfile = new File( buildDir, nbmFile.getName() );
+            FileUtils.getFileUtils().copyFile( nbmFile, nbmfile );
+            projectHelper.attachArtifact( project, "nbm-file", null, nbmfile );
+        }
+        catch ( IOException ex )
+        {
+            throw new MojoExecutionException( "Cannot copy nbm to build directory", ex );
+        }
+    }
+
+    public void contextualize( Context context )
+            throws ContextException
+    {
+        this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
+    }
+
+    private String createDefaultLicenseHeader()
+    {
+        String organization = "";
+        Organization org = project.getOrganization();
+        if (org != null) {
+            organization = org.getName();
+}
+        if (organization == null) {
+            List devs = project.getDevelopers();
+            if (devs.size() > 0) {
+                Iterator dvs = devs.iterator();
+                String devsString = "";
+                while (dvs.hasNext()) {
+                    Developer d = ( Developer )dvs.next();
+                    devsString = devsString + "," + d.getName() != null ? d.getName() : d.getId();
+                }
+                organization = devsString.substring( 1 );    
+            }
+        }
+        if (organization == null) {
+            organization = ""; //what's a good default value?
+        }
+        String date = "";
+        if (project.getInceptionYear() != null) {
+            date = project.getInceptionYear();
+        }
+        String year = Integer.toString( Calendar.getInstance().get( Calendar.YEAR ));
+        if (!year.equals( date ) ) {
+            date = date.length() == 0 ? year : date + "-" + year;
+        }
+        return "Copyright " + organization + " " + date;
+    }
+    
+    private String createDefaultLicenseText() {
+        String toRet = "License terms:\n";
+        
+        List licenses = project.getLicenses();
+        if (licenses != null && licenses.size() > 0) {
+            Iterator lic = licenses.iterator();
+            while (lic.hasNext()) {
+                License ll = ( License )lic.next();
+                
+                if (ll.getName() != null) {
+                   toRet = toRet + ll.getName() + " - "; 
+                }
+                if (ll.getUrl() != null) {
+                    toRet = toRet + ll.getUrl();
+                }
+                if (lic.hasNext()) {
+                    toRet = toRet + ",\n";
+                }
+            }
+        } else {
+           toRet = toRet + "Unknown";
+        }
+        return toRet;
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateNetBeansFileStructure.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateNetBeansFileStructure.java
new file mode 100644
index 0000000..f6ae5a4
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateNetBeansFileStructure.java
@@ -0,0 +1,660 @@
+/* ==========================================================================
+ * Copyright 2003-2004 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.*;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+//import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.shared.filtering.MavenFilteringException;
+import org.codehaus.mojo.nbm.model.NbmResource;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.filtering.MavenResourcesExecution;
+import org.apache.maven.shared.filtering.MavenResourcesFiltering;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Copy;
+import org.apache.tools.ant.taskdefs.Jar;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.netbeans.nbbuild.CreateModuleXML;
+import org.netbeans.nbbuild.MakeListOfNBM;
+import org.codehaus.mojo.nbm.model.NetBeansModule;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.netbeans.nbbuild.JHIndexer;
+
+/**
+ * Create the NetBeans module directory structure, a prerequisite for nbm creation and cluster creation.
+ * 
+ *
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ *
+ */
+public abstract class CreateNetBeansFileStructure
+        extends AbstractNbmMojo
+{
+
+    /**
+     * NetBeans module assembly build directory.
+     * directory where the the NetBeans jar and nbm file get constructed.
+     */
+    @Parameter(defaultValue="${project.build.directory}/nbm", property="maven.nbm.buildDir")
+    protected File nbmBuildDir;
+    /**
+     * Build directory
+     */
+    @Parameter(required=true, readonly=true, property="project.build.directory")
+    protected File buildDir;
+    /**
+     * Name of the jar packaged by the jar:jar plugin
+     */
+    @Parameter(alias="jarname", property="project.build.finalName")
+    protected String finalName;
+    /**
+     * a NetBeans module descriptor containing dependency information and more..
+     * @deprecated all content from the module descriptor can be defined as plugin configuration now, will be removed in 4.0 entirely
+     */
+    @Parameter(defaultValue="${basedir}/src/main/nbm/module.xml")
+    protected File descriptor;
+    /**
+     * NetBeans module's cluster. Replaces the cluster element in module descriptor.
+     *
+     */
+    @Parameter(required=true, defaultValue="extra")
+    protected String cluster;
+    /**
+     * The location of JavaHelp sources for the project. The documentation
+     * itself is expected to be in the directory structure based on codenamebase of the module.
+     * eg. if your codenamebase is "org.netbeans.modules.apisupport", then the actual docs
+     * files shall go to ${basedir}/src/main/javahelp/org/netbeans/modules/apisupport/docs.
+     * @deprecated Obsolete as of NetBeans 7.0 with &#64;HelpSetRegistration.
+     * @since 2.7
+     */
+    @Deprecated
+    @Parameter(defaultValue="${basedir}/src/main/javahelp")
+    protected File nbmJavahelpSource;
+
+    @Parameter(required=true, readonly=true, property="project")
+    protected MavenProject project;
+
+    /**
+     * A list of additional resources to include in the NBM file.
+     * (Not in the module JAR; see <code>InstalledFileLocator</code> for retrieval.)
+     * Supersedes similarly-named configuration in the module descriptor file.
+     * <p>For example, to include native libraries:</p>
+     *
+     <pre>
+            &lt;nbmResource&gt;
+            &nbsp;&nbsp;&lt;directory&gt;src/main/libs&lt;/directory&gt;
+            &nbsp;&nbsp;&lt;targetPath&gt;modules/lib&lt;/targetPath&gt;
+            &nbsp;&nbsp;&lt;includes&gt;
+            &nbsp;&nbsp;&nbsp;&nbsp;&lt;include&gt;*.dll&lt;/include&gt;
+            &nbsp;&nbsp;&nbsp;&nbsp;&lt;include&gt;*.so&lt;/include&gt;
+            &nbsp;&nbsp;&lt;/includes&gt;
+            &lt;/nbmResource&gt;
+     </pre>
+     *
+     * @since 3.2
+     */
+    @Parameter
+    protected Resource[] nbmResources;
+
+    /**
+     * The character encoding scheme to be applied when filtering nbm resources.
+     *
+     * @since 3.2
+     */
+    @Parameter(property="encoding", defaultValue="${project.build.sourceEncoding}")
+    
+    protected String encoding;
+    
+    /**
+     * Deployment type of the module, allowed values are <code>normal</code>,<code>eager</code>,<code>autoload</code>,
+     * <code>disabled</code>.
+     * <p>
+     * <code>autoload</code> - Such a module is
+     * automatically enabled when some other module requires it and
+     * automatically disabled otherwise.</p>
+     *                     <p><code>eager</code> - This module type gets
+     * automatically enabled when all it's dependencies are
+     * satisfied. Disabled otherwise.</p>
+     *                     <p><code>normal</code> - This is the default
+     * value. This kind of module is enabled/disabled manually by
+     * the user. It installs enabled.</p>
+     *                     <p><code>disabled</code> - This kind of module is enabled/disabled manually by
+     * the user. It installs disabled. Since 3.11</p>
+     *
+     * For details, see <a href="http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html#enablement">Netbeans Module system docs</a>
+     *
+     * Since 3.14, for autoload and eager modules, we automatically set AutoUpdate-Show-In-Client manifest entry to false, if not defined already otherwise in the manifest.
+     * See issue <a href="http://jira.codehaus.org/browse/MNBMODULE-194">MNBMODULE-194</a>
+     *
+     * 
+     * @since 3.8
+     */ 
+    @Parameter(defaultValue="normal")
+    protected String moduleType;
+    
+    /**
+     * codename base of the module, uniquely identifying the module within the NetBeans runtime. usually the package name equivalent.
+     * Can include the major release version.
+     * See <a href="http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html#how-manifest"> NetBeans Module system docs</a>
+     * @since 3.8
+     */
+    @Parameter(defaultValue="${project.groupId}.${project.artifactId}")
+    private String codeNameBase;
+    
+    /**
+     * list of groupId:artifactId pairs describing libraries that go into the nbm file and will only include the .external reference in the nbm
+     * instead of the actual binary. See <a href="http://netbeans.org/bugzilla/show_bug.cgi?id=195041">NetBeans issue #195041</a> for details.
+     * Please note that the scheme will only work for artifacts present in central repository but no effort is made at build time to enforce that.
+     * Additionally at runtime when installing the module, the user has to be online and be capable of reaching central using maven. 
+     * You have been warned.
+     * @since 3.8
+     */ 
+    @Parameter
+    private List<String> externals;
+
+
+    @Component
+    protected MavenResourcesFiltering mavenResourcesFiltering;
+
+    @Parameter(property="session", readonly=true, required=true)
+    protected MavenSession session;
+
+
+    //items used by the CreateNBMMojo.
+    protected Project antProject;
+    protected NetBeansModule module;
+    protected File clusterDir;
+    protected String moduleJarName;
+
+    public void execute()
+            throws MojoExecutionException, MojoFailureException
+    {
+        antProject = registerNbmAntTasks();
+        if ( descriptor != null && descriptor.exists() )
+        {
+            module = readModuleDescriptor( descriptor );
+        } else
+        {
+            module = createDefaultDescriptor( project, false );
+        }
+        //same moduleType related code in NetBeansManifestUpdateMojo.java
+        String type = moduleType;
+        if ("normal".equals(type) && module.getModuleType() != null) {
+            type = module.getModuleType();
+            getLog().warn( "moduleType in module descriptor is deprecated, use the plugin's parameter moduleType");
+        }
+        if (!"normal".equals(type) && !"autoload".equals(type) && !"eager".equals(type) && !"disabled".equals(type)) {
+            getLog().error( "Only 'normal,autoload,eager,disabled' are allowed values in the moduleType parameter");
+        }
+        boolean autoload = "autoload".equals( type );
+        boolean eager = "eager".equals( type );
+        boolean disabled = "disabled".equals( type );
+        // 1. initialization
+        String moduleName = codeNameBase;
+        if (module.getCodeNameBase() != null) {
+            moduleName = module.getCodeNameBase();
+            getLog().warn( "codeNameBase in module descriptor is deprecated, use the plugin's parameter codeNameBase");
+        }
+        moduleName = NetBeansManifestUpdateMojo.stripVersionFromCodebaseName( moduleName.replaceAll( "-", "." ) );
+        moduleJarName = moduleName.replace( '.', '-' );
+        if ( "extra".equals( cluster ) && module.getCluster() != null )
+        {
+            getLog().warn(
+                    "Parameter cluster in module descriptor is deprecated, use the plugin configuration element." );
+            cluster = module.getCluster();
+        }
+        File jarFile = new File( buildDir, finalName + ".jar" );
+        clusterDir = new File( nbmBuildDir, "netbeans" + File.separator + cluster );
+        File moduleJarLocation = new File( clusterDir, "modules" );
+        moduleJarLocation.mkdirs();
+
+        //2. create nbm resources
+        File moduleFile = new File( moduleJarLocation, moduleJarName + ".jar" );
+
+        try
+        {
+            boolean needPlainCopy = false;
+            InputStream is = new FileInputStream( jarFile );
+            try
+            {
+                JarInputStream jis = new JarInputStream( is );
+                Manifest m = jis.getManifest();
+                Attributes a = m.getMainAttributes();
+                String classPath = ( String ) a.remove( new Attributes.Name( "X-Class-Path" ) );
+                if ( classPath == null )
+                {
+                    needPlainCopy = true;
+                }
+                else // MNBMODULE-133
+                {
+                    getLog().info( "Copying module JAR to " + moduleJarLocation + " with manifest updates" );
+                    a.putValue( "Class-Path", classPath );
+                    a.remove( new Attributes.Name( "Maven-Class-Path" ) );
+                    OutputStream os = new FileOutputStream( moduleFile );
+                    try
+                    {
+                        JarOutputStream jos = new JarOutputStream( os, m );
+                        JarEntry entry;
+                        while ( ( entry = jis.getNextJarEntry() ) != null )
+                        {
+                            JarEntry entry2 = new JarEntry( entry );
+                            jos.putNextEntry( entry2 );
+                            int c;
+                            while ( ( c = jis.read() ) != -1 )
+                            {
+                                jos.write( c );
+                            }
+                            jos.closeEntry();
+                        }
+                        jos.finish();
+                        jos.close();
+                    }
+                    finally
+                    {
+                        os.close();
+                    }
+                }
+            }
+            finally
+            {
+                is.close();
+            }
+            if ( needPlainCopy )
+            {
+                getLog().info( "Copying module JAR to " + moduleJarLocation );
+                FileUtils.getFileUtils().copyFile( jarFile, moduleFile, null, true, false );
+            }
+        }
+        catch ( IOException x )
+        {
+            throw new MojoExecutionException( "Cannot copy module jar", x );
+        }
+
+        ExamineManifest modExaminator = new ExamineManifest( getLog() );
+        modExaminator.setJarFile( moduleFile );
+        modExaminator.checkFile();
+        String classpathValue = modExaminator.getClasspath();
+
+        if ( module != null )
+        {
+            // copy libraries to the designated place..
+            @SuppressWarnings("unchecked")
+            List<Artifact> artifacts = project.getRuntimeArtifacts();
+            for ( Artifact artifact : artifacts )
+            {
+                File source = artifact.getFile();
+                
+                String path = NetBeansManifestUpdateMojo.artifactToClassPathEntry( artifact, codeNameBase );
+                
+                if ( classpathValue.contains( path ) )
+                {
+                    File target = new File( moduleJarLocation, path );
+
+                    File targetDir = target.getParentFile();
+                    targetDir.mkdirs();
+
+                    try
+                    {
+                        FileUtils.getFileUtils().copyFile( source, target, null, true, false );
+                        if ( externals != null && externals.contains(artifact.getGroupId() + ":" + artifact.getArtifactId())) // MNBMODULE-138
+                        {
+                            String name = target.getName();
+                            getLog().info( "Using *.external replacement for " + name );
+                            PrintWriter external = new PrintWriter( new File( targetDir, name + ".external" ), "UTF-8" );
+                            try
+                            {
+                                writeExternal( external, artifact );
+                            }
+                            finally
+                            {
+                                external.close();
+                            }
+                        }
+                    }
+                    catch ( IOException ex )
+                    {
+                        getLog().error( "Cannot copy library jar" );
+                        throw new MojoExecutionException( "Cannot copy library jar", ex );
+                    }
+                }
+            }
+            if ( nbmResources != null )
+            {
+                copyNbmResources();
+            }
+            copyDeprecatedNbmResources();
+        }
+
+        //javahelp stuff.
+        if ( nbmJavahelpSource.exists() )
+        {
+            getLog().warn( "src/main/javahelp/ deprecated; use @HelpSetRegistration instead" );
+            File javahelp_target = new File( buildDir, "javahelp" );
+            String javahelpbase = moduleJarName.replace( '-', File.separatorChar ) + File.separator + "docs";
+            String javahelpSearch = "JavaHelpSearch";
+            File b = new File( javahelp_target, javahelpbase );
+            File p = new File( b, javahelpSearch );
+            p.mkdirs();
+            Copy cp = (Copy) antProject.createTask( "copy" );
+            cp.setTodir( javahelp_target );
+            FileSet set = new FileSet();
+            set.setDir( nbmJavahelpSource );
+            cp.addFileset( set );
+            cp.execute();
+            getLog().info( "Generating JavaHelp Index..." );
+
+            JHIndexer jhTask = (JHIndexer) antProject.createTask( "jhindexer" );
+            jhTask.setBasedir( b );
+            jhTask.setDb( p );
+            jhTask.setIncludes( "**/*.html" );
+            jhTask.setExcludes( javahelpSearch );
+            Path path = new Path( antProject );
+            jhTask.setClassPath( path );
+            clearStaticFieldsInJavaHelpIndexer();
+            try
+            {
+                jhTask.execute();
+            }
+            catch ( BuildException e )
+            {
+                getLog().error( "Cannot generate JavaHelp index." );
+                throw new MojoExecutionException( e.getMessage(), e );
+            }
+            File helpJarLocation = new File( clusterDir, "modules/docs" );
+            helpJarLocation.mkdirs();
+            Jar jar = (Jar) antProject.createTask( "jar" );
+            jar.setDestFile( new File( helpJarLocation, moduleJarName + ".jar" ) );
+            set = new FileSet();
+            set.setDir( javahelp_target );
+            jar.addFileset( set );
+            jar.execute();
+        }
+
+        File configDir = new File( clusterDir, "config" + File.separator + "Modules" );
+        configDir.mkdirs();
+        CreateModuleXML moduleXmlTask = (CreateModuleXML) antProject.createTask( "createmodulexml" );
+        moduleXmlTask.setXmldir( configDir );
+        FileSet fs = new FileSet();
+        fs.setDir( clusterDir );
+        fs.setIncludes( "modules" + File.separator + moduleJarName + ".jar" );
+        if ( autoload )
+        {
+            moduleXmlTask.addAutoload( fs );
+        }
+        else if ( eager )
+        {
+            moduleXmlTask.addEager( fs );
+        }
+        else if ( disabled )
+        {
+            moduleXmlTask.addDisabled( fs );
+        }
+        else
+        {
+            moduleXmlTask.addEnabled( fs );
+        }
+        try
+        {
+            moduleXmlTask.execute();
+        }
+        catch ( BuildException e )
+        {
+            getLog().error( "Cannot generate config file." );
+            throw new MojoExecutionException( e.getMessage(), e );
+        }
+        MakeListOfNBM makeTask = (MakeListOfNBM) antProject.createTask( "genlist" );
+        antProject.setNewProperty( "module.name", finalName );
+        antProject.setProperty( "cluster.dir", cluster );
+        FileSet set = makeTask.createFileSet();
+        set.setDir( clusterDir );
+        PatternSet pattern = set.createPatternSet();
+        pattern.setIncludes( "**" );
+        makeTask.setModule( "modules" + File.separator + moduleJarName + ".jar" );
+        makeTask.setOutputfiledir( clusterDir );
+        try
+        {
+            makeTask.execute();
+        }
+        catch ( BuildException e )
+        {
+            getLog().error( "Cannot Generate nbm list" );
+            throw new MojoExecutionException( e.getMessage(), e );
+        }
+
+    }
+
+    private void copyDeprecatedNbmResources()
+        throws BuildException, MojoExecutionException
+    {
+        // copy additional resources..
+        List<NbmResource> ress = module.getNbmResources();
+        if ( ress.size() > 0 )
+        {
+            getLog().warn( "NBM resources defined in module descriptor are deprecated. Please configure NBM resources in plugin configuration." );
+            Copy cp = (Copy) antProject.createTask( "copy" );
+            cp.setTodir( clusterDir );
+            HashMap<File, Collection<FileSet>> customPaths = new HashMap<File, Collection<FileSet>>();
+            boolean hasStandard = false;
+            for ( NbmResource res : ress )
+            {
+                if ( res.getBaseDirectory() != null )
+                {
+                    File base = new File( project.getBasedir(), res.getBaseDirectory() );
+                    FileSet set = new FileSet();
+                    set.setDir( base );
+                    for ( String inc : res.getIncludes() )
+                    {
+                        set.createInclude().setName( inc );
+                    }
+                    for ( String exc : res.getExcludes() )
+                    {
+                        set.createExclude().setName( exc );
+                    }
+
+                    if ( res.getRelativeClusterPath() != null )
+                    {
+                        File path = new File( clusterDir, res.getRelativeClusterPath() );
+                        Collection<FileSet> col = customPaths.get( path );
+                        if ( col == null )
+                        {
+                            col = new ArrayList<FileSet>();
+                            customPaths.put( path, col );
+                        }
+                        col.add( set );
+                    }
+                    else
+                    {
+                        cp.addFileset( set );
+                        hasStandard = true;
+                    }
+                }
+            }
+            try
+            {
+                if ( hasStandard )
+                {
+                    cp.execute();
+                }
+                if ( customPaths.size() > 0 )
+                {
+                    for ( Map.Entry<File, Collection<FileSet>> ent : customPaths.entrySet() )
+                    {
+                        cp = (Copy) antProject.createTask( "copy" );
+                        cp.setTodir( ent.getKey() );
+                        for ( FileSet set : ent.getValue() )
+                        {
+                            cp.addFileset( set );
+                        }
+                        cp.execute();
+                    }
+                }
+            }
+            catch ( BuildException e )
+            {
+                getLog().error( "Cannot copy additional resources into the nbm file" );
+                throw new MojoExecutionException( e.getMessage(), e );
+            }
+        }
+    }
+
+    // repeated invokation of the javahelp indexer (possibly via multiple classloaders)
+    // is causing trouble, residue from previous invokations seems to cause errors
+    // this is a nasty workaround for the problem.
+    // alternatively we could try invoking the indexer from a separate jvm i guess,
+    // ut that's more work.
+    private void clearStaticFieldsInJavaHelpIndexer() // MNBMODULE-51 hack
+    {
+        try
+        {
+            Class clazz = Class.forName( "com.sun.java.help.search.Indexer" );
+            Field fld = clazz.getDeclaredField( "kitRegistry" );
+            fld.setAccessible( true );
+            Hashtable hash = (Hashtable) fld.get( null );
+            hash.clear();
+
+            clazz = Class.forName( "com.sun.java.help.search.HTMLIndexerKit" );
+            fld = clazz.getDeclaredField( "defaultParser" );
+            fld.setAccessible( true );
+            fld.set( null, null);
+
+            fld = clazz.getDeclaredField( "defaultCallback" );
+            fld.setAccessible( true );
+            fld.set( null, null);
+
+        }
+        catch ( IllegalArgumentException ex )
+        {
+            Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
+        }
+        catch ( IllegalAccessException ex )
+        {
+            Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
+        }
+        catch ( NoSuchFieldException ex )
+        {
+            Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
+        }
+        catch ( SecurityException ex )
+        {
+            Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
+        }
+        catch ( ClassNotFoundException ex )
+        {
+            Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
+        }
+    }
+
+    private void copyNbmResources()
+        throws MojoExecutionException
+    {
+        try
+        {
+            if ( StringUtils.isEmpty( encoding ) && isFilteringEnabled( nbmResources ) )
+            {
+                getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
+                                   + ", i.e. build is platform dependent!" );
+            }
+            MavenResourcesExecution mavenResourcesExecution =
+                new MavenResourcesExecution( Arrays.asList( nbmResources ), clusterDir, project, encoding,
+                                             Collections.EMPTY_LIST, Collections.EMPTY_LIST, session );
+            mavenResourcesExecution.setEscapeWindowsPaths( true );
+            mavenResourcesFiltering.filterResources( mavenResourcesExecution );
+        }
+        catch ( MavenFilteringException ex )
+        {
+            throw new MojoExecutionException( ex.getMessage(), ex );
+        }
+    }
+
+    /**
+     * Determines whether filtering has been enabled for any resource.
+     *
+     * @param resources The set of resources to check for filtering.
+     * @return <code>true</code> if at least one resource uses filtering, <code>false</code> otherwise.
+     */
+    private boolean isFilteringEnabled( Resource[] resources )
+    {
+        for ( Resource resource : resources )
+        {
+            if ( resource.isFiltering() )
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static void writeExternal( PrintWriter w, Artifact artifact )
+        throws IOException
+    {
+        w.write( "CRC:" );
+        File file = artifact.getFile();
+        w.write( Long.toString( CreateClusterAppMojo.crcForFile( file ).getValue() ) );
+        w.write( "\nSIZE:" );
+        w.write( Long.toString( file.length() ) );
+        w.write( "\nURL:m2:/" );
+        w.write( artifact.getGroupId() );
+        w.write( ':' );
+        w.write( artifact.getArtifactId() );
+        w.write( ':' );
+        w.write( artifact.getVersion() );
+        w.write( ':' );
+        w.write( artifact.getType() );
+        if ( artifact.getClassifier() != null )
+        {
+            w.write( ':' );
+            w.write( artifact.getClassifier() );
+        }
+        w.write( "\nURL:" );
+        // artifact.repository is null, so cannot use its url, and anyway might be a mirror
+        w.write( /* M3: RepositorySystem.DEFAULT_REMOTE_REPO_URL + '/' */ "http://repo.maven.apache.org/maven2/" );
+        w.write( new DefaultRepositoryLayout().pathOf( artifact ) );
+        w.write( '\n' );
+        w.flush();
+    }
+
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateStandaloneMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateStandaloneMojo.java
new file mode 100644
index 0000000..7e3e485
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateStandaloneMojo.java
@@ -0,0 +1,104 @@
+/*
+ *  Copyright 2008 Johan Andrén.
+ * 
+ *  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.
+ *  under the License.
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.util.DefaultFileSet;
+import org.codehaus.plexus.archiver.zip.ZipArchiver;
+
+/**
+ * Create a standalone application out of the composed clusters of nbm-application
+ *
+ * @author <a href="mailto:johan.andren@databyran.se">Johan Andrén</a>
+ * @author Milos Kleint
+ */
+@Mojo(name="standalone-zip", requiresProject=true, threadSafe = true)
+public class CreateStandaloneMojo
+        extends AbstractMojo
+{
+
+    /**
+     * The branding token for the application based on NetBeans platform.
+     */
+    @Parameter(property="netbeans.branding.token", required=true)
+    protected String brandingToken;
+    /**
+     * output directory where the the NetBeans application will be created.
+     */
+    @Parameter(required=true, defaultValue="${project.build.directory}")
+    private File outputDirectory;
+    /**
+     * Name of the zip artifact produced by the goal (without .zip extension)
+     */
+    @Parameter(defaultValue="${project.build.finalName}")
+    private String finalName;
+    /**
+     * The Maven project.
+     */
+    @Parameter(required=true, readonly=true, property="project")
+    private MavenProject project;
+
+    /**
+     * 
+     * @throws MojoExecutionException if an unexpected problem occurs
+     * @throws MojoFailureException if an expected problem occurs
+     */
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+
+        try
+        {
+            File nbmBuildDirFile = new File( outputDirectory, brandingToken );
+
+            ZipArchiver archiver = new ZipArchiver();
+            DefaultFileSet fs = new DefaultFileSet();
+            fs.setDirectory( outputDirectory );
+            fs.setIncludes( new String[] {
+                brandingToken + "/**",
+            } );
+            fs.setExcludes( new String[] {
+                brandingToken + "/bin/*",
+            } );
+            archiver.addFileSet( fs );
+            File bins = new File( nbmBuildDirFile, "bin" );
+            for ( File bin : bins.listFiles() )
+            {
+                archiver.addFile( bin, brandingToken + "/bin/" + bin.getName(), 0755 );
+            }
+            File zipFile = new File( outputDirectory, finalName + ".zip" );
+            //TODO - somehow check for last modified content to see if we shall be
+            //recreating the zip file.
+            archiver.setDestFile( zipFile );
+            archiver.setForced( false );
+            archiver.createArchive();
+            project.getArtifact().setFile( zipFile );
+
+        }
+        catch ( Exception ex )
+        {
+            throw new MojoExecutionException( "", ex );
+        }
+
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateUpdateSiteMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateUpdateSiteMojo.java
new file mode 100644
index 0000000..9b04f6f
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateUpdateSiteMojo.java
@@ -0,0 +1,412 @@
+/* ==========================================================================
+ * Copyright 2003-2004 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.DefaultArtifactRepository;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Copy;
+import org.apache.tools.ant.types.FileSet;
+import org.codehaus.plexus.PlexusConstants;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.archiver.gzip.GZipArchiver;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.context.Context;
+import org.codehaus.plexus.context.ContextException;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
+import org.netbeans.nbbuild.MakeUpdateDesc;
+
+/**
+ * Create the NetBeans auto update site definition.
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ *
+ */
+@Mojo(name="autoupdate", 
+        defaultPhase= LifecyclePhase.PACKAGE, 
+        aggregator=true, 
+        requiresDependencyResolution= ResolutionScope.RUNTIME )
+public class CreateUpdateSiteMojo
+        extends AbstractNbmMojo
+        implements Contextualizable
+{
+
+    /**
+     * output directory.
+     */
+    @Parameter(required=true, defaultValue="${project.build.directory}")
+    protected File outputDirectory;
+    /**
+     * autoupdate site xml file name.
+     */
+    @Parameter( defaultValue="updates.xml", property="maven.nbm.updatesitexml")
+    protected String fileName;
+    /**
+     * A custom distribution base for the nbms in the update site.
+     * If NOT defined, the update site will use a simple relative URL, which is generally what you want.
+     * Defining it as "auto" will pick up the distribution URL from each NBM, which is generally wrong. 
+     * See <code>distributionUrl</code> in nbm mojo for what url will be used in that case.
+     * <p/>
+     * The value is either a direct http protocol based URL that points to
+     * the location under which all nbm files are located, or
+     * <p/>
+     * allows to create an update site based on maven repository content.
+     * The resulting autoupdate site document can be uploaded as tar.gz to repository as well
+     * as attached artifact to the 'nbm-application' project.
+     * <br/>
+     * Format: id::layout::url same as in maven-deploy-plugin
+     * <br/>
+     * with the 'default' and 'legacy' layouts. (maven2 vs maven1 layout)
+     * <br/>
+     * If the value doesn't contain :: characters,
+     * it's assumed to be the flat structure and the value is just the URL.
+     * 
+     * @since 3.0 it's also possible to add remote repository as base
+     */
+    @Parameter(defaultValue=".", property="maven.nbm.customDistBase")
+    private String distBase;
+
+    /**
+     * The Maven Project.
+     *
+     */
+    @Parameter(required=true, readonly=true, property="project")
+    private MavenProject project;
+
+    /**
+     * If the executed project is a reactor project, this will contains the full list of projects in the reactor.
+     */
+    @Parameter(required=true, readonly=true, defaultValue="${reactorProjects}")
+    private List reactorProjects;
+    
+    /**
+     * List of Ant style patterns on artifact GA (groupID:artifactID) that should be included in the update site.
+     * Eg. org.netbeans.* matches all artifacts with any groupID starting with 'org.netbeans.',
+     * org.*:api will match any artifact with artifactId of 'api' and groupId starting with 'org.'
+     * @since 3.14
+     */
+    @Parameter
+    private List<String> updateSiteIncludes;
+    
+
+    // <editor-fold defaultstate="collapsed" desc="Component parameters">
+
+    @Component
+    private ArtifactFactory artifactFactory;
+    /**
+     * Contextualized.
+     */
+    private PlexusContainer container;
+    /**
+     * Used for attaching the artifact in the project
+     *
+     */
+    @Component
+    private MavenProjectHelper projectHelper;
+
+    @Component
+    private ArtifactResolver artifactResolver;
+
+    /**
+     * Local maven repository.
+     *
+     */
+    @Parameter(readonly=true, required=true, defaultValue="${localRepository}")
+    protected ArtifactRepository localRepository;
+
+    // </editor-fold>
+
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        Project antProject = registerNbmAntTasks();
+        File nbmBuildDirFile = new File( outputDirectory, "netbeans_site" );
+        if ( !nbmBuildDirFile.exists() )
+        {
+            nbmBuildDirFile.mkdirs();
+        }
+
+        boolean isRepository = false;
+        if ( "auto".equals( distBase ) )
+        {
+            distBase = null;
+        }
+        ArtifactRepository distRepository = getDeploymentRepository( distBase, container, getLog() );
+        String oldDistBase = null;
+        if ( distRepository != null )
+        {
+            isRepository = true;
+        }
+        else
+        {
+            if ( distBase != null && !distBase.contains( "::" ) )
+            {
+                oldDistBase = distBase;
+            }
+        }
+
+        if ( "nbm-application".equals( project.getPackaging() ) )
+        {
+            @SuppressWarnings( "unchecked" )
+            Set<Artifact> artifacts = project.getArtifacts();
+            for ( Artifact art : artifacts )
+            {
+                if (!matchesIncludes(art)) {
+                    continue;
+                }
+                ArtifactResult res =
+                    turnJarToNbmFile( art, artifactFactory, artifactResolver, project, localRepository );
+                if ( res.hasConvertedArtifact() )
+                {
+                    art = res.getConvertedArtifact();
+                }
+
+                if ( art.getType().equals( "nbm-file" ) )
+                {
+                    Copy copyTask = (Copy) antProject.createTask( "copy" );
+                    copyTask.setOverwrite( true );
+                    copyTask.setFile( art.getFile() );
+                    if ( !isRepository )
+                    {
+                        copyTask.setFlatten( true );
+                        copyTask.setTodir( nbmBuildDirFile );
+                    }
+                    else
+                    {
+                        String path = distRepository.pathOf( art );
+                        File f = new File( nbmBuildDirFile, path.replace( '/', File.separatorChar ) );
+                        copyTask.setTofile( f );
+                    }
+                    try
+                    {
+                        copyTask.execute();
+                    }
+                    catch ( BuildException ex )
+                    {
+                        throw new MojoExecutionException( "Cannot merge nbm files into autoupdate site", ex );
+                    }
+
+                }
+                if ( res.isOSGiBundle() )
+                {
+                    // TODO check for bundles
+                }
+            }
+            getLog().info( "Created NetBeans module cluster(s) at " + nbmBuildDirFile.getAbsoluteFile() );
+
+        }
+        else if ( reactorProjects != null && reactorProjects.size() > 0 )
+        {
+
+            Iterator it = reactorProjects.iterator();
+            while ( it.hasNext() )
+            {
+                MavenProject proj = (MavenProject) it.next();
+                //TODO how to figure where the the buildDir/nbm directory is
+                File moduleDir = proj.getFile().getParentFile();
+                if ( moduleDir != null && moduleDir.exists() )
+                {
+                    Copy copyTask = (Copy) antProject.createTask( "copy" );
+                    if ( !isRepository )
+                    {
+                        FileSet fs = new FileSet();
+                        File projOutputDirectory = new File( proj.getBuild().getDirectory() );
+                        fs.setDir( projOutputDirectory );
+                        fs.createInclude().setName( "*.nbm" );
+                        copyTask.addFileset( fs );
+                        copyTask.setOverwrite( true );
+                        copyTask.setFlatten( true );
+                        copyTask.setTodir( nbmBuildDirFile );
+                    }
+                    else
+                    {
+                        File target = new File( proj.getBuild().getDirectory() );
+                        boolean has = false;
+                        File[] fls = target.listFiles();
+                        if ( fls != null )
+                        {
+                            for ( File fl : fls )
+                            {
+                                if ( fl.getName().endsWith( ".nbm" ) )
+                                {
+                                    copyTask.setFile( fl );
+                                    has = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if ( !has )
+                        {
+                            continue;
+                        }
+                        Artifact art =
+                            artifactFactory.createArtifact( proj.getGroupId(), proj.getArtifactId(), proj.getVersion(),
+                                                            null, "nbm-file" );
+                        String path = distRepository.pathOf( art );
+                        File f = new File( nbmBuildDirFile, path.replace( '/', File.separatorChar ) );
+                        copyTask.setTofile( f );
+                    }
+                    try
+                    {
+                        copyTask.execute();
+                    }
+                    catch ( BuildException ex )
+                    {
+                        throw new MojoExecutionException( "Cannot merge nbm files into autoupdate site", ex );
+                    }
+                }
+            }
+        }
+        else
+        {
+            throw new MojoExecutionException(
+                    "This goal only makes sense on reactor projects or project with 'nbm-application' packaging." );
+
+        }
+        MakeUpdateDesc descTask = (MakeUpdateDesc) antProject.createTask( "updatedist" );
+        File xmlFile = new File( nbmBuildDirFile, fileName );
+        descTask.setDesc( xmlFile );
+        if ( oldDistBase != null )
+        {
+            descTask.setDistBase( oldDistBase );
+        }
+        if ( distRepository != null )
+        {
+            descTask.setDistBase( distRepository.getUrl() );
+        }
+        FileSet fs = new FileSet();
+        fs.setDir( nbmBuildDirFile );
+        fs.createInclude().setName( "**/*.nbm" );
+        descTask.addFileset( fs );
+        try
+        {
+            descTask.execute();
+        }
+        catch ( BuildException ex )
+        {
+            throw new MojoExecutionException( "Cannot create autoupdate site xml file", ex );
+        }
+        getLog().info( "Generated autoupdate site content at " + nbmBuildDirFile.getAbsolutePath() );
+
+        try
+        {
+            GZipArchiver gz = new GZipArchiver();
+            gz.addFile( xmlFile, fileName );
+            File gzipped = new File( nbmBuildDirFile, fileName + ".gz" );
+            gz.setDestFile( gzipped );
+            gz.createArchive();
+            if ( "nbm-application".equals( project.getPackaging() ) )
+            {
+                projectHelper.attachArtifact( project, "xml.gz", "updatesite", gzipped );
+            }
+        }
+        catch ( Exception ex )
+        {
+            throw new MojoExecutionException( "Cannot create gzipped version of the update site xml file.", ex );
+        }
+
+    }
+
+    private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" );
+
+    static ArtifactRepository getDeploymentRepository( String distBase, PlexusContainer container, Log log )
+        throws MojoExecutionException, MojoFailureException
+    {
+
+        ArtifactRepository repo = null;
+
+        if ( distBase != null )
+        {
+
+            Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher( distBase );
+
+            if ( !matcher.matches() )
+            {
+                if ( !distBase.contains( "::" ) )
+                {
+                    //backward compatibility gag.
+                    return null;
+                }
+                throw new MojoFailureException( distBase,
+                        "Invalid syntax for repository.",
+                        "Invalid syntax for alternative repository. Use \"id::layout::url\"." );
+            }
+            else
+            {
+                String id = matcher.group( 1 ).trim();
+                String layout = matcher.group( 2 ).trim();
+                String url = matcher.group( 3 ).trim();
+
+                ArtifactRepositoryLayout repoLayout;
+                try
+                {
+                    repoLayout = (ArtifactRepositoryLayout) container.lookup( ArtifactRepositoryLayout.ROLE, layout );
+                }
+                catch ( ComponentLookupException e )
+                {
+                    throw new MojoExecutionException( "Cannot find repository layout: " + layout, e );
+                }
+
+                repo = new DefaultArtifactRepository( id, url, repoLayout );
+            }
+        }
+        return repo;
+    }
+
+    public void contextualize( Context context )
+        throws ContextException
+    {
+        this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
+    }
+
+    private boolean matchesIncludes( Artifact art )
+    {
+        if (updateSiteIncludes != null) {
+            String s = art.getGroupId() + ":" + art.getArtifactId();
+            for (String p : updateSiteIncludes) {
+                //TODO optimize and only do once per execution.
+                p = p.replace(".", "\\.").replace( "*", ".*");
+                Pattern patt = Pattern.compile( p );
+                if (patt.matcher( s).matches()) {
+                    return true;
+                }
+            }
+            return false;    
+        }
+        return true;
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateWebstartAppMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateWebstartAppMojo.java
new file mode 100644
index 0000000..e53b832
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/CreateWebstartAppMojo.java
@@ -0,0 +1,698 @@
+/*
+ *  Copyright 2008 Johan Andrén.
+ * 
+ *  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.
+ *  under the License.
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URL;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.GenerateKey;
+import org.apache.tools.ant.taskdefs.SignJar;
+import org.apache.tools.ant.taskdefs.Taskdef;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.selectors.AndSelector;
+import org.apache.tools.ant.types.selectors.FilenameSelector;
+import org.apache.tools.ant.types.selectors.OrSelector;
+import org.codehaus.plexus.archiver.zip.ZipArchiver;
+import org.codehaus.plexus.components.io.resources.PlexusIoResource;
+import org.codehaus.plexus.util.DirectoryScanner;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.InterpolationFilterReader;
+import org.netbeans.nbbuild.MakeJNLP;
+import org.netbeans.nbbuild.ModuleSelector;
+import org.netbeans.nbbuild.VerifyJNLP;
+
+/**
+ * Create webstartable binaries for a 'nbm-application'.
+ * @author <a href="mailto:johan.andren@databyran.se">Johan Andrén</a>
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ * @since 3.0
+ */
+@Mojo(name="webstart-app", defaultPhase= LifecyclePhase.PACKAGE )
+public class CreateWebstartAppMojo
+    extends AbstractNbmMojo
+{
+
+    /**
+     * The Maven project.
+
+     */
+    @org.apache.maven.plugins.annotations.Parameter(required=true, readonly=true, property="project")
+    private MavenProject project;
+
+    @Component
+    protected MavenProjectHelper projectHelper;
+
+    /**
+     * The branding token for the application based on NetBeans platform.
+     */
+    @org.apache.maven.plugins.annotations.Parameter(required=true, property="netbeans.branding.token")
+    protected String brandingToken;
+
+    /**
+     * output directory where the the NetBeans application will be created.
+     */
+    @org.apache.maven.plugins.annotations.Parameter(required=true, defaultValue="${project.build.directory}")
+    private File outputDirectory;
+
+    /**
+     * Ready-to-deploy WAR containing application in JNLP packaging.
+     * 
+     */
+    @org.apache.maven.plugins.annotations.Parameter(required=true, defaultValue="${project.build.directory}/${project.artifactId}-${project.version}-jnlp.war")
+    private File destinationFile;
+
+    /**
+     * Artifact Classifier to use for the webstart distributable zip file.
+     * @since 3.1
+     */
+    @org.apache.maven.plugins.annotations.Parameter(defaultValue="webstart", property="nbm.webstart.classifier")
+    private String webstartClassifier;
+
+    /**
+     * Codebase value within *.jnlp files.
+     * <strong>Defining this parameter is generally a bad idea.</strong>
+     */
+    @org.apache.maven.plugins.annotations.Parameter(property="nbm.webstart.codebase")
+    private String codebase;
+
+    /**
+     * A custom master JNLP file. If not defined, the 
+     * <a href="http://mojo.codehaus.org/nbm-maven-plugin/masterjnlp.txt">default one</a> is used.
+     * The following expressions can be used within the file and will
+     * be replaced when generating content.
+     * <ul>
+     * <li>${jnlp.resources}</li>
+     * <li>${jnlp.codebase} - the 'codebase' parameter value is passed in.</li>
+     * <li>${app.name}</li>
+     * <li>${app.title}</li>
+     * <li>${app.vendor}</li>
+     * <li>${app.description}</li>
+     * <li>${branding.token} - the 'brandingToken' parameter value is passed in.</li>
+     * <li>${netbeans.jnlp.fixPolicy}</li>
+     * </ul>
+     */
+    @org.apache.maven.plugins.annotations.Parameter
+    private File masterJnlpFile;
+    
+    /**
+     * The basename (minus .jnlp extension) of the master JNLP file in the output.
+     * This file will be the entry point for javaws.
+     * Defaults to the branding token.
+     * @since 3.5
+     */
+    @org.apache.maven.plugins.annotations.Parameter(property="master.jnlp.file.name")
+    private String masterJnlpFileName;
+
+    /**
+     * keystore location for signing the nbm file
+     */
+    @org.apache.maven.plugins.annotations.Parameter(property="keystore")
+    private String keystore;
+
+    /**
+     * keystore password
+     */
+    @org.apache.maven.plugins.annotations.Parameter(property="keystorepass")
+    private String keystorepassword;
+
+    /**
+     * keystore alias
+     */
+    @org.apache.maven.plugins.annotations.Parameter(property="keystorealias")
+    private String keystorealias;
+
+    /**
+     * keystore type
+     * @since 3.5
+     */
+    @org.apache.maven.plugins.annotations.Parameter(property="keystoretype")
+    private String keystoretype;
+
+    /**
+     * If set true, build-jnlp target creates versioning info in jnlp descriptors and version.xml files.
+     * This allows for incremental updates of Webstart applications, but requires download via
+     * JnlpDownloadServlet
+     * Defaults to false, which means versioning
+     * info is not generated (see
+     * http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/downloadservletguide.html#resources).
+     *
+     */
+    @org.apache.maven.plugins.annotations.Parameter(defaultValue="false", property="nbm.webstart.versions")
+    private boolean processJarVersions;
+    /**
+     * additional command line arguments. Eg.
+     * -J-Xdebug -J-Xnoagent -J-Xrunjdwp:transport=dt_socket,suspend=n,server=n,address=8888
+     * can be used to debug the IDE.
+     */
+    @org.apache.maven.plugins.annotations.Parameter(property="netbeans.run.params")
+    private String additionalArguments;
+
+    /**
+     * 
+     * @throws MojoExecutionException if an unexpected problem occurs
+     * @throws MojoFailureException if an expected problem occurs
+     */
+    @Override
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        if ( !"nbm-application".equals( project.getPackaging() ) )
+        {
+            throw new MojoExecutionException(
+                "This goal only makes sense on project with nbm-application packaging." );
+        }
+        Project antProject = antProject();
+        
+        getLog().warn( "WARNING: Unsigned and self-signed WebStart applications are deprecated from JDK7u21 onwards. To ensure future correct functionality please use trusted certificate.");
+
+        if ( keystore != null && keystorealias != null && keystorepassword != null )
+        {
+            File ks = new File( keystore );
+            if ( !ks.exists() )
+            {
+                throw new MojoFailureException( "Cannot find keystore file at " + ks.getAbsolutePath() );
+            }
+            else
+            {
+                //proceed..
+            }
+        }
+        else if ( keystore != null || keystorepassword != null || keystorealias != null )
+        {
+            throw new MojoFailureException(
+                "If you want to sign the jnlp application, you need to define all three keystore related parameters." );
+        }
+        else
+        {
+            File generatedKeystore = new File( outputDirectory, "generated.keystore" );
+            if ( ! generatedKeystore.exists() )
+            {
+                getLog().warn( "Keystore related parameters not set, generating a default keystore." );
+                GenerateKey genTask = (GenerateKey) antProject.createTask( "genkey" );
+                genTask.setAlias( "jnlp" );
+                genTask.setStorepass( "netbeans" );
+                genTask.setDname( "CN=" + System.getProperty( "user.name" ) );
+                genTask.setKeystore( generatedKeystore.getAbsolutePath() );
+                genTask.execute();
+            }
+            keystore = generatedKeystore.getAbsolutePath();
+            keystorepassword = "netbeans";
+            keystorealias = "jnlp";
+        }
+
+        Taskdef taskdef = (Taskdef) antProject.createTask( "taskdef" );
+        taskdef.setClassname( "org.netbeans.nbbuild.MakeJNLP" );
+        taskdef.setName( "makejnlp" );
+        taskdef.execute();
+
+        taskdef = (Taskdef) antProject.createTask( "taskdef" );
+        taskdef.setClassname( "org.netbeans.nbbuild.VerifyJNLP" );
+        taskdef.setName( "verifyjnlp" );
+        taskdef.execute();
+
+
+        try
+        {
+            File webstartBuildDir = new File(
+                outputDirectory + File.separator + "webstart" + File.separator + brandingToken );
+            if ( webstartBuildDir.exists() )
+            {
+                FileUtils.deleteDirectory( webstartBuildDir );
+            }
+            webstartBuildDir.mkdirs();
+            final String localCodebase = codebase != null ? codebase : webstartBuildDir.toURI().toString();
+            getLog().info( "Generating webstartable binaries at " + webstartBuildDir.getAbsolutePath() );
+
+            File nbmBuildDirFile = new File( outputDirectory, brandingToken );
+
+//            FileUtils.copyDirectoryStructureIfModified( nbmBuildDirFile, webstartBuildDir );
+
+            MakeJNLP jnlpTask = (MakeJNLP) antProject.createTask( "makejnlp" );
+            jnlpTask.setDir( webstartBuildDir );
+            jnlpTask.setCodebase( localCodebase );
+            //TODO, how to figure verify excludes..
+            jnlpTask.setVerify( false );
+            jnlpTask.setPermissions( "<security><all-permissions/></security>" );
+            jnlpTask.setSignJars( true );
+
+            jnlpTask.setAlias( keystorealias );
+            jnlpTask.setKeystore( keystore );
+            jnlpTask.setStorePass( keystorepassword );
+            if ( keystoretype != null )
+            {
+                jnlpTask.setStoreType( keystoretype );
+            }
+            jnlpTask.setProcessJarVersions( processJarVersions );
+
+            FileSet fs = jnlpTask.createModules();
+            fs.setDir( nbmBuildDirFile );
+            OrSelector or = new OrSelector();
+            AndSelector and = new AndSelector();
+            FilenameSelector inc = new FilenameSelector();
+            inc.setName( "*/modules/**/*.jar" );
+            or.addFilename( inc );
+            inc = new FilenameSelector();
+            inc.setName( "*/lib/**/*.jar" );
+            or.addFilename( inc );
+            inc = new FilenameSelector();
+            inc.setName( "*/core/**/*.jar" );
+            or.addFilename( inc );
+
+            ModuleSelector ms = new ModuleSelector();
+            Parameter included = new Parameter();
+            included.setName( "includeClusters" );
+            included.setValue( "" );
+            Parameter excluded = new Parameter();
+            excluded.setName( "excludeClusters" );
+            excluded.setValue( "" );
+            Parameter exModules = new Parameter();
+            exModules.setName( "excludeModules" );
+            exModules.setValue( "" );
+            ms.setParameters( new Parameter[]
+                {
+                    included,
+                    excluded,
+                    exModules
+                } );
+            and.add( or );
+            and.add( ms );
+            fs.addAnd( and );
+            jnlpTask.execute();
+
+            //TODO is it really netbeans/
+            String extSnippet = generateExtensions( fs, antProject, "" ); // "netbeans/"
+
+            if ( masterJnlpFileName == null )
+            {
+               masterJnlpFileName = brandingToken;
+            }
+
+            Properties props = new Properties();
+            props.setProperty( "jnlp.codebase", localCodebase );
+            props.setProperty( "app.name", brandingToken );
+            props.setProperty( "app.title", project.getName() );
+            if ( project.getOrganization() != null )
+            {
+                props.setProperty( "app.vendor", project.getOrganization().getName() );
+            }
+            else
+            {
+                props.setProperty( "app.vendor", "Nobody" );
+            }
+            String description = project.getDescription() != null ? project.getDescription() : "No Project Description";
+            props.setProperty( "app.description", description );
+            props.setProperty( "branding.token", brandingToken );
+            props.setProperty( "master.jnlp.file.name", masterJnlpFileName );
+            props.setProperty( "netbeans.jnlp.fixPolicy", "false" );
+
+            StringBuilder stBuilder = new StringBuilder();
+            if ( additionalArguments != null )
+            {
+                StringTokenizer st = new StringTokenizer( additionalArguments );
+                while ( st.hasMoreTokens() )
+                {
+                    String arg = st.nextToken();
+                    if ( arg.startsWith( "-J" ) )
+                    {
+                        if ( stBuilder.length() > 0 )
+                        {
+                            stBuilder.append( ' ' );
+                        }
+                        stBuilder.append( arg.substring( 2 ) );
+                    }
+                }
+            }
+            props.setProperty( "netbeans.run.params", stBuilder.toString() );
+
+            File masterJnlp = new File(
+                webstartBuildDir.getAbsolutePath() + File.separator + masterJnlpFileName + ".jnlp" );
+            filterCopy( masterJnlpFile, "master.jnlp", masterJnlp, props );
+
+
+            File startup = copyLauncher( outputDirectory, nbmBuildDirFile );
+            File jnlpDestination = new File(
+                webstartBuildDir.getAbsolutePath() + File.separator + "startup.jar" );
+
+            SignJar signTask = (SignJar) antProject.createTask( "signjar" );
+            signTask.setKeystore( keystore );
+            signTask.setStorepass( keystorepassword );
+            signTask.setAlias( keystorealias );
+            if ( keystoretype != null )
+            {
+                signTask.setStoretype( keystoretype );
+            }
+            signTask.setSignedjar( jnlpDestination );
+            signTask.setJar( startup );
+            signTask.execute();
+
+            //branding
+            DirectoryScanner ds = new DirectoryScanner();
+            ds.setBasedir( nbmBuildDirFile );
+            ds.setIncludes( new String[]
+                {
+                    "**/locale/*.jar"
+                } );
+            ds.scan();
+            String[] includes = ds.getIncludedFiles();
+            StringBuilder brandRefs = new StringBuilder();
+            if ( includes != null && includes.length > 0 )
+            {
+                File brandingDir = new File( webstartBuildDir, "branding" );
+                brandingDir.mkdirs();
+                for ( String incBran : includes )
+                {
+                    File source = new File( nbmBuildDirFile, incBran );
+                    File dest = new File( brandingDir, source.getName() );
+                    FileUtils.copyFile( source, dest );
+                    brandRefs.append( "    <jar href=\'branding/" ).append( dest.getName() ).append( "\'/>\n" );
+                }
+
+                signTask = (SignJar) antProject.createTask( "signjar" );
+                signTask.setKeystore( keystore );
+                signTask.setStorepass( keystorepassword );
+                signTask.setAlias( keystorealias );
+                if ( keystoretype != null )
+                {
+                    signTask.setStoretype( keystoretype );
+                }
+                
+                FileSet set = new FileSet();
+                set.setDir( brandingDir );
+                set.setIncludes( "*.jar" );
+                signTask.addFileset( set );
+                signTask.execute();
+            }
+
+            File modulesJnlp = new File(
+                webstartBuildDir.getAbsolutePath() + File.separator + "modules.jnlp" );
+            props.setProperty( "jnlp.branding.jars", brandRefs.toString() );
+            props.setProperty( "jnlp.resources", extSnippet );
+            filterCopy( null, /* filename is historical */"branding.jnlp", modulesJnlp, props );
+
+            getLog().info( "Verifying generated webstartable content." );
+            VerifyJNLP verifyTask = (VerifyJNLP) antProject.createTask( "verifyjnlp" );
+            FileSet verify = new FileSet();
+            verify.setFile( masterJnlp );
+            verifyTask.addConfiguredFileset( verify );
+            verifyTask.execute();
+
+
+            // create zip archive
+            if ( destinationFile.exists() )
+            {
+                destinationFile.delete();
+            }
+            ZipArchiver archiver = new ZipArchiver();
+            if ( codebase != null )
+            {
+                getLog().warn( "Defining <codebase>/${nbm.webstart.codebase} is generally unnecessary" );
+                archiver.addDirectory( webstartBuildDir );
+            }
+            else
+            {
+                archiver.addDirectory( webstartBuildDir, null, new String[] { "**/*.jnlp" } );
+                for ( final File jnlp : webstartBuildDir.listFiles() )
+                {
+                    if ( !jnlp.getName().endsWith( ".jnlp" ) )
+                    {
+                        continue;
+                    }
+                    archiver.addResource( new PlexusIoResource() {
+                        public @Override InputStream getContents() throws IOException
+                        {
+                            return new ByteArrayInputStream( FileUtils.fileRead( jnlp, "UTF-8" ).replace( localCodebase, "$$codebase" ).getBytes( "UTF-8" ) );
+                        }
+                        public @Override long getLastModified()
+                        {
+                            return jnlp.lastModified();
+                        }
+                        public @Override boolean isExisting()
+                        {
+                            return true;
+                        }
+                        public @Override long getSize()
+                        {
+                            return UNKNOWN_RESOURCE_SIZE;
+                        }
+                        public @Override URL getURL() throws IOException
+                        {
+                            return null;
+                        }
+                        public @Override String getName()
+                        {
+                            return jnlp.getAbsolutePath();
+                        }
+                        public @Override boolean isFile()
+                        {
+                            return true;
+                        }
+                        public @Override boolean isDirectory()
+                        {
+                            return false;
+                        }
+
+                        @Override
+                        public boolean isSymbolicLink()
+                        {
+                            return false;
+                        }
+                    }, jnlp.getName(), archiver.getDefaultFileMode() );
+                }
+            }
+            File jdkhome = new File( System.getProperty( "java.home" ) );
+            File servlet = new File( jdkhome, "sample/jnlp/servlet/jnlp-servlet.jar" );
+            if ( ! servlet.isFile() )
+            {
+                servlet = new File( jdkhome.getParentFile(), "sample/jnlp/servlet/jnlp-servlet.jar" );
+            }
+            if ( servlet.isFile() )
+            {
+                archiver.addFile( servlet, "WEB-INF/lib/jnlp-servlet.jar" );
+                archiver.addResource( new PlexusIoResource() {
+                    public @Override InputStream getContents() throws IOException
+                    {
+                        return new ByteArrayInputStream( ( "" +
+                            "<web-app>\n" +
+                            "    <servlet>\n" +
+                            "        <servlet-name>JnlpDownloadServlet</servlet-name>\n" +
+                            "        <servlet-class>jnlp.sample.servlet.JnlpDownloadServlet</servlet-class>\n" +
+                            "    </servlet>\n" +
+                            "    <servlet-mapping>\n" +
+                            "        <servlet-name>JnlpDownloadServlet</servlet-name>\n" +
+                            "        <url-pattern>*.jnlp</url-pattern>\n" +
+                            "    </servlet-mapping>\n" +
+                            "</web-app>\n" ).getBytes() );
+                    }
+                    public @Override long getLastModified()
+                    {
+                        return UNKNOWN_MODIFICATION_DATE;
+                    }
+                    public @Override boolean isExisting()
+                    {
+                        return true;
+                    }
+                    public @Override long getSize()
+                    {
+                        return UNKNOWN_RESOURCE_SIZE;
+                    }
+                    public @Override URL getURL() throws IOException
+                    {
+                        return null;
+                    }
+                    public @Override String getName()
+                    {
+                        return "web.xml";
+                    }
+                    public @Override boolean isFile()
+                    {
+                        return true;
+                    }
+                    public @Override boolean isDirectory()
+                    {
+                        return false;
+                    }
+
+                    @Override
+                    public boolean isSymbolicLink()
+                    {
+                        return false;
+                    }
+                }, "WEB-INF/web.xml", archiver.getDefaultFileMode() );
+            }
+            archiver.setDestFile( destinationFile );
+            archiver.createArchive();
+
+            // attach standalone so that it gets installed/deployed
+            projectHelper.attachArtifact( project, "war", webstartClassifier, destinationFile );
+
+        }
+        catch ( Exception ex )
+        {
+            throw new MojoExecutionException( "Error creating webstartable binary.", ex );
+        }
+    }
+
+    /**
+     * @param standaloneBuildDir
+     * @return The name of the jnlp-launcher jarfile in the build directory
+     */
+    private File copyLauncher( File standaloneBuildDir, File builtInstallation )
+        throws IOException
+    {
+        File jnlpStarter =
+            new File( builtInstallation.getAbsolutePath() + File.separator + "harness" + File.separator + "jnlp"
+                + File.separator + "jnlp-launcher.jar" );
+        // buffer so it isn't reading a byte at a time!
+        InputStream source = null;
+        FileOutputStream outstream = null;
+        try
+        {
+            if ( !jnlpStarter.exists() )
+            {
+                source = getClass().getClassLoader().getResourceAsStream(
+                    "harness/jnlp/jnlp-launcher.jar" );
+            }
+            else
+            {
+                source = new FileInputStream( jnlpStarter );
+            }
+            File jnlpDestination = new File(
+                standaloneBuildDir.getAbsolutePath() + File.separator + "jnlp-launcher.jar" );
+
+            outstream = new FileOutputStream( jnlpDestination );
+            IOUtil.copy( source, outstream );
+            return jnlpDestination;
+        }
+        finally
+        {
+            IOUtil.close( source );
+            IOUtil.close( outstream );
+        }
+    }
+
+    private void filterCopy( File sourceFile, String resourcePath, File destinationFile, Properties filterProperties )
+        throws IOException
+    {
+        // buffer so it isn't reading a byte at a time!
+        Reader source = null;
+        Writer destination = null;
+        try
+        {
+            InputStream instream;
+            if ( sourceFile != null )
+            {
+                instream = new FileInputStream( sourceFile );
+            }
+            else
+            {
+                instream = getClass().getClassLoader().getResourceAsStream( resourcePath );
+            }
+            FileOutputStream outstream = new FileOutputStream( destinationFile );
+
+            source = new BufferedReader( new InputStreamReader( instream, "UTF-8" ) );
+            destination = new OutputStreamWriter( outstream, "UTF-8" );
+
+            // support ${token}
+            Reader reader = new InterpolationFilterReader( source, filterProperties, "${", "}" );
+
+            IOUtil.copy( reader, destination );
+        }
+        finally
+        {
+            IOUtil.close( source );
+            IOUtil.close( destination );
+        }
+    }
+
+    /**
+     * copied from MakeMasterJNLP ant task.
+     * @param files
+     * @param antProject
+     * @param masterPrefix
+     * @return
+     * @throws java.io.IOException
+     */
+    private String generateExtensions( FileSet files, Project antProject, String masterPrefix )
+        throws IOException
+    {
+        StringBuilder buff = new StringBuilder();
+        for ( String nm : files.getDirectoryScanner( antProject ).getIncludedFiles() )
+        {
+            File jar = new File( files.getDir( antProject ), nm );
+
+            if ( !jar.canRead() )
+            {
+                throw new IOException( "Cannot read file: " + jar );
+            }
+
+            JarFile theJar = new JarFile( jar );
+            Attributes attr = theJar.getManifest().getMainAttributes();
+            String codenamebase = attr.getValue( "OpenIDE-Module" );
+            if ( codenamebase == null )
+            {
+                codenamebase = attr.getValue("Bundle-SymbolicName");
+            }
+            if ( codenamebase == null )
+            {
+                throw new IOException( "Not a NetBeans Module: " + jar );
+            }
+            
+            // see http://hg.netbeans.org/main-silver/rev/87823abb86d9
+            if (codenamebase.equals("org.objectweb.asm.all")
+                    && jar.getParentFile().getName().equals("core")
+                    && jar.getParentFile().getParentFile().getName().startsWith("platform")) {
+                continue;
+            }
+            {
+                int slash = codenamebase.indexOf( '/' );
+                if ( slash >= 0 )
+                {
+                    codenamebase = codenamebase.substring( 0, slash );
+                }
+            }
+            String dashcnb = codenamebase.replace( '.', '-' );
+
+            buff.append( "    <extension name='" ).append( codenamebase ).append( "' href='" ).append( masterPrefix ).append( dashcnb ).append( ".jnlp' />\n" );
+            theJar.close();
+        }
+        return buff.toString();
+
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/NetBeansManifestUpdateMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/NetBeansManifestUpdateMojo.java
new file mode 100644
index 0000000..87df4fb
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/NetBeansManifestUpdateMojo.java
@@ -0,0 +1,926 @@
+/* ==========================================================================
+ * Copyright 2003-2007 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.net.URL;
+import java.text.BreakIterator;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactCollector;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.codehaus.mojo.nbm.model.Dependency;
+import org.codehaus.mojo.nbm.model.NetBeansModule;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.dependency.analyzer.DefaultClassAnalyzer;
+import org.apache.maven.shared.dependency.analyzer.asm.ASMDependencyAnalyzer;
+import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
+import org.apache.maven.shared.dependency.graph.DependencyNode;
+import org.apache.tools.ant.taskdefs.Manifest;
+import org.apache.tools.ant.taskdefs.ManifestException;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+import org.codehaus.plexus.util.IOUtil;
+
+/**
+ * Goal for generating NetBeans module system specific manifest entries, part of <code>nbm</code> lifecycle/packaging.
+ *
+ * In order to have the generated manifest picked up by the maven-jar-plugin,
+ * one shall add the following configuration snippet to maven-jar-plugin.
+ * 
+ * <pre>
+ *  {@code
+   <plugin>
+       <groupId>org.apache.maven.plugins</groupId>
+       <artifactId>maven-jar-plugin</artifactId>
+       <version>3.0.2</version>
+       <configuration>
+           <archive>
+               <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+           </archive>
+       </configuration>
+   </plugin>
+ * }
+ * </pre>
+ *
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ */
+@Mojo(name="manifest", 
+        defaultPhase= LifecyclePhase.PROCESS_CLASSES, 
+        requiresProject=true, 
+        threadSafe = true,
+        requiresDependencyResolution= ResolutionScope.RUNTIME )
+public class NetBeansManifestUpdateMojo
+    extends AbstractNbmMojo
+{
+
+    /**
+     * NetBeans module assembly build directory.
+     * directory where the the NetBeans jar and nbm file get constructed.
+     */
+    @Parameter(defaultValue="${project.build.directory}/nbm", property="maven.nbm.buildDir")
+    protected File nbmBuildDir;
+
+    /**
+     * a NetBeans module descriptor containing dependency information and more
+     * @deprecated all content from the module descriptor can be defined as plugin configuration now, will be removed in 4.0 entirely
+     */
+    @Parameter(defaultValue="${basedir}/src/main/nbm/module.xml")
+    protected File descriptor;
+
+    /**
+     * maven project
+     */
+    @Parameter(required=true, readonly=true, property="project")
+    private MavenProject project;
+
+    /**
+     * The location of JavaHelp sources for the project. The documentation
+     * itself is expected to be in the directory structure based on codenamebase of the module.
+     * eg. if your codenamebase is "org.netbeans.modules.apisupport", then the actual docs
+     * files shall go to ${basedir}/src/main/javahelp/org/netbeans/modules/apisupport/docs.
+     * Obsolete as of NetBeans 7.0 with &#64;HelpSetRegistration.
+     * @since 2.7
+     */
+    @Parameter(defaultValue="${basedir}/src/main/javahelp")
+    protected File nbmJavahelpSource;
+
+    /**
+     * Path to manifest file that will be used as base and enhanced with generated content. Any entry specified in the original file
+     * will not be overwritten
+     * @since 3.0
+     */
+    @Parameter(required=true, defaultValue="${basedir}/src/main/nbm/manifest.mf")
+    private File sourceManifestFile;
+
+    /**
+     * Path to the generated MANIFEST file to use. It will be used by jar:jar plugin.
+     * @since 3.0
+     */
+    @Parameter(required=true, readonly=true, defaultValue="${project.build.outputDirectory}/META-INF/MANIFEST.MF")
+    private File targetManifestFile;
+
+    /**
+     * Verify the runtime NetBeans module dependencies and Class-Path items
+     * generated from Maven dependencies. The check is done by matching classes used
+     * in current project. Allowed values for the parameter are <code>fail</code>, <code>warn</code> and <code>skip</code>.
+     * The default is <code>fail</code> in which case the validation failure results in a failed build,
+     * in the vast majority of cases the module would fail at runtime anyway.
+     *
+     * @since 3.0
+     */
+    @Parameter(property="maven.nbm.verify", defaultValue="fail")
+    private String verifyRuntime;
+    
+    private static final String FAIL = "fail";
+    private static final String WARN = "warn";
+    private static final String SKIP = "skip";
+
+    /**
+     * A list of module's public packages. If not defined, no packages are exported as public.
+     * Allowed values are single package names
+     * or package names ending with .* which represent the package and all subpackages.
+     * <p/>
+     * Eg. "org.kleint.milos.api" designates just the one package, while "org.kleint.milos.spi.*"
+     * denotes the spi package an all it's subpackages.
+     * @since 3.0
+     */
+    @Parameter
+    private List<String> publicPackages;
+
+    /**
+     * When encountering an OSGi bundle among dependencies, the plugin will generate a direct dependency
+     * on the bundle and will not include the bundle's jar into the nbm. Will only work with NetBeans 6.9+ runtime.
+     * Therefore it is off by default.
+     * WARNING: Additionally existing applications/modules need to check modules wrapping
+     * external libraries for library jars that are also OSGi bundles. Such modules will no longer include the OSGi bundles
+     * as part of the module but will include a modular dependency on the bundle. Modules depending on these old wrappers
+     * shall depend directly on the bundle, eventually rendering the old library wrapper module obsolete.
+     *
+     * @since 3.2
+     */
+    @Parameter(defaultValue="false")
+    private boolean useOSGiDependencies;
+    
+    /**
+     * codename base of the module, uniquely identifying the module within the NetBeans runtime. usually the package name equivalent.
+     * Can include the major release version.
+     * See <a href="http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html#how-manifest"> NetBeans Module system docs</a>
+     * @since 3.8
+     */
+    @Parameter(defaultValue="${project.groupId}.${project.artifactId}")
+    private String codeNameBase;
+    
+    /**
+     * List of explicit module dependency declarations overriding the default specification dependency. Useful when depending on a range of major versions,
+     * depending on implementation version etc.
+     * <p>The format is:
+     * <pre>
+     * &lt;dependency&gt;
+     *    &lt;id&gt;groupId:artifactId&lt;/id&gt;
+     *    &lt;type&gt;spec|impl|loose&lt;/type&gt;
+     *    &lt;explicitValue&gt;the entire dependency token&lt;/explicitValue&gt;
+     * &lt;/dependency&gt;
+     * </pre>
+     * </p>
+     * <p>
+     * where <code>id</code> is composed of grouId and artifactId of a dependency defined in effective pom, separated by double colon. This is mandatory.</p>
+     * <p>
+     * Then there are 2 exclusively optional fields <code>type</code> and <code>explicitValue</code>, if both are defined <code>explicitValue</code> gets applied.
+     * </p>
+     * <p><code>type</code> values: <code>spec</code> means specification dependency.That's the default. 
+     * <code>impl</code> means implementation dependency, only the exact version match will satisfy the constraint. 
+     * <code>loose</code> means loose dependency, no requirement on version, the module just has to be present. Not very common option.
+     * 
+     * @since 3.8
+     */
+    @Parameter
+    private Dependency[] moduleDependencies;
+    
+/**
+     * Deployment type of the module, allowed values are <code>normal</code>,<code>eager</code>,<code>autoload</code>,
+     * <code>disabled</code>.
+     * <p>
+     * <code>autoload</code> - Such a module is
+     * automatically enabled when some other module requires it and
+     * automatically disabled otherwise.</p>
+     *                     <p><code>eager</code> - This module type gets
+     * automatically enabled when all it's dependencies are
+     * satisfied. Disabled otherwise.</p>
+     *                     <p><code>normal</code> - This is the default
+     * value. This kind of module is enabled/disabled manually by
+     * the user. It installs enabled.</p>
+     *                     <p><code>disabled</code> - This kind of module is enabled/disabled manually by
+     * the user. It installs disabled. Since 3.11</p>
+     *
+     * For details, see <a href="http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html#enablement">Netbeans Module system docs</a>
+     * 
+     * Since 3.14, for autoload and eager modules, we automatically set AutoUpdate-Show-In-Client manifest entry to false, if not defined already otherwise in the manifest.
+     * See issue <a href="http://jira.codehaus.org/browse/MNBMODULE-194">MNBMODULE-194</a>
+     * 
+     * @since 3.8 (3.14 in manifest goal)
+     */ 
+    @Parameter(defaultValue="normal")
+    protected String moduleType;    
+
+    // <editor-fold defaultstate="collapsed" desc="Component parameters">
+
+    /**
+     * The artifact repository to use.
+
+     */
+    @Parameter(required=true, readonly=true, defaultValue="${localRepository}")
+    private ArtifactRepository localRepository;
+
+    /**
+     * The artifact factory to use.
+     */
+    @Component
+    private ArtifactFactory artifactFactory;
+
+    /**
+     * The artifact metadata source to use.
+     */
+    @Component
+    private ArtifactMetadataSource artifactMetadataSource;
+
+    /**
+     * The artifact collector to use.
+     */
+    @Component
+    private ArtifactCollector artifactCollector;
+
+    /**
+     * The dependency tree builder to use.
+     */
+    @Component( hint = "default" )
+    private DependencyGraphBuilder dependencyGraphBuilder;
+
+// end of component params custom code folding
+// </editor-fold> 
+
+    /**
+     * execute plugin
+     * @throws MojoExecutionException if an unexpected problem occurs
+     * @throws MojoFailureException if an expected problem occurs
+     */
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+
+    {
+        //need to do this to chekc for javahelp on CP.
+        super.registerNbmAntTasks();
+        NetBeansModule module;
+        if ( descriptor != null && descriptor.exists() )
+        {
+            module = readModuleDescriptor( descriptor );
+            getLog().warn( "descriptor parameter is deprecated, use equivalent mojo parameters instead.");
+        }
+        else
+        {
+            module = createDefaultDescriptor( project, false );
+        }
+        
+        String mtype = moduleType;
+        //same moduleType related code in CreateNetBeansFileStructure.java
+        if ("normal".equals(mtype) && module.getModuleType() != null) {
+            mtype = module.getModuleType();
+            getLog().warn( "moduleType in module descriptor is deprecated, use the plugin's parameter moduleType");
+        }
+        if (!"normal".equals(mtype) && !"autoload".equals(mtype) && !"eager".equals(mtype) && !"disabled".equals(mtype)) {
+            getLog().error( "Only 'normal,autoload,eager,disabled' are allowed values in the moduleType parameter");
+        }
+        boolean autoload = "autoload".equals( mtype );
+        boolean eager = "eager".equals( mtype );
+        
+
+        String moduleName = codeNameBase;
+        if (module.getCodeNameBase() != null) {
+            moduleName = module.getCodeNameBase();
+            getLog().warn( "codeNameBase in module descriptor is deprecated, use the plugin's parameter codeNameBase");
+        }
+        moduleName = moduleName.replaceAll( "-", "." );
+//<!-- if a NetBeans specific manifest is defined, examine this one, otherwise the already included one.
+// ignoring the case when some of the NetBeans attributes are already defined in the jar and more is included.
+        File specialManifest = sourceManifestFile;
+        File nbmManifest = ( module.getManifest() != null ? new File(
+            project.getBasedir(), module.getManifest() ) : null );
+        if ( nbmManifest != null && nbmManifest.exists() )
+        {
+            //deprecated, but if actually defined, will use it.
+            specialManifest = nbmManifest;
+        }
+        ExamineManifest examinator = new ExamineManifest( getLog() );
+        if ( specialManifest != null && specialManifest.exists() )
+        {
+            examinator.setManifestFile( specialManifest );
+            examinator.checkFile();
+        }
+        else
+        {
+//            examinator.setJarFile( jarFile );
+        }
+
+        getLog().info( "NBM Plugin generates manifest" );
+
+        Manifest manifest = null;
+        if ( specialManifest != null && specialManifest.exists() )
+        {
+            Reader reader = null;
+            try
+            {
+                reader = new InputStreamReader( new FileInputStream( specialManifest ) );
+                manifest = new Manifest( reader );
+            }
+            catch ( IOException exc )
+            {
+                manifest = new Manifest();
+                getLog().warn( "Error reading manifest at " + specialManifest, exc );
+            }
+            catch ( ManifestException ex )
+            {
+                getLog().warn( "Error reading manifest at " + specialManifest, ex );
+                manifest = new Manifest();
+            }
+            finally
+            {
+                IOUtil.close( reader );
+            }
+        }
+        else
+        {
+            manifest = new Manifest();
+        }
+        Date date = new Date();
+        String specVersion = AdaptNbVersion.adaptVersion( project.getVersion(),
+            AdaptNbVersion.TYPE_SPECIFICATION, date );
+        String implVersion = AdaptNbVersion.adaptVersion( project.getVersion(),
+            AdaptNbVersion.TYPE_IMPLEMENTATION, date );
+        Manifest.Section mainSection = manifest.getMainSection();
+        conditionallyAddAttribute( mainSection,
+            "OpenIDE-Module-Specification-Version", specVersion );
+        conditionallyAddAttribute( mainSection,
+            "OpenIDE-Module-Implementation-Version", implVersion );
+        if (autoload || eager) { //MNBMODULE-194
+            conditionallyAddAttribute( mainSection, "AutoUpdate-Show-In-Client", "false");
+        }
+        final String timestamp = createTimestamp( date );
+        conditionallyAddAttribute( mainSection, "OpenIDE-Module-Build-Version",
+            timestamp );
+        String projectCNB = conditionallyAddAttribute( mainSection, "OpenIDE-Module", moduleName );
+        String packagesValue;
+        if ( publicPackages != null && publicPackages.size() > 0 )
+        {
+            StringBuilder sb = new StringBuilder();
+            for ( String pub : publicPackages )
+            {
+                if (pub == null) { //#MNBMODULE-237
+                    continue;
+                }
+                if ( pub.endsWith( ".**" ) )
+                {
+                    // well, just sort of wrong value but accept
+                    sb.append( pub );
+                }
+                else if ( pub.endsWith( ".*" ) )
+                {
+                    //multipackage value
+                    sb.append( pub ).append( "*" );
+                }
+                else
+                {
+                    sb.append( pub ).append( ".*" );
+                }
+                sb.append( ", " );
+            }
+            if (sb.length() > 1) { //if only item is null, we have empty builder
+                sb.setLength( sb.length() - 2 ); //cut the last 2 ", " characters
+                packagesValue = sb.toString();
+            } else {
+                // no packages available
+                packagesValue = "-";
+            }
+        }
+        else
+        {
+            // no packages available
+            packagesValue = "-";
+        }
+        conditionallyAddAttribute( mainSection, "OpenIDE-Module-Public-Packages", packagesValue );
+
+        //See http://www.netbeans.org/download/dev/javadoc/org-openide-modules/apichanges.html#split-of-openide-jar
+        conditionallyAddAttribute( mainSection, "OpenIDE-Module-Requires",
+            "org.openide.modules.ModuleFormat1" );
+//        conditionallyAddAttribute(mainSection, "OpenIDE-Module-IDE-Dependencies", "IDE/1 > 3.40");
+        // localization items
+        if ( !examinator.isLocalized() )
+        {
+            conditionallyAddAttribute( mainSection,
+                "OpenIDE-Module-Display-Category", project.getGroupId() );
+            conditionallyAddAttribute( mainSection, "OpenIDE-Module-Name",
+                project.getName() );
+            conditionallyAddAttribute( mainSection,
+                "OpenIDE-Module-Short-Description", shorten( project.getDescription() ) );
+            conditionallyAddAttribute( mainSection,
+                "OpenIDE-Module-Long-Description", project.getDescription() );
+        }
+        getLog().debug( "module =" + module );
+        
+            DependencyNode treeroot = createDependencyTree( project, dependencyGraphBuilder, "compile" );
+            Map<Artifact, ExamineManifest> examinerCache = new HashMap<Artifact, ExamineManifest>();
+            @SuppressWarnings( "unchecked" )
+            List<Artifact> libArtifacts = getLibraryArtifacts( treeroot, module, project.getRuntimeArtifacts(),
+                examinerCache, getLog(), useOSGiDependencies );
+            List<ModuleWrapper> moduleArtifacts = getModuleDependencyArtifacts( treeroot, module, moduleDependencies, project, examinerCache,
+                libArtifacts, getLog(), useOSGiDependencies );
+            StringBuilder classPath = new StringBuilder();
+            StringBuilder mavenClassPath = new StringBuilder();
+            String dependencies = "";
+            String depSeparator = " ";
+
+            for ( Artifact a : libArtifacts )
+            {
+                if (classPath.length() > 0)
+                {
+                    classPath.append(' ');
+                }
+                classPath.append(artifactToClassPathEntry( a, codeNameBase ));
+                if ( mavenClassPath.length() > 0 )
+                {
+                    mavenClassPath.append( ' ' );
+                }
+                mavenClassPath.append( a.getGroupId() ).append( ':' ).append( a.getArtifactId() ).append( ':' ).append( a.getBaseVersion() );
+                if (a.getClassifier() != null) 
+                {
+                    mavenClassPath.append(":").append(a.getClassifier());
+            }
+            }
+
+            for ( ModuleWrapper wr : moduleArtifacts )
+            {
+                if ( wr.transitive )
+                {
+                    continue;
+                }
+                Dependency dep = wr.dependency;
+                Artifact artifact = wr.artifact;
+                ExamineManifest depExaminator = examinerCache.get( artifact );
+                String type = dep.getType();
+                String depToken = dep.getExplicitValue();
+                if ( depToken == null )
+                {
+                    if ( "loose".equals( type ) )
+                    {
+                        depToken = depExaminator.getModuleWithRelease();
+                    }
+                    else if ( "spec".equals( type ) )
+                    {
+                        depToken =
+                            depExaminator.getModuleWithRelease()
+                                + " > "
+                                + ( depExaminator.isNetBeansModule() ? depExaminator.getSpecVersion()
+                                                : AdaptNbVersion.adaptVersion( depExaminator.getSpecVersion(),
+                                                                               AdaptNbVersion.TYPE_SPECIFICATION, date ) );
+                    }
+                    else if ( "impl".equals( type ) )
+                    {
+                        depToken =
+                            depExaminator.getModuleWithRelease()
+                                + " = "
+                                + ( depExaminator.isNetBeansModule() ? depExaminator.getImplVersion()
+                                                : AdaptNbVersion.adaptVersion( depExaminator.getImplVersion(),
+                                                                               AdaptNbVersion.TYPE_IMPLEMENTATION, date ) );
+                    }
+                    else
+                    {
+                        throw new MojoExecutionException(
+                            "Wrong type of NetBeans dependency: " + type + " Allowed values are: loose, spec, impl." );
+                    }
+                }
+                if ( depToken == null )
+                {
+                    //TODO report
+                    getLog().error(
+                        "Cannot properly resolve the NetBeans dependency for " + dep.getId() );
+                }
+                else
+                {
+                    dependencies = dependencies + depSeparator + depToken;
+                    depSeparator = ", ";
+                }
+            }
+            if ( !verifyRuntime.equalsIgnoreCase( SKIP ) )
+            {
+                try
+                {
+                    checkModuleClassPath( treeroot, libArtifacts, examinerCache, moduleArtifacts, projectCNB );
+                }
+                catch ( IOException ex )
+                {
+                    throw new MojoExecutionException( "Error while checking runtime dependencies", ex );
+                }
+            }
+
+            if ( nbmJavahelpSource.exists() )
+            {
+                String moduleJarName = stripVersionFromCodebaseName( moduleName ).replace( ".", "-" );
+                classPath.append( " docs/").append( moduleJarName ).append( ".jar" );
+            }
+
+            if ( classPath.length() > 0 )
+            {
+                conditionallyAddAttribute( mainSection, "X-Class-Path", classPath.toString().trim() );
+            }
+            if ( mavenClassPath.length() > 0)
+            {
+                conditionallyAddAttribute( mainSection, "Maven-Class-Path", mavenClassPath.toString() );
+            }
+            if ( dependencies.length() > 0 )
+            {
+                conditionallyAddAttribute( mainSection, "OpenIDE-Module-Module-Dependencies", dependencies );
+            }
+//            if ( librList.size() > 0 )
+//            {
+//                String list = "";
+//                for ( int i = 0; i < librList.size(); i++ )
+//                {
+//                    list = list + " " + librList.get( i );
+//                }
+//                getLog().warn(
+//                        "Some libraries could not be found in the dependency chain: " + list );
+//            }
+        PrintWriter writer = null;
+        try
+        {
+            if ( !targetManifestFile.exists() )
+            {
+                targetManifestFile.getParentFile().mkdirs();
+                targetManifestFile.createNewFile();
+            }
+            writer = new PrintWriter( targetManifestFile, "UTF-8" ); //TODO really UTF-8??
+            manifest.write( writer );
+        }
+        catch ( IOException ex )
+        {
+            throw new MojoExecutionException( ex.getMessage(), ex );
+        }
+        finally
+        {
+            IOUtil.close( writer );
+        }
+    }
+
+    //MNBMODULE-137
+    static String artifactToClassPathEntry( Artifact a, String codenamebase )
+    {
+        return "ext/" + codenamebase + "/" + a.getGroupId().replace( '.', '-') + "/" + a.getArtifactId() + ( a.getClassifier() != null ? "-" + a.getClassifier() : "" ) + "." + a.getArtifactHandler().getExtension();
+    }
+
+    /**
+     * Create a timestamp for <code>OpenIDE-Module-Build-Version</code> manifest
+     * entry.
+     *
+     * It's created from the current time and formatted using a UTC timezone
+     * explicitly which makes created timestamp timezone-independent.
+     *
+     * @return timestamp represented as <code>201012292045</code>
+     */
+    private static String createTimestamp( Date date )
+    {
+        final SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyyMMddHHmm" );
+        dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
+        final String timestamp = dateFormat.format( date );
+        return timestamp;
+    }
+
+    static String stripVersionFromCodebaseName( String cnb )
+    {
+        // it can happen the moduleName is in format org.milos/1
+        String base = cnb;
+        int index = base.indexOf( '/' );
+        if ( index > -1 )
+        {
+            base = base.substring( 0, index ).trim();
+        }
+        return base;
+    }
+
+    String conditionallyAddAttribute( Manifest.Section section, String key, String value )
+    {
+        Manifest.Attribute attr = section.getAttribute( key );
+        if ( attr == null )
+        {
+            attr = new Manifest.Attribute();
+            attr.setName( key );
+            attr.setValue( value != null ? value.replaceAll("\\s+", " ").trim() : "<undefined>" );
+            try
+            {
+                section.addConfiguredAttribute( attr );
+            }
+            catch ( ManifestException ex )
+            {
+                getLog().error( "Cannot update manifest (key=" + key + ")" );
+                ex.printStackTrace();
+            }
+        }
+        return attr.getValue();
+    }
+
+    /**
+     * Pick out the first sentence of a paragraph.
+     * @param paragraph some text (may be null)
+     * @return the first sentence (may be null)
+     */
+    static String shorten( String paragraph )
+    {
+        if ( paragraph == null || paragraph.length() == 0 )
+        {
+            return null;
+        }
+        BreakIterator breaker = BreakIterator.getSentenceInstance();
+        breaker.setText( paragraph );
+        return paragraph.substring( 0, breaker.following( 0 ) ).trim();
+    }
+
+//----------------------------------------------------------------------------------
+// classpat checking related.
+//----------------------------------------------------------------------------------
+    private void checkModuleClassPath( DependencyNode treeroot,
+        List<Artifact> libArtifacts,
+        Map<Artifact, ExamineManifest> examinerCache, List<ModuleWrapper> moduleArtifacts, String projectCodeNameBase )
+        throws IOException, MojoExecutionException, MojoFailureException
+    {
+        Set<String> deps = buildProjectDependencyClasses( project, libArtifacts );
+        deps.retainAll( allProjectClasses( project ) );
+
+        Set<String> own = projectModuleOwnClasses( project, libArtifacts );
+        deps.removeAll( own );
+        CollectModuleLibrariesNodeVisitor visitor = new CollectModuleLibrariesNodeVisitor(
+            project.getRuntimeArtifacts(), examinerCache, getLog(), treeroot, useOSGiDependencies );
+        treeroot.accept( visitor );
+        Map<String, List<Artifact>> modules = visitor.getDeclaredArtifacts();
+        Map<Artifact, Set<String>> moduleAllClasses = new HashMap<Artifact, Set<String>>();
+
+        for ( ModuleWrapper wr : moduleArtifacts )
+        {
+            if ( modules.containsKey( wr.artifact.getDependencyConflictId() ) )
+            {
+                ExamineManifest man = examinerCache.get( wr.artifact );
+                List<Artifact> arts = modules.get( wr.artifact.getDependencyConflictId() );
+                Set<String>[] classes = visibleModuleClasses( arts, man, wr.dependency, projectCodeNameBase, false );
+                deps.removeAll( classes[0] );
+                moduleAllClasses.put( wr.artifact, classes[1] );
+            }
+        }
+
+        //now we have the classes that are not in public packages of declared modules,
+        //but are being used
+        if ( !deps.isEmpty() )
+        {
+            Map<String, List<Artifact>> transmodules = visitor.getTransitiveArtifacts();
+            for ( ModuleWrapper wr : moduleArtifacts )
+            {
+                if ( transmodules.containsKey( wr.artifact.getDependencyConflictId() ) )
+                {
+                    ExamineManifest man = examinerCache.get( wr.artifact );
+                    List<Artifact> arts = transmodules.get( wr.artifact.getDependencyConflictId() );
+                    Set<String>[] classes = visibleModuleClasses( arts, man, wr.dependency, projectCodeNameBase, true );
+                    classes[0].retainAll( deps );
+                    if ( classes[0].size() > 0 )
+                    {
+                        String module = wr.osgi ? "OSGi bundle" : "module";
+                        getLog().error(
+                            "Project uses classes from transitive " + module + " " + wr.artifact.getId() + " which will not be accessible at runtime." );
+                        getLog().info( "    To fix the problem, add this module as direct dependency. For OSGi bundles that are supposed to be wrapped in NetBeans modules, use the useOSGiDependencies=false parameter");
+                        deps.removeAll( classes[0] );
+                    }
+                    classes[1].retainAll( deps );
+                    if ( classes[1].size() > 0 )
+                    {
+                        getLog().info( "Private classes referenced in transitive module: " + Arrays.toString( classes[1].toArray() ) );
+                        getLog().error(
+                            "Project depends on packages not accessible at runtime in transitive module " + wr.artifact.getId() + " which will not be accessible at runtime." );
+                        deps.removeAll( classes[1] );
+                    }
+                }
+            }
+            for ( Map.Entry<Artifact, Set<String>> e : moduleAllClasses.entrySet() )
+            {
+                List<String> strs = new ArrayList<String>( deps );
+                if ( deps.removeAll( e.getValue() ) )
+                {
+                    strs.retainAll( e.getValue() );
+                    getLog().info( "Private classes referenced in module: " + Arrays.toString( strs.toArray() ) );
+                    getLog().error( "Project depends on packages not accessible at runtime in module " + e.getKey().getId() );
+                }
+            }
+            if ( verifyRuntime.equalsIgnoreCase( FAIL ) )
+            {
+                if ( !deps.isEmpty() )
+                {
+                    throw new MojoFailureException( "Uncategorized problems with NetBeans dependency verification (maybe MNBMODULE-102 or wrong maven dependency metadata). Supposedly external classes are used in the project's binaries but the classes are not found on classpath. Class usages: " + deps );
+                }
+                else
+                {
+                    throw new MojoFailureException( "See above for failures in runtime NetBeans dependencies verification." );
+                }
+            }
+        }
+    }
+
+    /**
+     * The current projects's dependencies, includes classes used in teh module itself
+     * and the classpath libraries as well.
+     * @param project
+     * @param libraries
+     * @return
+     * @throws java.io.IOException
+     */
+    private Set<String> buildProjectDependencyClasses( MavenProject project, List<Artifact> libraries )
+        throws IOException
+    {
+        Set<String> dependencyClasses = new HashSet<String>();
+
+        String outputDirectory = project.getBuild().getOutputDirectory();
+        dependencyClasses.addAll( buildDependencyClasses( outputDirectory ) );
+
+        for ( Artifact lib : libraries )
+        {
+            dependencyClasses.addAll( buildDependencyClasses( lib.getFile().getAbsolutePath() ) );
+        }
+        return dependencyClasses;
+    }
+
+    @SuppressWarnings( "unchecked" )
+    private Set<String> projectModuleOwnClasses( MavenProject project, List<Artifact> libraries )
+        throws IOException
+    {
+        Set<String> projectClasses = new HashSet<String>();
+        DefaultClassAnalyzer analyzer = new DefaultClassAnalyzer();
+
+        String outputDirectory = project.getBuild().getOutputDirectory();
+        URL fl = new File( outputDirectory ).toURI().toURL();
+        projectClasses.addAll( analyzer.analyze( fl ) );
+
+        for ( Artifact lib : libraries )
+        {
+            URL url = lib.getFile().toURI().toURL();
+            projectClasses.addAll( analyzer.analyze( url ) );
+        }
+
+        return projectClasses;
+    }
+
+    /**
+     * complete list of classes on project runtime classpath (excluding
+     * jdk bit)
+     * @param project
+     * @return
+     * @throws java.io.IOException
+     */
+    @SuppressWarnings( "unchecked" )
+    private Set<String> allProjectClasses( MavenProject project )
+        throws IOException
+    {
+        Set<String> projectClasses = new HashSet<String>();
+        DefaultClassAnalyzer analyzer = new DefaultClassAnalyzer();
+
+        String outputDirectory = project.getBuild().getOutputDirectory();
+        URL fl = new File( outputDirectory ).toURI().toURL();
+        projectClasses.addAll( analyzer.analyze( fl ) );
+
+        List<Artifact> libs = project.getRuntimeArtifacts();
+
+        for ( Artifact lib : libs )
+        {
+            URL url = lib.getFile().toURI().toURL();
+            projectClasses.addAll( analyzer.analyze( url ) );
+        }
+
+        return projectClasses;
+    }
+
+    private Set<String>[] visibleModuleClasses( List<Artifact> moduleLibraries,
+        ExamineManifest manifest, Dependency dep, String projectCodeNameBase,
+        boolean transitive)
+        throws IOException, MojoFailureException
+    {
+        Set<String> moduleClasses = new HashSet<String>();
+        Set<String> visibleModuleClasses = new HashSet<String>();
+        DefaultClassAnalyzer analyzer = new DefaultClassAnalyzer();
+        String type = dep.getType();
+        if ( dep.getExplicitValue() != null )
+        {
+            if ( dep.getExplicitValue().contains( "=" ) )
+            {
+                type = "impl";
+            }
+        }
+        if ( type == null || "loose".equals( type ) )
+        {
+            type = "spec";
+        }
+
+        for ( Artifact lib : moduleLibraries )
+        {
+            URL url = lib.getFile().toURI().toURL();
+            moduleClasses.addAll( analyzer.analyze( url ) );
+        }
+
+        if ( "spec".equals( type ) )
+        {
+            String cnb = stripVersionFromCodebaseName( projectCodeNameBase );
+            if ( !transitive && manifest.hasFriendPackages() && !manifest.getFriends().contains( cnb ) )
+            {
+                String message = "Module has friend dependency on " + manifest.getModule() + " but is not listed as a friend.";
+                if ( verifyRuntime.equalsIgnoreCase( FAIL ) )
+                {
+                    throw new MojoFailureException( message );
+                }
+                else
+                {
+                    getLog().warn( message );
+                }
+            }
+            List<Pattern> compiled = createCompiledPatternList( manifest.getPackages() );
+            if ( useOSGiDependencies && manifest.isOsgiBundle() )
+            {
+                // TODO how to extract the public packages in osgi bundles easily..
+                compiled = Collections.singletonList( Pattern.compile( "(.+)" ) );
+            }
+            for ( String clazz : moduleClasses )
+            {
+                for ( Pattern patt : compiled )
+                {
+                    if ( patt.matcher( clazz ).matches() ) 
+                    {
+                        visibleModuleClasses.add( clazz );
+                        break;
+                    }
+                }
+            }
+
+        }
+        else if ( "impl".equals( type ) )
+        {
+            visibleModuleClasses.addAll( moduleClasses );
+        }
+        else
+        {
+            //HUH?
+            throw new MojoFailureException( "Wrong type of module dependency " + type );
+        }
+
+        return new Set[]
+            {
+                visibleModuleClasses,
+                moduleClasses
+            };
+    }
+
+    static List<Pattern> createCompiledPatternList( List<String> packages )
+    {
+        List<Pattern> toRet = new ArrayList<Pattern>();
+        for ( String token : packages )
+        {
+            if ( token.endsWith( ".**" ) )
+            {
+                String patt = "^" + Pattern.quote( token.substring( 0, token.length() - 2 ) ) + "(.+)";
+                toRet.add( 0, Pattern.compile( patt ) );
+            }
+            else
+            {
+                String patt = "^" + Pattern.quote( token.substring( 0, token.length() - 1 ) ) + "([^\\.]+)";
+                toRet.add( Pattern.compile( patt ) );
+            }
+        }
+        return toRet;
+    }
+
+    @SuppressWarnings( "unchecked" )
+    private Set<String> buildDependencyClasses( String path )
+        throws IOException
+    {
+        URL url = new File( path ).toURI().toURL();
+        ASMDependencyAnalyzer dependencyAnalyzer = new ASMDependencyAnalyzer();
+        return dependencyAnalyzer.analyze( url );
+    }
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/RunNetBeansMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/RunNetBeansMojo.java
new file mode 100644
index 0000000..f4a7187
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/RunNetBeansMojo.java
@@ -0,0 +1,251 @@
+/* ==========================================================================
+ * Copyright 2003-2007 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.Os;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+import org.codehaus.plexus.util.cli.StreamConsumer;
+
+/**
+ * Run NetBeans IDE with additional custom module clusters, 
+ * to be used in conjunction with nbm:cluster.
+ * Semi-deprecated; used only for standalone modules and "suites".
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ *
+ */
+@Mojo(name="run-ide", aggregator=true, requiresDependencyResolution= ResolutionScope.RUNTIME )
+public class RunNetBeansMojo
+        extends AbstractMojo
+{
+
+    /**
+     * directory where the module(s)' NetBeans cluster(s) are located.
+     * is related to nbm:cluster goal.
+     */
+    @Parameter(required=true, defaultValue="${project.build.directory}/netbeans_clusters")
+    protected File clusterBuildDir;
+    /**
+     * directory where the the NetBeans platform/IDE installation is,
+     * denotes the root directory of NetBeans installation.
+     */
+    @Parameter(required=true, property="netbeans.installation")
+    protected File netbeansInstallation;
+    /**
+     * NetBeans user directory for the executed instance.
+     */
+    @Parameter(required=true, defaultValue="${project.build.directory}/userdir", property="netbeans.userdir")
+    protected File netbeansUserdir;
+    /**
+     * additional command line arguments. 
+     */
+    @Parameter(property="netbeans.run.params")
+    protected String additionalArguments;
+    
+    /**
+     * Attach a debugger to the application JVM. If set to "true", the process will suspend and wait for a debugger to attach
+     * on port 5005. If set to some other string, that string will be appended to the <code>additionalArguments</code>, allowing you to configure
+     * arbitrary debug-ability options (without overwriting the other options specified through the <code>additionalArguments</code>
+     * parameter).
+     * @since 3.11.1
+     */
+    @Parameter(property="netbeans.run.params.debug")
+    protected String debugAdditionalArguments;    
+
+    /**
+     * 
+     * @throws MojoExecutionException if an unexpected problem occurs
+     * @throws MojoFailureException if an expected problem occurs
+     */
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        netbeansUserdir.mkdirs();
+
+        List<File> clusters = new ArrayList<File>();
+        if ( !clusterBuildDir.exists() || clusterBuildDir.listFiles() == null )
+        {
+            throw new MojoExecutionException(
+                                              "No clusters to include in execution found. Please run the nbm:cluster or nbm:cluster-app goals before this one." );
+        }
+        File[] fls = clusterBuildDir.listFiles();
+        for ( int i = 0; i < fls.length; i++ )
+        {
+            if ( fls[i].isDirectory() )
+            {
+                clusters.add( fls[i] );
+            }
+        }
+        StringBuilder buff = new StringBuilder();
+        for ( File cluster : clusters )
+        {
+            buff.append( cluster.getAbsolutePath() );
+            buff.append( ":" );
+        }
+        if ( buff.lastIndexOf( ":" ) > -1 )
+        {
+            buff.deleteCharAt( buff.lastIndexOf( ":" ) );
+        }
+        //http://www.netbeans.org/issues/show_bug.cgi?id=174819
+        StringReader sr =
+            new StringReader( "netbeans_extraclusters=\"" + buff.toString() + "\"\n" + "extraclusters=\""
+                + buff.toString() + "\"\n" + "extra_clusters=\"" + buff.toString() + "\"" );
+
+        //now check what the exec names are to figure the right XXX.clusters name
+        File binDir = new File( netbeansInstallation, "bin" );
+        File[] execs = binDir.listFiles();
+        String clust = null;
+        if ( execs != null )
+        {
+            for ( File f : execs )
+            {
+                String name = f.getName();
+                if ( name.contains( "_w.exe" ) )
+                {
+                    continue;
+                }
+                name = name.replaceFirst( "(64)?([.]exe)?$", "" );
+                if ( !name.contains( "." ) )
+                {
+                    if ( clust == null )
+                    {
+                        clust = name;
+                    }
+                    else
+                    {
+                        if ( !clust.equals( name ) )
+                        {
+                            getLog().debug( "When examining executable names, found clashing results " + f.getName()
+                                                + " " + clust );
+                        }
+                    }
+                }
+            }
+        }
+        if ( clust == null )
+        {
+            clust = "netbeans";
+        }
+
+        // write XXX.conf file with cluster information...
+        File etc = new File( netbeansUserdir, "etc" );
+        etc.mkdirs();
+        File confFile = new File( etc, clust + ".conf" );
+        FileOutputStream conf = null;
+        try
+        {
+            conf = new FileOutputStream( confFile );
+            IOUtil.copy( sr, conf );
+        }
+        catch ( IOException ex )
+        {
+            throw new MojoExecutionException( "Error writing " + confFile, ex );
+        }
+        finally
+        {
+            IOUtil.close( conf );
+        }
+
+        boolean windows = Os.isFamily( "windows" );
+        Commandline cmdLine = new Commandline();
+        File exec;
+        if ( windows )
+        {
+            exec = new File( netbeansInstallation, "bin\\nb.exe" );
+            if ( !exec.exists() )
+            {
+                // in 6.7 and onward, there's no nb.exe file.
+                exec = new File( netbeansInstallation, "bin\\" + clust + ".exe" );
+                String jdkHome = System.getenv( "JAVA_HOME" );
+                if ( jdkHome != null )
+                {
+                    if ( new File( jdkHome, "jre\\lib\\amd64\\jvm.cfg" ).exists() )
+                    {
+                        File exec64 = new File( netbeansInstallation, "bin\\" + clust + "64.exe" );
+                        if ( exec64.isFile() )
+                        {
+                            exec = exec64;
+                        }
+                    }
+                }
+                cmdLine.addArguments( new String[] { "--console", "suppress" } );
+            }
+        }
+        else
+        {
+            exec = new File( netbeansInstallation, "bin/" + clust );
+        }
+        cmdLine.setExecutable( exec.getAbsolutePath() );
+
+        try
+        {
+            String[] args = new String[]
+            {
+                //TODO --jdkhome
+                "--userdir",
+                netbeansUserdir.getAbsolutePath(),
+                "-J-Dnetbeans.logger.console=true",
+                "-J-ea",
+            };
+            cmdLine.addArguments( args );
+            getLog().info( "Additional arguments=" + additionalArguments );
+            cmdLine.addArguments( CommandLineUtils.translateCommandline( additionalArguments ) );
+            cmdLine.addArguments( CommandLineUtils.translateCommandline( getDebugAdditionalArguments() ) );
+            for ( int i = 0; i < cmdLine.getArguments().length; i++ )
+            {
+                getLog().info( "      " + cmdLine.getArguments()[i] );
+            }
+            getLog().info( "Executing: " + cmdLine.toString() );
+            StreamConsumer out = new StreamConsumer()
+            {
+
+                public void consumeLine( String line )
+                {
+                    getLog().info( line );
+                }
+            };
+            CommandLineUtils.executeCommandLine( cmdLine, out, out );
+
+        }
+        catch ( Exception e )
+        {
+            throw new MojoExecutionException( "Failed executing NetBeans", e );
+        }
+    }
+    
+    private String getDebugAdditionalArguments()
+    {
+       if ( "true".equals( debugAdditionalArguments ) )
+        {
+            return "-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005";
+        }
+        return debugAdditionalArguments;
+    }    
+}
diff --git a/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/RunPlatformAppMojo.java b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/RunPlatformAppMojo.java
new file mode 100644
index 0000000..0d595f2
--- /dev/null
+++ b/nbm-maven-plugin/src/main/java/org/codehaus/mojo/nbm/RunPlatformAppMojo.java
@@ -0,0 +1,187 @@
+/* ==========================================================================
+ * Copyright 2007 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.util.List;
+import java.util.ArrayList;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.Os;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+import org.codehaus.plexus.util.cli.StreamConsumer;
+
+/**
+ * Run a branded application on top of NetBeans Platform. To be used with projects
+ * with nbm-application packaging only and the project needs to be built first.
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ *
+ */
+@Mojo(name="run-platform", requiresDependencyResolution= ResolutionScope.RUNTIME )
+public class RunPlatformAppMojo
+        extends AbstractMojo
+{
+
+    /**
+     * The branding token for the application based on NetBeans platform.
+     */
+    @Parameter(required=true, property="netbeans.branding.token")
+    protected String brandingToken;
+    /**
+     * output directory where the the NetBeans application is created.
+     */
+    @Parameter(required=true, defaultValue="${project.build.directory}")
+    private File outputDirectory;
+
+    /**
+     * NetBeans user directory for the executed instance.
+     */
+    @Parameter(required=true, defaultValue="${project.build.directory}/userdir", property="netbeans.userdir")
+    protected File netbeansUserdir;
+    /**
+     * additional command line arguments passed to the application.
+     * can be used to debug the IDE.
+     */
+    @Parameter(property="netbeans.run.params")
+    protected String additionalArguments;
+    
+    /**
+     * Attach a debugger to the application JVM. If set to "true", the process will suspend and wait for a debugger to attach
+     * on port 5005. If set to some other string, that string will be appended to the <code>additionalArguments</code>, allowing you to configure
+     * arbitrary debug-ability options (without overwriting the other options specified through the <code>additionalArguments</code>
+     * parameter).
+     * @since 3.11
+     */
+    @Parameter(property="netbeans.run.params.debug")
+    protected String debugAdditionalArguments;
+    
+    /**
+     * The Maven Project.
+     *
+     */
+    @Parameter(required=true, readonly=true, property="project")
+    private MavenProject project;
+
+    /**
+     *
+     * @throws MojoExecutionException if an unexpected problem occurs
+     * @throws MojoFailureException if an expected problem occurs
+     */
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        if ( !"nbm-application".equals( project.getPackaging() ) )
+        {
+            throw new MojoFailureException( "The nbm:run-platform goal shall be used within a NetBeans Application project only ('nbm-application' packaging)");
+        }
+
+        netbeansUserdir.mkdirs();
+
+        File appbasedir = new File( outputDirectory, brandingToken );
+
+        if ( !appbasedir.exists() )
+        {
+            throw new MojoExecutionException( "The directory that shall contain built application, doesn't exist ("
+                + appbasedir.getAbsolutePath() + ")\n Please invoke 'mvn install' on the project first" );
+        }
+
+        boolean windows = Os.isFamily( "windows" );
+
+        Commandline cmdLine = new Commandline();
+        File exec;
+        if ( windows )
+        {
+            exec = new File( appbasedir, "bin" + brandingToken + "_w.exe" );
+            if ( !exec.exists() )
+            { // Was removed as of nb 6.7
+                exec = new File( appbasedir, "bin\\" + brandingToken + ".exe" );
+                // if jdk is 32 or 64-bit
+                String jdkHome = System.getenv( "JAVA_HOME" );
+                if ( jdkHome != null )
+                {
+                    if ( new File( jdkHome, "jre\\lib\\amd64\\jvm.cfg" ).exists() )
+                    {
+                        File exec64 = new File( appbasedir, "bin\\" + brandingToken + "64.exe" );
+                        if ( exec64.isFile() )
+                        {
+                            exec = exec64;
+                        }
+                    }
+                }
+                cmdLine.addArguments( new String[] { "--console", "suppress" } );
+            }
+        }
+        else
+        {
+            exec = new File( appbasedir, "bin/" + brandingToken );
+        }
+
+        cmdLine.setExecutable( exec.getAbsolutePath() );
+
+        try
+        {
+
+            List<String> args = new ArrayList<String>();
+            args.add( "--userdir" );
+            args.add( netbeansUserdir.getAbsolutePath() );
+            args.add( "-J-Dnetbeans.logger.console=true" );
+            args.add( "-J-ea" );
+            args.add( "--branding" );
+            args.add( brandingToken );
+
+            // use JAVA_HOME if set
+            if ( System.getenv( "JAVA_HOME" ) != null )
+            {
+                args.add( "--jdkhome" );
+                args.add( System.getenv( "JAVA_HOME" ) );
+            }
+
+            cmdLine.addArguments( args.toArray( new String[0] ) );
+            cmdLine.addArguments( CommandLineUtils.translateCommandline( additionalArguments ) );
+            cmdLine.addArguments( CommandLineUtils.translateCommandline( getDebugAdditionalArguments() ) );
+            getLog().info( "Executing: " + cmdLine.toString() );
+            StreamConsumer out = new StreamConsumer()
+            {
+
+                public void consumeLine( String line )
+                {
+                    getLog().info( line );
+                }
+            };
+            CommandLineUtils.executeCommandLine( cmdLine, out, out );
+        }
+        catch ( Exception e )
+        {
+            throw new MojoExecutionException( "Failed executing NetBeans", e );
+        }
+    }
+
+    private String getDebugAdditionalArguments()
+    {
+       if ( "true".equals( debugAdditionalArguments ) )
+        {
+            return "-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005";
+        }
+        return debugAdditionalArguments;
+    }
+}
diff --git a/nbm-maven-plugin/src/main/mdo/descriptor.mdo b/nbm-maven-plugin/src/main/mdo/descriptor.mdo
new file mode 100644
index 0000000..c9a12ed
--- /dev/null
+++ b/nbm-maven-plugin/src/main/mdo/descriptor.mdo
@@ -0,0 +1,231 @@
+<?xml version="1.0"?>
+
+<model>
+    <id>nbm</id>
+    <name>NetBeansModule</name>
+    <description><![CDATA[Maven's model for the NetBeans module descriptor.]]></description>
+    <defaults>
+        <default>
+            <key>package</key>
+            <value>org.codehaus.mojo.nbm.model</value>
+        </default>
+    </defaults>
+    <classes>
+        <class rootElement="true" xml.tagName="nbm">
+            <name>NetBeansModule</name>
+            <description>Describes the layout, dependencies and packaging of a NetBeans module.</description>
+            <version>1.0.0+</version>
+            <fields>
+                <field>
+                    <name>moduleType</name>
+                    <version>1.0.0+</version>
+                    <description><![CDATA[
+                    <p>DEPRECATED, use the plugin configuration instead. Type of the module. Possible values are </p>
+                    <p><b>autoload</b> - Such a module is automatically enabled when some other module requires it and automatically disabled otherwise.</p>
+                    <p><b>eager</b> - This module type gets automatically enabled when all it's dependencies are satisfied. Disabled otherwise.</p>
+                    <p><b>normal</b> - This is the default value. This kind of module is enabled/disabled manually by the user. It installs enabled.</p>
+                    ]]>        </description>
+                    <type>String</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+                <field>
+                    <name>codeNameBase</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Codenamebase of the module. Primary identification of the module. Usually the package name. Eg. "org.codehaus.mevenide.project". 
+                    If not defined here, the default value is constructed from groupId and artifactId.</description>
+                    <type>String</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+                <field>
+                    <name>cluster</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Each modules should belong to a cluster. A cluster is a group of related modules. For individual modules it's not that important. Refer to netbeans.org documentation for more details.</description>
+                    <type>String</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+                <field>
+                    <name>requiresRestart</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Determines if the module requires restart of the IDE/platform upon installation.</description>
+                    <type>boolean</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+                <field>
+                    <name>manifest</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Location of the manifest file with NetBeans specific manifest entries.
+                        </description>
+                    <type>String</type>
+                    <!--defaultValue>src/main/nbm/manifest.mf</defaultValue-->
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+                <field>
+                    <name>homepageUrl</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Homepage URL of the module. Is accessible from NetBeans UI upon installation, should point to place with additional information about the functionality. If not defined, it defaults to POM's url element.</description>
+                    <type>String</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+                <field>
+                    <name>distributionUrl</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Http URL of the location where the module can be downloaded from the internet. This value put into the NBM and used when generating the Autoupdate Site. Should point directly to the NBM download.</description>
+                    <type>String</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+                <field>
+                    <name>author</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Author of the module. Is used when generating the NBM file.</description>
+                    <type>String</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+        
+                <field>
+                    <name>licenseName</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Name of the license. If the user already agreed to the same license before, he/she won't be asked again to agree.</description>
+                    <type>String</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+                <field>
+                    <name>licenseFile</name>
+                    <version>1.0.0+</version>
+                    <description>DEPRECATED, use the plugin configuration instead. Path to the license agreement file.</description>
+                    <type>String</type>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+        
+                <field>
+                    <name>libraries</name>
+                    <version>1.0.0+</version>
+                    <description>groupId:artifactId of artifacts that shall become part of the module and be added on the classpath 
+                    (ClassPath: manifest entry gets created and the jar is included in the nbm file)</description>
+                    <association>
+                        <type>String</type>
+                        <multiplicity>*</multiplicity>
+                    </association>
+                </field>
+                 <field>
+                    <name>dependencies</name>
+                    <description>DEPRECATED, use the plugin configuration instead. List of module dependencies. The plugin will use it to Generate the OpenIDE-Module-Module-Dependencies manifest entry.</description>
+                    <version>1.0.0+</version>
+                    <association>
+                        <type>Dependency</type>
+                        <multiplicity>*</multiplicity>
+                    </association>
+                </field>
+                <field>
+                    <name>nbmResources</name>
+                    <description>DEPRECATED, use the plugin configuration instead. List of resources that shall be also included into the Nbm file along with the module jar and library jars.</description>
+                    <version>1.0.0+</version>
+                    <association>
+                        <type>NbmResource</type>
+                        <multiplicity>*</multiplicity>
+                    </association>
+                    <annotations>
+                        <annotation>@Deprecated</annotation>
+                    </annotations>
+                </field>
+            </fields>
+        </class>
+        <class>
+            <name>Dependency</name>
+            <description></description>
+            <version>1.0.0+</version>
+            <fields>
+                <field>
+                    <name>id</name>
+                    <description>groupId:artifactId of the dependency defined in the POM (or a transitive dependency)</description>
+                    <version>1.0.0+</version>
+                    <type>String</type>
+                    <required>true</required>
+                </field>
+                <field>
+                    <name>type</name>
+                    <description><![CDATA[
+                        Type of module dependency. 3 possible values allowed.
+                        <p><b>spec</b> - specification dependency, module can only use public APIs in public packages. Works with the version defined and any later version.</p>
+                        <p><b>impl</b> - implementation dependency, module can use any class in the dependency module, but works with just the one version of the module.</p>
+                        <p><b>loose</b> - similar to spec, but isa very loose connection, no version is required, just the module presence.</p>
+                        ]]>
+                    </description>
+                    <version>1.0.0+</version>
+                    <type>String</type>
+                    <defaultValue>spec</defaultValue>
+                </field>
+                <field>
+                    <name>explicitValue</name>
+                    <description><![CDATA[
+                        The plugin tries to resolve the correct module name and module specification/implementation version by examining the
+                        dependency jar's manifest.
+                        You can override this behaviour by explicitly defining the value here. For example org.openide.io/1 &gt; 10.1 for a "spec" type of dependency.
+          
+                        ]]>              
+                    </description>
+                    <version>1.0.0+</version>
+                    <type>String</type>
+                </field>
+            </fields>
+        </class>
+        <class>
+            <name>NbmResource</name>
+            <version>1.0.0+</version>
+            <fields>
+                <field>
+                    <name>baseDirectory</name>
+                    <description>The base directory, all paths within the nbm file will be the same as paths within the base directory.</description>
+                    <version>1.0.0+</version>
+                    <type>String</type>
+                    <required>true</required>
+                </field>
+                <field>
+                    <name>relativeClusterPath</name>
+                    <description>A relative path to be added to cluster root where the files will be copied to.</description>
+                    <version>1.0.0+</version>
+                    <type>String</type>
+                    <required>false</required>
+                </field>
+                <field>
+                    <name>includes</name>
+                    <description>Include pattern, what shall be included in the nbm. </description>
+                    <version>1.0.0+</version>
+                    <association>
+                        <type>String</type>
+                        <multiplicity>*</multiplicity>
+                    </association>
+                </field>
+                <field>
+                    <name>excludes</name>
+                    <description>Exclude pattern, what files within the basedir shall not be included. </description>
+                    <version>1.0.0+</version>
+                    <association>
+                        <type>String</type>
+                        <multiplicity>*</multiplicity>
+                    </association>
+                </field>
+            </fields>
+        </class>
+    </classes>
+</model>
+
diff --git a/nbm-maven-plugin/src/main/resources/META-INF/plexus/components.xml b/nbm-maven-plugin/src/main/resources/META-INF/plexus/components.xml
new file mode 100644
index 0000000..9cbf15a
--- /dev/null
+++ b/nbm-maven-plugin/src/main/resources/META-INF/plexus/components.xml
@@ -0,0 +1,90 @@
+<component-set>
+  <components>
+    <!--component>
+      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+      <role-hint>jar</role-hint>
+      <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+      <configuration>
+        <type>jar</type>
+        <extension>jar</extension>
+      </configuration>
+    </component-->
+    <component>
+      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+      <role-hint>nbm</role-hint>
+      <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+      <configuration>
+        <type>nbm</type>
+        <extension>jar</extension>
+        <packaging>nbm</packaging>
+        <addedToClasspath>true</addedToClasspath>
+        <language>java</language>
+        <includesDependencies>true</includesDependencies>
+      </configuration>
+    </component>
+    <component>
+      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+      <role-hint>nbm-file</role-hint>
+      <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+      <configuration>
+        <type>nbm-file</type>
+        <extension>nbm</extension>
+        <packaging>nbm-file</packaging>
+        <addedToClasspath>false</addedToClasspath>
+        <language>java</language>
+        <includesDependencies>true</includesDependencies>
+      </configuration>
+    </component>
+    <component>
+      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+      <role-hint>nbm-application</role-hint>
+      <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+      <configuration>
+        <type>nbm-application</type>
+        <extension>zip</extension>
+        <packaging>nbm-application</packaging>
+        <addedToClasspath>false</addedToClasspath>
+        <language>java</language>
+        <includesDependencies>false</includesDependencies>
+      </configuration>
+    </component>
+    
+    <component>
+      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
+      <role-hint>nbm</role-hint>
+      <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
+      <configuration>
+        <phases>
+          <process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
+          <compile>org.apache.maven.plugins:maven-compiler-plugin:compile</compile>
+          <process-classes>org.codehaus.mojo:nbm-maven-plugin:manifest</process-classes>
+          <process-test-resources>org.apache.maven.plugins:maven-resources-plugin:testResources</process-test-resources>
+          <test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
+          <test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
+          <package>org.apache.maven.plugins:maven-jar-plugin:jar, 
+                   org.codehaus.mojo:nbm-maven-plugin:branding,
+                   org.codehaus.mojo:nbm-maven-plugin:nbm
+          </package>
+          <install>org.apache.maven.plugins:maven-install-plugin:install</install>
+          <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
+        </phases>
+      </configuration>
+    </component>
+
+    <component>
+      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
+      <role-hint>nbm-application</role-hint>
+      <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
+      <configuration>
+        <phases>
+          <process-test-resources>org.apache.maven.plugins:maven-resources-plugin:testResources</process-test-resources>
+          <test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
+          <package>org.codehaus.mojo:nbm-maven-plugin:cluster-app,org.codehaus.mojo:nbm-maven-plugin:standalone-zip</package>
+          <integration-test>org.apache.maven.plugins:maven-surefire-plugin:test</integration-test>
+          <install>org.apache.maven.plugins:maven-install-plugin:install</install>
+          <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
+        </phases>
+      </configuration>
+    </component>
+  </components>
+</component-set>
diff --git a/nbm-maven-plugin/src/main/resources/branding.jnlp b/nbm-maven-plugin/src/main/resources/branding.jnlp
new file mode 100644
index 0000000..cb788fb
--- /dev/null
+++ b/nbm-maven-plugin/src/main/resources/branding.jnlp
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE jnlp PUBLIC "-//Sun Microsystems, Inc//DTD JNLP Descriptor 6.0//EN" "http://java.sun.com/dtd/JNLP-6.0.dtd">
+<jnlp spec="1.0+" codebase="${jnlp.codebase}">
+  <information>
+      <title>${app.title}</title>
+      <vendor>${app.vendor}</vendor>
+      <description>${app.description}</description>
+  </information>
+  <security><all-permissions/></security>
+  <resources>
+    ${jnlp.branding.jars}
+    ${jnlp.resources}
+  </resources>
+  <component-desc/>
+</jnlp>
\ No newline at end of file
diff --git a/nbm-maven-plugin/src/main/resources/master.jnlp b/nbm-maven-plugin/src/main/resources/master.jnlp
new file mode 100644
index 0000000..c4c0d07
--- /dev/null
+++ b/nbm-maven-plugin/src/main/resources/master.jnlp
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE jnlp PUBLIC "-//Sun Microsystems, Inc//DTD JNLP Descriptor 6.0//EN" "http://java.sun.com/dtd/JNLP-6.0.dtd">
+<jnlp spec="1.0+" codebase="${jnlp.codebase}" href="${master.jnlp.file.name}.jnlp">
+  <information>
+      <title>${app.title}</title>
+      <vendor>${app.vendor}</vendor>
+      <description>${app.description}</description>
+      <offline-allowed/>
+  </information>
+  <security><all-permissions/></security>
+  <resources>
+    <!-- The following property is needed when running with unsigned jars: -->
+    <property name="netbeans.jnlp.fixPolicy" value="${netbeans.jnlp.fixPolicy}"/>
+    <extension name="modules" href="modules.jnlp"/>
+    <java version="1.6+" href="http://java.sun.com/products/autodl/j2se" java-vm-args="${netbeans.run.params}"/>
+    <jar href="startup.jar"/>
+    <property name="netbeans.user" value="${user.home}/.${branding.token}"/>
+  </resources>
+  <resources os="Mac OS X">
+      <property name="netbeans.user" value="${user.home}/Library/Application Support/${branding.token}"/>
+  </resources>
+  <application-desc>
+    <argument>--branding</argument>
+    <argument>${branding.token}</argument>
+  </application-desc>
+</jnlp> 
\ No newline at end of file
diff --git a/nbm-maven-plugin/src/site/apt/buildinstexample.apt b/nbm-maven-plugin/src/site/apt/buildinstexample.apt
new file mode 100644
index 0000000..7df8d19
--- /dev/null
+++ b/nbm-maven-plugin/src/site/apt/buildinstexample.apt
@@ -0,0 +1,128 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ ------
+ Maven 2 NBM Plugin 
+ ------
+ Frantisek Mantlik
+ <frantisek@mantlik.cz>
+ ------
+ 2012-02-12
+
+HOWTO: Customize installers generated by nbm:build-installers
+
+ Generated installers can be customized by providing user-defined 
+ customized templateFile and pass parameters to it with
+ userSettings parameter.
+ See {{{./build-installers-mojo.html}<<<build-installers>>> goal}} description.
+
+ User defined template can be used to modify generated installer
+ behavior, e.g. branding of installation environment etc.
+
+*Example 1: Simple change in installer code
+
+ Simple changes into original Harness installer code can be made by filtering
+ corresponding file using Ant in templateFile.
+
+ Following code added into <<<prepare-sources>>> target takes rid of the "Run application
+ when installer finished" checkbox at the last page of installer wizard:
+
++-----+
+<replace file="${installer.build.dir}/ext/engine/src/org/mycompany/installer/wizard/components/panels/PostInstallSummaryPanel.java" encoding="utf-8">
+    <replacefilter token="runAppNow.doClick();" value="runAppNow.setVisible(false);"/>
+</replace>
++-----+
+
+*Example 2: More complex installer code changes
+
+ If the code changes become more complex better solution is to replace entire
+ Harness files with modified versions.
+
+ For example, you would like to register file associations for your application.
+
+ First of all, prepare your modified version of the file ConfigurationLogic.java
+ according to the instructions at {{{http://wiki.netbeans.org/NBIFileAssosiations}http://wiki.netbeans.org/NBIFileAssosiations}}.
+ 
+ As a next step add a copy task into <<<prepare-sources>>> target in your templateFile:
+
++-----+
+<copy file="${configuration.logic.file}" overwrite="true" tofile="${installer.build.dir}/ext/components/products/helloworld/src/org/mycompany/ConfigurationLogic.java"/>
++-----+
+
+ and finally define <<<configuration.logic.file>>> parameter in the application's pom:
+
++-----+
+<plugin>
+    <groupId>org.codehaus.mojo</groupId>
+    <artifactId>nbm-maven-plugin</artifactId>
+    <configuration>
+        <templateFile>${basedir}/installer/template.xml</templateFile>
+        <userSettings>
+            <configuration.logic.file>${basedir}/installer/ConfigurationLogic.java</configuration.logic.file>
+        </userSettings>
+    </configuration>
+</plugin>
++-----+
+
+*Example 3: Branding of installer images
+
+ If installer left corner image has to be branded,
+ following code can be added to templateFile target
+ <<<prepare-sources>>>:
+
++-----+
+<condition property="ilc.path" value="${nbi.instleftcorner.file}">
+     <and>
+         <isset property="nbi.instleftcorner.file"/>
+         <available file="${nbi.instleftcorner.file}"/>
+     </and>
+</condition>
+<condition property="ilc.defined">
+     <and>
+         <isset property="nbi.instleftcorner.file"/>
+         <available file="${nbi.instleftcorner.file}"/>
+     </and>
+</condition> 
+<antcall target="-prepare-ilc"/>
++-----+
+
+ In addition, new target <<<-prepare-ilc>>> has to be defined, e.g. at the end of templateFile:
+
++-----+
+<target name="-prepare-ilc" if="ilc.defined">
+    <copy file="${ilc.path}" tofile="${installer.build.dir}/ext/engine/src/org/mycompany/installer/wizard/wizard-description-background-left.png" overwrite="true"/>
+</target>
++-----+
+
+ which effectively replaces the desired image.
+
+ Finally, update application's pom:
+
++-----+
+<plugin>
+    <groupId>org.codehaus.mojo</groupId>
+    <artifactId>nbm-maven-plugin</artifactId>
+    <configuration>
+        <templateFile>${basedir}/installer/template.xml</templateFile>
+        <userSettings>
+            <nbi.instleftcorner.file>${basedir}/installer/ilc.png</nbi.instleftcorner.file>
+        </userSettings>
+    </configuration>
+</plugin>
++-----+
+
+ More information: {{{http://wiki.netbeans.org/NBI}http://wiki.netbeans.org/NBI}}
diff --git a/nbm-maven-plugin/src/site/apt/descriptor.apt b/nbm-maven-plugin/src/site/apt/descriptor.apt
new file mode 100644
index 0000000..8af0158
--- /dev/null
+++ b/nbm-maven-plugin/src/site/apt/descriptor.apt
@@ -0,0 +1,111 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ ------
+ Maven 2 NBM Plugin 
+ ------
+ Milos Kleint
+ <mkleint@codehaus.org>
+ ------
+ 2007-06-15
+
+Example nbm descriptors - since 3.8 DEPRECATED.
+
+ These descriptors are referenced from the {{{./nbm-mojo.html}nbm:nbm}} mojo. The descriptor file is deprecated since version 3.8.
+ 
+*Usual case
+
+ A rather common module descriptor. Basic properties filled in, defines some libraries that ship with the module and
+ declared dependencies on other NetBeans modules.
+
++-----+
+<nbm>
+   <moduleType>normal</moduleType>
+   <codeNameBase>org.codehaus.mevenide.netbeans/2</codeNameBase>
+   <cluster>mevenide</cluster>
+   <manifest>src/main/nbm/manifest.mf</manifest>
+   <!-- distributionUrl important when creating an autoupdate center. The expected download URL for the module is:
+            ${distributionUrl}/${finalName}.nbm
+     -->
+   <distributionUrl>http://mevenide.codehaus.org/nbm_release2</distributionUrl>
+   <licenseName>Apache License, Version 2.0</licenseName>
+   <licenseFile>license.txt</licenseFile>
+   <libraries>
+       <!-- these dependencies get copied to modules/ext directory in the mevenide cluster and
+            get referenced from the module's jar usign the Class-Path manifest entry. 
+            Not necessary since 2.5 version of nbm-maven-plugin
+         -->
+       <library>org.netbeans.api:org-netbeans-graph</library>
+       <library>org.netbeans.api:org-netbeans-graph-vmd</library>
+   </libraries>
+   <dependencies>
+      <!-- all of these dependencies get referrenced as module dependencies of this project's artifact. 
+        Not necessary since 2.5 version of nbm-maven-plugin
+        -->
+      <dependency>
+          <id>org.codehaus.mevenide:run-jar-bridge</id>
+      </dependency>
+      <dependency>
+          <id>org.codehaus.mevenide:debugger-bridge</id>
+      </dependency>
+      <dependency>
+          <id>org.netbeans.api:org-netbeans-api-debugger-jpda</id>
+      </dependency>
+      <dependency>
+          <id>org.netbeans.api:org-netbeans-api-debugger</id>
+      </dependency>
+      <dependency>
+          <id>org.netbeans.api:org-netbeans-modules-options-api</id>
+      </dependency>
+      <dependency>
+          <id>org.netbeans.api:org-openide-io</id>
+      </dependency>
+      <dependency>
+          <id>org.netbeans.api:org-openide-modules</id>
+      </dependency>
+   </dependencies> 
+</nbm>
++-----+
+
+*Additional custom files in module
+
+ Apart from the usual properties, this one declares additional files that ought to be packed into the module.
+
++-----+
+<nbm>
+   <moduleType>eager</moduleType>
+   <codeNameBase>org.codehaus.mevenide.netbeans.nbrepo/2</codeNameBase>
+   <cluster>mevenide</cluster>
+   <manifest>src/main/nbm/manifest.mf</manifest>
+   <distributionUrl>http://mevenide.codehaus.org/nbm_release2</distributionUrl>
+   <licenseName>Apache License, Version 2.0</licenseName>
+   <licenseFile>license.txt</licenseFile>
+   <dependencies>
+       <dependency>
+           <id>org.codehaus.mevenide:nb-project</id>
+       </dependency>
+   </dependencies> 
+   <nbmResources>
+       <nbmResource>
+           <baseDirectory>../ide-mojos/target</baseDirectory>
+           <includes>
+               <include>m2-repository/**</include>
+           </includes>
+       </nbmResource>
+   </nbmResources>
+</nbm>
++-----+
diff --git a/nbm-maven-plugin/src/site/apt/index.apt.vm b/nbm-maven-plugin/src/site/apt/index.apt.vm
new file mode 100644
index 0000000..088b17d
--- /dev/null
+++ b/nbm-maven-plugin/src/site/apt/index.apt.vm
@@ -0,0 +1,321 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License. 
+
+ ------
+ Maven 2 NBM Plugin 
+ ------
+ Milos Kleint
+ <mkleint@codehaus.org>
+ ------
+ 2010-11-04
+
+NetBeans Module plugin
+
+ This m2 plugin is able to create NetBeans module(plugin) artifacts. It registers a new packaging type <<<nbm>>>. Any project with
+this packaging will be automatically turned into a NetBeans module project. Additionally it allows to create clusters of modules, generate
+an autoupdate site content or build and assemble an application on top of NetBeans platform.
+
+ Note: The <<<nbm:populate-repository>>> goal has been moved to it's own plugin {{{../nb-repository-plugin/index.html}nb-repository-plugin}}.
+
+ To get access to a repository with NetBeans.org module artifacts and metadata, add {{{http://bits.netbeans.org/maven2/}http://bits.netbeans.org/maven2/}} repository to your project POM
+or the repository manager you are using. The repository hosts binaries of NetBeans 6.5 and later.
+
+ Also see: {{{http://wiki.netbeans.org/NetBeansDeveloperFAQ#Mavenized_Builds}Maven NBM development FAQs}}
+
+ Sample <<<pom.xml>>> excerpts for creation of a NetBeans module:
+
++-----+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>example-netbeans-module</artifactId>
+  <groupId>org.mycompany.myproject</groupId>
+  <!--here is the packaging and lifecycle defined-->
+  <packaging>nbm</packaging>
+
+....
+  <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+                <version>${project.version}</version>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin> <!-- required since nbm-plugin 3.0-->
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.0.2</version>
+                <configuration>
+                    <archive>
+                        <manifestFile>#[[${project.build.outputDirectory}]]#/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+  </build>
+
+ ....
+    <!-- this section is important only to access the binaries of NetBeans that you use as dependencies -->
+    <repositories>
+        <repository>
+            <id>netbeans</id>
+            <name>repository hosting netbeans.org api artifacts</name>
+            <url>http://bits.netbeans.org/maven2/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
++-----+
+
+ To build the project then, just type
+
++-------------------------------------------------------------------------------+
+mvn install
++-------------------------------------------------------------------------------+
+
+
+Maven Dependency vs. NetBeans runtime dependency
+
+ There are important differences between Maven's dependency mechanism and NetBeans runtime dependencies.
+Maven's dependencies are transitive, so at compile time you get not only direct dependencies you declared, but also
+dependencies of dependencies etc. In NetBeans, the module dependencies are non-transitive by nature, you have to explicitly declare all at runtime.
+Additionally next to module dependencies there are also library jars attached and shipped with the module's main artifact.
+In the NetBeans terminology there is a special sort of modules called "library wrappers". These library wrappers
+add the libraries on the module's classpath and allow other modules to depend on the libraries within the IDE's runtime.
+
+ The ways in which the nbm-maven-plugin tries to adress these issues has changed over time.
+
+ The plugin walks the dependency tree to detect and identify module dependencies
+and classpath libraries.
+
+  A maven dependency is turned into a NetBeans runtime dependency when:
+
+    * for NetBeans module dependencies (dependency jars that have the NetBeans specific entries in META-INF/MANIFEST.MF)
+
+        * It's a direct dependency (non-transitive) and is a NetBeans module itself. Preferred way of declaring
+module dependencies. 
+
+        * It's defined in existing (though optional) module.xml file in <<<dependencies>>> section.
+Try to avoid this, but still useful if one wants to put an explicit dependency value on the module, or use implementation dependency.
+
+        * When the dependency is of type <<<nbm>>>. Deprecated in 3.0.x, only helpful in older versions.
+Such dependencies don't include their transitive deps on compilation classpath.
+That should allow one to simulate the rumtime dependencies at compilation time in maven, however there's one major drawback. Not only are the nbm's module dependencies hidden, but the libraries associated with the
+given nbm module are also hidden. So you can end up with less stuff on classpath  as opposed to more stuff with <<<jar typed dependencies>>>.
+
+    * for module libraries (jars that are packed together with the module and appear on it's classpath directly, not by a dependency relationship.)
+
+        * It's a direct dependency and is not of <<<provided>>> scope.
+
+        * It's a transitive dependency, pulled in by a direct dependency (only non-module one - see first bullet) This is new in <<3.0+>>
+
+        * It's defined in existing (though optional) module.xml file in <libraries> section. Consider this deprecated in <<3.0+>>.
+
+
+ The complete {{{./nbm.html}nbm descriptor format}} documentation, and {{{./descriptor.html}example descriptors}} are also available. 
+Please note that since 3.8 version, the descriptor is deprecated and replaced by plugin configuration parameters.
+
+ Additionally we perform dependency analysis in order to warn the user when runtime dependencies are wrong.
+So project's own classes and it's classpath libraries' classes are checked against the module dependencies
+(with appropriate filtering for public packages/private packages).
+If the classes depend on declared module dependency's private classes or on transitive module dependency's classes,
+the build fails. That should prevent ClassNotFoundException's later at runtime, when the NetBeans module
+system constructs the classpath for the module based on our metadata generated.
+
+Using OSGi bundles in NetBeans platform based applications
+
+ Starting with version <<3.2>>, it's possible for the NetBeans modules to depend on OSGi bundles. A proper module dependency section will be generated.
+To include the bundle in the application, add dependency on the bundle from nbm-application.
+There are a few prerequisites.
+
+   * It works only in NetBeans 6.9 and later which support the embedding of bundles at runtime
+
+   * Add <<<\<useOSGiDependencies\>true\</useOSGiDependencies\>>>> configuration entry to all the modules depending on OSGi bundles.
+     Existing applications/modules need to check modules wrapping
+     external libraries for library jars that are also OSGi bundles. Such modules will no longer include the OSGi bundles
+     as part of the module NBM but will include a modular dependency reference on the bundle only. Modules depending on these old wrapper modules
+     shall depend directly on the bundle, eventually rendering the old library wrapper module obsolete.
+
+   * in the distribution, all bundles will be included in the default cluster (<<<extra>>> if not configured otherwise), 
+    in <<3.10 and later>> the plugin will attempt to guess the cluster based on modules depending on it.
+
+   * Before version <<3.10>> all bundles will be autoload, thus requiring at least one depending regular module to enable them. In <<3.10 and later>>, developers of the OSGi bundles
+     can influence the autoload vs regular behaviour by adding <<Nbm-Maven-Plugin-Autoload>> attribute to the bundle's manifest with "true" or "false" values. 
+     False means the module will be enabled on start, even without any other modules depending on it.
+
+
+Multi module setup
+
+ If you have a set of NetBeans modules, or are building on top of NetBeans Platform,
+you will make use of the additional goals provided by the plugin.
+
+ If you are building a Platform-based application, use a project
+with <<<nbm-application>>> packaging to perform the final application assembly.
+This packaging type (defined in nbm-maven-plugin) should have your module projects
+and all dependencies of the target NetBeans Platform included as dependencies.
+
+ For the NetBeans Platform/IDE modules, there are artifacts that aggregate modules in clusters.
+These are put in the <<<org.netbeans.clusters>>> groupId (on <<<bits.netbeans.org>>> or in your own repository).
+The following snippet will include the basic NetBeans platform cluster and your own
+module in the application. You can use standard dependency exclusion lists to cut out modules from the Platform that
+you don't need.
+
++-----+
+    <artifactId>application</artifactId>
+    <packaging>nbm-application</packaging>
+    <version>1.0-SNAPSHOT</version>
+    <dependencies>
+        <dependency>
+            <groupId>org.netbeans.cluster</groupId>
+            <artifactId>platform8</artifactId>
+            <version>${netbeans.version}</version>
+            <type>pom</type>
+        </dependency>
+        <dependency>
+            <groupId>com.mycompany</groupId>
+            <artifactId>module1</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+    ....
++-----+
+
+ The nbm-application project/packaging defines a build lifecycle that creates a final application
+from the NBM files in local/remote repotories and bundles them in a ZIP file (also uploadable to the repository).
+In addition to that you can configure the project to generate an autoupdate site and/or
+webstartable binaries of the applications (typically in a deployment profile):
+
++-----+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>extra</id>
+                        <goals>
+                            <goal>autoupdate</goal>
+                            <goal>webstart-app</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
++-----+
+
+ See the {{{./autoupdate-mojo.html}autoupdate}} and {{{./webstart-app-mojo.html}webstart-app}} goals
+for more details.
+
++-------------------------------------------------------------------------------+
+mvn nbm:cluster
++-------------------------------------------------------------------------------+
+
+ This goal aggregates output of multiple NetBeans module projects and creates one 
+or more clusters in the current project. So usually one runs this goal on the parent POM project,
+which aggregates the content of all its modules. 
+The resulting cluster structure can later be used for running the application, creating an installer or similar.
+A variant of this goal is also included in the nbm-application project's default lifecycle.
+
++-------------------------------------------------------------------------------+
+mvn nbm:branding
++-------------------------------------------------------------------------------+
+
+ Branding is to used when one builds an application based on NetBeans Platform (as opposed to creating set of modules for the IDE).
+Branding contains all the resources that are to be changed in the platform binaries (resource bundles, images, HTML files etc.) 
+to give the application its unique look.
+
+ This goal can be attached to one of the nbm module projects that will be part of the
+NetBeans Platform-based application.
+
+ For more detailed tutorial, check the {{{http://netbeans.dzone.com/videos/screencast-maven-and-netbeans}Screencast: Maven and the NetBeans Platform}}
+video recorded by Fabrizio Giudici. It describes to Fabrizio's open source project {{{http://kenai.com/projects/forceten}ForceTen}} which can be used as reference setup for Maven NetBeans Platform based apps.
+
+ The branding is included as part of a regular nbm subproject and cannot be attached to a <<<pom>>> packaged root project.
+
++-------------------------------------------------------------------------------+
+mvn nbm:run-ide nbm:run-platform
++-------------------------------------------------------------------------------+
+ 
+ These two goals do almost the same, they allow you to execute your projects content within
+the IDE or NetBeans platform.
+
+ <<<nbm:run-platform>>> only makes sense to execute on projects with <<<nbm-application>>> packaging.
+
+ For more information on plugin configuration and customization, see {{{./plugin-info.html}goal documentation}}.
+
+
+Public packages declaration
+
+ By default all your module's packages (and classes) and private to the given module. If you want to expose
+any API to other modules, you will need to declare those public packages in your <<<pom.xml>>>. This includes
+not only your own classes but also any other 3rd party library classes that are packaged with your module
+and are to be exposed for reuse by other modules.
+
+ For example:
+
++-----+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+                <version>${project.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                   <publicPackages>
+                       <publicPackage>org.foo.api</publicPackage>
+                       <publicPackage>org.apache.commons.*</publicPackage>
+                   </publicPackages>
+                </configuration>
+            </plugin>
++-----+
+
+ there is a package <<<org.foo.api>>> made public (but not <<<org.foo.api.impl>>> package) and
+any package starting with <<<org.apache.commons>>>, so both <<<org.apache.commons.io>>> and <<<org.apache.commons.exec>>> packages are exposed to the outside
+
+
+
+Archetypes anyone?
+ 
+ There are two basic archetypes:
+
+ The first once creates a single project preconfigured to be a NetBeans module. Use this
+one if you are developing a NetBeans IDE module, or a module for a NetBeans Platform-based application.
+
++-------------------------------------------------------------------------------+
+mvn -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=nbm-archetype -DarchetypeVersion=... \
+  -DgroupId=org.kleint -DartifactId=milos -Dversion=1.0 archetype:generate
++-------------------------------------------------------------------------------+
+
+ The second one creates a parent POM project containing configuration and application branding for your NetBeans Platform-based application.
+
++-------------------------------------------------------------------------------+
+mvn -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=netbeans-platform-app-archetype \
+  -DarchetypeVersion=... -DgroupId=org.kleint -DartifactId=milos -Dversion=1.0 archetype:generate
++-------------------------------------------------------------------------------+
+
+IDE support
+
+ The NetBeans IDE has Maven support. Among other features, it
+contains additional support for working with NetBeans module projects. The support includes file templates,
+important nodes in projects view, running module(s) in the IDE or Platform.
+
+Sample real life application
+
+ Check the {{{http://netbeans.dzone.com/videos/screencast-maven-and-netbeans}Screencast: Maven and the NetBeans Platform}}
+video recorded by Fabrizio Giudici. It describes to Fabrizio's open source project {{{http://kenai.com/projects/forceten}ForceTen}} which can be used as reference setup for Maven NetBeans Platform based apps.
diff --git a/nbm-maven-plugin/src/site/apt/upgrade.apt b/nbm-maven-plugin/src/site/apt/upgrade.apt
new file mode 100644
index 0000000..11b0813
--- /dev/null
+++ b/nbm-maven-plugin/src/site/apt/upgrade.apt
@@ -0,0 +1,144 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ ------
+ Maven 2 NBM Plugin 
+ ------
+ Milos Kleint
+ <mkleint@codehaus.org>
+ ------
+ 2007-06-15 Sep 30, 2008  Jun 15, 2007
+
+
+HOW TO: Migrate from older version of the plugin
+
+
+  {{{Upgrading_to_3.9} Upgrading to 3.9}}
+
+  {{{Upgrading_to_3.8} Upgrading to 3.8}}
+
+  {{{Upgrading_from_2.6_version_to_3.0} Upgrading from 2.6 to 3.0}}
+
+  {{{Upgrading_from_2.4_version_to_2.5} Upgrading from 2.4 to 2.5}}
+
+{Upgrading to 3.9}
+
+ In 3.9, the <<<populate-repository>>> goal is moved to separate plugin.
+
+{Upgrading to 3.8}
+
+ In 3.8 the <<<descriptor>>> parameter is deprecated and is replaced by equivalent plugin parameters. 
+The values from descriptor are still applied, warnings are printed. In future releases the parameter will be removed.
+
+{Upgrading from 2.6 version to 3.0}
+
+ There are a few significant incompatible changes introduced in <<3.0's>> version of
+NBM packaging lifecycle. The result should be easier to setup builds and better support for building
+NetBeans platform based applications.
+
+   * The lifecycle mappings have changed. There is no more <<<nbm:jar>>> goal and
+it was replaced by <<<nbm:manifest>>> which is executed at different phase, namely <<<process-classes>>>, right after
+the module's classes are compiled.
+
+ <<Important>>: In order to have maven-jar-plugin to pick up the generated manifest, you need to add the following
+configuration snippet to your projects with <<<nbm>>> packaging.
+
++-----+
+    <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>3.0.2</version>
+        <configuration>
+            <archive>
+                <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+            </archive>
+        </configuration>
+    </plugin>
++-----+
+
+   * The project's dependencies that shall end up on <<Class-Path>> of the module and
+now processed transitively. In earlier versions, you had to either explicitly list
+all such items in the pom as direct dependencies, or list them in the module descriptor.
+Only transitive dependencies that descend from non-NetBeans module direct dependencies are
+included, eg. if you depend on module that includes Apache's commons-httpclient, the library will not
+be included (unless defined in your project directly). Possible trouble makers are transitive depedencies that are
+defined both in a dependening module and a regular jar dependency. Based on Maven dependency tree resolution,
+the binary could end up on the <<Class-Path>> or not. The resolution to the problem is to define
+The troubled dependency directly and either define the scope as <<<provided>>> if you don't want it included in <<Class-Path>>,
+or keep the default <<<compile>>> scope if you want.
+
+   * NBM file is always generated for any NetBeans module project. You can skip the NBM file
+generation by setting the parameter to nbm:nbm goal, but please be aware that having NBM files in local and
+remote repositories is crucial for the new tools that create a NetBeans Platform based application
+binaries.
+
+   * In previous versions the ultimate final binary for the platform based application,
+ was a directory with the cluster(s) of modules. Now a new packaging is defined <<<nbm-application>>> that
+allows for creating a final application zip file, webstartable jnlp files, and an update site.
+All are constructed solely from the repository content (assuming all relevant modules have NBM files in repositories)
+and the primary project for the binaries is the <<<nbm-application>>> packaging project, unlike in previous versions
+where the root pom was the primary project and required all included modules to be built as part of the reactor
+in the same build.
+
+   * The <<<nbm:manifest>>> goal besides generating the manifest, will also check if the runtime dependencies
+match the actual classes being used in the project and it's libraries on <<Class-Path>>. That's analogous to
+the {{{http://maven.apache.org/plugins/maven-dependency-plugin/analyze-mojo.html}<<<dependency:analyze>>>}}
+goal but takes the NetBeans module system constraints into account (non-transitivity of module dependencies,
+public vs. private packages constraint etc)
+
+   * The previous versions didn't define the <<<OpenIDE-Module-Public-Packages>>> entry in the manifest file.
+The result was a deprecated state that made all classes publicly accessible from other modules
+and printed a warning to the application's log file. In <<3.0>>, we introduced a new optional parameter <<<publicPackages>>>
+that lists all public packages in the module. If not defined, no package is exported as public. See
+{{{https://github.com/mojohaus/nbm-maven-plugin/issues/3}issue}} for details. If you have previously
+placed the <<OpenIDE-Module-Public-Packages>> entry in the manifest file manually, it will not be overriden by the new parameter.
+
+=======================================================================
+
+{Upgrading from 2.4 version to 2.5}
+
+ There are  significant changes in how NetBeans module system dependencies are mapped to maven's own 
+dependencies model. The <<2.4>> and older version all module system deps had to be explicitly defined in the module descriptor at <<<src/main/nbm/module.xml>>>.
+That is no longer a requirement in <<2.5>> for most cases. The plugin will try to decide based on the declaration
+in maven POM file. 
+ 
+ These are the rules:
+
+    * for NetBeans module dependencies (jars that have the NetBeans specific entries in META-INF/MANIFEST.MF)
+
+        * It's defined in existing (though optional) <<<module.xml>>> file in <<<dependencies>>> section.
+
+        * It's a direct dependency (non-transitive) and is a NetBeans module.
+
+        * When the dependency is of type <<<nbm>>>. Such dependencies don't include their transitive deps on compilation classpath.
+
+    * for module libraries (jars that are packed together with the module and appear on it's classpath directly, not by a dependency relationship.)
+
+        * It's defined in existing (though optional) <<<module.xml>>> file in <<<libraries>>> section
+
+        * It's a direct dependency (non-transitive) and is not of <<<provided>>> scope.
+
+ So if you have used <<2.4>> and older before, you need to check your dependencies when upgrading to <<2.5>>.
+
+    * The <<2.5>> plugin can pick up and declare more module dependencies than the previous version. Module dependencies are safe. 
+You either declared them in your <<<module.xml>>> file. Some additional ones can appear if you have them as direct dependencies in your pom.
+Use the {{{http://maven.apache.org/plugins/maven-dependency-plugin/analyze-mojo.html}<<<dependency:analyze>>>}} goal to check for used/unused direct dependencies.
+
+    * The <<2.5>> plugin can also pick up and declare more module libraries. That's something to watch out for! That happens again only when you declared the jars as direct dependencies.
+You could end up with a single jar being added to multiple modules and get runtime classpath issues and of course your download size 
+will get higher than necessary. Again the {{{http://maven.apache.org/plugins/maven-dependency-plugin/analyze-mojo.html}<<<dependency:analyze>>>}} goal shall help. If you know the jar is required but is provided by a module you depend on, use the <<<provided>>> scope to prevent inclusion.
+
diff --git a/nbm-maven-plugin/src/site/resources/masterjnlp.txt b/nbm-maven-plugin/src/site/resources/masterjnlp.txt
new file mode 100644
index 0000000..3d506a9
--- /dev/null
+++ b/nbm-maven-plugin/src/site/resources/masterjnlp.txt
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE jnlp PUBLIC "-//Sun Microsystems, Inc//DTD JNLP Discriptor 1.5//EN" "http://java.sun.com/dtd/JNLP-1.5.dtd">
+<jnlp spec="1.0+" codebase="${jnlp.codebase}">
+  <information>
+      <title>${app.title}</title>
+      <vendor>${app.title} vendor</vendor>
+      <description>${app.name} application</description>
+      <icon href="${app.icon}"/>
+  </information>
+  <security><all-permissions/></security>
+  <resources>
+    <!-- The following property is needed when running with unsigned jars: -->
+    <property name="netbeans.jnlp.fixPolicy" value="${netbeans.jnlp.fixPolicy}"/>
+    <extension name='branding' href='branding.jnlp' />
+    <j2se version="1.5+"/>
+    <jar href="startup.jar"/>
+    <property name="netbeans.user" value="${user.home}/.${branding.token}"/>
+
+<!-- The following line will be replaced with an automatically generated list of resources: -->
+    ${jnlp.resources}
+  </resources>
+  <resources os="Mac OS X">
+      <property name="netbeans.user" value="${user.home}/Library/Application Support/${branding.token}"/>
+  </resources>
+  <application-desc>
+    <argument>--branding</argument>
+    <argument>${branding.token}</argument>
+  </application-desc>
+</jnlp> 
\ No newline at end of file
diff --git a/nbm-maven-plugin/src/site/site.xml b/nbm-maven-plugin/src/site/site.xml
new file mode 100644
index 0000000..f632f8d
--- /dev/null
+++ b/nbm-maven-plugin/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+-->
+<project xmlns="http://maven.apache.org/DECORATION/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd">
+  <body>
+    <menu name="Overview">
+      <item name="Usage" href="index.html"/>
+      <item name="Plugin Goals" href="plugin-info.html"/>
+      <!-- <item name="Javadoc" href="apidocs/index.html"/> -->
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+    <!--<menu name="Upgrade">   
+      <item name="2.4 -> 2.5 upgrade" href="2425upgrade.html"/>
+      <item name="2.6 -> 3.0 upgrade" href="2630upgrade.html"/>
+    </menu>-->
+    <menu name="HOWTOs ">
+      <item name="Customize installers" href="buildinstexample.html"/>
+      <item name="Upgrade from older versions" href="upgrade.html"/>
+    </menu>
+    <menu name="Deprecated">
+      <item name="Descriptor Format" href="nbm.html"/>
+      <item name="Example Descriptor" href="descriptor.html"/>
+    </menu>
+  </body>
+</project>
+
diff --git a/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/AbstractNbmMojoTest.java b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/AbstractNbmMojoTest.java
new file mode 100644
index 0000000..f66bd9b
--- /dev/null
+++ b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/AbstractNbmMojoTest.java
@@ -0,0 +1,268 @@
+/*
+ *  Copyright 2008 mkleint.
+ * 
+ *  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.
+ *  under the License.
+ */
+
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import junit.framework.TestCase;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugin.logging.SystemStreamLog;
+import org.apache.maven.shared.dependency.graph.DependencyNode;
+import org.apache.maven.shared.dependency.graph.internal.DefaultDependencyNode;
+import org.codehaus.mojo.nbm.model.Dependency;
+import org.codehaus.mojo.nbm.model.NetBeansModule;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+
+/**
+ *
+ * @author mkleint
+ */
+public class AbstractNbmMojoTest extends TestCase {
+    Log log = null;
+    DefaultDependencyNode treeRoot = null;
+    
+    public AbstractNbmMojoTest(String testName) {
+        super(testName);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        log = new SystemStreamLog();
+        treeRoot = createNode(null, "root", "root", "1.0", "jar", "", true, new ArrayList<Artifact>(), new HashMap<Artifact,ExamineManifest>());
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Test of matchesLibrary method, of class AbstractNbmMojo.
+     */
+    public void testMatchesLibrary() {
+        System.out.println("matchesLibrary");
+        Artifact artifact = createArtifact("group", "artifact", "1.0", "jar", "compile");
+        List<String> libraries = new ArrayList<String>();
+        libraries.add("group:artifact");
+        ExamineManifest depExaminator = createNonModule();
+        boolean result = AbstractNbmMojo.matchesLibrary(artifact, libraries, depExaminator, log, false);
+        assertTrue("explicitly defined libraries in descriptor are included", result);
+
+        artifact = createArtifact("group", "artifact", "1.0", "jar", "provided");
+        libraries = new ArrayList<String>();
+        result = AbstractNbmMojo.matchesLibrary(artifact, libraries, depExaminator, log, false);
+        assertFalse("provided artifacts are not included", result);
+
+        artifact = createArtifact("group", "artifact", "1.0", "jar", "system");
+        libraries = new ArrayList<String>();
+        result = AbstractNbmMojo.matchesLibrary(artifact, libraries, depExaminator, log, false);
+        assertFalse("system artifacts are not included", result);
+
+        artifact = createArtifact("group", "artifact", "1.0", "jar", "compile");
+        libraries = new ArrayList<String>();
+        libraries.add("group:artifact");
+        depExaminator = createModule();
+        result = AbstractNbmMojo.matchesLibrary(artifact, libraries, depExaminator, log, false);
+        assertTrue("netbeans modules are included if explicitly marked in descriptor", result);
+
+        libraries = new ArrayList<String>();
+        result = AbstractNbmMojo.matchesLibrary(artifact, libraries, depExaminator, log, false);
+        assertFalse("netbeans modules are omitted", result);
+
+        artifact = createArtifact("group", "artifact", "1.0", "nbm", "compile");
+        libraries = new ArrayList<String>();
+        result = AbstractNbmMojo.matchesLibrary(artifact, libraries, depExaminator, log, false);
+        assertFalse("netbeans modules are omitted", result);
+
+    }
+
+    /**
+     * Test of resolveNetBeansDependency method, of class AbstractNbmMojo.
+     */
+    public void testResolveNetBeansDependency() {
+        Artifact artifact = createArtifact("group", "artifact", "1.0", "jar", "compile");
+        List<Dependency> deps = new ArrayList<Dependency>();
+        ExamineManifest manifest = createNonModule();
+        Dependency result = AbstractNbmMojo.resolveNetBeansDependency(artifact, deps, manifest, log);
+        assertNull("not a NetBeans module", result);
+
+        manifest = createModule();
+        result = AbstractNbmMojo.resolveNetBeansDependency(artifact, deps, manifest, log);
+        assertNotNull("is a NetBeans module", result);
+
+        artifact = createArtifact("group", "artifact", "1.0", "nbm", "compile");
+        manifest = createNonModule();
+        result = AbstractNbmMojo.resolveNetBeansDependency(artifact, deps, manifest, log);
+        assertNotNull("nbm type is a NetBeans module", result);
+
+
+        artifact = createArtifact("group", "artifact", "1.0", "jar", "compile");
+        deps = new ArrayList<Dependency>();
+        Dependency d = new Dependency();
+        d.setId("group:artifact");
+        deps.add(d);
+        manifest = createNonModule();
+        result = AbstractNbmMojo.resolveNetBeansDependency(artifact, deps, manifest, log);
+        assertNull("not a NetBeans module, declared in deps but without explicit value", result);
+
+        d.setExplicitValue("XXX > 1.0");
+        result = AbstractNbmMojo.resolveNetBeansDependency(artifact, deps, manifest, log);
+        assertEquals("not a NetBeans module but declared with explicit value", result, d);
+
+        d.setExplicitValue(null);
+        manifest = createModule();
+        result = AbstractNbmMojo.resolveNetBeansDependency(artifact, deps, manifest, log);
+        assertEquals("netbeans module defined in descriptor", result, d);
+    }
+
+    /**
+     * Module is not a library
+     * @throws java.lang.Exception if AbstractNbmMojo.getLibraryArtifacts fail
+     */
+    public void testGetLibraryArtifacts1() throws Exception {
+        System.out.println("getLibraryArtifacts1");
+        Map<Artifact, ExamineManifest> examinerCache = new HashMap<Artifact, ExamineManifest>();
+        List<Artifact> runtimes = new ArrayList<Artifact>();
+        DependencyNode module = createNode(treeRoot, "gr1", "ar1", "1.0", "jar", "compile", true, runtimes, examinerCache);
+        treeRoot.setChildren( Collections.singletonList( module ));
+        NetBeansModule mdl = new NetBeansModule();
+        List<Artifact> result = AbstractNbmMojo.getLibraryArtifacts(treeRoot, mdl, runtimes, examinerCache, log, false);
+        assertEquals(0, result.size());
+    }
+
+    /**
+     * direct dependency is a library
+     * @throws java.lang.Exception if AbstractNbmMojo.getLibraryArtifacts fail
+     */
+    public void testGetLibraryArtifact2() throws Exception {
+        System.out.println("getLibraryArtifacts2");
+        Map<Artifact, ExamineManifest> examinerCache = new HashMap<Artifact, ExamineManifest>();
+        List<Artifact> runtimes = new ArrayList<Artifact>();
+        DependencyNode library = createNode(treeRoot, "gr1", "ar1", "1.0", "jar", "compile", false, runtimes, examinerCache);
+        treeRoot.setChildren( Collections.singletonList( library ));
+        NetBeansModule mdl = new NetBeansModule();
+        List<Artifact> result = AbstractNbmMojo.getLibraryArtifacts(treeRoot, mdl, runtimes, examinerCache, log, false);
+        assertEquals(1, result.size());
+    }
+
+    
+    /**
+     * transitive dependency gets included as well.
+     * @throws java.lang.Exception if AbstractNbmMojo.getLibraryArtifacts fail
+     */
+    public void testGetLibraryArtifact3() throws Exception {
+        System.out.println("getLibraryArtifacts3");
+        Map<Artifact, ExamineManifest> examinerCache = new HashMap<Artifact, ExamineManifest>();
+        List<Artifact> runtimes = new ArrayList<Artifact>();
+        DependencyNode library = createNode(treeRoot, "gr1", "ar1", "1.0", "jar", "compile", false, runtimes, examinerCache);
+        treeRoot.setChildren( Collections.singletonList( library ));
+        DependencyNode translibrary = createNode(library, "gr2", "ar2", "1.0", "jar", "runtime", false, runtimes, examinerCache);
+        ((DefaultDependencyNode)library).setChildren( Collections.singletonList( translibrary ) );
+        
+        NetBeansModule mdl = new NetBeansModule();
+        List<Artifact> result = AbstractNbmMojo.getLibraryArtifacts(treeRoot, mdl, runtimes, examinerCache, log, false);
+        assertEquals(2, result.size());
+    }
+
+    /**
+     * transitive dependency of a module doesn't get included as library
+     * @throws java.lang.Exception if AbstractNbmMojo.getLibraryArtifacts fail
+     */
+    public void testGetLibraryArtifact4() throws Exception {
+        System.out.println("getLibraryArtifacts4");
+        Map<Artifact, ExamineManifest> examinerCache = new HashMap<Artifact, ExamineManifest>();
+        List<Artifact> runtimes = new ArrayList<Artifact>();
+        DependencyNode module = createNode(treeRoot, "gr1", "ar1", "1.0", "jar", "compile", true, runtimes, examinerCache);
+        treeRoot.setChildren( Collections.singletonList( module ));
+        DependencyNode translibrary = createNode(module, "gr2", "ar2", "1.0", "jar", "runtime", false, runtimes, examinerCache);
+        ((DefaultDependencyNode)module).setChildren( Collections.singletonList( translibrary ) );
+        NetBeansModule mdl = new NetBeansModule();
+        List<Artifact> result = AbstractNbmMojo.getLibraryArtifacts(treeRoot, mdl, runtimes, examinerCache, log, false);
+        assertEquals(0, result.size());
+    }
+
+    /**
+     * transitive dependency of a library is a duplicate of a transitive dependency of a module
+     * -&gt;doesn't get included.
+     * @throws java.lang.Exception if AbstractNbmMojo.getLibraryArtifacts fail
+     */
+    public void testGetLibraryArtifact5() throws Exception {
+        System.out.println("getLibraryArtifacts5");
+        Map<Artifact, ExamineManifest> examinerCache = new HashMap<Artifact, ExamineManifest>();
+        List<Artifact> runtimes = new ArrayList<Artifact>();
+        DependencyNode module = createNode(treeRoot, "gr1", "ar1", "1.0", "jar", "compile", true, runtimes, examinerCache);
+        DependencyNode translibrary = createNode(module, "gr2", "ar2", "1.0", "jar", "runtime", false, runtimes, examinerCache);
+        ((DefaultDependencyNode)module).setChildren( Collections.singletonList( translibrary ) );
+
+        DependencyNode library = createNode(treeRoot, "gr3", "ar3", "1.0", "jar", "compile", false, runtimes, examinerCache);
+        DependencyNode translibrary2 = createNode(library, "gr4", "ar4", "1.0", "jar", "runtime", false, runtimes, examinerCache);
+        ((DefaultDependencyNode)library).setChildren( Collections.singletonList( translibrary2 ) );
+        treeRoot.setChildren( Arrays.asList( new DependencyNode[] { module, library}));
+
+
+        NetBeansModule mdl = new NetBeansModule();
+        List<Artifact> result = AbstractNbmMojo.getLibraryArtifacts(treeRoot, mdl, runtimes, examinerCache, log, false);
+        assertEquals(2, result.size());
+        assertEquals(result.get(0).getId(), library.getArtifact().getId());
+        assertEquals(result.get(1).getId(), translibrary2.getArtifact().getId());
+    }
+
+    private DefaultDependencyNode createNode(DependencyNode parent, String gr, String art, String ver, String pack, String scope, boolean isModule, List<Artifact> runtimes, Map<Artifact, ExamineManifest> cache) {
+        Artifact a = createArtifact(gr, art, ver, pack, scope);
+        DefaultDependencyNode nd = new DefaultDependencyNode(parent, a, ver, scope, ver);
+        ExamineManifest manifest = isModule ? createModule() : createNonModule();
+        runtimes.add(a);
+        cache.put(a, manifest);
+        nd.setChildren( Collections.<DependencyNode>emptyList() );
+        return nd;
+    }
+
+//    private DependencyNode createNode(Artifact a, int state) {
+//        DependencyNode nd = new DefaultDependencyNode(a, state, a);
+//        return nd;
+//    }
+
+    private Artifact createArtifact(String gr, String art, String ver, String pack, String scope) {
+        VersionRange rng = VersionRange.createFromVersion(ver);
+        Artifact a = new DefaultArtifact(gr, art, rng, scope, pack, "classifier", null);
+        a.setDependencyTrail(Collections.EMPTY_LIST);
+        a.setFile(new File(gr + File.separator + art + File.separator + art + "-"+ ver + ".jar"));
+        return a;
+    }
+
+    private ExamineManifest createNonModule() {
+        ExamineManifest manifest = new ExamineManifest(log);
+        manifest.setNetBeansModule(false);
+        return manifest;
+    }
+
+    private ExamineManifest createModule() {
+        ExamineManifest manifest = new ExamineManifest(log);
+        manifest.setNetBeansModule(true);
+        return manifest;
+    }
+}
diff --git a/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/BrandingMojoTest.java b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/BrandingMojoTest.java
new file mode 100644
index 0000000..caa97d9
--- /dev/null
+++ b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/BrandingMojoTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2013 Codehaus.
+ *
+ * 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.
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author mkleint
+ */
+public class BrandingMojoTest
+{
+    
+    public BrandingMojoTest()
+    {
+    }
+
+    /**
+     * Test of destinationFileName method, of class BrandingMojo.
+     */
+    @Test
+    public void testDestinationFileName()
+    {
+        assertEquals( "cut_brandingToken.gif", BrandingMojo.destinationFileName( "cut.gif", "brandingToken" ) );
+        assertEquals( "cut_brandingToken", BrandingMojo.destinationFileName( "cut", "brandingToken" ) );
+        assertEquals( "cut_pressed_brandingToken.gif", BrandingMojo.destinationFileName( "cut_pressed.gif", "brandingToken" ) );
+        assertEquals( "path1" + File.separator + "path2" + File.separator + "cut_brandingToken", BrandingMojo.destinationFileName( "path1" + File.separator + "path2" + File.separator + "cut", "brandingToken" ) );
+        assertEquals( "path.1" + File.separator + "path.2" + File.separator + "cut_brandingToken", BrandingMojo.destinationFileName( "path.1" + File.separator + "path.2" + File.separator + "cut", "brandingToken" ) );
+        assertEquals( "path.1" + File.separator + "cut_pressed_brandingToken.gif", BrandingMojo.destinationFileName( "path.1" + File.separator + "cut_pressed.gif", "brandingToken" ) );
+    }
+    
+    @Test
+    public void testLocale() {
+        assertEquals("en_us", BrandingMojo.getLocale( "aaa_en_us.properties")[1]);
+        assertEquals("en_us_ca", BrandingMojo.getLocale( "aaa_en_us_ca.properties")[1]);
+        assertEquals("en_us_ca", BrandingMojo.getLocale( "aa_en_us_ca.properties")[1]);
+        assertEquals("en_us_ca", BrandingMojo.getLocale( "bb_aa_en_us_ca.properties")[1]);
+        assertEquals("en", BrandingMojo.getLocale( "bb_aaa_en.properties")[1]);
+        assertEquals(null, BrandingMojo.getLocale( "bb_aaa_end.properties")[1]);
+        assertEquals(null, BrandingMojo.getLocale( "bb_aa_end.properties")[1]);
+        assertEquals(null, BrandingMojo.getLocale( "bb.properties")[1]);
+    }
+}
diff --git a/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/CreateClusterAppMojoTest.java b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/CreateClusterAppMojoTest.java
new file mode 100644
index 0000000..c761d25
--- /dev/null
+++ b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/CreateClusterAppMojoTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2013 Codehaus.
+ *
+ * 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.
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.codehaus.mojo.nbm.CreateClusterAppMojo.BundleTuple;
+import org.codehaus.mojo.nbm.utils.ExamineManifest;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+/**
+ *
+ * @author mkleint
+ */
+public class CreateClusterAppMojoTest
+{
+    
+    public CreateClusterAppMojoTest()
+    {
+    }
+    
+    @Test
+    public void computeClusterOrderingTest() throws Exception {
+        HashMap<String, Set<String>> clusterDeps = new HashMap<String, Set<String>>();
+        HashMap<String, Set<String>> clusterModules = new HashMap<String, Set<String>>();
+        clusterModules.put( "platform", new HashSet<String>(Arrays.asList( new String[] {"pl-a", "pl-b", "pl-c"})));
+        clusterModules.put( "ide", new HashSet<String>(Arrays.asList( new String[] {"i-a", "i-b", "i-c"})));
+        clusterModules.put( "java", new HashSet<String>(Arrays.asList( new String[] {"j-a", "j-b", "j-c"})));
+        
+        clusterDeps.put( "java", new HashSet<String>(Arrays.asList( new String[] {"i-a", "pl-b", "pl-c"})));
+        clusterDeps.put( "ide", new HashSet<String>(Arrays.asList( new String[] {"pl-b", "pl-c"})));
+        Map<String, Set<String>> res = CreateClusterAppMojo.computeClusterOrdering( clusterDeps, clusterModules);
+        assertNotNull( res );
+        Set<String> resJava = res.get( "java");
+        assertNotNull( resJava );
+        assertEquals( resJava.size(), 2);
+        assertTrue( resJava.contains( "ide"));
+        assertTrue( resJava.contains( "platform"));
+        
+        Set<String> resIde = res.get( "ide");
+        assertNotNull( resIde );
+        assertEquals( resIde.size(), 1);
+        assertTrue( resIde.contains( "platform"));
+        
+    }
+    
+    @Test
+    public void assignClustersToBundles() throws Exception {
+        ArrayList<BundleTuple> bundles = new ArrayList<BundleTuple>();
+        BundleTuple tup1 = createBundleTuple("a.b.c", new File(getClass().getResource( "/osgimanifests" + File.separator + "a.b.c.MF").toURI()));
+        bundles.add( tup1 );
+        BundleTuple tup2 = createBundleTuple("b.c.d", new File(getClass().getResource( "/osgimanifests" + File.separator + "b.c.d.MF").toURI()));
+        assertTrue(Arrays.toString( tup2.manifest.getOsgiImports().toArray()),  tup2.manifest.getOsgiImports().contains( "a.b.c"));
+        bundles.add( tup2 );
+        HashMap<String, Set<String>> clusterDeps = new HashMap<String, Set<String>>();
+        clusterDeps.put( "java", new HashSet<String>(Arrays.asList( new String[] {"i-a", "pl-b", "pl-c"})));
+        clusterDeps.put( "ide", new HashSet<String>(Arrays.asList( new String[] {"pl-b", "pl-c", "a.b.c"})));
+        
+        CreateClusterAppMojo.assignClustersToBundles(bundles, Collections.<String>emptySet(), clusterDeps, Collections.<String, Set<String>>emptyMap(), null);
+        assertEquals( "ide", tup1.cluster);
+        assertEquals( "ide", tup2.cluster);
+        
+        clusterDeps.clear();
+        clusterDeps.put( "ide", new HashSet<String>(Arrays.asList( new String[] {"i-a", "pl-b", "pl-c"})));
+        clusterDeps.put( "java", new HashSet<String>(Arrays.asList( new String[] {"pl-b", "pl-c", "b.c.d"})));
+        tup2.cluster = null;
+        tup1.cluster = null;
+        
+        CreateClusterAppMojo.assignClustersToBundles(bundles, Collections.<String>emptySet(), clusterDeps, Collections.<String, Set<String>>emptyMap(), null);
+        assertEquals( "java", tup2.cluster);
+        assertEquals( "java", tup1.cluster);
+        
+    }
+
+    private BundleTuple createBundleTuple( String cnb, File file ) throws MojoExecutionException
+    {
+        assertTrue( file.exists());
+        
+        ExamineManifest em = new ExamineManifest( null );
+        em.setManifestFile( file );
+        em.setPopulateDependencies( true);
+        em.checkFile();
+        assertEquals( cnb, em.getModule());
+        BundleTuple toRet = new BundleTuple( null, em);
+                
+        return toRet;
+    }
+}
\ No newline at end of file
diff --git a/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/CreateNetBeansFileStructureTest.java b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/CreateNetBeansFileStructureTest.java
new file mode 100644
index 0000000..48a57d5
--- /dev/null
+++ b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/CreateNetBeansFileStructureTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 Codehaus.
+ *
+ * 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.
+ */
+package org.codehaus.mojo.nbm;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collections;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.DefaultArtifactRepository;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.plugin.testing.AbstractMojoTestCase;
+
+public class CreateNetBeansFileStructureTest
+        extends AbstractMojoTestCase
+{
+
+    public void testWriteExternal()
+            throws Exception
+    {
+        String localRepository = System.getProperty( "localRepository" );
+        ArtifactFactory artifactFactory = (ArtifactFactory) lookup( ArtifactFactory.class.getName() );
+        ArtifactResolver artifactResolver = (ArtifactResolver) lookup( ArtifactResolver.class.getName() );
+        Artifact a = artifactFactory.createBuildArtifact( "junit", "junit", "4.12", "jar" );
+//        DefaultArtifactRepository central = new DefaultArtifactRepository( "central", "http://repo.maven.apache.org/maven2", new DefaultRepositoryLayout() );
+        artifactResolver.resolve( a, Collections.<ArtifactRepository>emptyList(), new DefaultArtifactRepository( "local", new File(localRepository).toURI().toString(), new DefaultRepositoryLayout() ) );
+        StringWriter w = new StringWriter();
+        CreateNetBeansFileStructure.writeExternal( new PrintWriter( w ), a );
+        assertEquals( "CRC:1355517765\nSIZE:314932\nURL:m2:/junit:junit:4.12:jar\nURL:http://repo.maven.apache.org/maven2/junit/junit/4.12/junit-4.12.jar\n", w.toString() );
+    }
+
+}
diff --git a/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/NetBeansManifestUpdateMojoTest.java b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/NetBeansManifestUpdateMojoTest.java
new file mode 100644
index 0000000..c49ca20
--- /dev/null
+++ b/nbm-maven-plugin/src/test/java/org/codehaus/mojo/nbm/NetBeansManifestUpdateMojoTest.java
@@ -0,0 +1,97 @@
+/*
+ *  Copyright 2008 mkleint.
+ * 
+ *  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.
+ *  under the License.
+ */
+
+package org.codehaus.mojo.nbm;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Pattern;
+import junit.framework.TestCase;
+import org.apache.tools.ant.taskdefs.Manifest;
+
+public class NetBeansManifestUpdateMojoTest extends TestCase {
+    
+    public NetBeansManifestUpdateMojoTest(String testName) {
+        super(testName);
+    }
+
+    public void testCreateCompiledPatternList()
+    {
+        List<String> subpackages = Arrays.asList( new String[] {
+                "org.milos.**",
+                "org.tomas.**"
+        });
+        List<Pattern> result = NetBeansManifestUpdateMojo.createCompiledPatternList( subpackages );
+        assertTrue( matches( "org.milos.Test", result));
+        assertTrue( matches( "org.milos.pack.Test", result));
+        assertTrue( matches( "org.tomas.pack.Test$Inside", result));
+        assertFalse( matches( "org.milan", result));
+        assertFalse( matches( "org.milosclass", result));
+
+        List<String> packages = Arrays.asList( new String[] {
+                "org.milos.*",
+                "org.tomas.*"
+        });
+        result = NetBeansManifestUpdateMojo.createCompiledPatternList( packages );
+        assertTrue( matches( "org.milos.Test", result));
+        assertFalse( matches( "org.milos.pack.Test", result));
+        assertFalse( matches( "org.tomas.pack.Test$Inside", result));
+        assertTrue( matches( "org.tomas.Test$Inside", result));
+        assertFalse( matches( "org.milan", result));
+        assertFalse( matches( "org.milosclass", result));
+
+    }
+
+    private boolean matches(String className, List<Pattern> matchers) {
+        for (Pattern patt : matchers) {
+            if (patt.matcher( className ).matches()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void testShorten()
+    {
+        Locale old = Locale.getDefault();
+        Locale.setDefault( Locale.US );
+        try
+        {
+            assertEquals( null, NetBeansManifestUpdateMojo.shorten ( null ) );
+            assertEquals( null, NetBeansManifestUpdateMojo.shorten ( "" ) );
+            assertEquals( "I typed some description here", NetBeansManifestUpdateMojo.shorten ( "I typed some description here" ) );
+            assertEquals( "Now I'm trying to be serious.", NetBeansManifestUpdateMojo.shorten ( "Now I'm trying to be serious." ) );
+            assertEquals( "A meaningful description.", NetBeansManifestUpdateMojo.shorten ( "A meaningful description. But will it work?" ) );
+            assertEquals( "I have no idea what this module does, do you?", NetBeansManifestUpdateMojo.shorten ( "I have no idea what this module does, do you? No? Fine." ) );
+        }
+        finally
+        {
+            Locale.setDefault( old );
+        }
+    }
+
+    public void testNewlines()
+        throws Exception
+    {
+        Manifest m = new Manifest();
+        Manifest.Section s = m.getMainSection();
+        new NetBeansManifestUpdateMojo().conditionallyAddAttribute( s, "Desc", "Something.\n   Else.\n" );
+        assertEquals( "Something. Else.", s.getAttributeValue( "Desc" ));
+    }
+
+}
diff --git a/nbm-maven-plugin/src/test/resources/osgimanifests/a.b.c.MF b/nbm-maven-plugin/src/test/resources/osgimanifests/a.b.c.MF
new file mode 100644
index 0000000..4b61376
--- /dev/null
+++ b/nbm-maven-plugin/src/test/resources/osgimanifests/a.b.c.MF
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Bundle-Localization: plugin
+Bundle-SymbolicName: a.b.c; singleton:=true
+Require-Bundle: org.eclipse.osgi;bundle-version="[3.7.0,4.0.0)";visibi
+ lity:=reexport,org.eclipse.equinox.common;bundle-version="[3.5.0,4.0.
+ 0)";visibility:=reexport,org.eclipse.core.jobs;bundle-version="[3.2.0
+ ,4.0.0)";visibility:=reexport,org.eclipse.equinox.registry;bundle-ver
+ sion="[3.4.0,4.0.0)";visibility:=reexport,org.eclipse.equinox.prefere
+ nces;bundle-version="[3.4.0,4.0.0)";visibility:=reexport,org.eclipse.
+ core.contenttype;bundle-version="[3.3.0,4.0.0)";visibility:=reexport,
+ org.eclipse.core.runtime.compatibility.auth;bundle-version="[3.2.0,4.
+ 0.0)";resolution:=optional,org.eclipse.equinox.app;bundle-version="1.
+ 0.0";visibility:=reexport
+Export-Package: a.b.c;x-interna
+ l:=true,a.b.c.d;x-friends:="org.eclipse.cor
+ e.runtime.compatibility"
+Bundle-Version: 3.7.0.v20110110
+Bundle-ActivationPolicy: lazy
+Bundle-Vendor: %providerName
+Bundle-Name: %pluginName
+Bundle-ManifestVersion: 2
+
diff --git a/nbm-maven-plugin/src/test/resources/osgimanifests/b.c.d.MF b/nbm-maven-plugin/src/test/resources/osgimanifests/b.c.d.MF
new file mode 100644
index 0000000..2b1c729
--- /dev/null
+++ b/nbm-maven-plugin/src/test/resources/osgimanifests/b.c.d.MF
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Bundle-Localization: plugin
+Bundle-RequiredExecutionEnvironment: CDC-1.1/Foundation-1.1,J2SE-1.4
+Bundle-SymbolicName: b.c.d; singleton:=true
+Eclipse-LazyStart: true
+Export-Package: b.c.d;x-friends:="org.eclipse
+ .core.resources,org.eclipse.core.runtime.compatibility,org.eclipse.pd
+ e.build",b.c.d.d;common=split;mandatory:=co
+ mmon; x-friends:="org.eclipse.core.contenttype
+Bundle-Version: 3.6.0.v20110523
+Bundle-ActivationPolicy: lazy
+Bundle-Vendor: %providerName
+Bundle-Name: %pluginName
+Import-Package: a.b.c;version="[1.0,2.0)",a.b.c.d;version="[1.1, 2.0)"
+Bundle-ManifestVersion: 2
+
diff --git a/nbm-shared/pom.xml b/nbm-shared/pom.xml
new file mode 100644
index 0000000..680b83e
--- /dev/null
+++ b/nbm-shared/pom.xml
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>mojo-parent</artifactId>
+        <version>40</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>nb-shared</artifactId>
+    <version>1.3-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <name>NBM Plugins Utilities</name>
+    <description>Maven plugin for creating Maven Repository out of a NetBeans installation (and other sources) for consumption by the projects using nbm-maven-plugin.
+    </description>
+    <inceptionYear>2005</inceptionYear>
+    <url>https://github.com/mojohaus/nbm-shared</url>
+    <issueManagement>
+        <system>GitHub</system>
+        <url>https://github.com/mojohaus/nbm-shared/issues</url>
+    </issueManagement>
+    <licenses>
+        <license>
+            <name>Apache License 2</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+    <scm>
+        <connection>scm:git:https://github.com/mojohaus/nbm-shared.git</connection>
+        <developerConnection>scm:git:ssh://git@github.com/mojohaus/nbm-shared.git</developerConnection>
+        <url>https://github.com/mojohaus/nbm-shared/tree/${project.scm.tag}</url>
+        <tag>master</tag>
+    </scm>
+    <developers>
+        <developer>
+            <id>mkleint</id>
+            <name>Milos Kleint</name>
+            <email>mkleint@codehaus.org</email>
+            <organization>Codehaus</organization>
+            <roles>
+                <role>Developer</role>
+            </roles>
+        </developer>
+        <developer>
+            <id>jglick</id>
+            <name>Jesse Glick</name>
+            <email>jglick@codehaus.org</email>
+            <organization>Codehaus</organization>
+            <roles>
+                <role>Developer</role>
+            </roles>
+        </developer>
+    </developers>
+    <contributors>
+        <contributor>
+            <name>Johan Andrén</name>
+            <email>protected</email>
+            <roles>
+                <role>Patch Contributor</role>
+                <role>Goal Contributor</role>
+            </roles>
+        </contributor>
+        <contributor>
+            <name>Mykola Nikishov</name>
+            <email>mn@mn.com.ua</email>
+            <roles>
+                <role>Patch Contributor</role>
+            </roles>
+        </contributor>
+        <contributor>
+            <name>Frantisek Mantlik</name>
+            <email>frantisek@mantlik.cz</email>
+            <roles>
+                <role>Goal Contributor</role>
+            </roles>
+        </contributor>
+    </contributors>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>animal-sniffer-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                           <goal>check</goal>
+                        </goals>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java16</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-site-plugin</artifactId>
+                <version>3.6</version>
+            </plugin>
+        </plugins>
+    </build>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-project-info-reports-plugin</artifactId>
+                <version>2.9</version>
+                <reportSets>
+                    <reportSet>
+                        <reports>
+                            <report>plugin-management</report>
+                            <report>plugins</report>
+                            <report>project-team</report>
+                            <report>scm</report>
+                            <report>summary</report>
+                            <!-- <report>cim</report> -->
+                        </reports>
+                    </reportSet>
+                </reportSets>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-changes-plugin</artifactId>
+                <version>2.12.1</version>
+                <configuration>
+                   <!-- <onlyCurrentVersion>true</onlyCurrentVersion>-->
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <version>2.9.1</version>
+                <configuration>
+                    <configLocation>config/maven_checks.xml</configLocation>
+                    <headerLocation>config/maven-header.txt</headerLocation>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>3.0.0-M1</version>
+                <configuration>
+                    <quiet>true</quiet>
+                    <links>
+                        <!--<link>http://download-llnw.oracle.com/javaee/1.4/api/</link>-->
+                        <link>http://commons.apache.org/collections/apidocs-COLLECTIONS_3_0/</link>
+                        <link>http://commons.apache.org/dbcp/apidocs/</link>
+                        <link>http://commons.apache.org/fileupload/apidocs/</link>
+                        <link>http://commons.apache.org/logging/apidocs/</link>
+                        <link>http://commons.apache.org/pool/apidocs/</link>
+                        <link>http://junit.sourceforge.net/javadoc/</link>
+                        <link>http://logging.apache.org/log4j/1.2/apidocs/</link>
+                        <link>http://jakarta.apache.org/regexp/apidocs/</link>
+                        <link>http://velocity.apache.org/engine/releases/velocity-1.5/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${maven.version}/maven-artifact/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${maven.version}/maven-artifact-manager/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${maven.version}/maven-model/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${maven.version}/maven-plugin-api/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${maven.version}/maven-project/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${maven.version}/maven-reporting/maven-reporting-api/apidocs/</link>
+                        <link>http://maven.apache.org/ref/${maven.version}/maven-settings/apidocs/</link>
+                    </links>
+                    <tagletArtifacts>
+                        <tagletArtifact>
+                            <groupId>org.apache.maven.plugin-tools</groupId>
+                            <artifactId>maven-plugin-tools-javadoc</artifactId>
+                            <version>2.8</version>
+                        </tagletArtifact>
+                        <tagletArtifact>
+                            <groupId>org.codehaus.plexus</groupId>
+                            <artifactId>plexus-component-javadoc</artifactId>
+                            <version>1.5.5</version>
+                        </tagletArtifact>
+                    </tagletArtifacts>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jxr-plugin</artifactId>
+                <version>2.5</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-pmd-plugin</artifactId>
+                <version>3.8</version>
+                <configuration>
+                    <targetJdk>1.5</targetJdk>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-linkcheck-plugin</artifactId>
+                <version>1.2</version>
+                <configuration>
+                    <excludedLinks>
+                        <excludedLink>../../images/codehaus-small.png</excludedLink>
+                        <excludedLink>../../images/mojo_logo.png</excludedLink>
+                        <excludedLink>plugin-info.html</excludedLink>
+                    </excludedLinks>
+                    <!--<excludedPages>
+                        <excludedPage>dependencies.html</excludedPage> 
+                    </excludedPages>-->
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>cobertura-maven-plugin</artifactId>
+                <version>2.7</version>
+            </plugin> 
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>taglist-maven-plugin</artifactId>
+                <version>2.4</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <version>0.12</version>
+            </plugin>
+        </plugins>
+    </reporting>
+    <!--profiles>
+        <profile>
+            <id>tools.jar</id>
+            <activation>
+                <file>
+                    <exists>${java.home}/../lib/tools.jar</exists>
+                </file>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>com.sun</groupId>
+                    <artifactId>tools</artifactId>
+                    <version>1.5.0</version>
+                    <scope>system</scope>
+                    <systemPath>${java.home}/../lib/tools.jar</systemPath>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles-->
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>3.0.4</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>1.9.2</version>
+            <scope>compile</scope>
+            <type>jar</type>
+        </dependency>
+    </dependencies>
+    <properties>
+        <mojo.java.target>1.6</mojo.java.target>
+        <maven.version>3.0.4</maven.version>
+    </properties>
+</project>
diff --git a/nbm-shared/src/main/java/org/codehaus/mojo/nbm/utils/AbstractNetbeansMojo.java b/nbm-shared/src/main/java/org/codehaus/mojo/nbm/utils/AbstractNetbeansMojo.java
new file mode 100644
index 0000000..c005bb9
--- /dev/null
+++ b/nbm-shared/src/main/java/org/codehaus/mojo/nbm/utils/AbstractNetbeansMojo.java
@@ -0,0 +1,132 @@
+/* ==========================================================================
+ * Copyright 2003-2004 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm.utils;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Taskdef;
+
+public abstract class AbstractNetbeansMojo
+    extends AbstractMojo
+{
+
+    /**
+     * Creates a project initialized with the same logger.
+     * @return project
+     */
+    protected final Project antProject()
+    {
+        Project antProject = new Project();
+        antProject.init();
+        antProject.addBuildListener( new BuildListener()
+        {
+            @Override
+            public void buildStarted( BuildEvent be )
+            {
+                getLog().debug( "Ant build started" );
+            }
+            @Override
+            public void buildFinished( BuildEvent be )
+            {
+                if ( be.getException() != null )
+                {
+                    getLog().error( be.getMessage(), be.getException() );
+                }
+                else
+                {
+                    getLog().debug( "Ant build finished" );
+                }
+            }
+            @Override
+            public void targetStarted( BuildEvent be )
+            {
+                getLog().info( be.getTarget().getName() + ":" );
+            }
+            @Override
+            public void targetFinished( BuildEvent be )
+            {
+                getLog().debug( be.getTarget().getName() + " finished" );
+            }
+            @Override
+            public void taskStarted( BuildEvent be )
+            {
+                getLog().debug( be.getTask().getTaskName() + " started" );
+            }
+            @Override
+            public void taskFinished( BuildEvent be )
+            {
+                getLog().debug( be.getTask().getTaskName() + " finished" );
+            }
+            @Override
+            public void messageLogged( BuildEvent be )
+            {
+                switch ( be.getPriority() )
+                {
+                    case Project.MSG_ERR:
+                        getLog().error( be.getMessage() );
+                        break;
+                    case Project.MSG_WARN:
+                        getLog().warn( be.getMessage() );
+                        break;
+                    case Project.MSG_INFO:
+                        getLog().info( be.getMessage() );
+                        break;
+                    default:
+                        getLog().debug( be.getMessage() );
+                }
+            }
+        } );
+        return antProject;
+    }
+
+    protected final Project registerNbmAntTasks()
+    {
+        Project antProject = antProject();
+
+        Taskdef taskdef = (Taskdef) antProject.createTask( "taskdef" );
+        taskdef.setClassname( "org.netbeans.nbbuild.MakeListOfNBM" );
+        taskdef.setName( "genlist" );
+        taskdef.execute();
+
+        taskdef = (Taskdef) antProject.createTask( "taskdef" );
+        taskdef.setClassname( "org.netbeans.nbbuild.MakeNBM" );
+        taskdef.setName( "makenbm" );
+        taskdef.execute();
+
+        taskdef = (Taskdef) antProject.createTask( "taskdef" );
+        taskdef.setClassname( "org.netbeans.nbbuild.MakeUpdateDesc" );
+        taskdef.setName( "updatedist" );
+        taskdef.execute();
+
+        taskdef = (Taskdef) antProject.createTask( "taskdef" );
+        taskdef.setClassname( "org.netbeans.nbbuild.CreateModuleXML" );
+        taskdef.setName( "createmodulexml" );
+        taskdef.execute();
+
+        taskdef = (Taskdef) antProject.createTask( "taskdef" );
+        taskdef.setClassname( "org.netbeans.nbbuild.JHIndexer" );
+        taskdef.setName( "jhindexer" );
+        taskdef.execute();
+
+        return antProject;
+    }
+
+
+
+}
diff --git a/nbm-shared/src/main/java/org/codehaus/mojo/nbm/utils/ExamineManifest.java b/nbm-shared/src/main/java/org/codehaus/mojo/nbm/utils/ExamineManifest.java
new file mode 100644
index 0000000..730114d
--- /dev/null
+++ b/nbm-shared/src/main/java/org/codehaus/mojo/nbm/utils/ExamineManifest.java
@@ -0,0 +1,503 @@
+/* ==========================================================================
+ * Copyright 2003-2004 Mevenide Team
+ *
+ * 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.
+ * =========================================================================
+ */
+package org.codehaus.mojo.nbm.utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Tag examines the manifest of a jar file and retrieves NetBeans specific information.
+ * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
+ *
+ */
+public class ExamineManifest
+{
+
+    private final Log logger;
+    private File jarFile;
+    private File manifestFile;
+    private boolean netBeansModule;
+    private boolean osgiBundle;
+
+    private boolean localized;
+    private String specVersion;
+    private String implVersion;
+    private String module;
+    private String locBundle;
+    private String classpath;
+    private boolean publicPackages;
+    private boolean populateDependencies = false;
+    private List<String> dependencyTokens = Collections.<String>emptyList();
+    private Set<String> osgiImports = Collections.<String>emptySet();
+    private Set<String> osgiExports = Collections.<String>emptySet();
+
+    private boolean friendPackages = false;
+    private List<String> friends = Collections.<String>emptyList();
+    private List<String> packages = Collections.<String>emptyList();
+
+    private List<String> requires = Collections.<String>emptyList();
+
+    private List<String> provides = Collections.<String>emptyList();
+    //that's the default behaviour without the special manifest entry
+    private boolean bundleAutoload = true;
+
+    public ExamineManifest( Log logger )
+    {
+        this.logger = logger;
+    }
+
+    public void checkFile()
+        throws MojoExecutionException
+    {
+
+        resetExamination();
+
+        Manifest mf = null;
+        if ( jarFile != null )
+        {
+            JarFile jar = null;
+            try
+            {
+                jar = new JarFile( jarFile );
+                mf = jar.getManifest();
+            }
+            catch ( Exception exc )
+            {
+                throw new MojoExecutionException( "Could not open " + jarFile + ": " + exc.getMessage(), exc );
+            }
+            finally
+            {
+                if ( jar != null )
+                {
+                    try
+                    {
+                        jar.close();
+                    }
+                    catch ( IOException io )
+                    {
+                        throw new MojoExecutionException( io.getMessage(), io );
+                    }
+                }
+            }
+        }
+        else if ( manifestFile != null )
+        {
+            InputStream stream = null;
+            try
+            {
+                stream = new FileInputStream( manifestFile );
+                mf = new Manifest( stream );
+            }
+            catch ( Exception exc )
+            {
+                throw new MojoExecutionException( exc.getMessage(), exc );
+            }
+            finally
+            {
+                if ( stream != null )
+                {
+                    try
+                    {
+                        stream.close();
+                    }
+                    catch ( IOException io )
+                    {
+                        throw new MojoExecutionException( io.getMessage(), io );
+                    }
+                }
+            }
+        }
+        if ( mf != null )
+        {
+            processManifest( mf );
+        }
+        else
+        {
+            //MNBMODULE-22
+            File source = manifestFile;
+            if ( source == null )
+            {
+                source = jarFile;
+            }
+            if ( source == null )
+            {
+                logger.debug( "No manifest to examine" );
+            }
+            else
+            {
+                logger.debug( "Cannot find manifest entries in " + source.getAbsolutePath() );
+            }
+        }
+    }
+
+    private void resetExamination()
+    {
+        setNetBeansModule( false );
+        this.localized = false;
+        this.specVersion = null;
+        this.implVersion = null;
+        this.module = null;
+        this.locBundle = null;
+        this.publicPackages = false;
+        classpath = "";
+    }
+
+    private void processManifest( Manifest mf )
+    {
+        Attributes attrs = mf.getMainAttributes();
+        this.module = attrs.getValue( "OpenIDE-Module" );
+        setNetBeansModule( getModule() != null );
+        if ( isNetBeansModule() )
+        {
+            this.locBundle = attrs.getValue( "OpenIDE-Module-Localizing-Bundle" );
+            this.localized = locBundle != null;
+            this.specVersion = attrs.getValue( "OpenIDE-Module-Specification-Version" );
+            this.implVersion = attrs.getValue( "OpenIDE-Module-Implementation-Version" );
+            String cp = attrs.getValue( Attributes.Name.CLASS_PATH );
+            classpath = cp == null ? "" : cp;
+            String value = attrs.getValue( "OpenIDE-Module-Public-Packages" );
+            String frList = attrs.getValue( "OpenIDE-Module-Friends" );
+            if ( value == null || value.trim().equals( "-" ) )
+            {
+                this.publicPackages = false;
+            }
+            else
+            {
+                if ( frList != null )
+                {
+                    this.publicPackages = false;
+                    String[] friendList = StringUtils.stripAll( StringUtils.split( frList, "," ) );
+                    friendPackages = true;
+                    friends = Arrays.asList( friendList );
+                }
+                else
+                {
+                    this.publicPackages = true;
+                }
+                String[] packageList = StringUtils.stripAll( StringUtils.split( value, "," ) );
+                packages = Arrays.asList( packageList );
+            }
+            if ( populateDependencies )
+            {
+                String deps = attrs.getValue( "OpenIDE-Module-Module-Dependencies" );
+                if ( deps != null )
+                {
+                    StringTokenizer tokens = new StringTokenizer( deps, "," );
+                    List<String> depList = new ArrayList<String>();
+                    while ( tokens.hasMoreTokens() )
+                    {
+                        String tok = tokens.nextToken();
+                        //we are just interested in specification and loose dependencies.
+                        int spec = tok.indexOf( '>' );
+                        int impl = tok.indexOf( '=');
+                        if ( spec > 0 )
+                        {
+                            tok = tok.substring( 0, spec );
+                        }
+                        else if ( impl > 0 )
+                        {
+                            tok = tok.substring( 0, impl );
+                        }
+                        int slash = tok.indexOf( '/' );
+                        if ( slash > 0 )
+                        {
+                            tok = tok.substring( 0, slash );
+                        }
+                        depList.add( tok.trim().intern() );
+                    }
+                    this.dependencyTokens = depList;
+                }
+                String req = attrs.getValue( "OpenIDE-Module-Requires" );
+                String prov = attrs.getValue( "OpenIDE-Module-Provides" );
+                String needs = attrs.getValue( "OpenIDE-Module-Needs" );
+                if (prov != null) {
+                    provides = Arrays.asList( StringUtils.stripAll( StringUtils.split( prov, "," ) ));
+                }
+                if (req != null || needs != null) {
+                    requires = new ArrayList<String>();
+                    if (req != null) {
+                        requires.addAll(Arrays.asList( StringUtils.stripAll( StringUtils.split( req, "," ) )));
+                    }
+                    if (needs != null) {
+                        requires.addAll(Arrays.asList( StringUtils.stripAll( StringUtils.split( needs, "," ) )));
+                    }
+                }
+            }
+
+        }
+        else
+        {
+        
+            //check osgi headers first, let nb stuff override it, making nb default
+            String bndName = attrs.getValue( "Bundle-SymbolicName" );
+            if ( bndName != null )
+            {
+                this.osgiBundle = true;
+                this.module =
+                    bndName./* MNBMODULE-125 */replaceFirst( " *;.+", "" )./* MNBMODULE-96 */replace( '-', '_' );
+                this.specVersion = attrs.getValue( "Bundle-Version" );
+                String exp = attrs.getValue( "Export-Package" );
+                String autoload = attrs.getValue( "Nbm-Maven-Plugin-Autoload");
+                if (autoload != null) {
+                    bundleAutoload = Boolean.parseBoolean( autoload );
+                }
+                this.publicPackages = exp != null;
+                if ( populateDependencies )
+                {
+                    //well, this doesn't appear to cover the major way of declation dependencies in osgi - Import-Package
+                    String deps = attrs.getValue( "Require-Bundle" );
+                    if ( deps != null )
+                    {
+                        List<String> depList = new ArrayList<String>();
+                        // http://stackoverflow.com/questions/1757065/java-splitting-a-comma-separated-string-but-ignoring-commas-in-quotes
+                        for ( String piece : deps.split( ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)" ) )
+                        {
+                            depList.add( piece.replaceFirst( ";.+", "" ).trim().intern() );
+                        }
+                        this.dependencyTokens = depList;
+                    }
+                    String imps = attrs.getValue( "Import-Package" );
+                    if ( imps != null )
+                    {
+                        Set<String> depList = new HashSet<String>();
+                        // http://stackoverflow.com/questions/1757065/java-splitting-a-comma-separated-string-but-ignoring-commas-in-quotes
+                        for ( String piece : imps.split( ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)" ) )
+                        {
+                            depList.add( piece.replaceFirst( ";.+", "" ).trim().intern() );
+                        }
+                        this.osgiImports = depList;
+                    }
+                    String exps = attrs.getValue( "Export-Package" );
+                    if ( exps != null )
+                    {
+                        Set<String> depList = new HashSet<String>();
+                        // http://stackoverflow.com/questions/1757065/java-splitting-a-comma-separated-string-but-ignoring-commas-in-quotes
+                        for ( String piece : exps.split( ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)" ) )
+                        {
+                            depList.add( piece.replaceFirst( ";.+", "" ).trim().intern() );
+                        }
+                        this.osgiExports = depList;
+                    }
+                    
+                }
+            }
+            else
+            {
+
+                // for non-netbeans, non-osgi jars.
+                this.specVersion = attrs.getValue( "Specification-Version" );
+                this.implVersion = attrs.getValue( "Implementation-Version" );
+                this.module = attrs.getValue( "Package" );
+                this.publicPackages = false;
+                classpath = "";
+                /*    if ( module != null )
+                {
+                // now we have the package to make it a module definition, add the version there..
+                module = module + "/1";
+                }
+                 */
+                if ( getModule() == null )
+                {
+                    // do we want to do that?
+                    this.module = attrs.getValue( "Extension-Name" );
+                }
+            }
+        }
+
+    }
+
+    /**
+     * The jar file to examine. It is exclusive with manifestFile.
+     * @param jarFileLoc jar file
+     */
+    public void setJarFile( File jarFileLoc )
+    {
+        jarFile = jarFileLoc;
+    }
+
+    /** 
+     * Manifest file to be examined. It is exclusive with jarFile.
+     * @param manifestFileLoc manifedt file
+     */
+    public void setManifestFile( File manifestFileLoc )
+    {
+        manifestFile = manifestFileLoc;
+    }
+
+    /**
+     * Either call {@link #setJarFile} or {@link #setManifestFile} as appropriate.
+     * @param artifactFileLoc a JAR or folder
+     */
+    public void setArtifactFile( File artifactFileLoc )
+    {
+        if ( artifactFileLoc.isFile() )
+        {
+            setJarFile( artifactFileLoc );
+        }
+        else if ( artifactFileLoc.isDirectory() )
+        {
+            File mani = new File( artifactFileLoc, "META-INF/MANIFEST.MF" );
+            if ( mani.isFile() )
+            {
+                setManifestFile( mani );
+            } // else e.g. jarprj/target/classes has no manifest, so nothing to examine
+        }
+        else
+        {
+            throw new IllegalArgumentException( artifactFileLoc.getAbsolutePath() );
+        }
+    }
+
+    public String getClasspath()
+    {
+        return classpath;
+    }
+
+    public boolean isNetBeansModule()
+    {
+        return netBeansModule;
+    }
+
+    public void setNetBeansModule( boolean netBeansModule )
+    {
+        this.netBeansModule = netBeansModule;
+    }
+
+    public boolean isLocalized()
+    {
+        return localized;
+    }
+
+    public String getSpecVersion()
+    {
+        return specVersion;
+    }
+
+    public String getImplVersion()
+    {
+        return implVersion;
+    }
+
+    /**
+     * Code name base of the module only.
+     * Does not include any release version.
+     * @return module code name base
+     */
+    public String getModule()
+    {
+        return module != null ? module.replaceFirst( "/\\d+$", "" ) : module;
+    }
+
+    /**
+     * Full name of module: code name base, then optionally slash and major release version.
+     * @return module full name 
+     */
+    public String getModuleWithRelease()
+    {
+        return module;
+    }
+
+    /**
+     * returns true if there are defined public packages and there is no friend
+     * declaration.
+     * @return true if has public package
+     */
+    public boolean hasPublicPackages()
+    {
+        return publicPackages;
+    }
+
+    public void setPopulateDependencies( boolean populateDependencies )
+    {
+        this.populateDependencies = populateDependencies;
+    }
+
+    public List<String> getDependencyTokens()
+    {
+        return dependencyTokens;
+    }
+
+    /**
+     * returns true if both public packages and friend list are declared.
+     * @return true if has friend package
+     */
+    public boolean hasFriendPackages()
+    {
+        return friendPackages;
+    }
+
+    public List<String> getFriends()
+    {
+        return friends;
+    }
+
+    /**
+     * list of package statements from OpenIDE-Module-Public-Packages.
+     * All items end with .*
+     * @return list of package
+     */
+    public List<String> getPackages()
+    {
+        return packages;
+    }
+
+    public boolean isOsgiBundle()
+    {
+        return osgiBundle;
+    }
+
+    public Set<String> getOsgiImports()
+    {
+        return osgiImports;
+    }
+
+    public Set<String> getOsgiExports()
+    {
+        return osgiExports;
+    }
+    
+    public List<String> getNetBeansRequiresTokens()
+    {
+        return requires;
+    }
+
+    public List<String> getNetBeansProvidesTokens()
+    {
+        return provides;
+    }
+
+    public boolean isBundleAutoload()
+    {
+        return bundleAutoload;
+    }
+
+}
diff --git a/nbm-shared/src/test/java/org/codehaus/mojo/nbm/utils/ExamineManifestTest.java b/nbm-shared/src/test/java/org/codehaus/mojo/nbm/utils/ExamineManifestTest.java
new file mode 100644
index 0000000..f23827d
--- /dev/null
+++ b/nbm-shared/src/test/java/org/codehaus/mojo/nbm/utils/ExamineManifestTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010 jglick.
+ *
+ * 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.
+ * under the License.
+ */
+
+package org.codehaus.mojo.nbm.utils;
+
+import java.io.File;
+import java.io.PrintWriter;
+import junit.framework.TestCase;
+import org.apache.maven.plugin.logging.SystemStreamLog;
+
+public class ExamineManifestTest extends TestCase
+{
+    
+    public ExamineManifestTest( String testName )
+    {
+        super(testName);
+    }
+
+    public void testDependencyParsing()
+            throws Exception
+    {
+        ExamineManifest em = new ExamineManifest( new SystemStreamLog() );
+        File mf = File.createTempFile( "ExamineManifestTes", ".mf" );
+        mf.deleteOnExit();
+        PrintWriter w = new PrintWriter( mf );
+        w.println( "OpenIDE-Module: org.netbeans.modules.nbjunit/1" );
+        w.println( "OpenIDE-Module-Module-Dependencies: org.netbeans.insane/1, org.netbeans.libs.junit4 > 1.0" );
+        w.flush();
+        w.close();
+        em.setManifestFile( mf );
+        em.setPopulateDependencies( true );
+        em.checkFile();
+        assertEquals( "[org.netbeans.insane, org.netbeans.libs.junit4]", em.getDependencyTokens().toString() );
+        assertEquals( "org.netbeans.modules.nbjunit", em.getModule() );
+        assertEquals( "org.netbeans.modules.nbjunit/1", em.getModuleWithRelease() );
+        em = new ExamineManifest( new SystemStreamLog() );
+        mf.delete();
+        w = new PrintWriter( mf );
+        w.println( "Manifest-Version: 1.0" );
+        w.flush();
+        w.close();
+        em.setManifestFile( mf );
+        em.setPopulateDependencies( true );
+        em.checkFile();
+        assertEquals( null, em.getModule() );
+        assertEquals( null, em.getModuleWithRelease() );
+    }
+
+    public void testBundles()
+            throws Exception
+    {
+        ExamineManifest em = new ExamineManifest( new SystemStreamLog() );
+        File mf = File.createTempFile( "ExamineManifestTest", ".mf" );
+        mf.deleteOnExit();
+        PrintWriter w = new PrintWriter( mf );
+        w.println( "Bundle-SymbolicName: org.eclipse.jdt.core; singleton:=true" );
+        w.println( "Bundle-Version: 3.1.0" );
+        w.println( "Export-Package: org.eclipse.jdt.core," );
+        w.println( " org.eclipse.jdt.internal.formatter.old;x-internal:=true" );
+        w.println( "Require-Bundle: org.eclipse.equinox.registry;bundle-version=\"[3.4.0,4." );
+        w.println( " 0.0)\",org.eclipse.equinox.common;bundle-version=\"[3.2.0,4.0.0)\"" );
+        w.flush();
+        w.close();
+        em.setManifestFile( mf );
+        em.setPopulateDependencies( true );
+        em.checkFile();
+        assertEquals( "org.eclipse.jdt.core", em.getModule() );
+        assertEquals( "3.1.0", em.getSpecVersion() );
+        assertTrue( em.hasPublicPackages() );
+        assertEquals( "[org.eclipse.equinox.registry, org.eclipse.equinox.common]", em.getDependencyTokens().toString() );
+    }
+
+}