Skip to content

Commit c2b9a2a

Browse files
committed
export import settings
1 parent 86ebf70 commit c2b9a2a

File tree

4 files changed

+164
-123
lines changed

4 files changed

+164
-123
lines changed

ide-common/src/main/java/org/digma/intellij/plugin/settings/ProjectSettings.java

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -93,61 +93,7 @@ public void apply() throws ConfigurationException {
9393
//run all checks and only then update the settings.
9494
//never update the settings before checks are complete because then the settings will have incorrect data
9595

96-
try {
97-
Objects.requireNonNull(mySettingsComponent.getApiUrl(), "Api url can not be null");
98-
Objects.requireNonNull(mySettingsComponent.getRuntimeObservabilityBackendUrl(), "Runtime observability url can not be null");
99-
} catch (Exception e) {
100-
throw new ConfigurationException(e.getMessage());
101-
}
102-
103-
if (mySettingsComponent.getApiUrl().isBlank()) {
104-
throw new ConfigurationException("Api url can not be empty");
105-
}
106-
if (!CommonUtils.isHttpsUrl(mySettingsComponent.getApiUrl())) {
107-
throw new ConfigurationException("Api url schema must be https");
108-
}
109-
try {
110-
URLValidator.create(mySettingsComponent.getApiUrl()).validate();
111-
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
112-
URLValidator.IncorrectSchemaException e) {
113-
throw new ConfigurationException("Api url is not a well formed: " + e.getMessage());
114-
}
115-
116-
if (mySettingsComponent.getRuntimeObservabilityBackendUrl().isBlank()) {
117-
throw new ConfigurationException("Runtime observability url can not be empty");
118-
}
119-
try {
120-
URLValidator.create(mySettingsComponent.getRuntimeObservabilityBackendUrl()).validate();
121-
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
122-
URLValidator.IncorrectSchemaException e) {
123-
throw new ConfigurationException("Backend observability url is not a well formed: " + e.getMessage());
124-
}
125-
126-
127-
if (mySettingsComponent.getJaegerLinkMode() == JaegerLinkMode.Embedded) {
128-
if (mySettingsComponent.getJaegerQueryUrl() == null || mySettingsComponent.getJaegerQueryUrl().trim().isBlank()) {
129-
throw new ConfigurationException("Jaeger query url can not be empty in mode " + mySettingsComponent.getJaegerLinkMode());
130-
}
131-
try {
132-
URLValidator.create(mySettingsComponent.getJaegerQueryUrl()).validate();
133-
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
134-
URLValidator.IncorrectSchemaException e) {
135-
throw new ConfigurationException("Jaeger query url is not a well formed: " + e.getMessage());
136-
}
137-
} else {
138-
if (mySettingsComponent.getJaegerUrl() == null || mySettingsComponent.getJaegerUrl().trim().isBlank()) {
139-
throw new ConfigurationException("Jaeger url can not be empty in mode " + mySettingsComponent.getJaegerLinkMode());
140-
}
141-
try {
142-
if (mySettingsComponent.getJaegerUrl() != null) {
143-
URLValidator.create(mySettingsComponent.getJaegerUrl()).validate();
144-
}
145-
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
146-
URLValidator.IncorrectSchemaException e) {
147-
throw new ConfigurationException("Jaeger url is not a well formed: " + e.getMessage());
148-
}
149-
}
150-
96+
SettingsUtils.validateSettings(mySettingsComponent);
15197

15298
updateSettingsAndFireChange();
15399

ide-common/src/main/java/org/digma/intellij/plugin/settings/SettingsComponent.java

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.intellij.icons.AllIcons;
44
import com.intellij.openapi.fileChooser.*;
5+
import com.intellij.openapi.options.ConfigurationException;
56
import com.intellij.openapi.project.Project;
67
import com.intellij.openapi.ui.*;
78
import com.intellij.ui.*;
@@ -11,6 +12,7 @@
1112
import org.digma.intellij.plugin.analytics.BackendInfoHolder;
1213
import org.digma.intellij.plugin.auth.account.*;
1314
import org.digma.intellij.plugin.common.*;
15+
import org.digma.intellij.plugin.errorreporting.ErrorReporter;
1416
import org.jetbrains.annotations.*;
1517

1618
import javax.swing.*;
@@ -386,33 +388,45 @@ private static JBLabel createBackendVersionLabel() {
386388
private JPanel createImportExportPanel() {
387389
//noinspection ExtractMethodRecommender
388390
var exportSettingsButton = new JButton("Export Settings");
389-
exportSettingsButton.addActionListener(e -> {
391+
exportSettingsButton.addActionListener(actionEvent -> {
392+
try {
390393

391-
Messages.showInfoMessage("I Will export the saved settings, Not necessarily what is now showing. to export the shown values please first save and reopen settings to export.", "Export");
394+
SettingsUtils.validateSettings(this);
392395

393-
var dialog = FileChooserFactory.getInstance().createSaveFileDialog(new FileSaverDescriptor("Export To File", "Export settings to file", "conf"), (Project) null);
394-
var file = dialog.save("digma-setting.conf");
395-
if (file != null) {
396-
var exportResult = SettingsUtils.exportSettingsToFile(file.getFile());
397-
if (!exportResult) {
398-
Messages.showErrorDialog("Could not export settings,Please check the logs.", "Export Error");
396+
var dialog = FileChooserFactory.getInstance().createSaveFileDialog(new FileSaverDescriptor("Export To File", "Export settings to file", "conf"), (Project) null);
397+
var file = dialog.save("digma-setting.conf");
398+
if (file != null) {
399+
var exportResult = SettingsUtils.exportSettingsToFile(file.getFile(), toProperties());
400+
if (!exportResult) {
401+
Messages.showErrorDialog("Could not export settings,Please check the logs.", "Export Error");
402+
}
399403
}
404+
} catch (ConfigurationException configurationException) {
405+
Messages.showErrorDialog(configurationException.getMessage(), "Invalid Settings");
406+
} catch (Throwable e) {
407+
Messages.showErrorDialog(e.getMessage(), "Error");
408+
ErrorReporter.getInstance().reportError("SettingsComponent.exportSettingsButton.ActionListener", e);
400409
}
401410
});
402411

403412
var importSettingsButton = new JButton("Import Settings");
404-
importSettingsButton.addActionListener(e -> {
405-
var dialog = FileChooserFactory.getInstance().createPathChooser(new FileChooserDescriptor(true, false, false, false, false, false), null, myMainPanel);
406-
dialog.choose(null, virtualFiles -> {
407-
if (virtualFiles.size() == 1) {
408-
var properties = SettingsUtils.importSettingsFromFile(virtualFiles.get(0));
409-
if (properties == null) {
410-
Messages.showErrorDialog("Could not import settings,Please check the logs.", "Import Error");
411-
} else {
412-
resetFromSettings(SettingsState.fromProperties(properties));
413+
importSettingsButton.addActionListener(actionEvent -> {
414+
try {
415+
var dialog = FileChooserFactory.getInstance().createPathChooser(new FileChooserDescriptor(true, false, false, false, false, false), null, myMainPanel);
416+
dialog.choose(null, virtualFiles -> {
417+
if (virtualFiles.size() == 1) {
418+
var properties = SettingsUtils.importSettingsFromFile(virtualFiles.get(0));
419+
if (properties == null) {
420+
Messages.showErrorDialog("Could not import settings,Please check the logs.", "Import Error");
421+
} else {
422+
fromProperties(properties);
423+
}
413424
}
414-
}
415-
});
425+
});
426+
} catch (Throwable e) {
427+
Messages.showErrorDialog(e.getMessage(), "Error");
428+
ErrorReporter.getInstance().reportError("SettingsComponent.importSettingsButton.ActionListener", e);
429+
}
416430
});
417431

418432
var importExportPanel = new JPanel();
@@ -443,4 +457,41 @@ private JButton createResetPluginButton() {
443457
return resetPluginButton;
444458
}
445459

460+
461+
private Map<String, String> toProperties() {
462+
Map<String, String> properties = new HashMap<>();
463+
properties.put("apiUrl", getApiUrl());
464+
if (getApiToken() != null) {
465+
properties.put("apiToken", getApiToken());
466+
}
467+
if (getJaegerUrl() != null) {
468+
properties.put("jaegerUrl", getJaegerUrl());
469+
}
470+
if (getJaegerQueryUrl() != null) {
471+
properties.put("jaegerQueryUrl", getJaegerQueryUrl());
472+
}
473+
properties.put("jaegerLinkMode", getJaegerLinkMode().name());
474+
properties.put("springBootObservabilityMode", getSpringBootObservabilityMode().name());
475+
properties.put("runtimeObservabilityBackendUrl", getRuntimeObservabilityBackendUrl());
476+
if (getExtendedObservability() != null) {
477+
properties.put("extendedObservability", getExtendedObservability());
478+
}
479+
if (getExtendedObservabilityExclude() != null) {
480+
properties.put("extendedObservabilityExcludes", getExtendedObservabilityExclude());
481+
}
482+
return properties;
483+
}
484+
485+
private void fromProperties(Map<String, String> properties) {
486+
setApiUrl(properties.get("apiUrl"));
487+
setApiToken(properties.get("apiToken"));
488+
setJaegerUrl(properties.get("jaegerUrl"));
489+
setJaegerQueryUrl(properties.get("jaegerQueryUrl"));
490+
setJaegerLinkMode(JaegerLinkMode.valueOf(properties.get("jaegerLinkMode")));
491+
setSpringBootObservabilityMode(SpringBootObservabilityMode.valueOf(properties.get("springBootObservabilityMode")));
492+
setRuntimeObservabilityBackendUrl(properties.get("runtimeObservabilityBackendUrl"));
493+
setExtendedObservability(properties.get("extendedObservability"));
494+
setExtendedObservabilityExclude(properties.get("extendedObservabilityExcludes"));
495+
}
496+
446497
}

ide-common/src/main/java/org/digma/intellij/plugin/settings/SettingsState.java

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -205,44 +205,5 @@ public String getNormalizedExtendedObservabilityExcludes() {
205205
return normalizeExtendedObservabilityValue(extendedObservabilityExcludes);
206206
}
207207

208-
209-
public Properties asProperties() {
210-
Properties properties = new Properties();
211-
properties.put("apiUrl", apiUrl);
212-
if (apiToken != null) {
213-
properties.put("apiToken", apiToken);
214-
}
215-
if (jaegerUrl != null) {
216-
properties.put("jaegerUrl", jaegerUrl);
217-
}
218-
if (jaegerQueryUrl != null) {
219-
properties.put("jaegerQueryUrl", jaegerQueryUrl);
220-
}
221-
properties.put("jaegerLinkMode", jaegerLinkMode.name());
222-
properties.put("springBootObservabilityMode", springBootObservabilityMode.name());
223-
properties.put("runtimeObservabilityBackendUrl", runtimeObservabilityBackendUrl);
224-
if (extendedObservability != null) {
225-
properties.put("extendedObservability", extendedObservability);
226-
}
227-
if (extendedObservabilityExcludes != null) {
228-
properties.put("extendedObservabilityExcludes", extendedObservabilityExcludes);
229-
}
230-
return properties;
231-
}
232-
233-
234-
public static SettingsState fromProperties(Properties properties) {
235-
SettingsState settingsState = new SettingsState();
236-
settingsState.apiUrl = (String) properties.get("apiUrl");
237-
settingsState.apiToken = (String) properties.get("apiToken");
238-
settingsState.jaegerUrl = (String) properties.get("jaegerUrl");
239-
settingsState.jaegerQueryUrl = (String) properties.get("jaegerQueryUrl");
240-
settingsState.jaegerLinkMode = JaegerLinkMode.valueOf((String) properties.get("jaegerLinkMode"));
241-
settingsState.springBootObservabilityMode = SpringBootObservabilityMode.valueOf((String) properties.get("springBootObservabilityMode"));
242-
settingsState.runtimeObservabilityBackendUrl = (String) properties.get("runtimeObservabilityBackendUrl");
243-
settingsState.extendedObservability = (String) properties.get("extendedObservability");
244-
settingsState.extendedObservabilityExcludes = (String) properties.get("extendedObservabilityExcludes");
245-
return settingsState;
246-
}
247208
}
248209

ide-common/src/main/java/org/digma/intellij/plugin/settings/SettingsUtils.java

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,83 @@
11
package org.digma.intellij.plugin.settings;
22

33
import com.intellij.openapi.diagnostic.Logger;
4+
import com.intellij.openapi.options.ConfigurationException;
45
import com.intellij.openapi.vfs.VirtualFile;
6+
import org.digma.intellij.plugin.common.*;
57
import org.digma.intellij.plugin.errorreporting.ErrorReporter;
68
import org.digma.intellij.plugin.log.Log;
79
import org.jetbrains.annotations.*;
810

9-
import java.io.*;
11+
import java.io.File;
12+
import java.net.*;
13+
import java.nio.file.Files;
1014
import java.util.*;
1115

16+
import static java.nio.file.StandardOpenOption.*;
17+
1218
public class SettingsUtils {
1319

1420
private static final Logger LOGGER = Logger.getInstance(SettingsUtils.class);
1521

22+
23+
static void validateSettings(SettingsComponent settingsComponent) throws ConfigurationException {
24+
try {
25+
Objects.requireNonNull(settingsComponent.getApiUrl(), "Api url can not be null");
26+
Objects.requireNonNull(settingsComponent.getRuntimeObservabilityBackendUrl(), "Runtime observability url can not be null");
27+
} catch (Exception e) {
28+
throw new ConfigurationException(e.getMessage());
29+
}
30+
31+
if (settingsComponent.getApiUrl().isBlank()) {
32+
throw new ConfigurationException("Api url can not be empty");
33+
}
34+
if (!CommonUtils.isHttpsUrl(settingsComponent.getApiUrl())) {
35+
throw new ConfigurationException("Api url schema must be https");
36+
}
37+
try {
38+
URLValidator.create(settingsComponent.getApiUrl()).validate();
39+
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
40+
URLValidator.IncorrectSchemaException e) {
41+
throw new ConfigurationException("Api url is not a well formed: " + e.getMessage());
42+
}
43+
44+
if (settingsComponent.getRuntimeObservabilityBackendUrl().isBlank()) {
45+
throw new ConfigurationException("Runtime observability url can not be empty");
46+
}
47+
try {
48+
URLValidator.create(settingsComponent.getRuntimeObservabilityBackendUrl()).validate();
49+
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
50+
URLValidator.IncorrectSchemaException e) {
51+
throw new ConfigurationException("Backend observability url is not a well formed: " + e.getMessage());
52+
}
53+
54+
55+
if (settingsComponent.getJaegerLinkMode() == JaegerLinkMode.Embedded) {
56+
if (settingsComponent.getJaegerQueryUrl() == null || settingsComponent.getJaegerQueryUrl().trim().isBlank()) {
57+
throw new ConfigurationException("Jaeger query url can not be empty in mode " + settingsComponent.getJaegerLinkMode());
58+
}
59+
try {
60+
URLValidator.create(settingsComponent.getJaegerQueryUrl()).validate();
61+
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
62+
URLValidator.IncorrectSchemaException e) {
63+
throw new ConfigurationException("Jaeger query url is not a well formed: " + e.getMessage());
64+
}
65+
} else {
66+
if (settingsComponent.getJaegerUrl() == null || settingsComponent.getJaegerUrl().trim().isBlank()) {
67+
throw new ConfigurationException("Jaeger url can not be empty in mode " + settingsComponent.getJaegerLinkMode());
68+
}
69+
try {
70+
if (settingsComponent.getJaegerUrl() != null) {
71+
URLValidator.create(settingsComponent.getJaegerUrl()).validate();
72+
}
73+
} catch (MalformedURLException | URISyntaxException | URLValidator.InvalidUrlException | URLValidator.QueryNotAllowedException |
74+
URLValidator.IncorrectSchemaException e) {
75+
throw new ConfigurationException("Jaeger url is not a well formed: " + e.getMessage());
76+
}
77+
}
78+
}
79+
80+
1681
public static boolean isSettingsPointsToRemoteIp() {
1782

1883
//todo: real IP check of the url, can be mapped in hosts file,for example cam map mymachine to localhost
@@ -37,10 +102,13 @@ public static boolean isSettingsPointsToRemoteIp() {
37102
}
38103

39104

40-
public static boolean exportSettingsToFile(@NotNull File file) {
41-
try (OutputStream out = new FileOutputStream(file)) {
42-
var properties = SettingsState.getInstance().asProperties();
43-
properties.store(out, "Digma Plugin settings");
105+
public static boolean exportSettingsToFile(@NotNull File file, @NotNull Map<String, String> properties) {
106+
try {
107+
//using new ArrayList because the steam may return immutable list
108+
var lines = new ArrayList<String>();
109+
lines.add("## Digma plugin settings " + new Date());
110+
lines.addAll(properties.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toList());
111+
Files.write(file.toPath(), lines, CREATE, TRUNCATE_EXISTING, WRITE);
44112
return true;
45113
} catch (Throwable e) {
46114
Log.warnWithException(LOGGER, e, "error exporting settings {}", e);
@@ -51,15 +119,30 @@ public static boolean exportSettingsToFile(@NotNull File file) {
51119

52120

53121
@Nullable
54-
public static Properties importSettingsFromFile(@NotNull VirtualFile virtualFile) {
55-
try (InputStream in = new FileInputStream(virtualFile.toNioPath().toFile())) {
56-
Properties properties = new Properties();
57-
properties.load(in);
122+
public static Map<String, String> importSettingsFromFile(@NotNull VirtualFile virtualFile) {
123+
try {
124+
//using new ArrayList because Files.readAllLines may return immutable list
125+
var lines = new ArrayList<>(Files.readAllLines(virtualFile.toNioPath()));
126+
if (lines.isEmpty()) {
127+
return null;
128+
}
129+
130+
if (lines.get(0).contains("Digma plugin settings")) {
131+
lines.remove(0);
132+
}
133+
var properties = new HashMap<String, String>();
134+
lines.forEach(line -> {
135+
var entry = line.split("=", 2);
136+
if (entry.length == 2) {
137+
properties.put(entry[0], entry[1]);
138+
}
139+
});
58140
return properties;
59-
} catch (IOException e) {
141+
} catch (Throwable e) {
60142
Log.warnWithException(LOGGER, e, "error importing settings {}", e);
61143
ErrorReporter.getInstance().reportError("SettingsUtils.importSettingsFromFile", e);
62144
}
145+
63146
return null;
64147
}
65148
}

0 commit comments

Comments
 (0)