Skip to content

Commit

Permalink
Merge branch 'OpenLiberty:main' into ca_add_variable
Browse files Browse the repository at this point in the history
  • Loading branch information
arunvenmany-ibm authored Feb 11, 2025
2 parents 6b64abe + 050c719 commit 35c7595
Show file tree
Hide file tree
Showing 19 changed files with 484 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import java.util.Set;
import java.util.logging.Logger;

import io.openliberty.tools.langserver.lemminx.data.LibertyRuntime;
import io.openliberty.tools.langserver.lemminx.services.SettingsService;
import io.openliberty.tools.langserver.lemminx.util.LibertyUtils;
import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.commons.CodeActionFactory;
import org.eclipse.lemminx.commons.TextDocument;
Expand Down Expand Up @@ -63,7 +66,10 @@ public void doCodeAction(ICodeActionRequest request, List<CodeAction> codeAction
Diagnostic diagnostic = request.getDiagnostic();
DOMDocument document = request.getDocument();
TextDocument textDocument = document.getTextDocument();

LibertyRuntime runtimeInfo = LibertyUtils.getLibertyRuntimeInfo(document);
String libertyVersion = runtimeInfo == null ? null : runtimeInfo.getRuntimeVersion();
String libertyRuntime = runtimeInfo == null ? null : runtimeInfo.getRuntimeType();
final int requestDelay = SettingsService.getInstance().getRequestDelay();
LibertyWorkspace ws = LibertyProjectsManager.getInstance().getWorkspaceFolder(document.getDocumentURI());
FeatureListGraph featureGraph = null;
if (ws == null) {
Expand All @@ -90,6 +96,12 @@ public void doCodeAction(ICodeActionRequest request, List<CodeAction> codeAction
ArrayList<String> sortedFeatures = new ArrayList<String>();
sortedFeatures.addAll(featureCandidates);
Collections.sort(sortedFeatures);
// get existing platforms from the document
List<String> existingPlatforms = FeatureService.getInstance()
.collectExistingPlatforms(document, "");
// find version less features for all versioned features in the sorted features
Set<String> possibleVersionlessFeatures = FeatureService.getInstance()
.getVersionLessFeaturesForVersioned(sortedFeatures, libertyRuntime, libertyVersion, requestDelay, document.getDocumentURI());

String insertText = "";
int referenceRangeStart = 0;
Expand Down Expand Up @@ -137,6 +149,16 @@ public void doCodeAction(ICodeActionRequest request, List<CodeAction> codeAction
}
insertText = IndentUtil.formatText(insertText, indent, referenceRange.getStart().getCharacter());

// for each versionless features that has at least one matching platform to a specified platform in the document
for (String feature : possibleVersionlessFeatures) {
Set<String> allPlatforms = FeatureService.getInstance().getAllPlatformsForVersionLessFeature(feature, libertyVersion, libertyRuntime, requestDelay, document.getDocumentURI());
if (allPlatforms.stream().anyMatch(existingPlatforms::contains)) {
String title = "Add feature " + feature;
codeActions.add(CodeActionFactory.insert(
title, referenceRange.getEnd(),
String.format(insertText, feature), textDocument, diagnostic));
}
}
for (String feature : sortedFeatures) {
String title = "Add feature " + feature;
codeActions.add(CodeActionFactory.insert(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -755,4 +755,26 @@ public List<String> collectExistingPlatforms(DOMDocument document, String curren
}
return includedPlatforms;
}

/**
* get version less feature list for specified list of versioned features
* @param versionedFeatureNames list of versioned feature names
* @param libertyRuntime librty runtime
* @param libertyVersion runtime version
* @param requestDelay request delay
* @param documentURI server xml document uri
* @return version less feature list
*/
public Set<String> getVersionLessFeaturesForVersioned(List<String> versionedFeatureNames, String libertyRuntime, String libertyVersion,int requestDelay, String documentURI) {
FeaturesAndPlatforms featuresAndPlatforms = getFeaturesAndPlatforms( libertyVersion,libertyRuntime, requestDelay, documentURI);
Set<String> featureNames = featuresAndPlatforms.getPublicFeatures().stream()
.filter(feature -> feature.getWlpInformation() != null)
.map(feature -> feature.getWlpInformation().getShortName().toLowerCase())
.collect(Collectors.toSet());

return versionedFeatureNames.stream()
.map(LibertyUtils::stripVersion)
.filter(feature -> featureNames.contains(feature.toLowerCase()))
.collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,61 @@ public void testConfigElementSameNameAsVersionlessFeatureNoDiagnostics() throws

@Test
public void testConfigElementSameNameAsVersionlessFeatureWithDiagnosticsAndCodeAction() throws BadLocationException {
String configElement = "<mpMetrics authentication=\"false\"></mpMetrics>";
String serverXML = String.join(newLine,
"<server description=\"Sample Liberty server\">",
" <featureManager>",
" <platform>javaee-7.0</platform>",
" </featureManager>",
configElement,
"</server>"
);
Diagnostic diagnostic = new Diagnostic();
diagnostic.setRange(r(4, 0, 4, 46));
diagnostic.setCode(LibertyDiagnosticParticipant.MISSING_CONFIGURED_FEATURE_CODE);
diagnostic.setMessage(LibertyDiagnosticParticipant.MISSING_CONFIGURED_FEATURE_MESSAGE);

XMLAssert.testDiagnosticsFor(serverXML, null, null, sampleserverXMLURI, diagnostic);
diagnostic.setSource("mpMetrics");

List<String> featuresToAdd = new ArrayList<>();
// here javaee-7.0 platform is specified , which is not valid for mpMetrics
// hence versionless feature is not shown
featuresToAdd.add("mpMetrics-1.0");
featuresToAdd.add("mpMetrics-1.1");
featuresToAdd.add("mpMetrics-2.0");
featuresToAdd.add("mpMetrics-2.2");
featuresToAdd.add("mpMetrics-2.3");
featuresToAdd.add("mpMetrics-3.0");
featuresToAdd.add("mpMetrics-4.0");
featuresToAdd.add("mpMetrics-5.0");
featuresToAdd.add("mpMetrics-5.1");

Collections.sort(featuresToAdd);

List<CodeAction> codeActions = new ArrayList<>();
for (String nextFeature: featuresToAdd) {
String addFeature = String.format("%s<feature>%s</feature>",System.lineSeparator(),nextFeature);
TextEdit texted = te(2, 39, 2, 39, addFeature);
CodeAction invalidCodeAction = ca(diagnostic, texted);

TextDocumentEdit textDoc = tde(sampleserverXMLURI, 0, texted);
WorkspaceEdit workspaceEdit = new WorkspaceEdit(Collections.singletonList(Either.forLeft(textDoc)));

invalidCodeAction.setEdit(workspaceEdit);
codeActions.add(invalidCodeAction);
}

// diagnostic with code action expected
XMLAssert.testCodeActionsFor(serverXML, sampleserverXMLURI, diagnostic, (String) null,
codeActions.get(0), codeActions.get(1), codeActions.get(2),
codeActions.get(3), codeActions.get(4), codeActions.get(5),
codeActions.get(6), codeActions.get(7), codeActions.get(8)
);
}

@Test
public void testConfigElementDiagnosticsAndCodeActionWithVersionless() throws BadLocationException {
String configElement = "<mpMetrics authentication=\"false\"></mpMetrics>";
String serverXML = String.join(newLine,
"<server description=\"Sample Liberty server\">",
Expand All @@ -1106,10 +1161,12 @@ public void testConfigElementSameNameAsVersionlessFeatureWithDiagnosticsAndCodeA
diagnostic.setCode(LibertyDiagnosticParticipant.MISSING_CONFIGURED_FEATURE_CODE);
diagnostic.setMessage(LibertyDiagnosticParticipant.MISSING_CONFIGURED_FEATURE_MESSAGE);

XMLAssert.testDiagnosticsFor(serverXML, null, null, sampleserverXMLURI,diagnostic);
XMLAssert.testDiagnosticsFor(serverXML, null, null, sampleserverXMLURI, diagnostic);
diagnostic.setSource("mpMetrics");

List<String> featuresToAdd = new ArrayList<String>();
// show version less feature name since microprofile platform is added
featuresToAdd.add("mpMetrics");
featuresToAdd.add("mpMetrics-1.0");
featuresToAdd.add("mpMetrics-1.1");
featuresToAdd.add("mpMetrics-2.0");
Expand Down Expand Up @@ -1139,7 +1196,7 @@ public void testConfigElementSameNameAsVersionlessFeatureWithDiagnosticsAndCodeA
XMLAssert.testCodeActionsFor(serverXML, sampleserverXMLURI, diagnostic, (String) null,
codeActions.get(0), codeActions.get(1), codeActions.get(2),
codeActions.get(3), codeActions.get(4), codeActions.get(5),
codeActions.get(6), codeActions.get(7), codeActions.get(8)
codeActions.get(6), codeActions.get(7), codeActions.get(8), codeActions.get(9)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*******************************************************************************/
package io.openliberty.tools.langserver.codeactions;

import com.google.gson.JsonPrimitive;
import io.openliberty.tools.langserver.LibertyLanguageServer;
import io.openliberty.tools.langserver.LibertyTextDocumentService;
import io.openliberty.tools.langserver.ls.LibertyTextDocument;
Expand All @@ -32,6 +33,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public abstract class CodeActionQuickfixFactory {

Expand All @@ -46,6 +48,22 @@ protected CodeActionQuickfixFactory(LibertyTextDocumentService libertyTextDocume
/**
* returns list of code actions or commands.
* called from CodeActionParticipant
* 1. In case of quick fix for single value property
* a. show all allowed values in code action
* 2. Multi value property,
* a. If field has multiple values specified
* b. If any of the value is valid, show code action
* "Replace with {validValues}"
* "Replace with {validValues},${nextAllowedValue1}"
* ...
* "Replace with {validValues},${nextAllowedValueN}"
* example, user entered,WLP_LOGGING_CONSOLE_SOURCE=abc,audit,message,kyc
* quickfix should contain something like
* Replace with "audit,message
* Replace with "audit,message,trace"
* Replace with "audit,message,ffdc"
* Replace with "audit,message,auditLog"
*
* @param params code action params
* @return codeaction
*/
Expand All @@ -57,9 +75,19 @@ public List<Either<Command, CodeAction>> apply(CodeActionParams params) {
if (diagnostic.getCode() != null && getErrorCode().equals(diagnostic.getCode().getLeft())) {
String line = new ParserFileHelperUtil().getLine(new LibertyTextDocument(openedDocument), diagnostic.getRange().getStart().getLine());
if (line != null) {
String prefix = getUserEnteredValidValues(diagnostic);
if (!Objects.equals(prefix, "")) {
// add a code action to just replace with valid values
// present in current string
res.add(Either.forRight(createCodeAction(params, diagnostic, prefix)));
// append a comma so that completion will show all values
// for multi value
prefix += ",";
}
// fetch all completion values and shows them as quick fix
// prefix will contain all valid values in current entered string, or else ""
// completion returns empty list if no completion item is present
List<String> possibleProperties = retrieveCompletionValues(openedDocument, diagnostic.getRange().getStart());
List<String> possibleProperties = retrieveCompletionValues(openedDocument, diagnostic.getRange().getStart(), prefix);
for (String mostProbableProperty : possibleProperties) {
// expected format for a code action is <Command,CodeAction>
res.add(Either.forRight(createCodeAction(params, diagnostic, mostProbableProperty)));
Expand All @@ -70,6 +98,26 @@ public List<Either<Command, CodeAction>> apply(CodeActionParams params) {
return res;
}

/**
* get valid values entered by user in the current line
* in case of multi value property, user may have entered some valid and some invalid values
* @param diagnostic
* @return
*/
private static String getUserEnteredValidValues(Diagnostic diagnostic) {
String prefix = "";
// user entered valid values are passed in diagnostic.setData()
if (diagnostic.getData() != null) {
if (diagnostic.getData() instanceof JsonPrimitive) {
prefix = ((JsonPrimitive) diagnostic.getData()).getAsString();
}
if (diagnostic.getData() instanceof String) {
prefix = (String) diagnostic.getData();
}
}
return prefix;
}

/**
* used to create code action object for quickfix
* @param params codeaction params
Expand All @@ -88,7 +136,7 @@ protected CodeAction createCodeAction(CodeActionParams params, Diagnostic diagno
return codeAction;
}

protected abstract List<String> retrieveCompletionValues(TextDocumentItem textDocumentItem, Position position);
protected abstract List<String> retrieveCompletionValues(TextDocumentItem textDocumentItem, Position position, String prefix);

protected abstract String getErrorCode();
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,23 @@ protected String getErrorCode() {

/**
* retrieve list of completion items for a property key
*
* @param textDocumentItem text document
* @param position current position, used to compute key
* @param position current position, used to compute key
* @param prefix prefix value to trigger completion with
* @return list of string of completion item names
*/
@Override
protected List<String> retrieveCompletionValues(TextDocumentItem textDocumentItem,
Position position) {
Position position, String prefix) {
List<String> completionValues = new ArrayList<>();
try {
LibertyTextDocument openedDocument = libertyLanguageServer.getTextDocumentService().getOpenedDocument(textDocumentItem.getUri());
String line = new ParserFileHelperUtil().getLine(openedDocument, position);
PropertiesEntryInstance propertiesEntryInstance = new PropertiesEntryInstance(line, openedDocument);
CompletableFuture<List<CompletionItem>> completions;
// get all completions for current property key
CompletableFuture<List<CompletionItem>> completions = propertiesEntryInstance.getPropertyValueInstance().getCompletions("", position);
completions = propertiesEntryInstance.getPropertyValueInstance().getCompletions(prefix, position);
// map text values from completion items
completionValues = completions.thenApply(completionItems -> completionItems.stream()
.map(it -> it.getTextEdit().getLeft().getNewText())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ private List<Diagnostic> computeInvalidValuesDiagnostic(PropertiesValidationResu
String messageTemplate = DiagnosticMessages.getString(validationResult.getDiagnosticType());

// Currently the last arg (getIntegerRange) is only used for the Integer messages which use {2}. Otherwise null is passed and is ignored by the other messages.
String message = MessageFormat.format(messageTemplate, validationResult.getValue(), property, ServerPropertyValues.getIntegerRange(property));
String message = MessageFormat.format(messageTemplate, validationResult.getCustomValue() != null ? validationResult.getCustomValue() : validationResult.getValue(), property, ServerPropertyValues.getIntegerRange(property));
Diagnostic diagnostic = new Diagnostic(computeRange(validationResult, lineContentInError), message, DiagnosticSeverity.Error, "Liberty Config Language Server");
diagnostic.setCode(ERROR_CODE_INVALID_PROPERTY_VALUE);
diagnostic.setData(validationResult.getMultiValuePrefix());
lspDiagnostics.add(diagnostic);
}
return lspDiagnostics;
Expand Down
Loading

0 comments on commit 35c7595

Please sign in to comment.