diff --git a/pom.xml b/pom.xml index 0e8689d..b97ae6a 100644 --- a/pom.xml +++ b/pom.xml @@ -79,6 +79,10 @@ ai.wanaku.sdk capabilities-services-client + + ai.wanaku.sdk + capabilities-runtime-camel-common + diff --git a/src/main/java/ai/wanaku/code/engine/camel/CamelEngineMain.java b/src/main/java/ai/wanaku/code/engine/camel/CamelEngineMain.java index 624d879..58440f6 100644 --- a/src/main/java/ai/wanaku/code/engine/camel/CamelEngineMain.java +++ b/src/main/java/ai/wanaku/code/engine/camel/CamelEngineMain.java @@ -22,15 +22,15 @@ import ai.wanaku.capabilities.sdk.discovery.config.DefaultRegistrationConfig; import ai.wanaku.capabilities.sdk.discovery.deserializer.JacksonDeserializer; import ai.wanaku.capabilities.sdk.discovery.util.DiscoveryHelper; +import ai.wanaku.capabilities.sdk.runtime.camel.grpc.ProvisionBase; +import ai.wanaku.capabilities.sdk.runtime.camel.init.Initializer; +import ai.wanaku.capabilities.sdk.runtime.camel.init.InitializerFactory; import ai.wanaku.capabilities.sdk.security.TokenEndpoint; import ai.wanaku.capabilities.sdk.services.ServicesHttpClient; import ai.wanaku.code.engine.camel.codegen.CodeGenDiscoveryCallback; import ai.wanaku.code.engine.camel.codegen.CodeGenToolService; import ai.wanaku.code.engine.camel.grpc.CodeExecutorService; import ai.wanaku.code.engine.camel.grpc.CodeGenToolInvokerService; -import ai.wanaku.code.engine.camel.grpc.ProvisionBase; -import ai.wanaku.code.engine.camel.init.Initializer; -import ai.wanaku.code.engine.camel.init.InitializerFactory; import ai.wanaku.code.engine.camel.util.VersionHelper; import picocli.CommandLine; diff --git a/src/main/java/ai/wanaku/code/engine/camel/WanakuCamelManager.java b/src/main/java/ai/wanaku/code/engine/camel/WanakuCamelManager.java index 1521b57..b7ac5fd 100644 --- a/src/main/java/ai/wanaku/code/engine/camel/WanakuCamelManager.java +++ b/src/main/java/ai/wanaku/code/engine/camel/WanakuCamelManager.java @@ -6,8 +6,8 @@ import java.util.Map; import org.apache.camel.CamelContext; import org.apache.camel.impl.DefaultCamelContext; -import ai.wanaku.code.engine.camel.downloader.ResourceType; -import ai.wanaku.code.engine.camel.util.WanakuRoutesLoader; +import ai.wanaku.capabilities.sdk.runtime.camel.downloader.ResourceType; +import ai.wanaku.capabilities.sdk.runtime.camel.util.WanakuRoutesLoader; public class WanakuCamelManager { private final CamelContext context; @@ -49,6 +49,10 @@ private void loadRoutes() throws Exception { String routeFileUrl = String.format("file://%s", routesPath); routesLoader.loadRoute(context, routeFileUrl); context.start(); + + if (context.getRoutes().isEmpty()) { + throw new RuntimeException("Failed to load routes from " + routeFileUrl); + } } public CamelContext getCamelContext() { diff --git a/src/main/java/ai/wanaku/code/engine/camel/codegen/CodeGenDiscoveryCallback.java b/src/main/java/ai/wanaku/code/engine/camel/codegen/CodeGenDiscoveryCallback.java index 2e382ba..8beb512 100644 --- a/src/main/java/ai/wanaku/code/engine/camel/codegen/CodeGenDiscoveryCallback.java +++ b/src/main/java/ai/wanaku/code/engine/camel/codegen/CodeGenDiscoveryCallback.java @@ -4,8 +4,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.CountDownLatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,9 +11,7 @@ import ai.wanaku.capabilities.sdk.api.discovery.RegistrationManager; import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget; import ai.wanaku.capabilities.sdk.services.ServicesHttpClient; -import ai.wanaku.code.engine.camel.downloader.DownloaderFactory; -import ai.wanaku.code.engine.camel.downloader.ResourceRefs; -import ai.wanaku.code.engine.camel.downloader.ResourceType; +import ai.wanaku.code.engine.camel.downloader.TarBz2Downloader; /** * Discovery callback that initializes and registers code generation tools. @@ -147,15 +143,10 @@ private Path validateLocalPackage(Path localPath) { */ private Path downloadPackage() { try { - DownloaderFactory downloaderFactory = new DownloaderFactory(servicesHttpClient, dataDirPath); - + TarBz2Downloader archiveDownloader = new TarBz2Downloader(servicesHttpClient, dataDirPath); URI packageUri = URI.create(codegenPackageUri); - ResourceRefs resourceRef = new ResourceRefs<>(ResourceType.CODEGEN_PACKAGE, packageUri); - Map downloadedResources = new HashMap<>(); - - downloaderFactory.getDownloader(packageUri).downloadResource(resourceRef, downloadedResources); - Path downloaded = downloadedResources.get(ResourceType.CODEGEN_PACKAGE); + Path downloaded = archiveDownloader.downloadAndExtract(packageUri); if (downloaded == null) { LOG.error("Code generation package download failed"); } diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/DataStoreDownloader.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/DataStoreDownloader.java deleted file mode 100644 index e826f21..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/DataStoreDownloader.java +++ /dev/null @@ -1,59 +0,0 @@ -package ai.wanaku.code.engine.camel.downloader; - -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Base64; -import java.util.List; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import ai.wanaku.capabilities.sdk.api.types.DataStore; -import ai.wanaku.capabilities.sdk.api.types.WanakuResponse; -import ai.wanaku.capabilities.sdk.services.ServicesHttpClient; - -public class DataStoreDownloader implements Downloader { - private static final Logger LOG = LoggerFactory.getLogger(DataStoreDownloader.class); - private final ServicesHttpClient servicesHttpClient; - private final Path dataDir; - - public DataStoreDownloader(ServicesHttpClient servicesHttpClient, Path dataDir) { - this.servicesHttpClient = servicesHttpClient; - this.dataDir = dataDir; - } - - @Override - public void downloadResource(ResourceRefs resourceName, Map downloadedResources) - throws Exception { - final String resourceFileName = resourceName.ref().getHost(); - LOG.debug("Downloading resource: {}", resourceName.ref().getPath()); - - // Retrieve the data stores from the API - WanakuResponse> response = servicesHttpClient.getDataStoresByName(resourceFileName); - - if (response == null || response.data() == null || response.data().isEmpty()) { - LOG.warn("No data found for resource: {}", resourceName); - return; - } - - List dataStores = response.data(); - - // Process each DataStore entry (typically there should be one per resource name) - for (DataStore dataStore : dataStores) { - if (dataStore.getData() == null || dataStore.getData().isEmpty()) { - LOG.warn("DataStore entry for '{}' contains no data", resourceName); - continue; - } - - // Decode from base64 - byte[] decodedData = Base64.getDecoder().decode(dataStore.getData()); - - // Save to the configured data directory - Path filePath = dataDir.resolve(resourceFileName); - Files.write(filePath, decodedData); - downloadedResources.put(resourceName.resourceType(), filePath); - - LOG.info("Successfully downloaded resource '{}' to {}", resourceName, filePath.toAbsolutePath()); - } - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/Downloader.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/Downloader.java deleted file mode 100644 index 9ac2a53..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/Downloader.java +++ /dev/null @@ -1,10 +0,0 @@ -package ai.wanaku.code.engine.camel.downloader; - -import java.net.URI; -import java.nio.file.Path; -import java.util.Map; - -public interface Downloader { - - void downloadResource(ResourceRefs resourceName, Map downloadedResources) throws Exception; -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/DownloaderFactory.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/DownloaderFactory.java deleted file mode 100644 index 6369d06..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/DownloaderFactory.java +++ /dev/null @@ -1,83 +0,0 @@ -package ai.wanaku.code.engine.camel.downloader; - -import java.net.URI; -import java.nio.file.Path; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import ai.wanaku.capabilities.sdk.services.ServicesHttpClient; - -/** - * Factory for creating downloader instances based on URI scheme. - * - *

Supports the following schemes: - *

    - *
  • {@code datastore://} - downloads from Wanaku data store
  • - *
  • {@code file://} - copies from local filesystem
  • - *
  • {@code datastore-archive://} - downloads and extracts tar.bz2 from data store
  • - *
- */ -public class DownloaderFactory { - private static final Logger LOG = LoggerFactory.getLogger(DownloaderFactory.class); - - private final ServicesHttpClient servicesHttpClient; - private final Path dataDir; - - private FileDownloader fileDownloader; - private DataStoreDownloader dataStoreDownloader; - private TarBz2Downloader tarBz2Downloader; - - public DownloaderFactory(ServicesHttpClient servicesHttpClient, Path dataDir) { - this.servicesHttpClient = servicesHttpClient; - this.dataDir = dataDir; - } - - public Downloader getDownloader(URI uri) { - if (uri == null || uri.getScheme() == null) { - throw new IllegalArgumentException("URI and scheme cannot be null"); - } - - String scheme = uri.getScheme().toLowerCase(); - - return switch (scheme) { - case "datastore" -> getDataStoreDownloader(); - case "file" -> getFileDownloader(); - case "datastore-archive" -> getTarBz2Downloader(); - default -> - throw new IllegalArgumentException("Unsupported URI scheme: " + scheme - + ". Supported schemes: datastore://, file://, datastore-archive://"); - }; - } - - private DataStoreDownloader getDataStoreDownloader() { - if (dataStoreDownloader == null) { - LOG.debug("Creating DataStoreDownloader instance"); - dataStoreDownloader = new DataStoreDownloader(servicesHttpClient, dataDir); - } - return dataStoreDownloader; - } - - private FileDownloader getFileDownloader() { - if (fileDownloader == null) { - LOG.debug("Creating FileDownloader instance"); - fileDownloader = new FileDownloader(dataDir); - } - return fileDownloader; - } - - private TarBz2Downloader getTarBz2Downloader() { - if (tarBz2Downloader == null) { - LOG.debug("Creating TarBz2Downloader instance"); - tarBz2Downloader = new TarBz2Downloader(servicesHttpClient, dataDir); - } - return tarBz2Downloader; - } - - /** - * Returns the TarBz2Downloader instance for direct archive operations. - * - * @return the TarBz2Downloader instance - */ - public TarBz2Downloader getArchiveDownloader() { - return getTarBz2Downloader(); - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/FileDownloader.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/FileDownloader.java deleted file mode 100644 index 29c4f63..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/FileDownloader.java +++ /dev/null @@ -1,54 +0,0 @@ -package ai.wanaku.code.engine.camel.downloader; - -import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Downloader for local files using the file:// URI scheme. - * Copies files from the local filesystem to the data directory. - */ -public class FileDownloader implements Downloader { - private static final Logger LOG = LoggerFactory.getLogger(FileDownloader.class); - private final Path dataDir; - - public FileDownloader(Path dataDir) { - this.dataDir = dataDir; - } - - @Override - public void downloadResource(ResourceRefs resourceName, Map downloadedResources) - throws Exception { - final URI fileUri = resourceName.ref(); - LOG.debug("Processing file resource: {}", fileUri); - - // Construct the Path directly from the URI to correctly handle all valid file:// URIs - Path sourceFile = Paths.get(fileUri); - - if (!Files.exists(sourceFile)) { - throw new IOException("File not found: " + sourceFile.toAbsolutePath()); - } - - if (!Files.isRegularFile(sourceFile)) { - throw new IOException("Path is not a regular file: " + sourceFile.toAbsolutePath()); - } - - // Extract filename and copy to data directory - String fileName = sourceFile.getFileName().toString(); - Path targetPath = dataDir.resolve(fileName); - - Files.copy(sourceFile, targetPath, StandardCopyOption.REPLACE_EXISTING); - downloadedResources.put(resourceName.resourceType(), targetPath); - - LOG.info( - "Successfully copied file resource '{}' to {}", - sourceFile.toAbsolutePath(), - targetPath.toAbsolutePath()); - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceDownloaderCallback.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceDownloaderCallback.java deleted file mode 100644 index fbea935..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceDownloaderCallback.java +++ /dev/null @@ -1,86 +0,0 @@ -package ai.wanaku.code.engine.camel.downloader; - -import java.net.URI; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import ai.wanaku.capabilities.sdk.api.discovery.DiscoveryCallback; -import ai.wanaku.capabilities.sdk.api.discovery.RegistrationManager; -import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget; -import ai.wanaku.capabilities.sdk.common.exceptions.WanakuWebException; - -public class ResourceDownloaderCallback implements DiscoveryCallback { - private static final Logger LOG = LoggerFactory.getLogger(ResourceDownloaderCallback.class); - - private final List> resources; - private final CountDownLatch countDownLatch = new CountDownLatch(1); - - private final DownloaderFactory downloaderFactory; - private Map downloadedResources = new HashMap<>(); - - public ResourceDownloaderCallback(DownloaderFactory downloaderFactory, List> resources) { - this.resources = resources; - this.downloaderFactory = downloaderFactory; - } - - @Override - public void onPing(RegistrationManager manager, ServiceTarget target, int status) {} - - @Override - public void onRegistration(RegistrationManager manager, ServiceTarget target) { - downloadResources(); - } - - @Override - public void onDeregistration(RegistrationManager manager, ServiceTarget target, int status) {} - - private void downloadResources() { - if (resources == null || resources.isEmpty()) { - LOG.debug("No resources to download"); - return; - } - - try { - LOG.info("Starting download of {} resource(s)", resources.size()); - - for (ResourceRefs resourceName : resources) { - try { - Downloader downloader = downloaderFactory.getDownloader(resourceName.ref()); - downloader.downloadResource(resourceName, downloadedResources); - } catch (WanakuWebException e) { - if (e.getStatusCode() == 404) { - LOG.error( - "Failed to download resource (resource not found) '{}': {}", - resourceName, - e.getMessage()); - } else { - LOG.error("Failed to download resource '{}': {}", resourceName, e.getMessage()); - } - } catch (Exception e) { - LOG.error("Failed to download resource'{}': {}", resourceName, e.getMessage(), e); - } - } - } finally { - countDownLatch.countDown(); - } - } - - public boolean waitForDownloads() { - LOG.info("Waiting for resources to download"); - try { - countDownLatch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - return resources.size() == downloadedResources.size(); - } - - public Map getDownloadedResources() { - return downloadedResources; - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceListBuilder.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceListBuilder.java deleted file mode 100644 index 059a540..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceListBuilder.java +++ /dev/null @@ -1,81 +0,0 @@ -package ai.wanaku.code.engine.camel.downloader; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -/** - * Builder for creating a list of resource references to be used with ResourceDownloaderCallback. - * Provides a fluent API for constructing resource lists while handling optional parameters. - */ -public class ResourceListBuilder { - private final List> resources = new ArrayList<>(); - private boolean hasRoutesRef = false; - - private ResourceListBuilder() {} - - /** - * Creates a new ResourceListBuilder instance. - * - * @return a new builder instance - */ - public static ResourceListBuilder newBuilder() { - return new ResourceListBuilder(); - } - - /** - * Adds a routes reference to the resource list. - * This is a required resource and must be called before build(). - * - * @param routesRef the routes reference URI string (e.g., "datastore://routes.yaml" or "file:///path/to/routes.yaml") - * @return this builder for method chaining - */ - public ResourceListBuilder addRoutesRef(String routesRef) { - if (routesRef != null && !routesRef.isEmpty()) { - resources.add(ResourceRefs.newRoutesRef(routesRef)); - hasRoutesRef = true; - } - return this; - } - - /** - * Adds a rules reference to the resource list. - * This is an optional resource. - * - * @param rulesRef the rules reference URI string (e.g., "datastore://rules.yaml" or "file:///path/to/rules.yaml") - * @return this builder for method chaining - */ - public ResourceListBuilder addRulesRef(String rulesRef) { - if (rulesRef != null && !rulesRef.isEmpty()) { - resources.add(ResourceRefs.newRulesRef(rulesRef)); - } - return this; - } - - /** - * Adds a dependencies reference to the resource list. - * This is an optional resource. - * - * @param dependenciesRef the dependencies reference URI string (e.g., "datastore://dependencies.txt" or "file:///path/to/dependencies.txt") - * @return this builder for method chaining - */ - public ResourceListBuilder addDependenciesRef(String dependenciesRef) { - if (dependenciesRef != null && !dependenciesRef.isEmpty()) { - resources.add(ResourceRefs.newDependencyRef(dependenciesRef)); - } - return this; - } - - /** - * Builds and returns an unmodifiable list of resource references. - * - * @return an unmodifiable list of ResourceRefs - * @throws IllegalStateException if routes reference was not provided - */ - public List> build() { - if (!hasRoutesRef) { - throw new IllegalStateException("Routes reference is required but was not provided"); - } - return List.copyOf(resources); - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceRefs.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceRefs.java deleted file mode 100644 index 8573728..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceRefs.java +++ /dev/null @@ -1,18 +0,0 @@ -package ai.wanaku.code.engine.camel.downloader; - -import java.net.URI; - -public record ResourceRefs(ResourceType resourceType, T ref) { - - public static ResourceRefs newRoutesRef(String routesRef) { - return new ResourceRefs<>(ResourceType.ROUTES_REF, URI.create(routesRef)); - } - - public static ResourceRefs newRulesRef(String rulesRef) { - return new ResourceRefs<>(ResourceType.RULES_REF, URI.create(rulesRef)); - } - - public static ResourceRefs newDependencyRef(String dependencyRef) { - return new ResourceRefs<>(ResourceType.DEPENDENCY_REF, URI.create(dependencyRef)); - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceType.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceType.java deleted file mode 100644 index 9efdd1c..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/ResourceType.java +++ /dev/null @@ -1,15 +0,0 @@ -package ai.wanaku.code.engine.camel.downloader; - -/** - * Defines the types of resources that can be downloaded and managed by the code execution engine. - */ -public enum ResourceType { - /** Reference to Camel route definitions. */ - ROUTES_REF, - /** Reference to MCP rules definitions. */ - RULES_REF, - /** Reference to Maven dependency specifications. */ - DEPENDENCY_REF, - /** Reference to a code generation package (tar.bz2 archive). */ - CODEGEN_PACKAGE, -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/downloader/TarBz2Downloader.java b/src/main/java/ai/wanaku/code/engine/camel/downloader/TarBz2Downloader.java index 8d60356..dad9d29 100644 --- a/src/main/java/ai/wanaku/code/engine/camel/downloader/TarBz2Downloader.java +++ b/src/main/java/ai/wanaku/code/engine/camel/downloader/TarBz2Downloader.java @@ -2,11 +2,9 @@ import java.io.ByteArrayInputStream; import java.net.URI; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Base64; import java.util.List; -import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ai.wanaku.capabilities.sdk.api.types.DataStore; @@ -20,7 +18,7 @@ *

This downloader fetches base64-encoded tar.bz2 archives from the data store, * decodes them, and extracts their contents to a subdirectory within the data directory. */ -public class TarBz2Downloader implements Downloader { +public class TarBz2Downloader { private static final Logger LOG = LoggerFactory.getLogger(TarBz2Downloader.class); private final ServicesHttpClient servicesHttpClient; @@ -37,71 +35,47 @@ public TarBz2Downloader(ServicesHttpClient servicesHttpClient, Path dataDir) { this.dataDir = dataDir; } - @Override - public void downloadResource(ResourceRefs resourceName, Map downloadedResources) - throws Exception { - final String resourceFileName = resourceName.ref().getHost(); + /** + * Downloads a tar.bz2 archive from the data store and extracts it. + * + * @param archiveUri the URI of the archive in the data store (e.g., datastore-archive://name.tar.bz2) + * @return the path to the extracted directory + * @throws Exception if download or extraction fails + */ + public Path downloadAndExtract(URI archiveUri) throws Exception { + final String resourceFileName = archiveUri.getHost(); LOG.info("Downloading and extracting archive: {}", resourceFileName); - // Retrieve the data stores from the API WanakuResponse> response = servicesHttpClient.getDataStoresByName(resourceFileName); if (response == null || response.data() == null || response.data().isEmpty()) { - LOG.warn("No data found for resource: {}", resourceName); - return; + LOG.warn("No data found for resource: {}", resourceFileName); + return null; } List dataStores = response.data(); + Path extractDir = null; for (DataStore dataStore : dataStores) { if (dataStore.getData() == null || dataStore.getData().isEmpty()) { - LOG.warn("DataStore entry for '{}' contains no data", resourceName); + LOG.warn("DataStore entry for '{}' contains no data", resourceFileName); continue; } - // Decode from base64 byte[] decodedData = Base64.getDecoder().decode(dataStore.getData()); LOG.debug("Decoded {} bytes from base64", decodedData.length); - // Create extraction directory based on resource name (without extension) String extractDirName = getExtractDirectoryName(resourceFileName); - Path extractDir = dataDir.resolve(extractDirName); + extractDir = dataDir.resolve(extractDirName); - // Extract the archive try (ByteArrayInputStream bais = new ByteArrayInputStream(decodedData)) { ArchiveExtractor.extractTarBz2(bais, extractDir); } - // Store the path to the extracted directory - downloadedResources.put(resourceName.resourceType(), extractDir); - LOG.info("Successfully downloaded and extracted '{}' to {}", resourceFileName, extractDir.toAbsolutePath()); } - } - - /** - * Downloads and extracts a tar.bz2 archive from a local file. - * - * @param archivePath path to the local archive file - * @param downloadedResources map to store the result - * @throws Exception if download or extraction fails - */ - public void downloadFromFile(Path archivePath, Map downloadedResources) throws Exception { - String fileName = archivePath.getFileName().toString(); - LOG.info("Extracting local archive: {}", archivePath); - - if (!Files.exists(archivePath)) { - throw new IllegalArgumentException("Archive file not found: " + archivePath); - } - - String extractDirName = getExtractDirectoryName(fileName); - Path extractDir = dataDir.resolve(extractDirName); - - ArchiveExtractor.extractTarBz2(archivePath, extractDir); - - downloadedResources.put(ResourceType.CODEGEN_PACKAGE, extractDir); - LOG.info("Successfully extracted '{}' to {}", fileName, extractDir.toAbsolutePath()); + return extractDir; } /** diff --git a/src/main/java/ai/wanaku/code/engine/camel/grpc/ProvisionBase.java b/src/main/java/ai/wanaku/code/engine/camel/grpc/ProvisionBase.java deleted file mode 100644 index 6966f50..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/grpc/ProvisionBase.java +++ /dev/null @@ -1,53 +0,0 @@ -package ai.wanaku.code.engine.camel.grpc; - -import java.util.Map; -import io.grpc.stub.StreamObserver; -import ai.wanaku.capabilities.sdk.config.provider.api.ConfigProvisioner; -import ai.wanaku.capabilities.sdk.config.provider.api.ProvisionedConfig; -import ai.wanaku.capabilities.sdk.runtime.provisioners.FileProvisionerLoader; -import ai.wanaku.capabilities.sdk.util.ProvisioningHelper; -import ai.wanaku.core.exchange.v1.PropertySchema; -import ai.wanaku.core.exchange.v1.ProvisionReply; -import ai.wanaku.core.exchange.v1.ProvisionRequest; -import ai.wanaku.core.exchange.v1.ProvisionerGrpc; - -public class ProvisionBase extends ProvisionerGrpc.ProvisionerImplBase { - - private final String name; - - public ProvisionBase(String name) { - this.name = name; - } - - @Override - public void provision(ProvisionRequest request, StreamObserver responseObserver) { - - ConfigProvisioner provisioner = FileProvisionerLoader.newConfigProvisioner(request, name); - final ProvisionedConfig provision = ProvisioningHelper.provision(request, provisioner); - - responseObserver.onNext(ProvisionReply.newBuilder() - .putAllProperties(properties()) - .setConfigurationUri(provision.configurationsUri().toString()) - .setSecretUri(provision.secretsUri().toString()) - .build()); - responseObserver.onCompleted(); - } - - public Map properties() { - // Use this to push any server-side properties/arguments. Use the toPropertySchema to serialize their additional - // details - // Map.of("argument-name", toPropertySchema("The description for what argument-name is", "string", true)); - return Map.of(); - } - - /* - * You can use this to serialize the server-side properties to push. - */ - private static PropertySchema toPropertySchema(String description, String type, boolean required) { - return PropertySchema.newBuilder() - .setDescription(description) - .setType(type) - .setRequired(required) - .build(); - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/init/GitInitializer.java b/src/main/java/ai/wanaku/code/engine/camel/init/GitInitializer.java deleted file mode 100644 index 6a34c25..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/init/GitInitializer.java +++ /dev/null @@ -1,56 +0,0 @@ -package ai.wanaku.code.engine.camel.init; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.errors.GitAPIException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Initializer that clones a Git repository during application startup. - * The repository is cloned to {dataDir}/cloned-repo and reused if it already exists. - */ -public class GitInitializer implements Initializer { - private static final Logger LOG = LoggerFactory.getLogger(GitInitializer.class); - private static final String CLONED_REPO_DIR_NAME = "cloned-repo"; - - private final String gitRepoUrl; - private final Path dataDir; - private Path clonedRepoPath; - - public GitInitializer(String gitRepoUrl, Path dataDir) { - this.gitRepoUrl = gitRepoUrl; - this.dataDir = dataDir; - } - - @Override - public void initialize() throws GitAPIException, IOException { - clonedRepoPath = dataDir.resolve(CLONED_REPO_DIR_NAME); - File clonedRepoDir = clonedRepoPath.toFile(); - - if (clonedRepoDir.exists()) { - try (Git ignored = Git.open(clonedRepoDir)) { - LOG.info("Reusing existing cloned repository at {}", clonedRepoPath); - return; - } catch (IOException e) { - throw new IOException( - "Existing cloned repository at " + clonedRepoPath + " is not a valid Git repository", e); - } - } - - LOG.info("Cloning git repository from {} to {}", gitRepoUrl, clonedRepoPath); - - try (Git git = Git.cloneRepository() - .setURI(gitRepoUrl) - .setDirectory(clonedRepoDir) - .call()) { - LOG.info("Successfully cloned repository from {}", gitRepoUrl); - } - } - - public Path getClonedRepoPath() { - return clonedRepoPath; - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/init/Initializer.java b/src/main/java/ai/wanaku/code/engine/camel/init/Initializer.java deleted file mode 100644 index cc3755c..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/init/Initializer.java +++ /dev/null @@ -1,6 +0,0 @@ -package ai.wanaku.code.engine.camel.init; - -public interface Initializer { - - void initialize() throws Exception; -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/init/InitializerFactory.java b/src/main/java/ai/wanaku/code/engine/camel/init/InitializerFactory.java deleted file mode 100644 index c055509..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/init/InitializerFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package ai.wanaku.code.engine.camel.init; - -import java.nio.file.Path; - -/** - * Factory for creating initializers based on the initFrom parameter. - * Returns a GitInitializer if a repository URL is provided, otherwise returns NoOpInitializer. - */ -public final class InitializerFactory { - - /** - * Creates an appropriate initializer based on the initFrom parameter. - * - * @param initFrom Git repository URL (SSH or HTTPS), or null for no initialization - * @param dataDir Directory where the repository will be cloned - * @return GitInitializer if initFrom is provided, NoOpInitializer otherwise - */ - public static Initializer createInitializer(String initFrom, Path dataDir) { - final String normalizedInitFrom = initFrom == null ? null : initFrom.trim(); - if (normalizedInitFrom == null || normalizedInitFrom.isEmpty()) { - return new NoOpInitializer(); - } - - // Assume it's a Git repository URL (supports both SSH and HTTPS) - // Examples: git@github.com:user/repo.git or https://github.com/user/repo.git - return new GitInitializer(normalizedInitFrom, dataDir); - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/init/NoOpInitializer.java b/src/main/java/ai/wanaku/code/engine/camel/init/NoOpInitializer.java deleted file mode 100644 index 8ba0174..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/init/NoOpInitializer.java +++ /dev/null @@ -1,16 +0,0 @@ -package ai.wanaku.code.engine.camel.init; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * No-operation initializer used when no initialization is required. - */ -public class NoOpInitializer implements Initializer { - private static final Logger LOG = LoggerFactory.getLogger(NoOpInitializer.class); - - @Override - public void initialize() throws Exception { - LOG.debug("No initialization required"); - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/util/FileUtil.java b/src/main/java/ai/wanaku/code/engine/camel/util/FileUtil.java deleted file mode 100644 index faa5e93..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/util/FileUtil.java +++ /dev/null @@ -1,79 +0,0 @@ -package ai.wanaku.code.engine.camel.util; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.StandardWatchEventKinds; -import java.nio.file.WatchEvent; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class FileUtil { - private static final Logger LOG = LoggerFactory.getLogger(FileUtil.class); - - private FileUtil() {} - - public static boolean untilAvailable(File input, boolean isDirectory) throws IOException, InterruptedException { - WatchService watchService = FileSystems.getDefault().newWatchService(); - Path path = isDirectory ? input.toPath() : input.getParentFile().toPath(); - - if (input.exists()) { - LOG.info("File {} already available", input); - return true; - } - - // We watch for both the file creation and truncation - path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY); - - do { - LOG.info("Waiting indefinitely for {} to be available", input); - - WatchKey watchKey = watchService.poll(1, TimeUnit.SECONDS); - - if (watchKey == null) { - continue; - } - - for (WatchEvent event : watchKey.pollEvents()) { - - /* - It should return a Path object for ENTRY_CREATE and ENTRY_MODIFY events - */ - Object context = event.context(); - if (!(context instanceof Path contextPath)) { - LOG.warn("Received an unexpected event of kind {} for context {}", event.kind(), event.context()); - continue; - } - - if (contextPath.toString().equals(input.getName())) { - LOG.debug( - "File at the path {} had a matching event of type: {}", - input.getParentFile().getPath(), - event.kind()); - - if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE - || event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) { - LOG.info( - "File at the path {} was created or modified", - input.getParentFile().getPath()); - - break; - } - } else { - LOG.debug( - "Ignoring a watch event at build path {} of type {} for file: {}", - input.getParentFile().getPath(), - event.kind(), - contextPath.getFileName()); - } - } - watchKey.reset(); - } while (!input.exists()); - - return input.exists(); - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/util/GavUtil.java b/src/main/java/ai/wanaku/code/engine/camel/util/GavUtil.java deleted file mode 100644 index 1310724..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/util/GavUtil.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package ai.wanaku.code.engine.camel.util; - -public class GavUtil { - - public static String group(String gav) { - return gav.split(":")[0]; - } - - public static String artifact(String gav) { - return gav.split(":")[1]; - } - - public static String version(String gav) { - return gav.split(":")[2]; - } -} diff --git a/src/main/java/ai/wanaku/code/engine/camel/util/WanakuRoutesLoader.java b/src/main/java/ai/wanaku/code/engine/camel/util/WanakuRoutesLoader.java deleted file mode 100644 index ec0876b..0000000 --- a/src/main/java/ai/wanaku/code/engine/camel/util/WanakuRoutesLoader.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package ai.wanaku.code.engine.camel.util; - -import org.apache.camel.CamelContext; -import org.apache.camel.ExtendedCamelContext; -import org.apache.camel.main.download.DependencyDownloader; -import org.apache.camel.main.download.DependencyDownloaderClassLoader; -import org.apache.camel.main.download.DependencyDownloaderComponentResolver; -import org.apache.camel.main.download.DependencyDownloaderDataFormatResolver; -import org.apache.camel.main.download.DependencyDownloaderLanguageResolver; -import org.apache.camel.main.download.DependencyDownloaderRoutesLoader; -import org.apache.camel.main.download.DependencyDownloaderTransformerResolver; -import org.apache.camel.main.download.DependencyDownloaderUriFactoryResolver; -import org.apache.camel.main.download.MavenDependencyDownloader; -import org.apache.camel.spi.ComponentResolver; -import org.apache.camel.spi.DataFormatResolver; -import org.apache.camel.spi.LanguageResolver; -import org.apache.camel.spi.Resource; -import org.apache.camel.spi.ResourceLoader; -import org.apache.camel.spi.RoutesLoader; -import org.apache.camel.spi.TransformerResolver; -import org.apache.camel.spi.UriFactoryResolver; -import org.apache.camel.support.PluginHelper; -import org.slf4j.Logger; - -public class WanakuRoutesLoader { - private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(WanakuRoutesLoader.class); - - private final String dependenciesList; - private final String repositoriesList; - private final DependencyDownloaderClassLoader cl; - private final MavenDependencyDownloader downloader; - - public WanakuRoutesLoader(String dependenciesList, String repositoriesList) { - this.dependenciesList = dependenciesList; - this.repositoriesList = repositoriesList; - this.cl = createClassLoader(); - this.downloader = createDownloader(cl); - } - - public void loadRoute(CamelContext context, String path) throws Exception { - final ExtendedCamelContext camelContextExtension = context.getCamelContextExtension(); - - try { - context.addService(downloader); - } catch (Exception e) { - throw new RuntimeException(e); - } - - camelContextExtension.addContextPlugin( - ComponentResolver.class, new DependencyDownloaderComponentResolver(context, null, false, false)); - camelContextExtension.addContextPlugin( - DataFormatResolver.class, new DependencyDownloaderDataFormatResolver(context, null, false)); - camelContextExtension.addContextPlugin( - LanguageResolver.class, new DependencyDownloaderLanguageResolver(context, null, false)); - camelContextExtension.addContextPlugin( - TransformerResolver.class, new DependencyDownloaderTransformerResolver(context, null, false)); - camelContextExtension.addContextPlugin( - UriFactoryResolver.class, new DependencyDownloaderUriFactoryResolver(context)); - - downloadDependencies(context); - - DependencyDownloaderRoutesLoader loader = new DependencyDownloaderRoutesLoader(context); - camelContextExtension.addContextPlugin(RoutesLoader.class, loader); - - final ResourceLoader resourceLoader = PluginHelper.getResourceLoader(context); - final Resource resource = resourceLoader.resolveResource(path); - - loader.loadRoutes(resource); - - context.build(); - } - - private void downloadDependencies(CamelContext camelContext) { - ExtendedCamelContext camelContextExtension = camelContext.getCamelContextExtension(); - - if (dependenciesList != null) { - final String[] dependencies = dependenciesList.split(","); - for (String dependency : dependencies) { - // In case of empty file - if (!dependency.isEmpty()) { - dependency = dependency.trim(); - downloader.downloadDependency( - GavUtil.group(dependency), GavUtil.artifact(dependency), GavUtil.version(dependency)); - } - } - - cl.getDownloaded().forEach(d -> LOG.debug("Downloaded {}", d)); - } - - Thread.currentThread().setContextClassLoader(cl); - camelContextExtension.addContextPlugin(DependencyDownloader.class, downloader); - } - - private MavenDependencyDownloader createDownloader(DependencyDownloaderClassLoader cl) { - MavenDependencyDownloader downloader = new MavenDependencyDownloader(); - downloader.setClassLoader(cl); - - if (repositoriesList != null) { - downloader.setRepositories(repositoriesList); - } - - downloader.start(); - return downloader; - } - - private static DependencyDownloaderClassLoader createClassLoader() { - final ClassLoader parentCL = WanakuRoutesLoader.class.getClassLoader(); - - return new DependencyDownloaderClassLoader(parentCL); - } -}