Skip to content

Commit 3bd905c

Browse files
authored
Merge pull request #481 from ChinthakaJ98/fix-tryout
2 parents a64ef1c + 7d74854 commit 3bd905c

File tree

5 files changed

+199
-2
lines changed

5 files changed

+199
-2
lines changed

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/mediator/TryOutConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public class TryOutConstants {
103103
public static final Path PROJECT_RESOURCES_RELATIVE_PATH = Path.of("src", "main", "wso2mi", "resources");
104104
public static final String POST_CLEANUP = "POST_CLEANUP";
105105
public static final String IS_CONNECTOR_TEST = "IS_CONNECTOR_TEST";
106+
public static final Path TRYOUT_HISTORY_LOG_FILE = CAPP_CACHE_LOCATION.resolve("tryout_history.lock");
106107

107108
private TryOutConstants() {
108109

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/mediator/TryOutUtils.java

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,20 @@
5151
import org.w3c.dom.NodeList;
5252
import org.xml.sax.InputSource;
5353

54+
import java.io.BufferedReader;
5455
import java.io.File;
56+
import java.io.InputStreamReader;
5557
import java.io.IOException;
5658
import java.io.StringReader;
5759
import java.nio.file.Files;
5860
import java.nio.file.Path;
61+
import java.util.Arrays;
5962
import java.util.ArrayList;
6063
import java.util.Collections;
6164
import java.util.List;
6265
import java.util.UUID;
66+
import java.util.logging.Level;
67+
import java.util.logging.Logger;
6368
import java.util.stream.Stream;
6469

6570
import javax.xml.parsers.DocumentBuilder;
@@ -72,6 +77,8 @@ public class TryOutUtils {
7277
private static final String SOAP_ENVELOPE_URI = "http://schemas.xmlsoap.org/soap/envelope/";
7378
private static final String BODY = "Body";
7479

80+
private static final Logger LOGGER = Logger.getLogger(TryOutUtils.class.getName());
81+
7582
private TryOutUtils() {
7683

7784
}
@@ -686,4 +693,121 @@ public static Path findCAPP(Path targetPath) throws ArtifactDeploymentException
686693
throw new ArtifactDeploymentException(TryOutConstants.BUILD_FAILURE_MESSAGE);
687694
}
688695
}
696+
697+
/**
698+
* Get the project path hash from the tryout history log file.
699+
*
700+
* @return the project path hash
701+
*/
702+
public static String getProjectPathHash() {
703+
704+
String hash = null;
705+
try {
706+
String content = Files.readString(TryOutConstants.TRYOUT_HISTORY_LOG_FILE);
707+
String[] parts = content.split("\\s*-\\s*");
708+
if (parts.length >= 2) {
709+
hash = parts[0];
710+
}
711+
} catch (Exception e) {
712+
LOGGER.log(Level.SEVERE, "Error occurred while reading the tryout history log file. ", e);
713+
}
714+
return hash;
715+
}
716+
717+
/**
718+
* Get the process ID of a given port.
719+
*
720+
* @param port the port
721+
* @return the process ID
722+
*/
723+
public static int getProcessId(int port) {
724+
725+
String os = System.getProperty("os.name").toLowerCase();
726+
String findCommand;
727+
if (os.contains("win")) {
728+
findCommand = "netstat -ano | findstr :" + port;
729+
} else {
730+
findCommand = "lsof -i :" + port;
731+
}
732+
733+
String pid = null;
734+
try {
735+
String line;
736+
Process findProcess = Runtime.getRuntime().exec(new String[]{"bash", "-c", findCommand});
737+
BufferedReader reader = new BufferedReader(new InputStreamReader(findProcess.getInputStream()));
738+
while ((line = reader.readLine()) != null) {
739+
if (line.startsWith("COMMAND")) continue;
740+
if (os.contains("win")) {
741+
String[] parts = line.trim().split("\\s+");
742+
if (parts.length >= 5) {
743+
pid = parts[4];
744+
break;
745+
}
746+
} else {
747+
String[] parts = line.trim().split("\\s+");
748+
if (parts.length >= 2) {
749+
pid = parts[1];
750+
break;
751+
}
752+
}
753+
}
754+
reader.close();
755+
} catch (Exception e) {
756+
LOGGER.log(Level.SEVERE, "Error occurred while finding the process ID of port " + port + ". ", e);
757+
}
758+
return pid != null ? Integer.parseInt(pid) : -1;
759+
}
760+
761+
/**
762+
* Get the last updated timestamp from the tryout history log file.
763+
*
764+
* @return the timestamp
765+
*/
766+
public static String getTimestamp() {
767+
768+
String timestamp = null;
769+
try {
770+
String content = Files.readString(TryOutConstants.TRYOUT_HISTORY_LOG_FILE);
771+
String[] parts = content.split("\\s*-\\s*");
772+
if (parts.length == 3) {
773+
timestamp = parts[2];
774+
}
775+
} catch (Exception e) {
776+
LOGGER.log(Level.SEVERE, "Error occurred while reading the tryout history log file. ", e);
777+
}
778+
return timestamp;
779+
}
780+
781+
/**
782+
* Update the latest timestamp in the tryout history log file.
783+
*
784+
* @param projectUri the project URI from which the server is started
785+
* @param removeTimestamp whether to remove the existing timestamp
786+
*/
787+
public static void updateTimestamp(String projectUri, boolean removeTimestamp) {
788+
789+
if (Utils.getHash(projectUri).equals(getProjectPathHash())) {
790+
try {
791+
String content = Files.readString(TryOutConstants.TRYOUT_HISTORY_LOG_FILE);
792+
String[] parts = content.split("\\s*-\\s*");
793+
String currentTimestamp = String.valueOf(System.currentTimeMillis()/1000);
794+
String updatedContent = content;
795+
if (removeTimestamp && parts.length == 3) {
796+
updatedContent = String.join(" - ", Arrays.copyOf(parts, parts.length - 1));
797+
} else if (parts.length == 3) {
798+
// Already has a timestamp therefore replace it
799+
parts[2] = currentTimestamp;
800+
updatedContent = String.join(" - ", parts);
801+
} else if (parts.length == 2) {
802+
// No timestamp therefore append one
803+
updatedContent = content + " - " + currentTimestamp;
804+
}
805+
Files.createDirectories(TryOutConstants.TRYOUT_HISTORY_LOG_FILE.getParent());
806+
Files.writeString(TryOutConstants.TRYOUT_HISTORY_LOG_FILE, updatedContent);
807+
} catch (Exception e) {
808+
LOGGER.log(Level.SEVERE,
809+
"Error occurred while updating the timestamp in the tryout history log file. ", e);
810+
}
811+
}
812+
}
689813
}

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/mediator/tryout/TryOutHandler.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import com.google.gson.JsonObject;
1818
import org.apache.commons.lang3.StringUtils;
19+
import org.apache.woden.internal.wsdl20.Constants;
1920
import org.eclipse.lemminx.commons.BadLocationException;
2021
import org.eclipse.lemminx.customservice.SynapseLanguageClientAPI;
2122
import org.eclipse.lemminx.customservice.synapse.debugger.DebuggerHelper;
@@ -36,6 +37,7 @@
3637
import org.eclipse.lemminx.customservice.synapse.mediator.tryout.pojo.NoBreakpointHitException;
3738
import org.eclipse.lemminx.customservice.synapse.mediator.tryout.pojo.Property;
3839
import org.eclipse.lemminx.customservice.synapse.mediator.tryout.server.MIServer;
40+
import org.eclipse.lemminx.customservice.synapse.mediator.tryout.server.ManagementAPIClient;
3941
import org.eclipse.lemminx.customservice.synapse.syntaxTree.SyntaxTreeGenerator;
4042
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.NamedSequence;
4143
import org.eclipse.lemminx.customservice.synapse.syntaxTree.pojo.STNode;
@@ -67,6 +69,7 @@
6769
import java.util.logging.Level;
6870
import java.util.logging.Logger;
6971

72+
import static org.eclipse.lemminx.customservice.synapse.mediator.TryOutConstants.DEFAULT_SERVER_PORT;
7073
import static org.eclipse.lemminx.customservice.synapse.mediator.TryOutConstants.TEMP_FOLDER_PATH;
7174

7275
public class TryOutHandler {
@@ -119,6 +122,7 @@ public synchronized void init() {
119122
*/
120123
public synchronized MediatorTryoutInfo handle(MediatorTryoutRequest request) {
121124

125+
handleServerRestart(request);
122126
if (!server.isStarted()) {
123127
if (server.isServerRunning()) {
124128
return new MediatorTryoutInfo(TryOutConstants.SERVER_ALREADY_IN_USE_ERROR);
@@ -202,6 +206,7 @@ private MediatorTryoutInfo startTryOut(MediatorTryoutRequest request, boolean us
202206
getMediatorTryoutInfo(currentInvocationInfo.isNeedStepOver(), breakpointEventProcessor.isDone());
203207
currentTryoutID = response.getId();
204208
currentInputInfo = response.getInput();
209+
TryOutUtils.updateTimestamp(projectUri, false);
205210
return response;
206211
} catch (IOException | InvalidConfigurationException | ArtifactDeploymentException e) {
207212
LOGGER.log(Level.SEVERE, "Error while handling the tryout", e);
@@ -236,7 +241,9 @@ private MediatorTryoutInfo resumeTryOut(MediatorTryoutRequest request) {
236241
return createFaultTryOutInfo();
237242
}
238243
currentTryoutID = null;
239-
return getMediatorTryoutInfo(true, breakpointEventProcessor.isDone());
244+
MediatorTryoutInfo response = getMediatorTryoutInfo(true, breakpointEventProcessor.isDone());
245+
TryOutUtils.updateTimestamp(projectUri, true);
246+
return response;
240247
} catch (NoBreakpointHitException e) {
241248
LOGGER.log(Level.SEVERE, "Error while getting output info");
242249
return new MediatorTryoutInfo(TryOutConstants.TRYOUT_FAILURE_MESSAGE);
@@ -291,6 +298,9 @@ private void reRegisterBreakpoints(List<JsonObject> tempBreakpoints) throws Inva
291298
public MediatorTryoutInfo handleIsolatedTryOut(String projectPath, MediatorTryoutRequest request,
292299
boolean useSameCAPP, Properties context) {
293300

301+
if (Constants.VALUE_TRUE.equals(context.get(TryOutConstants.IS_CONNECTOR_TEST))) {
302+
handleServerRestart(request);
303+
}
294304
if (!server.isStarted()) {
295305
if (server.isServerRunning()) {
296306
return new MediatorTryoutInfo(TryOutConstants.SERVER_ALREADY_IN_USE_ERROR);
@@ -654,4 +664,37 @@ public boolean shutDown() {
654664
}
655665
return Boolean.FALSE;
656666
}
667+
668+
private void handleServerRestart(MediatorTryoutRequest request) {
669+
670+
if (!(isNewTryOut(request) || isCompleteTryOut(request))) {
671+
return;
672+
}
673+
String projectHash = TryOutUtils.getProjectPathHash();
674+
String existingTimestamp = TryOutUtils.getTimestamp();
675+
if (StringUtils.isBlank(existingTimestamp) ||
676+
(System.currentTimeMillis()/1000 - Long.parseLong(existingTimestamp) > 30)) {
677+
if (StringUtils.isNotBlank(projectHash) && !Utils.getHash(projectUri).equals(projectHash)) {
678+
try {
679+
if (commandClient != null && eventClient != null) {
680+
commandClient.close();
681+
eventClient.close();
682+
}
683+
if (TryOutUtils.getProcessId(DEFAULT_SERVER_PORT) != -1) {
684+
ManagementAPIClient managementAPIClient = new ManagementAPIClient();
685+
managementAPIClient.shutdown();
686+
}
687+
while (server.isServerRunning()) {
688+
Thread.sleep(2000);
689+
}
690+
reset();
691+
server.setStarted(false);
692+
} catch (Exception e) {
693+
LOGGER.log(Level.SEVERE, "Error occurred while trying to restart the MI server. ", e);
694+
}
695+
}
696+
} else {
697+
server.setStarted(false);
698+
}
699+
}
657700
}

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/mediator/tryout/server/MIServer.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414

1515
package org.eclipse.lemminx.customservice.synapse.mediator.tryout.server;
1616

17+
import org.apache.commons.lang3.StringUtils;
1718
import org.eclipse.lemminx.customservice.SynapseLanguageClientAPI;
1819
import org.eclipse.lemminx.customservice.synapse.mediator.TryOutConstants;
20+
import org.eclipse.lemminx.customservice.synapse.mediator.TryOutUtils;
1921
import org.eclipse.lemminx.customservice.synapse.mediator.tryout.pojo.ArtifactDeploymentException;
2022
import org.eclipse.lemminx.customservice.synapse.mediator.tryout.pojo.DeployedArtifactType;
2123
import org.eclipse.lemminx.customservice.synapse.syntaxTree.SyntaxTreeGenerator;
@@ -98,6 +100,10 @@ public MIServer(Path serverPath, String projectUri, SynapseLanguageClientAPI lan
98100
this.languageClient = languageClient;
99101
}
100102

103+
public void setStarted(boolean started) {
104+
isStarted = started;
105+
}
106+
101107
public synchronized void startServer() {
102108

103109
if (isStarted || isStarting || isServerRunning()) {
@@ -109,6 +115,9 @@ public synchronized void startServer() {
109115
}
110116
try {
111117
serverProcess = startServerProcess();
118+
String content = Utils.getHash(projectUri) + " - " + serverProcess.pid();
119+
Files.createDirectories(TryOutConstants.TRYOUT_HISTORY_LOG_FILE.getParent());
120+
Files.writeString(TryOutConstants.TRYOUT_HISTORY_LOG_FILE, content);
112121

113122
BufferedReader reader = new BufferedReader(
114123
new InputStreamReader(serverProcess.getInputStream(), StandardCharsets.UTF_8));
@@ -172,7 +181,7 @@ private synchronized Process startServerProcess() throws IOException {
172181
processBuilder.command("cmd", "/c", batchFile, "-Desb.debug=true", "-DgracefulShutdown=false");
173182
} else {
174183
// Unix-like systems
175-
processBuilder = new ProcessBuilder("./micro-integrator.sh", "-Desb.debug=true");
184+
processBuilder = new ProcessBuilder("./micro-integrator.sh", "-Desb.debug=true", "-DgracefulShutdown=false");
176185
}
177186
Map<String, String> env = processBuilder.environment();
178187
env.put("JAVA_HOME", System.getProperty("java.home"));
@@ -254,6 +263,10 @@ public boolean shutDown() {
254263
if (!isAlive) {
255264
isStarted = false;
256265
}
266+
if (Utils.getHash(projectUri).equals(TryOutUtils.getProjectPathHash())) {
267+
Files.createDirectories(TryOutConstants.TRYOUT_HISTORY_LOG_FILE.getParent());
268+
Files.writeString(TryOutConstants.TRYOUT_HISTORY_LOG_FILE, StringUtils.EMPTY);
269+
}
257270
return !isAlive;
258271
} catch (Exception e) {
259272
LOGGER.log(Level.SEVERE, String.format("Error terminating process tree: %s", e.getMessage()));

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/mediator/tryout/server/ManagementAPIClient.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public class ManagementAPIClient {
5151
private static final int DEFAULT_PORT = 9164;
5252
private static final String USERNAME = "admin";
5353
private static final String PASSWORD = "admin";
54+
private static final String SERVER_SHUTDOWN_PAYLOAD = "{ \"status\": \"shutdown\" }";
5455
private ObjectMapper objectMapper;
5556
private HttpClient client;
5657
private static final String HOST = TryOutConstants.LOCALHOST;
@@ -124,6 +125,21 @@ public void connect() throws InterruptedException {
124125
}
125126
}
126127

128+
public void shutdown() throws InterruptedException {
129+
130+
try {;
131+
HttpRequest request = HttpRequest.newBuilder()
132+
.uri(URI.create(String.format("https://%s:%d/management/server", HOST, port)))
133+
.header("Content-Type", "application/json")
134+
.header("Authorization", "Bearer " + accessToken)
135+
.method("PATCH", HttpRequest.BodyPublishers.ofString(SERVER_SHUTDOWN_PAYLOAD))
136+
.build();
137+
client.send(request, HttpResponse.BodyHandlers.ofString());
138+
} catch (IOException e) {
139+
LOGGER.severe("Failed to connect to the server: " + e.getMessage());
140+
}
141+
}
142+
127143
public List<String> getDeployedCapps() throws IOException, InterruptedException {
128144

129145
HttpRequest request = HttpRequest.newBuilder()

0 commit comments

Comments
 (0)