All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opalj.br.analyses.cg.ClosedPackages.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package br
package analyses
package cg

import net.ceedubs.ficus.Ficus._

import org.opalj.log.LogContext
import org.opalj.log.OPALLogger.warn

/**
 * Determines which packages are open or closed; that is, determines to which packages code
 * - which is not yet known - can potentially be contributed to. In other words, a package is
 * considered open, if a developer is allowed to define a new type within the package's
 * namespace. If a developer cannot define a new type within the package's namespace,
 * the package is considered closed.
 *
 * An example for closed packages are the packages within the java.* namespace of the JRE.
 * Additionally, with Java 9 packages defined in modules can be considered closed.
 *
 * The set of open/closed packages may influence call-graph construction as well as other analyses.
 *
 * The concrete set of open/closed packages is specified in OPAL's configuration file. The relevant
 * configuration key is: `org.opalj.br.analyses.cg.ClosedPackagesKey`.
 *
 * The concrete analysis which determines the open/closed packages is instantiated reflectively
 * by [[ClosedPackagesKey]]. This facilitates the configuration of project specific closed packages.
 * The class can be configured using the config key:
 * `org.opalj.br.analyses.cg.ClosedPackagesKey.analysis={ClosedPackagesAnalysis}`
 *
 * @note The concept of open and closed packages - and the reason why it matters - is discussed in
 *       "Call Graph Construction for Java Libraries"
 *
 * @author Michael Reif
 */
abstract class ClosedPackages extends (String => Boolean) {

    def project: SomeProject

    implicit def projectLogContext: LogContext = project.logContext

    /**
     * Returns `true` if the package with the given name is '''closed'''.
     */
    final override def apply(packageName: String): Boolean = isClosed(packageName)

    def isClosed(packageName: String): Boolean

}

/**
 * Treats all packages as being closed. This analysis is useable, e.g., for simple applications
 * which have no concept of plug-ins or a similar mechanism.
 * In this case every package is supposed to be closed since the entire code base
 * is available at analysis time.
 * Generally, not useable for libraries/frameworks/code which can be "freely" extended.
 *
 * To use this analysis set the config key:
 *  `org.opalj.br.analyses.cg.ClosedPackagesKey.analysis`
 * to
 *  `org.opalj.br.analyses.cg.[[AllPackagesClosed]]`
 *
 * @note An application that uses reflection to load functionality at runtime has a
 *       well-defined extension point and is not a ''simple application'' in the above sense.
 */
class AllPackagesClosed(val project: SomeProject) extends ClosedPackages {

    /** Always returns true. */
    override def isClosed(packageName: String): Boolean = true

}

/**
 * A conservative [[ClosedPackages]] analysis which considers all packages
 * (except of those starting with `java`) as being open. The `java.*` packages are protected
 * by the JVM itself.
 * This analysis can safely be used by every analysis, but - depending on the context -
 * may result in imprecise analysis results.
 *
 * To use this analysis set the config key:
 *  `org.opalj.br.analyses.cg.ClosedPackagesKey.analysis`
 * to
 *  `org.opalj.br.analyses.cg.[[OpenCodeBase]]`
 */
class OpenCodeBase(val project: SomeProject) extends ClosedPackages {

    override def isClosed(packageName: String): Boolean = packageName.startsWith("java/")

}

/**
 * Determines the closed packages using a regular expression.
 *
 * The regular expression can be defined using the general configuration key:
 * `org.opalj.br.analyses.cg.ClosedPackagesKey.closedPackages`
 *
 * @example
 *      {{{
 *      org.opalj.br.analyses.cg.ClosedPackagesKey.closedPackages = "java/*|com/sun/*"
 *      }}}
 *      The previous example treats all packages starting with `java` and `com.sun`
 *      as closed.
 */
class ClosedPackagesConfiguration(val project: SomeProject) extends ClosedPackages {

    private[this] val closedPackagesRegex = {
        val configKey = ClosedPackagesKey.ConfigKeyPrefix+"closedPackages"
        val closedPackages = project.config.as[Option[String]](configKey)

        if (closedPackages.isEmpty) {
            warn(
                "project configuration",
                s"$configKey is not set - all packages are considered closed"
            )
        }

        closedPackages.getOrElse(".*")
    }

    override def isClosed(packageName: String): Boolean = packageName matches closedPackagesRegex

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy