Enhancing OnosJar to build OSGi jars and wars if required.

Also, simplifying onos.bucklet by using the rule

Change-Id: If89633db2d83cbfc56a8e70d2bea665ffaf186ff
diff --git a/bucklets/onos.bucklet b/bucklets/onos.bucklet
index e5e4b0a..cf8d276 100644
--- a/bucklets/onos.bucklet
+++ b/bucklets/onos.bucklet
@@ -114,6 +114,7 @@
     api_description = NONE,
     resources = NONE,
     resources_root = None,
+    tests = None,
     **kwargs
     ):
 
@@ -134,76 +135,42 @@
       resources_root = RESOURCES_ROOT
 
   if api_title != NONE:
-      r = 'WEB-INF/classes/apidoc/swagger.json=bin/swagger.json'
+      r = 'WEB-INF/classes/apidoc/swagger.json=swagger.json'
       include_resources = include_resources + ',' + r if include_resources != NONE else r
 
-  bare_jar_name = name + '-jar'
-  osgi_jar_name = name + '-osgi'
   mvn_coords = group_id + ':' + name + ':' + version
 
-
   onos_jar(
-      name = bare_jar_name,
-      srcs = srcs,
+      name = name,
+      srcs = srcs + glob(['src/main/webapp/**']),
       deps = deps,
-      visibility = [], #intentially, not visible
+      visibility = visibility,
       resources = resources,
       resources_root = resources_root,
+      bundle_name = name,
+      group_id = group_id,
+      bundle_version = version,
+      bundle_license = license,
+      bundle_description = description,
+      import_packages = import_packages,
+      export_packages = export_packages,
+      include_resources = include_resources,
+      dynamicimport_packages = dynamicimport_packages,
       web_context = web_context,
       api_title = api_title,
       api_version = api_version,
       api_package = api_package,
       api_description = api_description,
+      tests = tests,
+      maven_coords = mvn_coords,
       **kwargs
   )
 
-  cp = ':'.join(['$(classpath %s)' % c for c in deps]) if deps else '""'
-
-  args = ( '$(location :%s)' % bare_jar_name, #input jar
-           '$OUT',                            #output jar
-           cp,                                #classpath
-           name,                              #bundle name
-           group_id,                          #group id
-           version,                           #version
-           license,                           #license url
-           "'%s'" % import_packages,          #packages to import
-           "'%s'" % export_packages,          #packages to export
-           include_resources,                 #custom includes to classpath
-           web_context,                       #web context (REST API only)
-           "'%s'" % dynamicimport_packages,   #DynamicImport-Package
-           description,                       #description
-          )
-
-  #TODO stage_jar is a horrendous hack
-  stage_jar = 'pushd $SRCDIR; mkdir bin; cd bin; jar xf $(location :%s); ls; popd; ' % bare_jar_name
-  wrap_jar = '$(exe //utils/osgiwrap:osgi-jar) ' + ' '.join(args)
-  bash = stage_jar + wrap_jar
-  if debug:
-    bash = stage_jar + DEBUG_ARG + ' ' + wrap_jar
-    print bash
-
-  # FIXME: make sure that /swagger.json gets filtered
-  genrule(
-    name = osgi_jar_name,
-    bash = bash,
-    out = '%s-%s.jar' % (name, version), #FIXME add version to jar file
-    srcs =  glob(['src/main/webapp/**']),
-    visibility = [], #intentially, not visible
-  )
-
-  # TODO we really should shade the jar with maven flavor
-  prebuilt_jar(
-    name = name,
-    maven_coords = mvn_coords,
-    binary_jar = ':' + osgi_jar_name,
-    visibility = visibility,
-  )
-
   ### Checkstyle
   checkstyle(
       name = name + '-checkstyle-files',
       srcs = srcs,
-      jar_target = ':'+ bare_jar_name,
+      jar_target = ':'+ name,
   )
 
   java_doc(
@@ -219,7 +186,7 @@
 
   # TODO add project config for intellij
   # project_config(
-  #   src_target = ':' + bare_jar_name,
+  #   src_target = ':' + name,
   #   src_roots = [ 'src/main/java' ],
   #   test_target = ':' + name + '-tests',
   #   test_roots = [ 'src/test/java' ],
@@ -247,6 +214,8 @@
 def osgi_jar_with_tests(
         name = None,
         deps = [],
+        group_id = ONOS_GROUP_ID,
+        version = ONOS_VERSION,
         test_srcs = None,
         test_deps = [ '//lib:TEST' ],
         test_resources = None,
@@ -260,7 +229,10 @@
 
   osgi_jar(name = name,
            deps = deps,
+           group_id = group_id,
+           version = version,
            visibility = visibility,
+           tests = [':' + name + '-tests'],
            **kwargs)
 
   if test_resources and not test_resources_root:
@@ -275,16 +247,18 @@
   if test_srcs is None:
       test_srcs = glob([TEST + '/*.java'])
 
+  mvn_coords = group_id + ':' + name + ':jar:tests:' + version
+
   java_test(
     name = name + '-tests',
     srcs = test_srcs,
     deps = deps +
            test_deps +
-           [':' + name + '-jar'],
-    source_under_test = [':' + name + '-jar'],
+           [':' + name + '#non-osgi'],
     resources = test_resources,
     resources_root = test_resources_root,
-    visibility = visibility
+    maven_coords = mvn_coords,
+    visibility = visibility,
   )
 
   checkstyle(
@@ -292,5 +266,3 @@
       srcs = test_srcs,
       jar_target = ':' + name + '-tests',
   )
-
-  #FIXME need to run checkstyle on test sources
diff --git a/tools/build/buck-plugin/BUCK b/tools/build/buck-plugin/BUCK
index 62e2875..37f1e8e 100644
--- a/tools/build/buck-plugin/BUCK
+++ b/tools/build/buck-plugin/BUCK
@@ -1,19 +1,23 @@
+# Comment the remote_jar out for local buck development
 remote_jar (
   name = 'buck-api',
   out = 'buck.jar',
-  url = 'https://github.com/bocon13/buck/releases/download/v2016.07.29.01-wip/buck.jar',
-  sha1 = 'f89324cb869b74fdcd4db9972233065a93d890a2',
+  url = 'https://github.com/bocon13/buck/releases/download/v2016.09.13.01/buck.jar',
+  sha1 = 'd5415b4326e5316675532a8cd48001a8456e8c9e',
   visibility = [],
 )
 
+# Uncomment the prebuilt_jar and copy buck-api to lib/buck.jar for local buck development
+# prebuilt_jar (
+#  name = 'buck-api',
+#  binary_jar = 'lib/buck.jar'
+# )
+
 COMPILE = [
   '//lib:qdox',
-  #'//lib:jackson-core',
-  #'//lib:jackson-databind',
-  #'//lib:jackson-annotations',
-]
-
-RUNTIME = [
+  '//lib:guava',
+  '//lib:bndlib',
+  '//lib:org.apache.felix.scr.bnd'
 ]
 
 java_library(
diff --git a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OSGiWrapper.java b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OSGiWrapper.java
new file mode 100644
index 0000000..aa529fc
--- /dev/null
+++ b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OSGiWrapper.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.onosproject.onosjar;
+
+import aQute.bnd.header.Attrs;
+import aQute.bnd.header.Parameters;
+import aQute.bnd.osgi.Analyzer;
+import aQute.bnd.osgi.Builder;
+import aQute.bnd.osgi.FileResource;
+import aQute.bnd.osgi.Jar;
+import aQute.bnd.osgi.Resource;
+import com.facebook.buck.step.ExecutionContext;
+import com.facebook.buck.step.Step;
+import com.facebook.buck.step.StepExecutionResult;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+
+import static java.nio.file.Files.walkFileTree;
+
+/**
+ * BND-based wrapper to convert Buck JARs to OSGi-compatible JARs.
+ */
+public class OSGiWrapper implements Step {
+
+    private Path inputJar;
+    private Path outputJar;
+    private Path sourcesDir;
+    private Path classesDir;
+    private List<String> classpath;
+
+    private String bundleName;
+    private String groupId;
+    private String bundleSymbolicName;
+    private String bundleVersion;
+
+    private String importPackages;
+    private String dynamicimportPackages;
+
+    private String exportPackages;
+    private String includeResources;
+    private Set<String> includedResources = Sets.newHashSet();
+
+    private String bundleDescription;
+    private String bundleLicense;
+
+    private String webContext;
+
+    private PrintStream stderr = System.err;
+
+    public OSGiWrapper(Path inputJar,
+                       Path outputJar,
+                       Path sourcesDir,
+                       Path classesDir,
+                       ImmutableSortedSet<Path> classpath,
+                       String bundleName,
+                       String groupId,
+                       String bundleVersion,
+                       String bundleLicense,
+                       String importPackages,
+                       String exportPackages,
+                       String includeResources,
+                       String webContext,
+                       String dynamicimportPackages,
+                       String bundleDescription) {
+        this.inputJar = inputJar;
+        this.sourcesDir = sourcesDir;
+        this.classesDir = classesDir;
+        this.classpath = Lists.newArrayList(
+                classpath.stream().map(Path::toString).collect(Collectors.toList()));
+        if (!this.classpath.contains(inputJar.toString())) {
+            this.classpath.add(0, inputJar.toString());
+        }
+        this.outputJar = outputJar;
+
+        this.bundleName = bundleName;
+        this.groupId = groupId;
+        this.bundleSymbolicName = String.format("%s.%s", groupId, bundleName);
+
+        this.bundleVersion = bundleVersion;
+        this.bundleLicense = bundleLicense;
+        this.bundleDescription = bundleDescription;
+
+        this.importPackages = importPackages;
+        this.dynamicimportPackages = dynamicimportPackages;
+        this.exportPackages = exportPackages;
+        this.includeResources = includeResources;
+
+        this.webContext = webContext;
+    }
+
+    private void setProperties(Analyzer analyzer) {
+        analyzer.setProperty(Analyzer.BUNDLE_NAME, bundleName);
+        analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, bundleSymbolicName);
+        analyzer.setProperty(Analyzer.BUNDLE_VERSION, bundleVersion.replace('-', '.'));
+
+        if (bundleDescription != null) {
+            analyzer.setProperty(Analyzer.BUNDLE_DESCRIPTION, bundleDescription);
+        }
+        if (bundleLicense != null) {
+            analyzer.setProperty(Analyzer.BUNDLE_LICENSE, bundleLicense);
+        }
+
+        //TODO consider using stricter version policy
+        //analyzer.setProperty("-provider-policy", "${range;[===,==+)}");
+        //analyzer.setProperty("-consumer-policy", "${range;[===,==+)}");
+
+        // There are no good defaults so make sure you set the Import-Package
+        analyzer.setProperty(Analyzer.IMPORT_PACKAGE, importPackages);
+
+        analyzer.setProperty(Analyzer.DYNAMICIMPORT_PACKAGE, dynamicimportPackages);
+
+        // TODO include version in export, but not in import
+        analyzer.setProperty(Analyzer.EXPORT_PACKAGE, exportPackages);
+
+        // TODO we may need INCLUDE_RESOURCE, or that might be done by Buck
+        if (includeResources != null) {
+            analyzer.setProperty(Analyzer.INCLUDE_RESOURCE, includeResources);
+        }
+
+        if (isWab()) {
+            analyzer.setProperty(Analyzer.WAB, "src/main/webapp/");
+            analyzer.setProperty("Web-ContextPath", webContext);
+            analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet,org.jvnet.mimepull\n");
+        }
+    }
+
+    public boolean execute() {
+        Analyzer analyzer = new Builder();
+        try {
+
+            Jar jar = new Jar(inputJar.toFile());  // where our data is
+            analyzer.setJar(jar);                   // give bnd the contents
+
+            // You can provide additional class path entries to allow
+            // bnd to pickup export version from the packageinfo file,
+            // Version annotation, or their manifests.
+            analyzer.addClasspath(classpath);
+
+            setProperties(analyzer);
+
+            //analyzer.setBase(classesDir.toFile());
+
+//            analyzer.setProperty("DESTDIR");
+//            analyzer.setBase();
+
+            // ------------- let's begin... -------------------------
+
+            // Analyze the target JAR first
+            analyzer.analyze();
+
+            // Scan the JAR for Felix SCR annotations and generate XML files
+            Map<String, String> properties = Maps.newHashMap();
+            properties.put("destdir", classesDir.toAbsolutePath().toString());
+            SCRDescriptorBndPlugin scrDescriptorBndPlugin = new SCRDescriptorBndPlugin();
+            scrDescriptorBndPlugin.setProperties(properties);
+            scrDescriptorBndPlugin.setReporter(analyzer);
+            scrDescriptorBndPlugin.analyzeJar(analyzer);
+
+            if (includeResources != null) {
+                doIncludeResources(analyzer);
+            }
+
+            // Repack the JAR as a WAR
+            doWabStaging(analyzer);
+
+            // Calculate the manifest
+            Manifest manifest = analyzer.calcManifest();
+            //OutputStream s = new FileOutputStream("/tmp/foo2.txt");
+            //manifest.write(s);
+            //s.close();
+
+            if (analyzer.isOk()) {
+                analyzer.getJar().setManifest(manifest);
+                if (analyzer.save(outputJar.toFile(), true)) {
+                    log("Saved!\n");
+                } else {
+                    warn("Failed to create jar \n");
+                    return false;
+                }
+            } else {
+                warn("Analyzer Errors:\n%s\n", analyzer.getErrors());
+                return false;
+            }
+
+            analyzer.close();
+
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    private boolean isWab() {
+        return webContext != null;
+    }
+
+    private void doWabStaging(Analyzer analyzer) throws Exception {
+        if (!isWab()) {
+            return;
+        }
+        String wab = analyzer.getProperty(analyzer.WAB);
+        Jar dot = analyzer.getJar();
+
+        log("wab %s", wab);
+        analyzer.setBundleClasspath("WEB-INF/classes," +
+                                    analyzer.getProperty(analyzer.BUNDLE_CLASSPATH));
+
+        Set<String> paths = new HashSet<>(dot.getResources().keySet());
+
+        for (String path : paths) {
+            if (path.indexOf('/') > 0 && !Character.isUpperCase(path.charAt(0))) {
+                log("wab: moving: %s", path);
+                dot.rename(path, "WEB-INF/classes/" + path);
+            }
+        }
+
+        Path wabRoot = Paths.get(wab);
+        includeFiles(dot, null, wabRoot.toString());
+    }
+
+    /**
+     * Parse the Bundle-Includes header. Files in the bundles Include header are
+     * included in the jar. The source can be a directory or a file.
+     *
+     * @throws Exception
+     */
+    private void doIncludeResources(Analyzer analyzer) throws Exception {
+        String includes = analyzer.getProperty(Analyzer.INCLUDE_RESOURCE);
+        if (includes == null) {
+            return;
+        }
+        Parameters clauses = analyzer.parseHeader(includes);
+        Jar jar = analyzer.getJar();
+
+        for (Map.Entry<String, Attrs> entry : clauses.entrySet()) {
+            String name = entry.getKey();
+            Map<String, String> extra = entry.getValue();
+            // TODO consider doing something with extras
+
+            String[] parts = name.split("\\s*=\\s*");
+            String source = parts[0];
+            String destination = parts[0];
+            if (parts.length == 2) {
+                source = parts[1];
+            }
+
+            includeFiles(jar, destination, source);
+        }
+    }
+
+    private void includeFiles(Jar jar, String destinationRoot, String sourceRoot)
+            throws IOException {
+
+        Path classesBasedPath = classesDir.resolve(sourceRoot);
+        Path sourceBasedPath = sourcesDir.resolve(sourceRoot);
+
+        File classFile = classesBasedPath.toFile();
+        File sourceFile = sourceBasedPath.toFile();
+
+        if (classFile.isFile()) {
+            addFileToJar(jar, destinationRoot, classesBasedPath.toAbsolutePath().toString());
+        } else if (sourceFile.isFile()) {
+            addFileToJar(jar, destinationRoot, sourceBasedPath.toAbsolutePath().toString());
+        } else if (classFile.isDirectory()) {
+            includeDirectory(jar, destinationRoot, classesBasedPath);
+        } else if (sourceFile.isDirectory()) {
+            includeDirectory(jar, destinationRoot, sourceBasedPath);
+        } else {
+            warn("Skipping resource in bundle %s: %s (File Not Found)\n",
+                 bundleSymbolicName, sourceRoot);
+        }
+    }
+
+    private void includeDirectory(Jar jar, String destinationRoot, Path sourceRoot)
+            throws IOException {
+        // iterate through sources
+        // put each source on the jar
+        FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                Path relativePath = sourceRoot.relativize(file);
+                String destination = destinationRoot != null ?
+                        destinationRoot + "/" + relativePath.toString() : //TODO
+                        relativePath.toString();
+
+                addFileToJar(jar, destination, file.toAbsolutePath().toString());
+                return FileVisitResult.CONTINUE;
+            }
+        };
+
+        walkFileTree(sourceRoot, visitor);
+    }
+
+    private boolean addFileToJar(Jar jar, String destination, String sourceAbsPath) {
+        if (includedResources.contains(sourceAbsPath)) {
+            log("Skipping already included resource: %s\n", sourceAbsPath);
+            return false;
+        }
+        File file = new File(sourceAbsPath);
+        if (!file.isFile()) {
+            throw new RuntimeException(
+                    String.format("Skipping non-existent file: %s\n", sourceAbsPath));
+        }
+        Resource resource = new FileResource(file);
+        if (jar.getResource(destination) != null) {
+            warn("Skipping duplicate resource: %s\n", destination);
+            return false;
+        }
+        jar.putResource(destination, resource);
+        includedResources.add(sourceAbsPath);
+        log("Adding resource: %s\n", destination);
+        return true;
+    }
+
+    private void log(String format, Object... objects) {
+        //System.err.printf(format, objects);
+    }
+
+    private void warn(String format, Object... objects) {
+        stderr.printf(format, objects);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("inputJar", inputJar)
+                .add("outputJar", outputJar)
+                .add("classpath", classpath)
+                .add("bundleName", bundleName)
+                .add("groupId", groupId)
+                .add("bundleSymbolicName", bundleSymbolicName)
+                .add("bundleVersion", bundleVersion)
+                .add("bundleDescription", bundleDescription)
+                .add("bundleLicense", bundleLicense)
+                .toString();
+
+    }
+
+    @Override
+    public StepExecutionResult execute(ExecutionContext executionContext)
+            throws IOException, InterruptedException {
+        stderr = executionContext.getStdErr();
+        boolean success = execute();
+        stderr = System.err;
+        return success ? StepExecutionResult.SUCCESS : StepExecutionResult.ERROR;
+    }
+
+    @Override
+    public String getShortName() {
+        return "osgiwrap";
+    }
+
+    @Override
+    public String getDescription(ExecutionContext executionContext) {
+        return "osgiwrap"; //FIXME
+    }
+}
diff --git a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJar.java b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJar.java
index a63c115..3c71968 100644
--- a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJar.java
+++ b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJar.java
@@ -17,6 +17,10 @@
 
 import com.facebook.buck.jvm.java.CompileToJarStepFactory;
 import com.facebook.buck.jvm.java.DefaultJavaLibrary;
+import com.facebook.buck.jvm.java.HasClasspathEntries;
+import com.facebook.buck.jvm.java.HasMavenCoordinates;
+import com.facebook.buck.jvm.java.JavaLibrary;
+import com.facebook.buck.jvm.java.MavenPublishable;
 import com.facebook.buck.model.BuildTarget;
 import com.facebook.buck.rules.AddToRuleKey;
 import com.facebook.buck.rules.BuildRule;
@@ -24,6 +28,7 @@
 import com.facebook.buck.rules.SourcePath;
 import com.facebook.buck.rules.SourcePathResolver;
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
@@ -36,7 +41,8 @@
  * Implementation of a build rule that generates a onosjar.json file for a set
  * of Java sources.
  */
-public class OnosJar extends DefaultJavaLibrary {
+public class OnosJar extends DefaultJavaLibrary
+        implements MavenPublishable{
 
     @AddToRuleKey
     final Optional<String> webContext;
@@ -53,6 +59,8 @@
     @AddToRuleKey
     final Optional<String> apiDescription;
 
+    private final ImmutableSortedSet<HasMavenCoordinates> mavenDeps;
+
     public OnosJar(BuildRuleParams params,
                    SourcePathResolver resolver,
                    Set<? extends SourcePath> srcs,
@@ -84,5 +92,32 @@
         this.apiVersion = apiVersion;
         this.apiPackage = apiPackage;
         this.apiDescription = apiDescription;
+        this.mavenDeps = computeMavenDeps();
+    }
+
+    private ImmutableSortedSet<HasMavenCoordinates> computeMavenDeps() {
+        ImmutableSortedSet.Builder<HasMavenCoordinates> mavenDeps = ImmutableSortedSet.naturalOrder();
+        for (JavaLibrary javaLibrary : getTransitiveClasspathDeps()) {
+            if (this.equals(javaLibrary)) {
+                // no need to include ourself
+                continue;
+            } else if (HasMavenCoordinates.MAVEN_COORDS_PRESENT_PREDICATE.apply(javaLibrary)) {
+                mavenDeps.add(javaLibrary);
+                //FIXME BOC do we always want to exclude all of a maven jar's dependencies? probably.
+                mavenDeps.addAll(javaLibrary.getTransitiveClasspathDeps());
+            }
+        }
+        return mavenDeps.build();
+    }
+
+    @Override
+    public Iterable<HasMavenCoordinates> getMavenDeps() {
+        return mavenDeps;
+    }
+
+    @Override
+    public Iterable<BuildRule> getPackagedDependencies() {
+        //FIXME this is not supported at the moment
+        return ImmutableList.of();
     }
 }
diff --git a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJarDescription.java b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJarDescription.java
index 7632ade..dff37c0 100644
--- a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJarDescription.java
+++ b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJarDescription.java
@@ -19,13 +19,21 @@
 import com.facebook.buck.jvm.java.CalculateAbi;
 import com.facebook.buck.jvm.java.DefaultJavaLibrary;
 import com.facebook.buck.jvm.java.JavaBuckConfig;
+import com.facebook.buck.jvm.java.JavaLibrary;
 import com.facebook.buck.jvm.java.JavaLibraryDescription;
 import com.facebook.buck.jvm.java.JavaOptions;
+import com.facebook.buck.jvm.java.JavaSourceJar;
 import com.facebook.buck.jvm.java.JavacOptions;
 import com.facebook.buck.jvm.java.JavacOptionsAmender;
 import com.facebook.buck.jvm.java.JavacOptionsFactory;
+import com.facebook.buck.jvm.java.JavacToJarStepFactory;
+import com.facebook.buck.jvm.java.JavadocJar;
+import com.facebook.buck.jvm.java.MavenUberJar;
+import com.facebook.buck.maven.AetherUtil;
 import com.facebook.buck.model.BuildTarget;
 import com.facebook.buck.model.Flavor;
+import com.facebook.buck.model.Flavored;
+import com.facebook.buck.model.ImmutableFlavor;
 import com.facebook.buck.parser.NoSuchBuildTargetException;
 import com.facebook.buck.rules.BuildRule;
 import com.facebook.buck.rules.BuildRuleParams;
@@ -37,7 +45,9 @@
 import com.facebook.buck.rules.SourcePathResolver;
 import com.facebook.buck.rules.SourcePaths;
 import com.facebook.buck.rules.TargetGraph;
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Iterables;
@@ -51,8 +61,16 @@
  *
  * Currently, this only does Swagger generation.
  */
-public class OnosJarDescription implements Description<OnosJarDescription.Arg> {
+public class OnosJarDescription implements Description<OnosJarDescription.Arg>, Flavored {
     public static final BuildRuleType TYPE = BuildRuleType.of("onos_jar");
+    public static final Flavor NON_OSGI_JAR = ImmutableFlavor.of("non-osgi");
+
+    public static final ImmutableSet<Flavor> SUPPORTED_FLAVORS = ImmutableSet.of(
+            JavaLibrary.SRC_JAR,
+            JavaLibrary.MAVEN_JAR,
+            JavaLibrary.JAVADOC_JAR,
+            NON_OSGI_JAR);
+
     private final JavacOptions defaultJavacOptions;
     private final JavaOptions defaultJavaOptions;
 
@@ -89,6 +107,63 @@
         ImmutableSortedSet<Flavor> flavors = target.getFlavors();
         BuildRuleParams paramsWithMavenFlavor = null;
 
+        if (flavors.contains(JavaLibrary.MAVEN_JAR)) {
+            paramsWithMavenFlavor = params;
+
+            // Maven rules will depend upon their vanilla versions, so the latter have to be constructed
+            // without the maven flavor to prevent output-path conflict
+            params = params.copyWithBuildTarget(
+                    params.getBuildTarget().withoutFlavors(ImmutableSet.of(JavaLibrary.MAVEN_JAR)));
+        }
+
+        if (flavors.contains(JavaLibrary.SRC_JAR)) {
+            args.mavenCoords = args.mavenCoords.transform(
+                    new Function<String, String>() {
+                        @Override
+                        public String apply(String input) {
+                            return AetherUtil.addClassifier(input, AetherUtil.CLASSIFIER_SOURCES);
+                        }
+                    });
+
+            if (!flavors.contains(JavaLibrary.MAVEN_JAR)) {
+                return new JavaSourceJar(
+                        params,
+                        pathResolver,
+                        args.srcs.get(),
+                        args.mavenCoords);
+            } else {
+                return MavenUberJar.SourceJar.create(
+                        Preconditions.checkNotNull(paramsWithMavenFlavor),
+                        pathResolver,
+                        args.srcs.get(),
+                        args.mavenCoords);
+            }
+        }
+
+        if (flavors.contains(JavaLibrary.JAVADOC_JAR)) {
+            args.mavenCoords = args.mavenCoords.transform(
+                    new Function<String, String>() {
+                        @Override
+                        public String apply(String input) {
+                            return AetherUtil.addClassifier(input, AetherUtil.CLASSIFIER_JAVADOC);
+                        }
+                    });
+
+            if (!flavors.contains(JavaLibrary.MAVEN_JAR)) {
+                return new JavadocJar(
+                        params,
+                        pathResolver,
+                        args.srcs.get(),
+                        args.mavenCoords);
+            } else {
+                return MavenUberJar.MavenJavadocJar.create(
+                        Preconditions.checkNotNull(paramsWithMavenFlavor),
+                        pathResolver,
+                        args.srcs.get(),
+                        args.mavenCoords);
+            }
+        }
+
         JavacOptions javacOptions = JavacOptionsFactory.create(
                 defaultJavacOptions,
                 params,
@@ -101,45 +176,84 @@
 
         ImmutableSortedSet<BuildRule> exportedDeps = resolver.getAllRules(args.exportedDeps.get());
 
-        DefaultJavaLibrary defaultJavaLibrary =
-                resolver.addToIndex(
-                        new OnosJar(
-                                params.appendExtraDeps(
-                                        Iterables.concat(
-                                                BuildRules.getExportedRules(
-                                                        Iterables.concat(
-                                                                params.getDeclaredDeps().get(),
-                                                                exportedDeps,
-                                                                resolver.getAllRules(args.providedDeps.get()))),
-                                                pathResolver.filterBuildRuleInputs(
-                                                        javacOptions.getInputs(pathResolver)))),
-                                pathResolver,
-                                args.srcs.get(),
-                                validateResources(
-                                        pathResolver,
-                                        params.getProjectFilesystem(),
-                                        args.resources.get()),
-                                javacOptions.getGeneratedSourceFolderName(),
-                                args.proguardConfig.transform(
-                                        SourcePaths.toSourcePath(params.getProjectFilesystem())),
-                                args.postprocessClassesCommands.get(), // FIXME this should be forbidden
-                                exportedDeps,
-                                resolver.getAllRules(args.providedDeps.get()),
-                                new BuildTargetSourcePath(abiJarTarget),
-                                javacOptions.trackClassUsage(),
+        final DefaultJavaLibrary defaultJavaLibrary;
+        if (!flavors.contains(NON_OSGI_JAR)) {
+            defaultJavaLibrary =
+                    resolver.addToIndex(
+                            new OnosJar(
+                                    params.appendExtraDeps(
+                                            Iterables.concat(
+                                                    BuildRules.getExportedRules(
+                                                            Iterables.concat(
+                                                                    params.getDeclaredDeps().get(),
+                                                                    exportedDeps,
+                                                                    resolver.getAllRules(args.providedDeps.get()))),
+                                                    pathResolver.filterBuildRuleInputs(
+                                                            javacOptions.getInputs(pathResolver)))),
+                                    pathResolver,
+                                    args.srcs.get(),
+                                    validateResources(
+                                            pathResolver,
+                                            params.getProjectFilesystem(),
+                                            args.resources.get()),
+                                    javacOptions.getGeneratedSourceFolderName(),
+                                    args.proguardConfig.transform(
+                                            SourcePaths.toSourcePath(params.getProjectFilesystem())),
+                                    args.postprocessClassesCommands.get(), // FIXME this should be forbidden
+                                    exportedDeps,
+                                    resolver.getAllRules(args.providedDeps.get()),
+                                    new BuildTargetSourcePath(abiJarTarget),
+                                    javacOptions.trackClassUsage(),
                                 /* additionalClasspathEntries */ ImmutableSet.<Path>of(),
-                                new OnosJarStepFactory(javacOptions, JavacOptionsAmender.IDENTITY,
-                                                       args.webContext, args.apiTitle, args.apiVersion,
-                                                       args.apiPackage, args.apiDescription, args.resources),
-                                args.resourcesRoot,
-                                args.mavenCoords,
-                                args.tests.get(),
-                                javacOptions.getClassesToRemoveFromJar(),
-                                args.webContext,
-                                args.apiTitle,
-                                args.apiVersion,
-                                args.apiPackage,
-                                args.apiDescription));
+                                    new OnosJarStepFactory(javacOptions, JavacOptionsAmender.IDENTITY,
+                                                           args.webContext, args.apiTitle, args.apiVersion,
+                                                           args.apiPackage, args.apiDescription, args.resources,
+                                                           args.groupId, args.bundleName, args.bundleVersion,
+                                                           args.bundleLicense, args.bundleDescription, args.importPackages,
+                                                           args.exportPackages, args.includeResources, args.dynamicimportPackages),
+                                    args.resourcesRoot,
+                                    args.mavenCoords,
+                                    args.tests.get(),
+                                    javacOptions.getClassesToRemoveFromJar(),
+                                    args.webContext,
+                                    args.apiTitle,
+                                    args.apiVersion,
+                                    args.apiPackage,
+                                    args.apiDescription));
+        } else {
+            defaultJavaLibrary =
+                    resolver.addToIndex(
+                            new DefaultJavaLibrary(
+                                    params.appendExtraDeps(
+                                            Iterables.concat(
+                                                    BuildRules.getExportedRules(
+                                                            Iterables.concat(
+                                                                    params.getDeclaredDeps().get(),
+                                                                    exportedDeps,
+                                                                    resolver.getAllRules(args.providedDeps.get()))),
+                                                    pathResolver.filterBuildRuleInputs(
+                                                            javacOptions.getInputs(pathResolver)))),
+                                    pathResolver,
+                                    args.srcs.get(),
+                                    validateResources(
+                                            pathResolver,
+                                            params.getProjectFilesystem(),
+                                            args.resources.get()),
+                                    javacOptions.getGeneratedSourceFolderName(),
+                                    args.proguardConfig.transform(
+                                            SourcePaths.toSourcePath(params.getProjectFilesystem())),
+                                    args.postprocessClassesCommands.get(),
+                                    exportedDeps,
+                                    resolver.getAllRules(args.providedDeps.get()),
+                                    new BuildTargetSourcePath(abiJarTarget),
+                                    javacOptions.trackClassUsage(),
+                                    /* additionalClasspathEntries */ ImmutableSet.<Path>of(),
+                                    new JavacToJarStepFactory(javacOptions, JavacOptionsAmender.IDENTITY),
+                                    args.resourcesRoot,
+                                    args.mavenCoords,
+                                    args.tests.get(),
+                                    javacOptions.getClassesToRemoveFromJar()));
+        }
 
         resolver.addToIndex(
                 CalculateAbi.of(
@@ -151,6 +265,10 @@
         return defaultJavaLibrary;
     }
 
+    @Override
+    public boolean hasFlavors(ImmutableSet<Flavor> flavors) {
+        return SUPPORTED_FLAVORS.containsAll(flavors);
+    }
 
     public static class Arg extends JavaLibraryDescription.Arg {
         public Optional<String> webContext;
@@ -158,5 +276,16 @@
         public Optional<String> apiVersion;
         public Optional<String> apiPackage;
         public Optional<String> apiDescription;
+
+        public Optional<String> groupId;
+        public Optional<String> bundleName;
+        public Optional<String> bundleVersion;
+        public Optional<String> bundleLicense;
+        public Optional<String> bundleDescription;
+
+        public Optional<String> importPackages;
+        public Optional<String> exportPackages;
+        public Optional<String> includeResources;
+        public Optional<String> dynamicimportPackages;
     }
 }
\ No newline at end of file
diff --git a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJarStepFactory.java b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJarStepFactory.java
index aa0e9f6..ae2853b 100644
--- a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJarStepFactory.java
+++ b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/OnosJarStepFactory.java
@@ -28,12 +28,14 @@
 import com.facebook.buck.rules.SourcePath;
 import com.facebook.buck.rules.SourcePathResolver;
 import com.facebook.buck.step.Step;
+import com.facebook.buck.step.fs.CopyStep;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -49,6 +51,15 @@
     private final String apiPackage;
     private final String apiDescription;
     private final Optional<ImmutableSortedSet<SourcePath>> resources;
+    private final String groupId;
+    private final String bundleName;
+    private final String bundleVersion;
+    private final String bundleLicense;
+    private final String bundleDescription;
+    private final String importPackages;
+    private final String exportPackages;
+    private final String includeResources;
+    private final String dynamicimportPackages;
 
     public OnosJarStepFactory(JavacOptions javacOptions,
                               JavacOptionsAmender amender,
@@ -57,8 +68,26 @@
                               Optional<String> apiVersion,
                               Optional<String> apiPackage,
                               Optional<String> apiDescription,
-                              Optional<ImmutableSortedSet<SourcePath>> resources) {
+                              Optional<ImmutableSortedSet<SourcePath>> resources,
+                              Optional<String> groupId,
+                              Optional<String> bundleName,
+                              Optional<String> bundleVersion,
+                              Optional<String> bundleLicense,
+                              Optional<String> bundleDescription,
+                              Optional<String> importPackages,
+                              Optional<String> exportPackages,
+                              Optional<String> includeResources,
+                              Optional<String> dynamicimportPackages) {
         super(javacOptions, amender);
+        this.bundleDescription = processParameter(bundleDescription);
+        this.importPackages = processParameter(importPackages);
+        this.exportPackages = processParameter(exportPackages);
+        this.includeResources = processParameter(includeResources);
+        this.dynamicimportPackages = processParameter(dynamicimportPackages);
+        this.groupId = processParameter(groupId);
+        this.bundleName = processParameter(bundleName);
+        this.bundleVersion = processParameter(bundleVersion);
+        this.bundleLicense = processParameter(bundleLicense);
         this.webContext = processParameter(webContext);
         this.apiTitle = processParameter(apiTitle);
         this.apiVersion = processParameter(apiVersion);
@@ -114,6 +143,11 @@
                                                       apiPackage, apiDescription);
             sourceFilePathBuilder.add(swaggerStep.apiRegistratorPath());
             steps.add(swaggerStep);
+
+//            steps.addAll(sourceFilePaths.stream()
+//                    .filter(sp -> sp.startsWith("src/main/webapp/"))
+//                    .map(sp -> CopyStep.forFile(filesystem, sp, outputDirectory))
+//                    .iterator());
         }
 
         createCompileStep(context,
@@ -132,6 +166,7 @@
 
         // post compilation steps
 
+
         // FIXME BOC: add mechanism to inject new Steps
         //context.additionalStepFactory(JavaStep.class);
 
@@ -143,6 +178,28 @@
                                        manifestFile.orNull(),
                                        true,
                                        blacklistBuilder.build()));
+
+        OSGiWrapper osgiStep = new OSGiWrapper(
+                outputJar, //input jar
+                outputJar, //Paths.get(outputJar.toString() + ".jar"), //output jar
+                invokingRule.getBasePath(), // sources dir
+                outputDirectory, // classes dir
+                declaredClasspathEntries, // classpath
+                bundleName, // bundle name
+                groupId, // groupId
+                bundleVersion, // bundle version
+                bundleLicense, // bundle license
+                importPackages, // import packages
+                exportPackages, // export packages
+                includeResources, // include resources
+                webContext, // web context
+                dynamicimportPackages, // dynamic import packages
+                bundleDescription  // bundle description
+        );
+        steps.add(osgiStep);
+
+        //steps.add(CopyStep.forFile(filesystem, Paths.get(outputJar.toString() + ".jar"), outputJar));
+
     }
 
     private ImmutableSortedSet<Path> findSwaggerModelDefs(SourcePathResolver resolver,
diff --git a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/SwaggerGenerator.java b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/SwaggerGenerator.java
index 898be8c..14d401b 100644
--- a/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/SwaggerGenerator.java
+++ b/tools/build/buck-plugin/src/main/java/org/onosproject/onosjar/SwaggerGenerator.java
@@ -102,10 +102,12 @@
             }
             if (srcs != null) {
                 srcs.forEach(src -> {
-                    try {
-                        builder.addSource(src);
-                    } catch (IOException e) {
-                        throw new RuntimeException(e);
+                    if (src.toString().endsWith(".java")) {
+                        try {
+                            builder.addSource(src);
+                        } catch (IOException e) {
+                            throw new RuntimeException(e);
+                        }
                     }
                 });
             }