Skip to content

Commit

Permalink
Introduce plugin system to deal with provider config and lifecycle
Browse files Browse the repository at this point in the history
Signed-off-by: nscuro <[email protected]>
  • Loading branch information
nscuro committed Jul 27, 2024
1 parent a8707c0 commit 2c34743
Show file tree
Hide file tree
Showing 22 changed files with 1,080 additions and 3 deletions.
106 changes: 106 additions & 0 deletions src/main/java/org/dependencytrack/plugin/ConfigRegistry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* This file is part of Dependency-Track.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) OWASP Foundation. All Rights Reserved.
*/
package org.dependencytrack.plugin;

import alpine.Config;

import java.util.Optional;

import static java.util.Objects.requireNonNull;
import static org.dependencytrack.persistence.jdbi.JdbiFactory.withJdbiHandle;

/**
* 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.
* <p>
* Namespacing is based on the plugin's, and the provider's name.
* Provider {@code foo} of plugin {@code bar} 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>
* </ul>
* <p>
* Runtime properties are sourced from the {@code CONFIGPROPERTY} database table.
* Deployment properties are sourced from environment variables, and the {@code application.properties} file.
*
* @since 5.6.0
*/
public class ConfigRegistry {

private final String pluginName;
private final String providerName;

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

/**
* @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);

return withJdbiHandle(handle -> handle.createQuery("""
SELECT "PROPERTYVALUE"
FROM "CONFIGPROPERTY"
WHERE "GROUPNAME" = 'plugin'
AND "PROPERTYNAME" = :propertyName
""")
.bind("propertyName", namespacedPropertyName)
.mapTo(String.class)
.findOne());
}

/**
* @param propertyName Name of the deployment property.
* @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);
return Optional.ofNullable(Config.getInstance().getProperty(key));
}

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

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

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

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

@Override
public Object getDefaultValue() {
return null;
}

}

}
46 changes: 46 additions & 0 deletions src/main/java/org/dependencytrack/plugin/Plugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* This file is part of Dependency-Track.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) OWASP Foundation. All Rights Reserved.
*/
package org.dependencytrack.plugin;

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

/**
* @return The name of the plugin. Can contain lowercase letters, numbers, and periods.
*/
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}
*/
Class<? extends Provider> providerClass();

}
47 changes: 47 additions & 0 deletions src/main/java/org/dependencytrack/plugin/PluginInitializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* This file is part of Dependency-Track.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) OWASP Foundation. All Rights Reserved.
*/
package org.dependencytrack.plugin;

import alpine.common.logging.Logger;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
* @since 5.6.0
*/
public class PluginInitializer implements ServletContextListener {

private static final Logger LOGGER = Logger.getLogger(PluginInitializer.class);

private final PluginManager pluginManager = PluginManager.getInstance();

@Override
public void contextInitialized(final ServletContextEvent event) {
LOGGER.info("Loading plugins");
pluginManager.loadPlugins();
}

@Override
public void contextDestroyed(final ServletContextEvent event) {
LOGGER.info("Unloading plugins");
pluginManager.unloadPlugins();
}

}
Loading

0 comments on commit 2c34743

Please sign in to comment.