summaryrefslogtreecommitdiffstats
path: root/bundle-plugin/src/main/scala/com/yahoo/container/plugin/bundle/AnalyzeBundle.scala
blob: 1b3979476bd2ff46eb601f99f17454c5a12d004e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.plugin.bundle

import java.io.File
import java.util.jar.{Manifest => JarManifest}

import com.yahoo.container.plugin.osgi.ExportPackageParser
import com.yahoo.container.plugin.osgi.ExportPackages.Export
import com.yahoo.container.plugin.util.JarFiles


/**
 * @author  tonytv
 */
object AnalyzeBundle {
  case class PublicPackages(exports : List[Export], globals : List[String])

  def publicPackagesAggregated(jarFiles : Iterable[File]) = aggregate(jarFiles map  {publicPackages(_)})

  def aggregate(publicPackagesList : Iterable[PublicPackages]) =
    (PublicPackages(List(), List()) /: publicPackagesList) { (a,b) =>
      PublicPackages(a.exports ++ b.exports, a.globals ++ b.globals)
    }

  def publicPackages(jarFile: File): PublicPackages = {
    try {

      (for {
        manifest <- JarFiles.getManifest(jarFile)
        if isOsgiManifest(manifest)
      } yield PublicPackages(parseExports(manifest), parseGlobals(manifest))).
      getOrElse(PublicPackages(List(), List()))

    } catch {
      case e : Exception => throw new RuntimeException("Invalid manifest in bundle '%s'".format(jarFile.getPath), e)
    }
  }

  def bundleSymbolicName(jarFile: File): Option[String] = {
    JarFiles.getManifest(jarFile).flatMap(getBundleSymbolicName)
  }

  private def parseExportsFromAttribute(manifest : JarManifest, attributeName : String) = {
    (for (export <- getMainAttributeValue(manifest, attributeName)) yield
      ExportPackageParser.parseAll(export) match {
        case noSuccess: ExportPackageParser.NoSuccess => throw new RuntimeException(
          "Failed parsing %s: %s".format(attributeName, noSuccess))
        case success => success.get
      }).
      getOrElse(List())
  }

  private def parseExports = parseExportsFromAttribute(_ : JarManifest, "Export-Package")

  private def parseGlobals(manifest : JarManifest) = {
    //TODO: Use separate parser for global packages.
    val globals = parseExportsFromAttribute(manifest, "Global-Package")

    if (globals map {_.parameters} exists {!_.isEmpty}) {
      throw new RuntimeException("Parameters not valid for Global-Package.")
    }

    globals flatMap {_.packageNames}
  }

  private def getMainAttributeValue(manifest: JarManifest, name: String): Option[String] =
    Option(manifest.getMainAttributes.getValue(name))

  private def isOsgiManifest = getBundleSymbolicName(_: JarManifest).isDefined

  private def getBundleSymbolicName = getMainAttributeValue(_: JarManifest, "Bundle-SymbolicName")
}