DslPluginRegistry.java
/*******************************************************************************
* Copyright (c) 2026 Carsten Hammer.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Carsten Hammer
*******************************************************************************/
package org.sandbox.jdt.triggerpattern.cleanup;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Registry for {@link AbstractPatternCleanupPlugin} instances, grouped by bundle ID.
*
* <p>Plugins register themselves (or are registered on their behalf) by calling
* {@link #register(AbstractPatternCleanupPlugin)}. Consumers such as
* {@code HintFileCleanUpCore} can then retrieve all plugins for a given bundle via
* {@link #getPluginsForBundle(String)}.</p>
*
* <p>Bundle IDs are derived from the plugin's {@code cleanupId} through
* {@link AbstractPatternCleanupPlugin#getBundleId()}. For example, a plugin
* whose {@code cleanupId} is {@code "cleanup.encoding.charset.forname.utf8"} will
* be associated with the bundle {@code "encoding"}.</p>
*
* @since 1.3.5
*/
public final class DslPluginRegistry {
/** All registered plugins keyed by their cleanup ID (preserves registration order). */
private static final Map<String, AbstractPatternCleanupPlugin<?>> BY_CLEANUP_ID = new LinkedHashMap<>();
/** Plugins grouped by bundle ID. */
private static final Map<String, List<AbstractPatternCleanupPlugin<?>>> BY_BUNDLE_ID = new LinkedHashMap<>();
private DslPluginRegistry() {
// utility class
}
/**
* Registers a plugin with the registry.
*
* <p>A plugin is only added once; a second registration whose
* {@link AbstractPatternCleanupPlugin#getCleanupId()} matches an already-registered
* plugin is silently ignored.</p>
*
* @param plugin the plugin to register; must not be {@code null}
* @throws IllegalArgumentException if {@code plugin} is {@code null}, or if its
* cleanup ID or bundle ID is {@code null} or empty
*/
public static synchronized void register(AbstractPatternCleanupPlugin<?> plugin) {
if (plugin == null) {
throw new IllegalArgumentException("plugin must not be null"); //$NON-NLS-1$
}
String id = plugin.getCleanupId();
if (id == null || id.isEmpty()) {
throw new IllegalArgumentException("cleanupId must not be null or empty"); //$NON-NLS-1$
}
if (BY_CLEANUP_ID.containsKey(id)) {
return; // already registered
}
String bundleId = plugin.getBundleId();
if (bundleId == null || bundleId.isEmpty()) {
throw new IllegalArgumentException(
"bundleId must not be null or empty for cleanupId " + id); //$NON-NLS-1$
}
BY_CLEANUP_ID.put(id, plugin);
BY_BUNDLE_ID.computeIfAbsent(bundleId, k -> new ArrayList<>()).add(plugin);
}
/**
* Returns all registered plugins.
*
* @return an unmodifiable view of all registered plugins (never {@code null})
*/
public static synchronized List<AbstractPatternCleanupPlugin<?>> getAllPlugins() {
return Collections.unmodifiableList(new ArrayList<>(BY_CLEANUP_ID.values()));
}
/**
* Returns all registered plugins whose bundle ID matches {@code bundleId}.
*
* @param bundleId the bundle identifier (e.g., {@code "encoding"})
* @return an unmodifiable view of matching plugins (never {@code null})
*/
public static synchronized List<AbstractPatternCleanupPlugin<?>> getPluginsForBundle(String bundleId) {
List<AbstractPatternCleanupPlugin<?>> plugins = BY_BUNDLE_ID.get(bundleId);
if (plugins == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(plugins);
}
}