Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
19531d0
Load connectors from dependent integration projects
chathuranga-jayanath-99 Mar 25, 2026
93eab38
Add dependent project connector loading test cases
chathuranga-jayanath-99 Mar 30, 2026
fbefb3e
Add tests for IntegrationProjectDownloadManager
chathuranga-jayanath-99 Apr 2, 2026
0340c89
Sync integration project downloads with the updated dependencies list
chathuranga-jayanath-99 Apr 2, 2026
431165a
Add refetch for integration project dependencies
chathuranga-jayanath-99 Apr 3, 2026
c8b2cba
Simplify code duplications in error message generation for failed dep…
chathuranga-jayanath-99 Apr 3, 2026
348c542
Resolve connector loader test failures caused after loading connector…
chathuranga-jayanath-99 Apr 3, 2026
e087b6e
Add tests for integration project download scenarios
chathuranga-jayanath-99 Apr 3, 2026
b0be962
Parameterize the use of USER_HOME in integration project download sce…
chathuranga-jayanath-99 Apr 3, 2026
11e8fe5
Update tests to use temp dir as user home and add add log comments.
chathuranga-jayanath-99 Apr 4, 2026
4f705e1
Address log comments
chathuranga-jayanath-99 Apr 4, 2026
4591fc8
Set last modified time to a past value to prevent same-timestamp conf…
chathuranga-jayanath-99 Apr 7, 2026
ddd8b75
Move expensive operations inside supplyAsync
chathuranga-jayanath-99 Apr 7, 2026
86673b7
Add missing import
chathuranga-jayanath-99 Apr 7, 2026
0969aa8
Address reviewed comments
chathuranga-jayanath-99 Apr 7, 2026
d1b4b25
Mark whether a connector is from project or from a dependent inetgrat…
chathuranga-jayanath-99 Apr 7, 2026
8d261aa
Add tests for marking connectors from project or from integration pro…
chathuranga-jayanath-99 Apr 7, 2026
981aa27
Add log improvements
chathuranga-jayanath-99 Apr 7, 2026
72ca3fe
Address reviewed comments
chathuranga-jayanath-99 Apr 7, 2026
ddea9e1
Skip downloading connectors already available from integration projec…
chathuranga-jayanath-99 Apr 8, 2026
a954637
Add tests for skipping connector download when available in integrati…
chathuranga-jayanath-99 Apr 8, 2026
a29ab58
Add error message when connector add is skipped due to integration pr…
chathuranga-jayanath-99 Apr 8, 2026
0164192
Add log improvements
chathuranga-jayanath-99 Apr 8, 2026
cdf21cc
Handle conflicting resources when loading dependent projects
chathuranga-jayanath-99 Apr 9, 2026
1ed2efb
Add tests for loading resources from dependent projects
chathuranga-jayanath-99 Apr 9, 2026
15f1a7a
Add log improvements
chathuranga-jayanath-99 Apr 12, 2026
ec1d026
Add more tests regarding load dependent resources
chathuranga-jayanath-99 Apr 13, 2026
7c84305
Update configurting USER_HOME to avoid system property updates in tests
chathuranga-jayanath-99 Apr 13, 2026
3b232a9
Move generic methods to Utils
chathuranga-jayanath-99 Apr 15, 2026
47977e8
Update to return the response of the load dependent resources service…
chathuranga-jayanath-99 Apr 19, 2026
338c1fa
Address reviewed comments
chathuranga-jayanath-99 Apr 27, 2026
ba0b572
Fail refetch if cached dependent files' directories cannot be deleted…
chathuranga-jayanath-99 Apr 27, 2026
db4dfa1
Maintain visited and resolved dependencies separately so only resolve…
chathuranga-jayanath-99 Apr 27, 2026
78dd666
Use exact HTTP connector name for conflict detection instead of prefi…
chathuranga-jayanath-99 Apr 27, 2026
86e9397
Address reviewed comments
chathuranga-jayanath-99 Apr 27, 2026
241093b
Revert updating license header year
chathuranga-jayanath-99 Apr 28, 2026
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
Expand Up @@ -99,6 +99,7 @@
import org.eclipse.lemminx.customservice.synapse.resourceFinder.ResourceUsageFinder;
import org.eclipse.lemminx.customservice.synapse.resourceFinder.ResourceUsagesRequest;
import org.eclipse.lemminx.customservice.synapse.resourceFinder.pojo.ResourceParam;
import org.eclipse.lemminx.customservice.synapse.resourceFinder.pojo.LoadDependentResourcesResponse;
import org.eclipse.lemminx.customservice.synapse.resourceFinder.pojo.ResourceResponse;
import org.eclipse.lemminx.customservice.synapse.connectors.ConnectorHolder;
import org.eclipse.lemminx.customservice.synapse.connectors.AbstractConnectorLoader;
Expand Down Expand Up @@ -684,16 +685,29 @@ public CompletableFuture<String> updateConnectorDependencies() {
return CompletableFuture.supplyAsync(() -> statusMessage);
}

@Override
public CompletableFuture<String> refetchIntegrationProjectDependencies() {

log.info("Refetching integration project dependencies for project: " + projectUri);
return CompletableFuture.supplyAsync(() -> {
return DependencyDownloadManager.refetchIntegrationProjectDependencies(projectUri);
});
}
Comment thread
chathuranga-jayanath-99 marked this conversation as resolved.
Comment thread
chathuranga-jayanath-99 marked this conversation as resolved.

@Override
public CompletableFuture<DependencyStatusResponse> getDependencyStatusList() {

return CompletableFuture.supplyAsync(() -> DependencyDownloadManager.getDependencyStatusList(projectUri));
}

@Override
public CompletableFuture<String> loadDependentResources() {
public CompletableFuture<LoadDependentResourcesResponse> loadDependentResources() {

return CompletableFuture.supplyAsync(() -> resourceFinder.loadDependentResources(projectUri));
return CompletableFuture.supplyAsync(() -> {
LoadDependentResourcesResponse result = resourceFinder.loadDependentResources(projectUri);
updateConnectors();
return result;
});
Comment thread
chathuranga-jayanath-99 marked this conversation as resolved.
}
Comment thread
chathuranga-jayanath-99 marked this conversation as resolved.

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import org.eclipse.lemminx.customservice.synapse.parser.config.ConfigurableEntry;
import org.eclipse.lemminx.customservice.synapse.resourceFinder.ResourceUsagesRequest;
import org.eclipse.lemminx.customservice.synapse.resourceFinder.pojo.ResourceParam;
import org.eclipse.lemminx.customservice.synapse.resourceFinder.pojo.LoadDependentResourcesResponse;
import org.eclipse.lemminx.customservice.synapse.resourceFinder.pojo.ResourceResponse;
import org.eclipse.lemminx.customservice.synapse.schemagen.util.SchemaGenFromContentRequest;
import org.eclipse.lemminx.customservice.synapse.schemagen.util.SchemaGenRequest;
Expand Down Expand Up @@ -245,7 +246,10 @@ public interface ISynapseLanguageService {
CompletableFuture<String> updateConnectorDependencies();

@JsonRequest
CompletableFuture<String> loadDependentResources();
CompletableFuture<String> refetchIntegrationProjectDependencies();

@JsonRequest
CompletableFuture<LoadDependentResourcesResponse> loadDependentResources();
Comment thread
coderabbitai[bot] marked this conversation as resolved.

@JsonRequest
CompletableFuture<TestConnectionResponse> testConnectorConnection(TestConnectionRequest request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
package org.eclipse.lemminx.customservice.synapse.connectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.lemminx.customservice.SynapseLanguageClientAPI;
import org.eclipse.lemminx.customservice.synapse.connectors.entity.Connector;
import org.eclipse.lemminx.customservice.synapse.inbound.conector.InboundConnectorHolder;
import org.eclipse.lemminx.customservice.synapse.mediator.TryOutConstants;
import org.eclipse.lemminx.customservice.synapse.utils.Constant;
Expand All @@ -24,8 +27,11 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
Expand All @@ -37,17 +43,23 @@ public class NewProjectConnectorLoader extends AbstractConnectorLoader {

private static final Logger log = Logger.getLogger(NewProjectConnectorLoader.class.getName());
private String projectId;
protected final List<String> baseConnectorsZipFolderPaths = new ArrayList<>();

public NewProjectConnectorLoader(SynapseLanguageClientAPI languageClient, ConnectorHolder connectorHolder,
InboundConnectorHolder inboundConnectorHolder) {

super(languageClient, connectorHolder, inboundConnectorHolder);
}

protected String getUserHome() {

return System.getProperty(Constant.USER_HOME);
}

@Override
protected File getConnectorExtractFolder() {

String tempFolderPath = Path.of(System.getProperty(Constant.USER_HOME), Constant.WSO2_MI,
String tempFolderPath = Path.of(getUserHome(), Constant.WSO2_MI,
Constant.CONNECTORS, projectId, Constant.EXTRACTED).toString();
File tempFolder = new File(tempFolderPath);
return tempFolder;
Expand Down Expand Up @@ -109,7 +121,7 @@ protected void cleanOldConnectors(File connectorExtractFolder, List<File> connec
.resolve(Constant.UI_SCHEMA_JSON).toFile());
String fileName = Utils.getJsonObject(schema).get(Constant.NAME).getAsString() + Constant.JSON_FILE_EXT;
String projectFolderName = connectorExtractFolder.getParentFile().getName();
File schemaToRemove = Path.of(System.getProperty(Constant.USER_HOME), Constant.WSO2_MI,
File schemaToRemove = Path.of(getUserHome(), Constant.WSO2_MI,
Constant.INBOUND_CONNECTORS).resolve(projectFolderName).resolve(fileName).toFile();
FileUtils.delete(schemaToRemove);
}
Expand All @@ -124,16 +136,103 @@ protected void cleanOldConnectors(File connectorExtractFolder, List<File> connec

private Path getConnnectorDownloadPath() {

return Path.of(System.getProperty(Constant.USER_HOME), Constant.WSO2_MI,
return Path.of(getUserHome(), Constant.WSO2_MI,
Constant.CONNECTORS, projectId, Constant.DOWNLOADED);
}

@Override
public void loadConnector() {

connectorsZipFolderPath.clear();
connectorsZipFolderPath.addAll(baseConnectorsZipFolderPaths);
addDependencyProjectConnectorPaths();
log.info("Loading connectors from " + connectorsZipFolderPath.size() + " paths for project: " + projectId);
super.loadConnector();
markProjectConnectors();
}
Comment thread
chathuranga-jayanath-99 marked this conversation as resolved.

/**
* Marks each loaded connector with whether it originates from the project itself.
* A connector is considered to be from the project if its zip was sourced from one of the
* base connector paths (the project's own connector directory or the USER_HOME downloaded
* directory). Connectors sourced from dependency integration project directories are marked
* as not from the project.
* If the same connector exists in both a base path and a dependency path, the base path takes
* precedence since it is loaded first.
*/
private void markProjectConnectors() {

log.info("Marking project connectors for project: " + projectId);
Set<String> projectConnectorZipNames = new HashSet<>();
for (File zip : connectorHolder.getConnectorZips()) {
if (baseConnectorsZipFolderPaths.contains(zip.getParent())) {
String name = zip.getName();
projectConnectorZipNames.add(name.substring(0, name.lastIndexOf(Constant.DOT)));
}
}
int markedCount = 0;
for (Connector connector : connectorHolder.getConnectors()) {
String extractedPath = connector.getExtractedConnectorPath();
if (StringUtils.isNotBlank(extractedPath)) {
boolean isFromProject = projectConnectorZipNames.contains(FilenameUtils.getName(extractedPath));
connector.setFromProject(isFromProject);
if (isFromProject) {
markedCount++;
}
}
}
log.info("Marked " + markedCount + " project connector(s) for project: " + projectId);
}

@Override
protected void setConnectorsZipFolderPath(String projectRoot) {

connectorsZipFolderPath.add(Path.of(projectRoot, Constant.SRC, Constant.MAIN, Constant.WSO2MI,
Constant.RESOURCES, Constant.CONNECTORS).toString());
projectId = new File(projectRoot).getName() + "_" + Utils.getHash(projectRoot);
connectorsZipFolderPath.add(getConnnectorDownloadPath().toString());
baseConnectorsZipFolderPaths.add(Path.of(projectRoot, Constant.SRC, Constant.MAIN, Constant.WSO2MI,
Constant.RESOURCES, Constant.CONNECTORS).toString());
baseConnectorsZipFolderPaths.add(getConnnectorDownloadPath().toString());
connectorsZipFolderPath.addAll(baseConnectorsZipFolderPaths);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/**
* Scans the extracted dependency project directories and adds their connector paths
* to the connector zip folder paths list.
*/
private void addDependencyProjectConnectorPaths() {

Path extractedDir = findProjectDependencyExtractedDir();
if (extractedDir == null) {
return;
}
File[] dependentProjects = extractedDir.toFile().listFiles(File::isDirectory);
if (dependentProjects == null) {
return;
}
Comment thread
chathuranga-jayanath-99 marked this conversation as resolved.
for (File dependentProject : dependentProjects) {
Path connectorPath = dependentProject.toPath()
.resolve(Constant.SRC).resolve(Constant.MAIN).resolve(Constant.WSO2MI)
.resolve(Constant.RESOURCES).resolve(Constant.CONNECTORS);
if (connectorPath.toFile().isDirectory()) {
connectorsZipFolderPath.add(connectorPath.toString());
log.info("Added connector path from dependency project: " + connectorPath);
}
}
}

/**
* Returns the extracted directory for the current project's integration project dependencies,
* or null if it does not exist.
*/
private Path findProjectDependencyExtractedDir() {

if (StringUtils.isEmpty(projectId)) {
return null;
}
Path expectedDir = Path.of(getUserHome(), Constant.WSO2_MI,
Constant.INTEGRATION_PROJECT_DEPENDENCIES, projectId, Constant.EXTRACTED);
if (expectedDir.toFile().isDirectory()) {
return expectedDir;
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class Connector {
private String uiSchemaPath;
private String outputSchemaPath;
private String ballerinaModulePath;
private boolean fromProject;
Comment thread
coderabbitai[bot] marked this conversation as resolved.

public Connector() {

Expand Down Expand Up @@ -212,4 +213,12 @@ public String getBallerinaModulePath() {
public void setBallerinaModulePath(String ballerinaModulePath) {
this.ballerinaModulePath = ballerinaModulePath;
}

public boolean isFromProject() {
return fromProject;
}

public void setFromProject(boolean fromProject) {
this.fromProject = fromProject;
}
Comment thread
chathuranga-jayanath-99 marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2026, WSO2 LLC. (http://www.wso2.com).
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* WSO2 LLC - support for WSO2 Micro Integrator Configuration
*/

package org.eclipse.lemminx.customservice.synapse.parser;

import java.util.List;

/**
* Encapsulates the results of connector dependency download operations.
* <p>
* Contains two lists: connectors that failed to download due to general errors,
* and connectors that were skipped because they are already provided by an
* integration project dependency.
* </p>
*/
public class ConnectorDependencyDownloadResult {

private List<String> failedDependencies;
private List<String> fromIntegrationProjectDependencies;

public ConnectorDependencyDownloadResult(List<String> failedDependencies,
List<String> fromIntegrationProjectDependencies) {
this.failedDependencies = failedDependencies;
this.fromIntegrationProjectDependencies = fromIntegrationProjectDependencies;
}

public List<String> getFailedDependencies() {
return failedDependencies;
}

public List<String> getFromIntegrationProjectDependencies() {
return fromIntegrationProjectDependencies;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ public class ConnectorDownloadManager {

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

public static List<String> downloadDependencies(String projectPath, List<DependencyDetails> dependencies) {
public static ConnectorDependencyDownloadResult downloadDependencies(String projectPath, List<DependencyDetails> dependencies) {

LOGGER.log(Level.INFO, "Starting connector dependency download for project: " + new File(projectPath).getName()
+ " with " + dependencies.size() + " dependencies");
String projectId = new File(projectPath).getName() + "_" + Utils.getHash(projectPath);
File directory = Path.of(System.getProperty(Constant.USER_HOME), Constant.WSO2_MI, Constant.CONNECTORS,
projectId).toFile();
Expand All @@ -63,8 +65,17 @@ public static List<String> downloadDependencies(String projectPath, List<Depende

deleteRemovedConnectors(downloadDirectory, dependencies, projectPath);
List<String> failedDependencies = new ArrayList<>();
List<String> fromIntegrationProjectDependencies = new ArrayList<>();

for (DependencyDetails dependency : dependencies) {
String dependencyId =
dependency.getGroupId() + Constant.HYPHEN + dependency.getArtifact() + Constant.HYPHEN + dependency.getVersion();
if (isConnectorFromIntegrationProjectDependency(dependency.getArtifact())) {
LOGGER.log(Level.WARNING, "Connector " + dependencyId +
" is provided by an integration project dependency. Download not allowed.");
fromIntegrationProjectDependencies.add(dependencyId);
continue;
}
try {
File connector = Path.of(downloadDirectory.getAbsolutePath(),
dependency.getArtifact() + "-" + dependency.getVersion() + Constant.ZIP_EXTENSION).toFile();
Expand All @@ -81,12 +92,25 @@ public static List<String> downloadDependencies(String projectPath, List<Depende
dependency.getVersion(), downloadDirectory, Constant.ZIP_EXTENSION_NO_DOT, projectPath);
}
} catch (Exception e) {
String failedDependency = dependency.getGroupId() + "-" + dependency.getArtifact() + "-" + dependency.getVersion();
LOGGER.log(Level.WARNING, "Error occurred while downloading dependency " + failedDependency + ": " + e.getMessage());
failedDependencies.add(failedDependency);
LOGGER.log(Level.WARNING,
"Error occurred while downloading dependency " + dependencyId + ": " + e.getMessage());
failedDependencies.add(dependencyId);
}
}
return failedDependencies;
LOGGER.log(Level.INFO, "Connector dependency download completed for project: " + new File(projectPath).getName()
+ ". Failed: " + failedDependencies.size() + ", From integration project dependencies: "
+ fromIntegrationProjectDependencies.size());
return new ConnectorDependencyDownloadResult(failedDependencies, fromIntegrationProjectDependencies);
}

/**
* Returns true if the connector with the given artifact ID is already loaded from an integration
* project dependency (i.e. not owned by the current project).
*/
private static boolean isConnectorFromIntegrationProjectDependency(String artifactId) {

return ConnectorHolder.getInstance().getConnectors().stream()
.anyMatch(c -> artifactId.equalsIgnoreCase(c.getArtifactId()) && !c.isFromProject());
}

private static void deleteRemovedConnectors(File downloadDirectory, List<DependencyDetails> dependencies,
Expand Down
Loading
Loading