[ONOS-5724],[ONOS-5725],[ONOS-5736] onos buck plugin modifications for support of private package property.

Change-Id: Ic3a2f13c14816e803debc208826445ef27b49a4f
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
index aa529fc..8cf91af 100644
--- 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
@@ -20,8 +20,12 @@
 import aQute.bnd.header.Parameters;
 import aQute.bnd.osgi.Analyzer;
 import aQute.bnd.osgi.Builder;
+import aQute.bnd.osgi.Constants;
+import aQute.bnd.osgi.Descriptors;
 import aQute.bnd.osgi.FileResource;
 import aQute.bnd.osgi.Jar;
+import aQute.bnd.osgi.Packages;
+import aQute.bnd.osgi.Processor;
 import aQute.bnd.osgi.Resource;
 import com.facebook.buck.step.ExecutionContext;
 import com.facebook.buck.step.Step;
@@ -32,6 +36,7 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin;
+import org.codehaus.plexus.util.DirectoryScanner;
 
 import java.io.File;
 import java.io.IOException;
@@ -45,6 +50,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 import java.util.jar.Manifest;
 import java.util.stream.Collectors;
@@ -68,6 +74,7 @@
     private String bundleVersion;
 
     private String importPackages;
+    private String privatePackages;
     private String dynamicimportPackages;
 
     private String exportPackages;
@@ -95,7 +102,8 @@
                        String includeResources,
                        String webContext,
                        String dynamicimportPackages,
-                       String bundleDescription) {
+                       String bundleDescription,
+                       String privatePackages) {
         this.inputJar = inputJar;
         this.sourcesDir = sourcesDir;
         this.classesDir = classesDir;
@@ -115,6 +123,7 @@
         this.bundleDescription = bundleDescription;
 
         this.importPackages = importPackages;
+        this.privatePackages = privatePackages;
         this.dynamicimportPackages = dynamicimportPackages;
         this.exportPackages = exportPackages;
         this.includeResources = includeResources;
@@ -140,11 +149,16 @@
 
         // There are no good defaults so make sure you set the Import-Package
         analyzer.setProperty(Analyzer.IMPORT_PACKAGE, importPackages);
+        if (privatePackages != null) {
+            analyzer.setProperty(Analyzer.PRIVATE_PACKAGE, privatePackages);
+        }
+        analyzer.setProperty(Analyzer.REMOVEHEADERS, "Private-Package,Include-Resource");
 
-        analyzer.setProperty(Analyzer.DYNAMICIMPORT_PACKAGE, dynamicimportPackages);
+        analyzer.setProperty(Analyzer.DYNAMICIMPORT_PACKAGE,
+                             dynamicimportPackages);
 
         // TODO include version in export, but not in import
-        analyzer.setProperty(Analyzer.EXPORT_PACKAGE, exportPackages);
+        //    analyzer.setProperty(Analyzer.EXPORT_PACKAGE, exportPackages);
 
         // TODO we may need INCLUDE_RESOURCE, or that might be done by Buck
         if (includeResources != null) {
@@ -159,7 +173,7 @@
     }
 
     public boolean execute() {
-        Analyzer analyzer = new Builder();
+        Builder analyzer = new Builder();
         try {
 
             Jar jar = new Jar(inputJar.toFile());  // where our data is
@@ -179,17 +193,11 @@
 
             // ------------- let's begin... -------------------------
 
-            // Analyze the target JAR first
-            analyzer.analyze();
+            //Add local packges to jar file.
+            addLocalPackages(new File(classesDir.toString()), analyzer);
+//            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);
-
+            //add resources.
             if (includeResources != null) {
                 doIncludeResources(analyzer);
             }
@@ -198,13 +206,27 @@
             doWabStaging(analyzer);
 
             // Calculate the manifest
-            Manifest manifest = analyzer.calcManifest();
+//            Manifest manifest = analyzer.calcManifest();
             //OutputStream s = new FileOutputStream("/tmp/foo2.txt");
             //manifest.write(s);
             //s.close();
 
             if (analyzer.isOk()) {
+                //Build the jar files
+                analyzer.build();
+                Map<String, String> properties = Maps.newHashMap();
+
+                // Scan the JAR for Felix SCR annotations and generate XML files
+                properties.put("destdir", classesDir.toAbsolutePath().toString());
+                SCRDescriptorBndPlugin scrDescriptorBndPlugin = new SCRDescriptorBndPlugin();
+                scrDescriptorBndPlugin.setProperties(properties);
+                scrDescriptorBndPlugin.setReporter(analyzer);
+                scrDescriptorBndPlugin.analyzeJar(analyzer);
+
+                //add calculated manifest file.
+                Manifest manifest = analyzer.calcManifest();
                 analyzer.getJar().setManifest(manifest);
+
                 if (analyzer.save(outputJar.toFile(), true)) {
                     log("Saved!\n");
                 } else {
@@ -225,6 +247,75 @@
         }
     }
 
+    private static void addLocalPackages(File outputDirectory, Analyzer analyzer) throws IOException {
+        Packages packages = new Packages();
+
+        if (outputDirectory != null && outputDirectory.isDirectory()) {
+            // scan classes directory for potential packages
+            DirectoryScanner scanner = new DirectoryScanner();
+            scanner.setBasedir(outputDirectory);
+            scanner.setIncludes(new String[]
+                                        {"**/*.class"});
+
+            scanner.addDefaultExcludes();
+            scanner.scan();
+
+            String[] paths = scanner.getIncludedFiles();
+            for (int i = 0; i < paths.length; i++) {
+                packages.put(analyzer.getPackageRef(getPackageName(paths[i])));
+            }
+        }
+
+        Packages exportedPkgs = new Packages();
+        Packages privatePkgs = new Packages();
+
+        boolean noprivatePackages = "!*".equals(analyzer.getProperty(Analyzer.PRIVATE_PACKAGE));
+
+        for (Descriptors.PackageRef pkg : packages.keySet()) {
+            // mark all source packages as private by default (can be overridden by export list)
+            privatePkgs.put(pkg);
+
+            // we can't export the default package (".") and we shouldn't export internal packages
+            String fqn = pkg.getFQN();
+            if (noprivatePackages || !(".".equals(fqn) || fqn.contains(".internal") || fqn.contains(".impl"))) {
+                exportedPkgs.put(pkg);
+            }
+        }
+
+        Properties properties = analyzer.getProperties();
+        String exported = properties.getProperty(Analyzer.EXPORT_PACKAGE);
+        if (exported == null) {
+            if (!properties.containsKey(Analyzer.EXPORT_CONTENTS)) {
+                // no -exportcontents overriding the exports, so use our computed list
+                for (Attrs attrs : exportedPkgs.values()) {
+                    attrs.put(Constants.SPLIT_PACKAGE_DIRECTIVE, "merge-first");
+                }
+                properties.setProperty(Analyzer.EXPORT_PACKAGE, Processor.printClauses(exportedPkgs));
+            } else {
+                // leave Export-Package empty (but non-null) as we have -exportcontents
+                properties.setProperty(Analyzer.EXPORT_PACKAGE, "");
+            }
+        }
+
+        String internal = properties.getProperty(Analyzer.PRIVATE_PACKAGE);
+        if (internal == null) {
+            if (!privatePkgs.isEmpty()) {
+                for (Attrs attrs : privatePkgs.values()) {
+                    attrs.put(Constants.SPLIT_PACKAGE_DIRECTIVE, "merge-first");
+                }
+                properties.setProperty(Analyzer.PRIVATE_PACKAGE, Processor.printClauses(privatePkgs));
+            } else {
+                // if there are really no private packages then use "!*" as this will keep the Bnd Tool happy
+                properties.setProperty(Analyzer.PRIVATE_PACKAGE, "!*");
+            }
+        }
+    }
+
+    private static String getPackageName(String filename) {
+        int n = filename.lastIndexOf(File.separatorChar);
+        return n < 0 ? "." : filename.substring(0, n).replace(File.separatorChar, '.');
+    }
+
     private boolean isWab() {
         return webContext != null;
     }
@@ -238,7 +329,7 @@
 
         log("wab %s", wab);
         analyzer.setBundleClasspath("WEB-INF/classes," +
-                                    analyzer.getProperty(analyzer.BUNDLE_CLASSPATH));
+                                            analyzer.getProperty(analyzer.BUNDLE_CLASSPATH));
 
         Set<String> paths = new HashSet<>(dot.getResources().keySet());
 
@@ -368,7 +459,6 @@
                 .add("bundleDescription", bundleDescription)
                 .add("bundleLicense", bundleLicense)
                 .toString();
-
     }
 
     @Override
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 6885c07..0f80bd5 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
@@ -21,7 +21,6 @@
 import com.facebook.buck.jvm.java.JavaLibrary;
 import com.facebook.buck.jvm.java.MavenPublishable;
 import com.facebook.buck.model.BuildTarget;
-import com.facebook.buck.model.Pair;
 import com.facebook.buck.rules.AddToRuleKey;
 import com.facebook.buck.rules.BuildRule;
 import com.facebook.buck.rules.BuildRuleParams;
@@ -29,7 +28,6 @@
 import com.facebook.buck.rules.SourcePathResolver;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedMap;
 import com.google.common.collect.ImmutableSortedSet;
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 6ba61cf..620182b 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
@@ -34,7 +34,6 @@
 import com.facebook.buck.model.Flavor;
 import com.facebook.buck.model.Flavored;
 import com.facebook.buck.model.ImmutableFlavor;
-import com.facebook.buck.model.Pair;
 import com.facebook.buck.parser.NoSuchBuildTargetException;
 import com.facebook.buck.rules.BuildRule;
 import com.facebook.buck.rules.BuildRuleParams;
@@ -58,8 +57,6 @@
 
 import java.nio.file.Path;
 import java.util.List;
-import java.util.function.BinaryOperator;
-import java.util.stream.Collectors;
 
 import static com.facebook.buck.jvm.common.ResourceValidator.validateResources;
 
@@ -250,7 +247,8 @@
                                                            args.apiPackage, args.apiDescription, args.resources,
                                                            args.groupId, args.bundleName, args.bundleVersion,
                                                            args.bundleLicense, args.bundleDescription, args.importPackages,
-                                                           args.exportPackages, includedResourcesString, args.dynamicimportPackages),
+                                                           args.exportPackages, includedResourcesString,
+                                                           args.dynamicimportPackages, args.privatePackages),
                                     args.resourcesRoot,
                                     args.manifestFile,
                                     args.mavenCoords,
@@ -327,6 +325,7 @@
         public Optional<String> bundleDescription;
 
         public Optional<String> importPackages;
+        public Optional<String> privatePackages;
         public Optional<String> exportPackages;
         public Optional<ImmutableSortedMap<String, SourcePath>> includeResources;
         public Optional<String> dynamicimportPackages;
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 ae2853b..fff225e3 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
@@ -57,6 +57,7 @@
     private final String bundleLicense;
     private final String bundleDescription;
     private final String importPackages;
+    private final String privatePackages;
     private final String exportPackages;
     private final String includeResources;
     private final String dynamicimportPackages;
@@ -77,10 +78,12 @@
                               Optional<String> importPackages,
                               Optional<String> exportPackages,
                               Optional<String> includeResources,
-                              Optional<String> dynamicimportPackages) {
+                              Optional<String> dynamicimportPackages,
+                              Optional<String> privatePackages) {
         super(javacOptions, amender);
         this.bundleDescription = processParameter(bundleDescription);
         this.importPackages = processParameter(importPackages);
+        this.privatePackages = processParameter(privatePackages);
         this.exportPackages = processParameter(exportPackages);
         this.includeResources = processParameter(includeResources);
         this.dynamicimportPackages = processParameter(dynamicimportPackages);
@@ -194,7 +197,8 @@
                 includeResources, // include resources
                 webContext, // web context
                 dynamicimportPackages, // dynamic import packages
-                bundleDescription  // bundle description
+                bundleDescription,  // bundle description
+                privatePackages // private packages
         );
         steps.add(osgiStep);