Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.kaoto.forage.plugin.config;

import java.io.File;
import java.util.Set;

/**
* Strategy that stores all Forage configuration in a single {@code application.properties} file.
*
* <p>Every factory type reads from and writes to the same file; wildcard matching is disabled
* so only the explicit {@code application.properties} is picked up.
*
* @see PropertiesFileStrategy
*/
final class ApplicationPropertiesStrategy implements PropertiesFileStrategy {

static final String APPLICATION_PROPERTIES = "application.properties";

@Override
public Set<String> getTargetFileNames() {
return Set.of(APPLICATION_PROPERTIES);
}

@Override
public boolean matchesWildcard(String fileName) {
return false;
}

@Override
public String getPropertiesFileName(String factoryTypeKey) {
return APPLICATION_PROPERTIES;
}

@Override
public Set<File> getScanableProperties(File directory) {
File appProps = new File(directory, APPLICATION_PROPERTIES);
return appProps.exists() ? Set.of(appProps) : Set.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public class ConfigReadCommand extends CamelCommand {

private ForageCatalogReader catalog;

private PropertiesFileStrategy strategyResolver;

public ConfigReadCommand(CamelJBangMain main) {
super(main);
}
Expand All @@ -81,6 +83,7 @@ private boolean isKnownFactoryKey(String key) {
public Integer doCall() throws Exception {
try {
catalog = ForageCatalogReader.getInstance();
strategyResolver = PropertiesFileStrategy.from(strategy, catalog);

if (directory == null) {
directory = new File(System.getProperty("user.dir"));
Expand Down Expand Up @@ -120,7 +123,7 @@ private List<File> findPropertiesFiles(File dir) throws IOException {
List<File> result = new ArrayList<>();

// Determine which files to search based on strategy
final Set<String> targetFileNames = determineTargetFileNames();
final Set<String> targetFileNames = strategyResolver.getTargetFileNames();

// Search for matching properties files
try (Stream<Path> paths = Files.walk(dir.toPath())) {
Expand All @@ -132,37 +135,14 @@ private List<File> findPropertiesFiles(File dir) throws IOException {
return true;
}
// Also match any forage-*.properties files for extensibility
if (!"application".equalsIgnoreCase(strategy)
&& fileName.startsWith("forage-")
&& fileName.endsWith(".properties")) {
return true;
}
return false;
return strategyResolver.matchesWildcard(fileName);
})
.forEach(p -> result.add(p.toFile()));
}

return result;
}

private Set<String> determineTargetFileNames() {
Set<String> targetFileNames = new java.util.HashSet<>();

if ("application".equalsIgnoreCase(strategy)) {
// Only search in application.properties
targetFileNames.add("application.properties");
} else {
// Get properties file names from the catalog
for (ForageCatalogReader.FactoryMetadata metadata : catalog.getAllFactories()) {
String propsFile = metadata.propertiesFileName();
if (propsFile != null && !propsFile.isEmpty()) {
targetFileNames.add(propsFile);
}
}
}
return targetFileNames;
}

private List<BeanInfo> parsePropertiesFile(File file) throws IOException {
Properties props = new Properties();
try (FileInputStream fis = new FileInputStream(file)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public class ConfigWriteCommand extends CamelCommand {

private ForageCatalogReader catalog;

private PropertiesFileStrategy strategyResolver;

public ConfigWriteCommand(CamelJBangMain main) {
super(main);
}
Expand All @@ -69,6 +71,7 @@ public ConfigWriteCommand(CamelJBangMain main) {
public Integer doCall() throws Exception {
try {
catalog = ForageCatalogReader.getInstance();
strategyResolver = PropertiesFileStrategy.from(strategy, catalog);

if (directory == null) {
directory = new File(System.getProperty("user.dir"));
Expand Down Expand Up @@ -368,10 +371,7 @@ private String buildPropertyKey(String beanName, String inputKey) {
}

private String getPropertiesFileName(String factoryTypeKey) {
if ("application".equalsIgnoreCase(strategy)) {
return "application.properties";
}
return catalog.getPropertiesFileName(factoryTypeKey).orElse(null);
return strategyResolver.getPropertiesFileName(factoryTypeKey);
}

/**
Expand Down Expand Up @@ -668,24 +668,7 @@ private int handleDelete() throws IOException {
}

private Set<File> determineScanableProperties() {
Set<File> propertiesFilesToScan = new HashSet<>();
if ("application".equalsIgnoreCase(strategy)) {
File appProps = new File(directory, "application.properties");
if (appProps.exists()) {
propertiesFilesToScan.add(appProps);
}
} else {
for (ForageCatalogReader.FactoryMetadata metadata : catalog.getAllFactories()) {
String propertiesFileName = getPropertiesFileName(metadata.factoryTypeKey());
if (propertiesFileName != null) {
File propertiesFile = new File(directory, propertiesFileName);
if (propertiesFile.exists()) {
propertiesFilesToScan.add(propertiesFile);
}
}
}
}
return propertiesFilesToScan;
return strategyResolver.getScanableProperties(directory);
}

// Property key suffixes that contain the bean kind (e.g., *.db.kind, *.kind)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.kaoto.forage.plugin.config;

import java.io.File;
import java.util.HashSet;
import java.util.Set;
import io.kaoto.forage.catalog.reader.ForageCatalogReader;

/**
* Strategy that stores Forage configuration in per-factory {@code forage-{factoryType}.properties}
* files resolved from the catalog.
*
* <p>The read side also accepts any {@code forage-*.properties} file via the wildcard matcher
* so that modules not yet present in the catalog are still discovered. The write side returns
* {@code null} for factory types unknown to the catalog, signalling the caller to skip them.
*
* @see PropertiesFileStrategy
*/
final class ForageMultiFileStrategy implements PropertiesFileStrategy {

private static final String FORAGE_PREFIX = "forage-";
private static final String PROPERTIES_SUFFIX = ".properties";

private final ForageCatalogReader catalog;

ForageMultiFileStrategy(ForageCatalogReader catalog) {
this.catalog = catalog;
}

@Override
public Set<String> getTargetFileNames() {
Set<String> targetFileNames = new HashSet<>();
for (ForageCatalogReader.FactoryMetadata metadata : catalog.getAllFactories()) {
String propsFile = metadata.propertiesFileName();
if (propsFile != null && !propsFile.isEmpty()) {
targetFileNames.add(propsFile);
}
}
return targetFileNames;
}

@Override
public boolean matchesWildcard(String fileName) {
return fileName.startsWith(FORAGE_PREFIX) && fileName.endsWith(PROPERTIES_SUFFIX);
}

@Override
public String getPropertiesFileName(String factoryTypeKey) {
return catalog.getPropertiesFileName(factoryTypeKey).orElse(null);
}

@Override
public Set<File> getScanableProperties(File directory) {
Set<File> propertiesFiles = new HashSet<>();
for (ForageCatalogReader.FactoryMetadata metadata : catalog.getAllFactories()) {
String propertiesFileName = getPropertiesFileName(metadata.factoryTypeKey());
if (propertiesFileName != null) {
File propertiesFile = new File(directory, propertiesFileName);
if (propertiesFile.exists()) {
propertiesFiles.add(propertiesFile);
}
}
}
return propertiesFiles;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.kaoto.forage.plugin.config;

import java.io.File;
import java.util.Set;
import io.kaoto.forage.catalog.reader.ForageCatalogReader;

/**
* Strategy for resolving which properties files a Forage configuration command reads from and writes to.
*
* <p>This is the Gang-of-Four Strategy pattern: each implementation encapsulates a complete
* resolution policy (file naming, scanning, and wildcard matching) so that command classes
* no longer branch on a string discriminator.
*
* <p>Two built-in strategies are provided:
* <ul>
* <li>{@link ApplicationPropertiesStrategy} &mdash; all factories share a single
* {@code application.properties} file.</li>
* <li>{@link ForageMultiFileStrategy} &mdash; each factory writes to its own
* {@code forage-{factoryType}.properties} file resolved from the catalog.</li>
* </ul>
*
* @since 1.4
*/
public interface PropertiesFileStrategy {

/**
* Returns the concrete set of property file names a read command should look for.
*
* <p>The returned set is used for exact-name matching when walking a directory.
*
* @return the set of target file names (never {@code null})
*/
Set<String> getTargetFileNames();

/**
* Indicates whether the given file name should be picked up by the read command's
* wildcard matcher in addition to {@link #getTargetFileNames()}.
*
* <p>The {@code application} strategy returns {@code false} for all names, while
* the {@code forage} strategy returns {@code true} for any {@code forage-*.properties}
* file so uncatalogued modules are still discovered.
*
* @param fileName the file name to test (never {@code null})
* @return {@code true} if the wildcard matcher should accept this file name
*/
boolean matchesWildcard(String fileName);

/**
* Resolves the properties file name a given factory type should be written to.
*
* @param factoryTypeKey the factory type key (e.g., {@code "jdbc"}, {@code "agent"})
* @return the file name, or {@code null} if the strategy cannot determine a target
* for this factory type (in which case the caller should skip it)
*/
String getPropertiesFileName(String factoryTypeKey);

/**
* Collects the existing on-disk properties files that should be scanned when
* deleting configuration or computing which types are still configured.
*
* @param directory the working directory to resolve files relative to (never {@code null})
* @return the set of existing files to scan (never {@code null})
*/
Set<File> getScanableProperties(File directory);

/**
* Resolves the strategy instance for the given string identifier.
*
* <p>The {@code "application"} identifier (case-insensitive) yields the
* {@link ApplicationPropertiesStrategy}; any other value (including the
* canonical {@code "forage"}) yields the {@link ForageMultiFileStrategy}.
*
* @param strategy the raw strategy identifier from the command line (may be {@code null})
* @param catalog the catalog reader used by the {@code forage} strategy; ignored by the
* {@code application} strategy (may be {@code null} when strategy is
* {@code "application"})
* @return the resolved strategy, never {@code null}
*/
static PropertiesFileStrategy from(String strategy, ForageCatalogReader catalog) {
if (strategy == null || "application".equalsIgnoreCase(strategy)) {
return new ApplicationPropertiesStrategy();
}
return new ForageMultiFileStrategy(catalog);
}
}