Skip to content

Commit

Permalink
Decouple concepts of "plugin" from "extension point"
Browse files Browse the repository at this point in the history
It doesn't make sense that plugins are defined by DT, and cannot be provided by users. Instead, DT defines "extension points", for which plugins can provide implementations ("extensions").

This change also enabled plugins to provide multiple extensions, not just one.

Signed-off-by: nscuro <[email protected]>
  • Loading branch information
nscuro committed Jul 28, 2024
1 parent 07ce559 commit 325d9bd
Show file tree
Hide file tree
Showing 21 changed files with 451 additions and 365 deletions.
41 changes: 21 additions & 20 deletions src/main/java/org/dependencytrack/plugin/ConfigRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
* A read-only registry for accessing application configuration.
* <p>
* The registry enforces namespacing of property names,
* to prevent {@link Provider}s from accessing values
* belonging to the core application, or other plugins.
* to prevent {@link ExtensionPoint}s from accessing values
* belonging to the core application, or other extension points.
* <p>
* Namespacing is based on the plugin's, and the provider's name.
* Provider {@code foo} of plugin {@code bar} can access:
* Namespacing is based on the extension point's, and the extension's name.
* Extension {@code bar} of extension point {@code foo} can access:
* <ul>
* <li>Runtime properties with {@code groupName} of {@code plugin} and {@code propertyName} starting with {@code bar.provider.foo}</li>
* <li>Deployment properties prefix {@code bar.provider.foo}</li>
* <li>Runtime properties with {@code groupName} of {@code foo} and {@code propertyName} prefixed with {@code extension.bar}</li>
* <li>Deployment properties prefixed with {@code foo.extension.bar}</li>
* </ul>
* <p>
* Runtime properties are sourced from the {@code CONFIGPROPERTY} database table.
Expand All @@ -46,27 +46,28 @@
*/
public class ConfigRegistry {

private final String pluginName;
private final String providerName;
private final String extensionPointName;
private final String extensionName;

public ConfigRegistry(final String pluginName, final String providerName) {
this.pluginName = requireNonNull(pluginName);
this.providerName = requireNonNull(providerName);
public ConfigRegistry(final String extensionPointName, final String extensionName) {
this.extensionPointName = requireNonNull(extensionPointName);
this.extensionName = requireNonNull(extensionName);
}

/**
* @param propertyName Name of the runtime property.
* @return An {@link Optional} holding the property value, or {@link Optional#empty()}.
*/
public Optional<String> getRuntimeProperty(final String propertyName) {
final String namespacedPropertyName = "%s.provider.%s.%s".formatted(pluginName, providerName, propertyName);
final String namespacedPropertyName = "extension.%s.%s".formatted(extensionName, propertyName);

return withJdbiHandle(handle -> handle.createQuery("""
SELECT "PROPERTYVALUE"
FROM "CONFIGPROPERTY"
WHERE "GROUPNAME" = 'plugin'
WHERE "GROUPNAME" = :extensionPointName
AND "PROPERTYNAME" = :propertyName
""")
.bind("extensionPointName", extensionPointName)
.bind("propertyName", namespacedPropertyName)
.mapTo(String.class)
.findOne());
Expand All @@ -77,23 +78,23 @@ public Optional<String> getRuntimeProperty(final String propertyName) {
* @return An {@link Optional} holding the property value, or {@link Optional#empty()}.
*/
public Optional<String> getDeploymentProperty(final String propertyName) {
final var key = new DeploymentConfigKey(pluginName, providerName, propertyName);
final var key = new DeploymentConfigKey(extensionPointName, extensionName, propertyName);
return Optional.ofNullable(Config.getInstance().getProperty(key));
}

record DeploymentConfigKey(String pluginName, String providerName, String name) implements Config.Key {
record DeploymentConfigKey(String extensionPointName, String extensionName, String name) implements Config.Key {

DeploymentConfigKey(final String pluginName, final String name) {
this(pluginName, null, name);
DeploymentConfigKey(final String extensionPointName, final String name) {
this(extensionPointName, null, name);
}

@Override
public String getPropertyName() {
if (providerName == null) {
return "%s.%s".formatted(pluginName, name);
if (extensionName == null) {
return "%s.%s".formatted(extensionPointName, name);
}

return "%s.provider.%s.%s".formatted(pluginName, providerName, name);
return "%s.extension.%s.%s".formatted(extensionPointName, extensionName, name);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,28 @@
*/
package org.dependencytrack.plugin;

import java.io.Closeable;

/**
* @since 5.6.0
*/
public interface ProviderFactory<T extends Provider> extends AutoCloseable {
public interface ExtensionFactory<T extends ExtensionPoint> extends Closeable {

int PRIORITY_HIGHEST = 0;
int PRIORITY_LOWEST = Integer.MAX_VALUE;

/**
* @return Name of the provider. Can contain lowercase letters, numbers, and periods.
* @return Name of the extension. Can contain lowercase letters, numbers, and periods.
*/
String extensionName();

/**
* @return {@link Class} of the extension.
*/
String providerName();
Class<? extends T> extensionClass();

/**
* @return Priority of the provider. Must be a value between {@value #PRIORITY_HIGHEST}
* @return Priority of the extension. Must be a value between {@value #PRIORITY_HIGHEST}
* (highest priority) and {@value #PRIORITY_LOWEST} (lowest priority).
*/
int priority();
Expand All @@ -45,7 +52,7 @@ public interface ProviderFactory<T extends Provider> extends AutoCloseable {
void init(final ConfigRegistry configRegistry);

/**
* @return An instance of {@link T}.
* @return An extension instance.
*/
T create();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
*/
package org.dependencytrack.plugin;

import java.io.Closeable;

/**
* @since 5.6.0
*/
public interface Provider extends AutoCloseable {
public interface ExtensionPoint extends Closeable {

/**
* {@inheritDoc}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,25 @@
*/
package org.dependencytrack.plugin;

public interface DummyProviderFactory extends ProviderFactory<DummyProvider> {
/**
* @since 5.6.0
*/
public interface ExtensionPointMetadata<T extends ExtensionPoint> {

/**
* @return The name of the {@link ExtensionPoint}. Can contain lowercase letters, numbers, and periods.
*/
String name();

/**
* @return Whether the {@link ExtensionPoint} is required.
* Required extension points must have at least one active implementation.
*/
boolean required();

/**
* @return The {@link Class} of the {@link ExtensionPoint}.
*/
Class<T> extensionPointClass();

}
18 changes: 5 additions & 13 deletions src/main/java/org/dependencytrack/plugin/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,21 @@
*/
package org.dependencytrack.plugin;

import java.util.Collection;

/**
* @since 5.6.0
*/
public interface Plugin {

/**
* @return The name of the plugin. Can contain lowercase letters, numbers, and periods.
* @return The name of the plugin.
*/
String name();

/**
* @return Whether this plugin is required. Required plugins must have at least one active {@link Provider}.
*/
boolean required();

/**
* @return Class of the {@link ProviderFactory}
*/
Class<? extends ProviderFactory<? extends Provider>> providerFactoryClass();

/**
* @return Class of the {@link Provider}
* @return The {@link ExtensionFactory}s provided by the plugin.
*/
Class<? extends Provider> providerClass();
Collection<? extends ExtensionFactory<? extends ExtensionPoint>> extensionFactories();

}
Loading

0 comments on commit 325d9bd

Please sign in to comment.