Skip to content
Merged
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,154 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat, Inc. Distributed under license by Red Hat, Inc.
* All rights reserved. This program is 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
*
* Contributors: Red Hat, Inc.
******************************************************************************/
package org.jboss.tools.rsp.client.cli;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ServerDescriptorUtil {

public static final String VARIABLE_PREFIX = "${rsp_import_export/";
public static final String VARIABLE_SUFFIX = "}";
public static final String FORMAT_VERSION_KEY = "rsp.descriptor.format.version";
public static final String FORMAT_VERSION = "1.0";
public static final String TYPE_ID_KEY = "org.jboss.tools.rsp.server.typeId";
private static final Set<String> EXCLUDED_EXPORT_KEYS = new HashSet<>(
Arrays.asList("id", "deployables"));

private static final Pattern VARIABLE_PATTERN = Pattern.compile(
"\\$\\{rsp_import_export/([^}]+)\\}");

private ServerDescriptorUtil() {
}

public static boolean isFilesystemPath(String value) {
if (value == null || value.isEmpty()) {
return false;
}
String trimmed = value.trim();

if (trimmed.startsWith("file://")) {
return true;
}

if (trimmed.startsWith("/")) {
String[] segments = trimmed.split("/");
long nonEmpty = Arrays.stream(segments).filter(s -> !s.isEmpty()).count();
return nonEmpty >= 2;
}

if (trimmed.length() >= 3
&& Character.isLetter(trimmed.charAt(0))
&& trimmed.charAt(1) == ':'
&& (trimmed.charAt(2) == '\\' || trimmed.charAt(2) == '/')) {
return true;
}

return false;
}

public static Map<String, String> detectPathAttributes(Map<String, Object> attrs) {
Map<String, String> pathAttrs = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : attrs.entrySet()) {
String key = entry.getKey();
if (EXCLUDED_EXPORT_KEYS.contains(key)
|| FORMAT_VERSION_KEY.equals(key)
|| TYPE_ID_KEY.equals(key)) {
continue;
}
Object val = entry.getValue();
if (val instanceof String && isFilesystemPath((String) val)) {
pathAttrs.put(key, (String) val);
}
}
return pathAttrs;
}

public static Map<String, Object> substitutePathsForExport(Map<String, Object> attrs) {
Map<String, String> pathAttrs = detectPathAttributes(attrs);

List<Map.Entry<String, String>> sortedPaths = new ArrayList<>(pathAttrs.entrySet());
sortedPaths.sort((a, b) -> b.getValue().length() - a.getValue().length());

Map<String, Object> result = new LinkedHashMap<>();
result.put(FORMAT_VERSION_KEY, FORMAT_VERSION);

for (Map.Entry<String, Object> entry : attrs.entrySet()) {
if (EXCLUDED_EXPORT_KEYS.contains(entry.getKey())) {
continue;
}

Object val = entry.getValue();
if (!(val instanceof String)) {
result.put(entry.getKey(), val);
continue;
}

String newValue = (String) val;
for (Map.Entry<String, String> pathEntry : sortedPaths) {
String variable = VARIABLE_PREFIX + pathEntry.getKey() + VARIABLE_SUFFIX;
while (newValue.contains(pathEntry.getValue())) {
newValue = newValue.replace(pathEntry.getValue(), variable);
}
}
result.put(entry.getKey(), newValue);
}

return result;
}

public static List<String> findVariables(Map<String, Object> attrs) {
Set<String> variables = new LinkedHashSet<>();
for (Object val : attrs.values()) {
if (!(val instanceof String)) {
continue;
}
Matcher matcher = VARIABLE_PATTERN.matcher((String) val);
while (matcher.find()) {
variables.add(matcher.group(1));
}
}
return new ArrayList<>(variables);
}

public static Map<String, Object> resolveVariables(
Map<String, Object> attrs, Map<String, String> values) {
Map<String, Object> result = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : attrs.entrySet()) {
if (FORMAT_VERSION_KEY.equals(entry.getKey())) {
continue;
}

Object val = entry.getValue();
if (!(val instanceof String)) {
result.put(entry.getKey(), val);
continue;
}

String newValue = (String) val;
for (Map.Entry<String, String> varEntry : values.entrySet()) {
String variable = VARIABLE_PREFIX + varEntry.getKey() + VARIABLE_SUFFIX;
while (newValue.contains(variable)) {
newValue = newValue.replace(variable, varEntry.getValue());
}
}
result.put(entry.getKey(), newValue);
}
return result;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,26 @@
package org.jboss.tools.rsp.client.cli;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import org.jboss.tools.rsp.api.ServerManagementAPIConstants;
import org.jboss.tools.rsp.api.dao.Attribute;
import org.jboss.tools.rsp.api.dao.Attributes;
Expand Down Expand Up @@ -497,6 +507,139 @@ public void execute(String command, ServerManagementClientLauncher launcher, Pro
}
}
},
EXPORT_SERVER("export server") {
@Override
public void execute(String command, ServerManagementClientLauncher launcher, PromptAssistant assistant) throws Exception {
ServerHandle sh = assistant.selectServer();
if (sh == null) {
System.out.println("No server selected.");
return;
}

GetServerJsonResponse resp = launcher.getServerProxy().getServerAsJson(sh).get();
if (!resp.getStatus().isOK()) {
System.out.println("Error: " + resp.getStatus().getMessage());
return;
}

Gson gson = new GsonBuilder().setPrettyPrinting().create();
java.lang.reflect.Type mapType = new TypeToken<LinkedHashMap<String, Object>>() {}.getType();
Map<String, Object> attrs = gson.fromJson(resp.getServerJson(), mapType);

Map<String, Object> exported = ServerDescriptorUtil.substitutePathsForExport(attrs);

String defaultName = sh.getId().replaceAll("[^a-zA-Z0-9_.-]", "_") + ".server.json";
System.out.println("Enter file path to export to [" + defaultName + "]: ");
String filePath = assistant.nextLine().trim();
if (filePath.isEmpty()) {
filePath = defaultName;
}
if (filePath.startsWith("~")) {
filePath = System.getProperty("user.home") + filePath.substring(1);
}

String content = gson.toJson(exported);
Files.write(Paths.get(filePath), content.getBytes(StandardCharsets.UTF_8));
System.out.println("Server descriptor exported to " + filePath);
}
},

IMPORT_SERVER("import server") {
@Override
public void execute(String command, ServerManagementClientLauncher launcher, PromptAssistant assistant) throws Exception {
System.out.println("Enter path to server descriptor file: ");
String filePath = assistant.nextLine().trim();
if (filePath.isEmpty()) {
System.out.println("No file specified.");
return;
}
if (filePath.startsWith("~")) {
filePath = System.getProperty("user.home") + filePath.substring(1);
}

Path path = Paths.get(filePath);
if (!Files.exists(path)) {
System.out.println("File not found: " + filePath);
return;
}

String content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
java.lang.reflect.Type mapType = new TypeToken<LinkedHashMap<String, Object>>() {}.getType();
Map<String, Object> attrs = gson.fromJson(content, mapType);

String serverTypeId = (String) attrs.get(ServerDescriptorUtil.TYPE_ID_KEY);
if (serverTypeId == null) {
System.out.println("Descriptor file does not contain a server type ID.");
return;
}

List<ServerType> serverTypes = launcher.getServerProxy().getServerTypes().get();
ServerType serverType = null;
for (ServerType st : serverTypes) {
if (st.getId().equals(serverTypeId)) {
serverType = st;
break;
}
}
if (serverType == null) {
System.out.println("Server type \"" + serverTypeId + "\" not supported by this RSP.");
return;
}

List<String> variables = ServerDescriptorUtil.findVariables(attrs);
Map<String, String> variableValues = new HashMap<>();
if (!variables.isEmpty()) {
System.out.println("The descriptor contains " + variables.size() + " path variable(s) that need local values:");
for (String varKey : variables) {
System.out.println("Enter local path for '" + varKey + "': ");
String val = assistant.nextLine().trim();
if (val.startsWith("~")) {
val = System.getProperty("user.home") + val.substring(1);
}
if (val.isEmpty()) {
System.out.println("Path cannot be empty. Aborting import.");
return;
}
variableValues.put(varKey, val);
}
}

Map<String, Object> resolved = ServerDescriptorUtil.resolveVariables(attrs, variableValues);

System.out.println("Enter a name for the new server: ");
String serverName = assistant.nextLine().trim();
if (serverName.isEmpty()) {
System.out.println("Server name cannot be empty.");
return;
}

Map<String, Object> serverAttrs = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : resolved.entrySet()) {
String key = entry.getKey();
if (ServerDescriptorUtil.TYPE_ID_KEY.equals(key)
|| "id".equals(key)
|| ServerDescriptorUtil.FORMAT_VERSION_KEY.equals(key)) {
continue;
}
Object val = entry.getValue();
if (val instanceof Boolean || val instanceof Number) {
serverAttrs.put(key, String.valueOf(val));
} else {
serverAttrs.put(key, val);
}
}

ServerAttributes csa = new ServerAttributes(serverTypeId, serverName, serverAttrs);
CreateServerResponse result = launcher.getServerProxy().createServer(csa).get();
if (result.getStatus().isOK()) {
System.out.println("Server \"" + serverName + "\" created from descriptor.");
} else {
System.out.println("Error creating server: " + result.getStatus().getMessage());
}
}
},

LIST_DEPLOYMENTS("list deployments") {
@Override
public void execute(String command, ServerManagementClientLauncher launcher, PromptAssistant assistant) {
Expand Down
Loading