diff --git a/SECURITY.md b/SECURITY.md index 3cdd26d5f9fb..af9267f4c48b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,3 +1,9 @@ +--- +layout: ballerina-inner-page +title: Reporting a Security Vulnerability +permalink: /security/ +--- + # Security Policy Ballerina project maintainers take security issues very seriously and all the vulnerability reports are treated with the highest priority and confidentiality. @@ -7,29 +13,32 @@ Ballerina project maintainers take security issues very seriously and all the vu ## Reporting a vulnerability -Ensure you are using the latest Ballerina version before you test a security issue, run an automated security scan or perform a penetration test. +Ensure you are using the latest Ballerina version before you run an automated security scan or perform a penetration test against it. -If you have any concerns regarding the security aspects of the source code or any other resource in this repo or have uncovered a security vulnerability, we strongly encourage you to report that to our private and highly confidential security mailing list: **[security@ballerina.io](mailto:security@ballerina.io)** first using the below key without disclosing them in any forums, sites, or other groups - public or private. +Based on the ethics of responsible disclosure, you must only use the **[security@ballerina.io](mailto:security@ballerina.io)** mailing list to report security vulnerabilities and any other concerns regarding the security aspects of the source code or any other resource in this repo. -security@ballerina.io: 0168 DA26 2989 0DB9 4ACD 8367 E683 061E 2F85 C381 [pgp.mit.edu](https://pgp.surfnet.nl/pks/lookup?op=vindex&fingerprint=on&search=0xE683061E2F85C381) +**WARNING:** To protect the end-user security, please do not use any other medium to report security vulnerabilities. Also, kindly refrain from disclosing the vulnerability details you come across with other individuals, in any forums, sites, or other groups - public or private before it’s mitigation actions and disclosure process are completed. -We will keep you informed of the progress towards a fix and disclosure of the vulnerability if reported issue is identified as a true positive. To protect the end-user security, these issues could be disclosed in other places only after it’s mitigation actions and disclosure process are completed. +Use the following key to send secure messages to security@ballerina.io: -**Warning:** Please do not create GitHub issues for security vulnerabilities. Further, kindly refrain from sharing the vulnerability details you come across with other individuals. +> security@ballerina.io: 0168 DA26 2989 0DB9 4ACD 8367 E683 061E 2F85 C381 [pgp.mit.edu](https://pgp.surfnet.nl/pks/lookup?op=vindex&fingerprint=on&search=0xE683061E2F85C381) Also, use the following template when reporting vulnerabilities so that it contains all the required information and helps expedite the analysis and mitigation process. -- Vulnerable Ballerina artifacts(s) and version(s) +- Vulnerable Ballerina artifact(s) and version(s) - Overview: High-level overview of the issue and self-assessed severity - Description: Include the steps to reproduce - Impact: Self-assessed impact - Solution: Any proposed solution +We will keep you informed of the progress towards a fix and disclosure of the vulnerability if the reported issue is identified as a true positive. + ## Handling a vulnerability The below is an overview of the vulnerability handling process. -1. The user privately reports the vulnerability to security@ballerina.io. (The initial response time will be less than 24 hours). -2. The WSO2 security team works privately with the user to fix the vulnerability and QA verifies the solution. -3. Apply the fix to the master branch and release a new version of the distribution if required. +1. The vulnerability will be reported privately to security@ballerina.io. (The initial response time will be less than 24 hours). +2. The reported vulnerability gets fixed and the solution gets verified by the relevant teams at WSO2. +3. The fix gets applied to the master branch and a new version of the distribution gets released if required. 4. The reported user is kept updated on the progress of the process. + diff --git a/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/MapUtils.java b/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/MapUtils.java index 658b0bcca1bb..414788ca99d0 100644 --- a/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/MapUtils.java +++ b/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/MapUtils.java @@ -26,6 +26,7 @@ import org.ballerinalang.jvm.util.exceptions.RuntimeErrors; import org.ballerinalang.jvm.values.ErrorValue; import org.ballerinalang.jvm.values.MapValue; +import org.ballerinalang.jvm.values.StringValue; import static java.lang.String.format; import static org.ballerinalang.jvm.util.BLangConstants.MAP_LANG_LIB; @@ -41,6 +42,56 @@ */ public class MapUtils { + public static void handleMapStore(MapValue mapValue, StringValue fieldName, Object value) { + BType mapType = mapValue.getType(); + switch (mapType.getTag()) { + case TypeTags.MAP_TAG: + if (!TypeChecker.checkIsType(value, ((BMapType) mapType).getConstrainedType())) { + BType expType = ((BMapType) mapType).getConstrainedType(); + BType valuesType = TypeChecker.getType(value); + throw BallerinaErrors.createError(getModulePrefixedReason(MAP_LANG_LIB, + INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), + BLangExceptionHelper.getErrorMessage(RuntimeErrors.INVALID_MAP_INSERTION, expType, + valuesType)); + } + mapValue.put(fieldName, value); + break; + case TypeTags.RECORD_TYPE_TAG: + BRecordType recType = (BRecordType) mapType; + //TODO: bstring - remove getValue + BField recField = recType.getFields().get(fieldName.getValue()); + BType recFieldType; + + if (recField != null) { + // If there is a corresponding field in the record, use it + recFieldType = recField.type; + } else if (recType.restFieldType != null) { + // If there isn't a corresponding field, but there is a rest field, use it + recFieldType = recType.restFieldType; + } else { + // If both of the above conditions fail, the implication is that this is an attempt to insert a + // value to a non-existent field in a closed record. + throw BallerinaErrors.createError(MAP_KEY_NOT_FOUND_ERROR, + //TODO: bstring - remove getValue after migrating error value + BLangExceptionHelper.getErrorMessage(RuntimeErrors.INVALID_RECORD_FIELD_ACCESS, + fieldName.getValue(), recType)); + } + + if (!TypeChecker.checkIsType(value, recFieldType)) { + BType valuesType = TypeChecker.getType(value); + throw BallerinaErrors.createError(getModulePrefixedReason(MAP_LANG_LIB, + INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), + //TODO: bstring - remove getValue after migrating error value + BLangExceptionHelper.getErrorMessage(RuntimeErrors.INVALID_RECORD_FIELD_ADDITION, + fieldName.getValue(), recFieldType, valuesType)); + } + + mapValue.put(fieldName, value); + break; + } + } + + @Deprecated public static void handleMapStore(MapValue mapValue, String fieldName, Object value) { BType mapType = mapValue.getType(); switch (mapType.getTag()) { diff --git a/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/values/BmpStringValue.java b/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/values/BmpStringValue.java index 1085b2ac8575..0a937a8eb612 100644 --- a/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/values/BmpStringValue.java +++ b/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/values/BmpStringValue.java @@ -58,4 +58,9 @@ public StringValue concat(StringValue str) { public String stringValue() { return value; } + + @Override + public int hashCode() { + return value.hashCode(); + } } diff --git a/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/values/NonBmpStringValue.java b/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/values/NonBmpStringValue.java index 0b1bbf96bc65..8848f7a2da21 100644 --- a/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/values/NonBmpStringValue.java +++ b/bvm/ballerina-runtime/src/main/java/org/ballerinalang/jvm/values/NonBmpStringValue.java @@ -80,4 +80,9 @@ public StringValue concat(StringValue str) { public String stringValue() { return value; } + + @Override + public int hashCode() { + return value.hashCode(); + } } diff --git a/cli/ballerina-packerina/build.gradle b/cli/ballerina-packerina/build.gradle index d0fc56839d08..5e92a30330c3 100644 --- a/cli/ballerina-packerina/build.gradle +++ b/cli/ballerina-packerina/build.gradle @@ -44,6 +44,8 @@ dependencies { implementation project(':docerina') implementation 'com.moandjiezana.toml:toml4j' implementation 'info.picocli:picocli' + implementation 'org.apache.commons:commons-compress:1.18' + testCompile 'org.testng:testng' testCompile 'com.moandjiezana.toml:toml4j' diff --git a/cli/ballerina-packerina/src/main/java/org/ballerinalang/packerina/task/CreateExecutableTask.java b/cli/ballerina-packerina/src/main/java/org/ballerinalang/packerina/task/CreateExecutableTask.java index f1a0bbae3eb6..5a6597b89219 100644 --- a/cli/ballerina-packerina/src/main/java/org/ballerinalang/packerina/task/CreateExecutableTask.java +++ b/cli/ballerina-packerina/src/main/java/org/ballerinalang/packerina/task/CreateExecutableTask.java @@ -18,6 +18,10 @@ package org.ballerinalang.packerina.task; +import org.apache.commons.compress.archivers.jar.JarArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntryPredicate; +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; +import org.apache.commons.compress.archivers.zip.ZipFile; import org.ballerinalang.packerina.buildcontext.BuildContext; import org.ballerinalang.packerina.buildcontext.BuildContextField; import org.ballerinalang.packerina.buildcontext.sourcecontext.SingleFileContext; @@ -25,21 +29,16 @@ import org.wso2.ballerinalang.compiler.tree.BLangPackage; import org.wso2.ballerinalang.util.Lists; -import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Optional; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; import static org.ballerinalang.tool.LauncherUtils.createLauncherException; @@ -47,29 +46,15 @@ * Task for creating the executable jar file. */ public class CreateExecutableTask implements Task { - - private static HashSet excludeExtensions = new HashSet<>(Lists.of("DSA", "SF")); - private static Field namesField; - static { - try { - // We need to access the already inserted names set to override the default behavior of throwing exception. - namesField = ZipOutputStream.class.getDeclaredField("names"); - AccessController.doPrivileged((PrivilegedAction) () -> { - namesField.setAccessible(true); - return null; - }); - } catch (NoSuchFieldException e) { - throw createLauncherException("unable to retrive the entry names field :" + e.getMessage()); - } - } + private static HashSet excludeExtensions = new HashSet<>(Lists.of("DSA", "SF")); @Override public void execute(BuildContext buildContext) { Optional modulesWithEntryPoints = buildContext.getModules().stream() .filter(m -> m.symbol.entryPointExists) .findAny(); - + if (modulesWithEntryPoints.isPresent()) { buildContext.out().println(); buildContext.out().println("Generating executables"); @@ -77,16 +62,10 @@ public void execute(BuildContext buildContext) { if (module.symbol.entryPointExists) { Path executablePath = buildContext.getExecutablePathFromTarget(module.packageID); Path jarFromCachePath = buildContext.getJarPathFromTargetCache(module.packageID); - /* - TODO: We earlier used ZipFileSystem but we cannot explicitly set the compression method in - java8 with ZipFileSystem. Once we moved to java11 we can revert back to ZipFileSystem then we can - get rid of with accessing names field as well. - */ - try (ZipOutputStream outStream = - new ZipOutputStream(new FileOutputStream(String.valueOf(executablePath)))) { + try (ZipArchiveOutputStream outStream = new ZipArchiveOutputStream(new BufferedOutputStream( + new FileOutputStream(String.valueOf(executablePath))))) { assembleExecutable(jarFromCachePath, - buildContext.moduleDependencyPathMap.get(module.packageID).platformLibs, - outStream); + buildContext.moduleDependencyPathMap.get(module.packageID).platformLibs, outStream); } catch (IOException e) { throw createLauncherException("unable to extract the uber jar :" + e.getMessage()); } @@ -100,7 +79,7 @@ public void execute(BuildContext buildContext) { case SINGLE_MODULE: SingleModuleContext singleModuleContext = buildContext.get(BuildContextField.SOURCE_CONTEXT); throw createLauncherException("no entry points found in '" + singleModuleContext.getModuleName() + - "'.\n" + + "'.\n" + "Use `ballerina build -c` to compile the module without building executables."); case ALL_MODULES: throw createLauncherException("no entry points found in any of the modules.\n" + @@ -111,62 +90,62 @@ public void execute(BuildContext buildContext) { } } - private void assembleExecutable(Path jarFromCachePath, HashSet dependencySet, ZipOutputStream outStream) { + private void assembleExecutable(Path jarFromCachePath, HashSet dependencySet, + ZipArchiveOutputStream outStream) { try { - HashSet entries = (HashSet) namesField.get(outStream); - HashMap services = new HashMap<>(); - copyJarToJar(outStream, jarFromCachePath.toString(), entries, services); + // Used to prevent adding duplicated entries during the final jar creation. + HashSet entries = new HashSet<>(); + // Used to process SPI related metadata entries separately. The reason is unlike the other entry types, + // service loader related information should be merged together in the final executable jar creation. + HashMap serviceEntries = new HashMap<>(); + // Copy executable thin jar and the dependency jars. + // Executable is created at given location. + // If no entry point is found, we do nothing. + copyJarToJar(outStream, jarFromCachePath.toString(), entries, serviceEntries); for (Path path : dependencySet) { - copyJarToJar(outStream, path.toString(), entries, services); + copyJarToJar(outStream, path.toString(), entries, serviceEntries); } - // Copy merged spi services - for (Map.Entry entry : services.entrySet()) { + // Copy merged spi services. + for (Map.Entry entry : serviceEntries.entrySet()) { String s = entry.getKey(); StringBuilder service = entry.getValue(); - ZipEntry e = new ZipEntry(s); - outStream.putNextEntry(e); + JarArchiveEntry e = new JarArchiveEntry(s); + outStream.putArchiveEntry(e); outStream.write(service.toString().getBytes(StandardCharsets.UTF_8)); - outStream.closeEntry(); + outStream.closeArchiveEntry(); } - // Copy dependency jar - // Copy dependency libraries - // Executable is created at give location. - // If no entry point is found we do nothing. - } catch (IOException | NullPointerException | IllegalAccessException e) { + } catch (IOException | NullPointerException e) { throw createLauncherException("unable to create the executable: " + e.getMessage()); } } /** - * Copy jar file to executable fat jar. + * Copies a given jar file into the executable fat jar. * - * @param outStream Executable jar out stream - * @param sourceJarFile Source file - * @param entries Entries set wiil be used ignore duplicate files + * @param outStream Output stream of the final uber jar. + * @param sourceJarFile Path of the source jar file. + * @param entries Entries set will be used to ignore duplicate files. * @param services Services will be used to temporary hold merged spi files. - * @throws IOException If file copy failed ioexception will be thrown + * @throws IOException If jar file copying is failed. */ - private void copyJarToJar(ZipOutputStream outStream, String sourceJarFile, HashSet entries, + private void copyJarToJar(ZipArchiveOutputStream outStream, String sourceJarFile, HashSet entries, HashMap services) throws IOException { - byte[] buffer = new byte[1024]; - int len; - try (ZipInputStream inStream = new ZipInputStream(new FileInputStream(sourceJarFile))) { - for (ZipEntry e; (e = inStream.getNextEntry()) != null; ) { - String entryName = e.getName(); - // Skip already copied files or excluded extensions. - if (e.isDirectory() || entries.contains(entryName) || - excludeExtensions.contains(entryName.substring(entryName.lastIndexOf(".") + 1))) { - continue; + ZipFile zipFile = new ZipFile(sourceJarFile); + ZipArchiveEntryPredicate predicate = entry -> { + + String entryName = entry.getName(); + if (entryName.startsWith("META-INF/services")) { + StringBuilder s = services.get(entryName); + if (s == null) { + s = new StringBuilder(); + services.put(entryName, s); } - // SPIs will be merged first and then put into jar separately. - if (entryName.startsWith("META-INF/services")) { - StringBuilder s = services.get(entryName); - if (s == null) { - s = new StringBuilder(); - services.put(entryName, s); - } - char c = '\n'; + char c = '\n'; + BufferedInputStream inStream = null; + try { + int len; + inStream = new BufferedInputStream(zipFile.getInputStream(entry)); while ((len = inStream.read()) != -1) { c = (char) len; s.append(c); @@ -174,14 +153,40 @@ private void copyJarToJar(ZipOutputStream outStream, String sourceJarFile, HashS if (c != '\n') { s.append('\n'); } - continue; - } - outStream.putNextEntry(e); - while ((len = inStream.read(buffer)) > 0) { - outStream.write(buffer, 0, len); + } catch (IOException e) { + throw createLauncherException( + "Error occurred while creating final executable jar due to: " + e.getMessage()); + } finally { + if (inStream != null) { + closeStream(inStream); + } } - outStream.closeEntry(); + // Its not required to copy SPI entries in here as we'll be adding merged SPI related entries + // separately. Therefore the predicate should be set as false. + return false; + } + // Skip already copied files or excluded extensions. + if (entries.contains(entryName) || + excludeExtensions.contains(entryName.substring(entryName.lastIndexOf(".") + 1))) { + return false; } + // SPIs will be merged first and then put into jar separately. + entries.add(entryName); + return true; + }; + + // Transfers selected entries from this zip file to the output stream, while preserving its compression and + // all the other original attributes. + zipFile.copyRawEntries(outStream, predicate); + zipFile.close(); + } + + private void closeStream(BufferedInputStream stream) { + try { + stream.close(); + } catch (IOException e) { + throw createLauncherException("error: Failed to close input stream while creating the final " + + "executable jar.\n" + e.getMessage()); } } } diff --git a/compiler/ballerina-backend-jvm-old/src/main/ballerina/src/compiler_backend_jvm/jvm_method_gen.bal b/compiler/ballerina-backend-jvm-old/src/main/ballerina/src/compiler_backend_jvm/jvm_method_gen.bal index 723c3c7f16a2..9b014424f36c 100644 --- a/compiler/ballerina-backend-jvm-old/src/main/ballerina/src/compiler_backend_jvm/jvm_method_gen.bal +++ b/compiler/ballerina-backend-jvm-old/src/main/ballerina/src/compiler_backend_jvm/jvm_method_gen.bal @@ -2538,6 +2538,13 @@ function nameOfBStringFunc(string nonBStringFuncName) returns string { return nonBStringFuncName + "$bstring"; } +function conditionalBStringName(string nonBStringName, boolean useBString) returns string { + if(useBString) { + return nameOfBStringFunc(nonBStringName); + } + return nonBStringName; +} + function nameOfNonBStringFunc(string funcName) returns string { if(isBStringFunc(funcName)) { return funcName.substring(0, funcName.length() - 8); diff --git a/compiler/ballerina-backend-jvm-old/src/main/ballerina/src/compiler_backend_jvm/jvm_value_gen.bal b/compiler/ballerina-backend-jvm-old/src/main/ballerina/src/compiler_backend_jvm/jvm_value_gen.bal index 4392150725c3..950595acae6c 100644 --- a/compiler/ballerina-backend-jvm-old/src/main/ballerina/src/compiler_backend_jvm/jvm_value_gen.bal +++ b/compiler/ballerina-backend-jvm-old/src/main/ballerina/src/compiler_backend_jvm/jvm_value_gen.bal @@ -71,11 +71,12 @@ public type ObjectGenerator object { self.createObjectInit(cw, fields, className); self.createCallMethod(cw, attachedFuncs, className, objectType.name.value, isService); - self.createObjectGetMethod(cw, fields, className); - self.createObjectSetMethod(cw, fields, className, false); if (IS_BSTRING) { + self.createObjectGetMethod(cw, fields, className, true); self.createObjectSetMethod(cw, fields, className, true); } + self.createObjectGetMethod(cw, fields, className, false); + self.createObjectSetMethod(cw, fields, className, false); self.createLambdas(cw); cw.visitEnd(); @@ -227,12 +228,20 @@ public type ObjectGenerator object { mv.visitEnd(); } - private function createObjectGetMethod(jvm:ClassWriter cw, bir:BObjectField?[] fields, string className) { + private function createObjectGetMethod(jvm:ClassWriter cw, bir:BObjectField?[] fields, string className, + boolean useBString) { jvm:MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", - io:sprintf("(L%s;)L%s;", STRING_VALUE, OBJECT), (), ()); + io:sprintf("(L%s;)L%s;", useBString ? I_STRING_VALUE : STRING_VALUE, OBJECT), (), ()); mv.visitCode(); int fieldNameRegIndex = 1; + if(useBString) { + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEINTERFACE, I_STRING_VALUE, "getValue", io:sprintf("()L%s;", STRING_VALUE) , true); + fieldNameRegIndex = 2; + mv.visitVarInsn(ASTORE, fieldNameRegIndex); + } + jvm:Label defaultCaseLabel = new jvm:Label(); // sort the fields before generating switch case @@ -250,7 +259,8 @@ public type ObjectGenerator object { jvm:Label targetLabel = targetLabels[i]; mv.visitLabel(targetLabel); mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, className, field.name.value, getTypeDesc(field.typeValue)); + mv.visitFieldInsn(GETFIELD, className, conditionalBStringName(field.name.value, useBString), + getTypeDesc(field.typeValue, useBString)); addBoxInsn(mv, field.typeValue); mv.visitInsn(ARETURN); i += 1; @@ -434,7 +444,12 @@ public type ObjectGenerator object { private function createRecordFields(jvm:ClassWriter cw, bir:BRecordField?[] fields) { foreach var field in fields { if (field is bir:BRecordField) { - jvm:FieldVisitor fv = cw.visitField(0, field.name.value, getTypeDesc(field.typeValue)); + jvm:FieldVisitor fv; + if(IS_BSTRING) { + fv = cw.visitField(0, nameOfBStringFunc(field.name.value), getTypeDesc(field.typeValue, true)); + fv.visitEnd(); + } + fv = cw.visitField(0, field.name.value, getTypeDesc(field.typeValue)); fv.visitEnd(); if (self.isOptionalRecordField(field)) { diff --git a/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_instruction_gen.bal b/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_instruction_gen.bal index a06190bf3774..a3b8fd00aef1 100644 --- a/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_instruction_gen.bal +++ b/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_instruction_gen.bal @@ -693,8 +693,8 @@ type InstructionGenerator object { io:sprintf("(L%s;L%s;L%s;)V", OBJECT, STRING_VALUE, OBJECT), false); } else { self.mv.visitMethodInsn(INVOKESTATIC, MAP_UTILS, "handleMapStore", - io:sprintf("(L%s;L%s;L%s;)V", MAP_VALUE, STRING_VALUE, OBJECT), - false); + io:sprintf("(L%s;L%s;L%s;)V", + MAP_VALUE, IS_BSTRING ? I_STRING_VALUE : STRING_VALUE, OBJECT), false); } } diff --git a/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_method_gen.bal b/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_method_gen.bal index 90bf31b057c9..81ea6ebcf651 100644 --- a/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_method_gen.bal +++ b/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_method_gen.bal @@ -2538,6 +2538,14 @@ function nameOfBStringFunc(string nonBStringFuncName) returns string { return nonBStringFuncName + "$bstring"; } +function conditionalBStringName(string nonBStringName, boolean useBString) returns string { + if(useBString) { + return nameOfBStringFunc(nonBStringName); + } + return nonBStringName; +} + + function nameOfNonBStringFunc(string funcName) returns string { if(isBStringFunc(funcName)) { return funcName.substring(0, funcName.length() - 8); diff --git a/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_value_gen.bal b/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_value_gen.bal index f4ae2de64641..ad51b6c78e97 100644 --- a/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_value_gen.bal +++ b/compiler/ballerina-backend-jvm/src/main/ballerina/src/compiler_backend_jvm/jvm_value_gen.bal @@ -71,11 +71,12 @@ public type ObjectGenerator object { self.createObjectInit(cw, fields, className); self.createCallMethod(cw, attachedFuncs, className, objectType.name.value, isService); - self.createObjectGetMethod(cw, fields, className); if (IS_BSTRING) { + self.createObjectGetMethod(cw, fields, className, true); self.createObjectSetMethod(cw, fields, className, true); } else { - self.createObjectSetMethod(cw, fields, className, false); + self.createObjectGetMethod(cw, fields, className, false); + self.createObjectSetMethod(cw, fields, className, false); } self.createLambdas(cw); @@ -229,12 +230,20 @@ public type ObjectGenerator object { mv.visitEnd(); } - private function createObjectGetMethod(jvm:ClassWriter cw, bir:BObjectField?[] fields, string className) { + private function createObjectGetMethod(jvm:ClassWriter cw, bir:BObjectField?[] fields, string className, + boolean useBString) { jvm:MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", - io:sprintf("(L%s;)L%s;", STRING_VALUE, OBJECT), (), ()); + io:sprintf("(L%s;)L%s;", useBString ? I_STRING_VALUE : STRING_VALUE, OBJECT), (), ()); mv.visitCode(); int fieldNameRegIndex = 1; + if(useBString) { + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEINTERFACE, I_STRING_VALUE, "getValue", io:sprintf("()L%s;", STRING_VALUE) , true); + fieldNameRegIndex = 2; + mv.visitVarInsn(ASTORE, fieldNameRegIndex); + } + jvm:Label defaultCaseLabel = new jvm:Label(); // sort the fields before generating switch case @@ -252,7 +261,8 @@ public type ObjectGenerator object { jvm:Label targetLabel = targetLabels[i]; mv.visitLabel(targetLabel); mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, className, field.name.value, getTypeDesc(field.typeValue)); + mv.visitFieldInsn(GETFIELD, className, conditionalBStringName(field.name.value, useBString), + getTypeDesc(field.typeValue, useBString)); addBoxInsn(mv, field.typeValue); mv.visitInsn(ARETURN); i += 1; @@ -436,7 +446,12 @@ public type ObjectGenerator object { private function createRecordFields(jvm:ClassWriter cw, bir:BRecordField?[] fields) { foreach var field in fields { if (field is bir:BRecordField) { - jvm:FieldVisitor fv = cw.visitField(0, field.name.value, getTypeDesc(field.typeValue)); + jvm:FieldVisitor fv; + if(IS_BSTRING) { + fv = cw.visitField(0, nameOfBStringFunc(field.name.value), getTypeDesc(field.typeValue, true)); + } else { + fv = cw.visitField(0, field.name.value, getTypeDesc(field.typeValue)); + } fv.visitEnd(); if (self.isOptionalRecordField(field)) { @@ -523,7 +538,10 @@ public type ObjectGenerator object { // cast key to java.lang.String mv.visitVarInsn(ALOAD, fieldNameRegIndex); - mv.visitTypeInsn(CHECKCAST, STRING_VALUE); + mv.visitTypeInsn(CHECKCAST, IS_BSTRING ? I_STRING_VALUE : STRING_VALUE); + if (IS_BSTRING) { + mv.visitMethodInsn(INVOKEINTERFACE, I_STRING_VALUE, "getValue", io:sprintf("()L%s;", STRING_VALUE) , true); + } mv.visitVarInsn(ASTORE, strKeyVarIndex); // sort the fields before generating switch case @@ -545,14 +563,13 @@ public type ObjectGenerator object { // load the existing value to return string fieldName = field.name.value; mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, className, fieldName, getTypeDesc(field.typeValue)); + mv.visitFieldInsn(GETFIELD, className, conditionalBStringName(fieldName, IS_BSTRING), getTypeDesc(field.typeValue, IS_BSTRING)); addBoxInsn(mv, field.typeValue); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, valueRegIndex); - addUnboxInsn(mv, field.typeValue); - mv.visitFieldInsn(PUTFIELD, className, fieldName, getTypeDesc(field.typeValue)); - + addUnboxInsn(mv, field.typeValue, IS_BSTRING); + mv.visitFieldInsn(PUTFIELD, className, conditionalBStringName(fieldName, IS_BSTRING), getTypeDesc(field.typeValue, IS_BSTRING)); // if the field is an optional-field, then also set the isPresent flag of that field to true. if (self.isOptionalRecordField(field)) { mv.visitVarInsn(ALOAD, 0); diff --git a/distribution/zip/jballerina-tools/build.gradle b/distribution/zip/jballerina-tools/build.gradle index 957275eb0166..ad3b3eff36d6 100644 --- a/distribution/zip/jballerina-tools/build.gradle +++ b/distribution/zip/jballerina-tools/build.gradle @@ -76,6 +76,7 @@ dependencies { // dist 'org.ow2.asm:asm:6.2.1' dist 'org.codehaus.woodstox:woodstox-core-asl:4.2.0' dist 'org.codehaus.woodstox:stax2-api:3.1.1' + dist 'org.apache.commons:commons-compress:1.18' // Following dependencies are required for kraal library dist 'org.jetbrains.kotlin:kotlin-stdlib:1.3.31' diff --git a/examples/websocket-retry/websocket_retry.bal b/examples/websocket-retry/websocket_retry.bal new file mode 100644 index 000000000000..39666709ceb3 --- /dev/null +++ b/examples/websocket-retry/websocket_retry.bal @@ -0,0 +1,142 @@ +import ballerina/http; +import ballerina/log; + +final string ASSOCIATED_CONNECTION = "ASSOCIATED_CONNECTION"; + +// The URL of the remote backend. +final string REMOTE_BACKEND = "ws://localhost:9095/retry/ws"; + +@http:WebSocketServiceConfig { + path: "/retry/ws" +} +service RetryProxyService on new http:Listener(9090) { + + // This resource gets invoked when a new client connects. + // Since messages to the server are not read by the service until the execution of the `onOpen` resource finishes, + // operations, which should happen before reading messages should be done in the `onOpen` resource. + resource function onOpen(http:WebSocketCaller caller) { + + // Defines the webSocket client endpoint. + http:WebSocketClient wsClientEp = new( + REMOTE_BACKEND, + {callbackService: RetryClientService, + // When creating client endpoint, if `readyOnConnect` flag is set to + // `false`, client endpoint does not start reading frames automatically. + readyOnConnect: false, + // Retry configuration options. + retryConfig: { + // The number of milliseconds to delay before attempting to reconnect. + intervalInMillis: 3000, + // The maximum number of retry attempts. + // If the count is zero, the client will retry indefinitely. + maxCount: 20, + // The rate of increase of the reconnect delay. + backOffFactor: 2.0, + // Upper limit of the retry interval in milliseconds. If + // `intervalInMillis` into `backOffFactor` value exceeded + // `maxWaitIntervalInMillis` interval value, then + // `maxWaitIntervalInMillis` will be considered as the retry interval. + maxWaitIntervalInMillis: 20000 + } + }); + + //Associate connections before starting to read messages. + wsClientEp.setAttribute(ASSOCIATED_CONNECTION, caller); + caller.setAttribute(ASSOCIATED_CONNECTION, wsClientEp); + + // Once the client is ready to receive frames, the remote function `ready` + // of the client needs to be called separately. + var err = wsClientEp->ready(); + if (err is http:WebSocketError) { + log:printError("Error calling ready on client", err); + } + } + + //This resource gets invoked upon receiving a new text frame from a client. + resource function onText(http:WebSocketCaller caller, string text, + boolean finalFrame) { + + http:WebSocketClient clientEp = + getAssociatedClientEndpoint(caller); + var err = clientEp->pushText(text, finalFrame); + if (err is http:WebSocketError) { + log:printError("Error occurred when sending text message", err); + } + } + + //This resource gets invoked when an error occurs in the connection. + resource function onError(http:WebSocketCaller caller, error err) { + + http:WebSocketClient clientEp = + getAssociatedClientEndpoint(caller); + var e = clientEp->close(statusCode = 1011, reason = "Unexpected condition"); + if (e is http:WebSocketError) { + log:printError("Error occurred when closing the connection", e); + } + _ = caller.removeAttribute(ASSOCIATED_CONNECTION); + log:printError("Unexpected error hence closing the connection", err); + } + + //This resource gets invoked when a client connection is closed from the client side. + resource function onClose(http:WebSocketCaller caller, int statusCode, + string reason) { + + http:WebSocketClient clientEp = getAssociatedClientEndpoint(caller); + var err = clientEp->close(statusCode = statusCode, reason = reason); + if (err is http:WebSocketError) { + log:printError("Error occurred when closing the connection", err); + } + _ = caller.removeAttribute(ASSOCIATED_CONNECTION); + } +} + +//Client service to receive frames from the remote server. +service RetryClientService = @http:WebSocketServiceConfig {} service { + + //This resource gets invoked upon receiving a new text frame from the remote backend. + resource function onText(http:WebSocketClient caller, string text, boolean finalFrame) { + + http:WebSocketCaller serverEp = getAssociatedServerEndpoint(caller); + var err = serverEp->pushText(text, finalFrame); + if (err is http:WebSocketError) { + log:printError("Error occurred when sending text message", err); + } + } + + //This resource gets invoked when an error occurs in the connection. + resource function onError(http:WebSocketClient caller, error err) { + + http:WebSocketCaller serverEp = getAssociatedServerEndpoint(caller); + var e = serverEp->close(statusCode = 1011, reason = "Unexpected condition"); + if (e is http:WebSocketError) { + log:printError("Error occurred when closing the connection", + err = e); + } + _ = caller.removeAttribute(ASSOCIATED_CONNECTION); + log:printError("Unexpected error hense closing the connection", err); + } + + //This resource gets invoked when a client connection is closed by the remote backend. + resource function onClose(http:WebSocketClient caller, int statusCode, + string reason) { + + http:WebSocketCaller serverEp = getAssociatedServerEndpoint(caller); + var err = serverEp->close(statusCode = statusCode, reason = reason); + if (err is http:WebSocketError) { + log:printError("Error occurred when closing the connection", err); + } + _ = caller.removeAttribute(ASSOCIATED_CONNECTION); + } +}; + +// Function to retrieve the associated client of a particular caller. +function getAssociatedClientEndpoint(http:WebSocketCaller ep) returns (http:WebSocketClient) { + http:WebSocketClient wsClient = ep.getAttribute(ASSOCIATED_CONNECTION); + return wsClient; +} + +// Function to retrieve the associated caller of a client. +function getAssociatedServerEndpoint(http:WebSocketClient ep) returns (http:WebSocketCaller) { + http:WebSocketCaller wsEndpoint = ep.getAttribute(ASSOCIATED_CONNECTION); + return wsEndpoint; +} diff --git a/examples/websocket-retry/websocket_retry.description b/examples/websocket-retry/websocket_retry.description new file mode 100644 index 000000000000..aaca647b0f46 --- /dev/null +++ b/examples/websocket-retry/websocket_retry.description @@ -0,0 +1 @@ +//If the WebSocket client lost a connection by the server being shut down or by getting any IOExceptions, Ballerina automatically reconnects to the same backend until the connection becomes successful or until the maximum reconnect attempts count is reached. diff --git a/examples/websocket-retry/websocket_retry.out b/examples/websocket-retry/websocket_retry.out new file mode 100644 index 000000000000..31f1f029ebdc --- /dev/null +++ b/examples/websocket-retry/websocket_retry.out @@ -0,0 +1,25 @@ +# To start the services, navigate to the directory that contains the +# `.bal` files and use the `ballerina run` command. + +$ ballerina run webSocket_service.bal +[ballerina/http] started HTTP/WS listener 0.0.0.0:9095 +$ ballerina run webSocket_retry.bal +[ballerina/http] started HTTP/WS listener 0.0.0.0:9090 + +# Now, this service can be invoked by any WebSocket client using the URL: "ws://localhost:9090/retry/ws". + +# To check the sample, you can use Chrome or Firefox JavaScript console and run the following commands.
+$ var ws = new WebSocket("ws://localhost:9090/retry/ws"); +$ ws.onmessage = function(frame) {console.log(frame.data)}; + +# Send messages. +$ ws.send("hello world"); + +# To stop the running service, press Ctrl + C. +# Restart the service. + +# Send messages. +$ ws.send("hello world"); + +#Close the connection. +$ ws.close(1000, "I want to go"); diff --git a/examples/websocket-retry/websocket_service.bal b/examples/websocket-retry/websocket_service.bal new file mode 100644 index 000000000000..bc149de72c75 --- /dev/null +++ b/examples/websocket-retry/websocket_service.bal @@ -0,0 +1,27 @@ +import ballerina/http; +import ballerina/log; + +// Annotations specifying the webSocket service. +@http:WebSocketServiceConfig { + path: "/retry/ws" +} + +// Define the backend service with port 9095, which is called by the client. +service server on new http:Listener(9095) { + + // This resource gets invoked when a new client connects. + // Since messages to the server are not read by the service until the execution of the `onOpen` resource finishes, + // operations which should happen before reading messages should be done in the `onOpen` resource. + resource function onOpen(http:WebSocketCaller caller) { + log:printInfo("WebSocket client connected wih the server. The Connection ID: " + + caller.getConnectionId()); + } + + // This resource gets invoked when a server is receiving a text message from the client. + resource function onText(http:WebSocketCaller caller, string text, boolean finalFrame) { + var err = caller->pushText(text, finalFrame); + if (err is http:WebSocketError) { + log:printError("Error occurred when sending text message", err); + } + } +} diff --git a/examples/websocket-retry/websocket_service.out b/examples/websocket-retry/websocket_service.out new file mode 100644 index 000000000000..b9de4a748c46 --- /dev/null +++ b/examples/websocket-retry/websocket_service.out @@ -0,0 +1,15 @@ +# To start the service, navigate to the directory that contains the +# `.bal` file, and use the `ballerina run` command. +$ ballerina run webSocket_service.bal + +[ballerina/http] started HTTP/WS listener 0.0.0.0:9095 +2019-11-20 13:31:38,842 INFO [] - WebSocket client connected wih the server. The Connection ID: 08d40cfffe258b13-00000bfd-00000001-a1eade696304c59e-7f64181e + +# To stop the running service, press Ctrl + C. +[ballerina/http] stopped HTTP/WS listener 0.0.0.0:9095 + +# Restart the service. +$ ballerina run webSocket_service.bal + +[ballerina/http] started HTTP/WS listener 0.0.0.0:9095 +2019-11-20 13:34:55,543 INFO [] - WebSocket client connected wih the server. The Connection ID: 08d40cfffe258b13-0000118b-00000001-9bc9b9fb2d07c5b5-8fb73e4f diff --git a/langlib/lang.string/src/main/java/org/ballerinalang/langlib/string/Next.java b/langlib/lang.string/src/main/java/org/ballerinalang/langlib/string/Next.java index 59c5088412ed..058cbe7a9700 100644 --- a/langlib/lang.string/src/main/java/org/ballerinalang/langlib/string/Next.java +++ b/langlib/lang.string/src/main/java/org/ballerinalang/langlib/string/Next.java @@ -19,12 +19,14 @@ package org.ballerinalang.langlib.string; import org.ballerinalang.jvm.BallerinaValues; +import org.ballerinalang.jvm.StringUtils; import org.ballerinalang.jvm.scheduling.Strand; import org.ballerinalang.jvm.types.BFunctionType; import org.ballerinalang.jvm.types.BRecordType; import org.ballerinalang.jvm.types.BUnionType; import org.ballerinalang.jvm.values.MapValueImpl; import org.ballerinalang.jvm.values.ObjectValue; +import org.ballerinalang.jvm.values.api.BString; import org.ballerinalang.model.types.TypeKind; import org.ballerinalang.natives.annotations.BallerinaFunction; import org.ballerinalang.natives.annotations.Receiver; @@ -47,11 +49,15 @@ isPublic = true ) public class Next { + public static final String IS_STRING_VALUE_PROP = "ballerina.bstring"; + public static final boolean USE_BSTRING = System.getProperty(IS_STRING_VALUE_PROP) != null; + //TODO: refactor hard coded values public static Object next(Strand strand, ObjectValue m) { StringCharacterIterator stringCharacterIterator = (StringCharacterIterator) m.getNativeData("&iterator&"); if (stringCharacterIterator == null) { - stringCharacterIterator = new StringCharacterIterator((String) m.get("m")); + String s = USE_BSTRING ? ((BString) m.get(StringUtils.fromString("m"))).getValue() : (String) m.get("m"); + stringCharacterIterator = new StringCharacterIterator(s); m.addNativeData("&iterator&", stringCharacterIterator); } @@ -60,7 +66,9 @@ public static Object next(Strand strand, ObjectValue m) { stringCharacterIterator.next(); BFunctionType nextFuncType = m.getType().getAttachedFunctions()[0].type; BRecordType recordType = (BRecordType) ((BUnionType) nextFuncType.retType).getMemberTypes().get(0); - return BallerinaValues.createRecord(new MapValueImpl<>(recordType), String.valueOf(character)); + Object charAsStr = USE_BSTRING ? StringUtils.fromString(String.valueOf(character)) : + String.valueOf(character); + return BallerinaValues.createRecord(new MapValueImpl<>(recordType), charAsStr); } return null; diff --git a/language-server/modules/langserver-commons/src/main/java/org/ballerinalang/langserver/commons/completion/LSCompletionItem.java b/language-server/modules/langserver-commons/src/main/java/org/ballerinalang/langserver/commons/completion/LSCompletionItem.java new file mode 100644 index 000000000000..ff965965e9e9 --- /dev/null +++ b/language-server/modules/langserver-commons/src/main/java/org/ballerinalang/langserver/commons/completion/LSCompletionItem.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.langserver.commons.completion; + +import org.eclipse.lsp4j.CompletionItem; + +/** + * Wrapper interface for a Completion item. + * + * @since 1.2.0 + */ +public interface LSCompletionItem { + CompletionItem getCompletionItem(); +} diff --git a/language-server/modules/langserver-commons/src/main/java/org/ballerinalang/langserver/commons/completion/spi/LSCompletionProvider.java b/language-server/modules/langserver-commons/src/main/java/org/ballerinalang/langserver/commons/completion/spi/LSCompletionProvider.java index b105c4185cbe..e1180446d1f2 100644 --- a/language-server/modules/langserver-commons/src/main/java/org/ballerinalang/langserver/commons/completion/spi/LSCompletionProvider.java +++ b/language-server/modules/langserver-commons/src/main/java/org/ballerinalang/langserver/commons/completion/spi/LSCompletionProvider.java @@ -19,7 +19,7 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.LSCompletionException; -import org.eclipse.lsp4j.CompletionItem; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import java.util.List; import java.util.Optional; @@ -48,7 +48,7 @@ enum Precedence { * @return {@link List} List of calculated Completion Items * @throws LSCompletionException when completion fails */ - List getCompletions(LSContext context) throws LSCompletionException; + List getCompletions(LSContext context) throws LSCompletionException; /** * Get the attachment points where the current provider attached to. diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/BallerinaTextDocumentService.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/BallerinaTextDocumentService.java index 9a298e03c51f..71a24364a2d4 100755 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/BallerinaTextDocumentService.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/BallerinaTextDocumentService.java @@ -39,7 +39,6 @@ import org.ballerinalang.langserver.compiler.format.FormattingVisitorEntry; import org.ballerinalang.langserver.compiler.format.TextDocumentFormatUtil; import org.ballerinalang.langserver.compiler.sourcegen.FormattingSourceGen; -import org.ballerinalang.langserver.completions.SymbolInfo; import org.ballerinalang.langserver.completions.exceptions.CompletionContextNotSupportedException; import org.ballerinalang.langserver.completions.util.CompletionUtil; import org.ballerinalang.langserver.diagnostic.DiagnosticsHelper; @@ -89,6 +88,7 @@ import org.eclipse.lsp4j.WorkspaceEdit; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.TextDocumentService; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol; import org.wso2.ballerinalang.compiler.tree.BLangCompilationUnit; import org.wso2.ballerinalang.compiler.tree.BLangPackage; @@ -113,7 +113,7 @@ import static org.ballerinalang.langserver.compiler.LSClientLogger.logError; import static org.ballerinalang.langserver.compiler.LSClientLogger.notifyUser; import static org.ballerinalang.langserver.compiler.LSCompilerUtil.getUntitledFilePath; -import static org.ballerinalang.langserver.signature.SignatureHelpUtil.getFuncSymbolInfo; +import static org.ballerinalang.langserver.signature.SignatureHelpUtil.getFuncScopeEntry; import static org.ballerinalang.langserver.signature.SignatureHelpUtil.getFunctionInvocationDetails; /** @@ -240,22 +240,21 @@ public CompletableFuture signatureHelp(TextDocumentPositionParams SignatureTreeVisitor signatureTreeVisitor = new SignatureTreeVisitor(context); bLangPackage.accept(signatureTreeVisitor); int activeParamIndex = 0; - List visibleSymbols = context.get(CommonKeys.VISIBLE_SYMBOLS_KEY); + List visibleSymbols = context.get(CommonKeys.VISIBLE_SYMBOLS_KEY); if (visibleSymbols == null) { throw new Exception("Couldn't find the symbol, visible symbols are NULL!"); } // Search function invocation symbol List signatures = new ArrayList<>(); - List symbols = new ArrayList<>(visibleSymbols); + List symbols = new ArrayList<>(visibleSymbols); Pair, Integer> funcPathAndParamIndexPair = getFunctionInvocationDetails(context); Optional funcPath = funcPathAndParamIndexPair.getLeft(); activeParamIndex = funcPathAndParamIndexPair.getRight(); funcPath.ifPresent(pathStr -> { - Optional searchSymbol = getFuncSymbolInfo(context, pathStr, - symbols); - searchSymbol.ifPresent(s -> { - if (s.getScopeEntry().symbol instanceof BInvokableSymbol) { - BInvokableSymbol symbol = (BInvokableSymbol) s.getScopeEntry().symbol; + Optional searchSymbol = getFuncScopeEntry(context, pathStr, symbols); + searchSymbol.ifPresent(entry -> { + if (entry.symbol instanceof BInvokableSymbol) { + BInvokableSymbol symbol = (BInvokableSymbol) entry.symbol; signatures.add(SignatureHelpUtil.getSignatureInformation(symbol, context)); } }); diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/SnippetBlock.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/SnippetBlock.java index 3ac957f391a0..33f7dd401a7c 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/SnippetBlock.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/SnippetBlock.java @@ -126,6 +126,10 @@ public String getLabel() { return label; } + public SnippetType getSnippetType() { + return snippetType; + } + /** * Represents Snippet Types in B7a LS. */ diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/SnippetGenerator.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/SnippetGenerator.java index 3046bd790ea6..ea71d197935a 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/SnippetGenerator.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/SnippetGenerator.java @@ -211,6 +211,16 @@ public static SnippetBlock getFunctionKeywordSnippet() { SnippetType.KEYWORD); } + /** + * Get resource Keyword Snippet Block. + * + * @return {@link SnippetBlock} Generated Snippet Block + */ + public static SnippetBlock getResourceKeywordSnippet() { + return new SnippetBlock(ItemResolverConstants.RESOURCE, "resource ", ItemResolverConstants.KEYWORD_TYPE, + SnippetType.KEYWORD); + } + /** * Get Continue Statement Snippet Block. * diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/command/CommandUtil.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/command/CommandUtil.java index c9b619ba213b..b86ceea174c8 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/command/CommandUtil.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/command/CommandUtil.java @@ -947,6 +947,9 @@ private static String getDiagnosedContent(Diagnostic diagnostic, LSContext conte private static Position offsetInvocation(String diagnosedContent, Position position) { // Diagnosed message only contains the erroneous part of the line // Thus we offset into last + int leftParenthesisIndex = diagnosedContent.indexOf("("); + diagnosedContent = (leftParenthesisIndex == -1) ? diagnosedContent + : diagnosedContent.substring(0, leftParenthesisIndex); String quotesRemoved = diagnosedContent .replaceAll(".*:", "") // package invocation .replaceAll(".*->", "") // action invocation diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/CommonKeys.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/CommonKeys.java index e5cdafbbf3ed..f16b2a8bc565 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/CommonKeys.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/CommonKeys.java @@ -18,7 +18,7 @@ package org.ballerinalang.langserver.common; import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.List; @@ -61,5 +61,5 @@ private CommonKeys() { public static final String SLASH_KEYWORD_KEY = "/"; - public static final LSContext.Key> VISIBLE_SYMBOLS_KEY = new LSContext.Key<>(); + public static final LSContext.Key> VISIBLE_SYMBOLS_KEY = new LSContext.Key<>(); } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/CommonUtil.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/CommonUtil.java index 5c710bbf083f..671a2020d5a3 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/CommonUtil.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/CommonUtil.java @@ -28,9 +28,12 @@ import org.ballerinalang.jvm.util.BLangConstants; import org.ballerinalang.langserver.common.CommonKeys; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.compiler.DocumentServiceKeys; import org.ballerinalang.langserver.compiler.common.modal.BallerinaPackage; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.completions.FieldCompletionItem; +import org.ballerinalang.langserver.completions.StaticCompletionItem; +import org.ballerinalang.langserver.completions.SymbolCompletionItem; import org.ballerinalang.langserver.completions.util.ItemResolverConstants; import org.ballerinalang.langserver.completions.util.Priority; import org.ballerinalang.model.elements.Flag; @@ -147,37 +150,6 @@ public class CommonUtil { private CommonUtil() { } - /** - * Get the package URI to the given package name. - * - * @param pkgName Name of the package that need the URI for - * @param pkgPath String URI of the current package - * @param currentPkgName Name of the current package - * @return String URI for the given path. - */ - public static String getPackageURI(String pkgName, String pkgPath, String currentPkgName) { - String newPackagePath; - // If current package path is not null and current package is not default package continue, - // else new package path is same as the current package path. - if (pkgPath != null && !currentPkgName.equals(".")) { - int indexOfCurrentPkgName = pkgPath.lastIndexOf(currentPkgName); - if (indexOfCurrentPkgName >= 0) { - newPackagePath = pkgPath.substring(0, indexOfCurrentPkgName); - } else { - newPackagePath = pkgPath; - } - - if (pkgName.equals(".")) { - newPackagePath = Paths.get(newPackagePath).toString(); - } else { - newPackagePath = Paths.get(newPackagePath, pkgName).toString(); - } - } else { - newPackagePath = pkgPath; - } - return newPackagePath; - } - /** * Calculate the user defined type position. * @@ -286,11 +258,11 @@ private static Optional getDefaultTokenToLeftOrRight(TokenStream tokenStr * @param annotationSymbol BLang annotation to extract the completion Item * @param ctx LS Service operation context, in this case completion context * @param pkgAlias LS Service operation context, in this case completion context - * @return {@link CompletionItem} Completion item for the annotation + * @return {@link LSCompletionItem} Completion item for the annotation */ - public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol, - LSContext ctx, CommonToken pkgAlias, - Map pkgAliasMap) { + public static LSCompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol, + LSContext ctx, CommonToken pkgAlias, + Map pkgAliasMap) { PackageID currentPkgID = ctx.get(DocumentServiceKeys.CURRENT_PACKAGE_ID_KEY); String currentProjectOrgName = currentPkgID == null ? "" : currentPkgID.orgName.value; @@ -314,10 +286,10 @@ public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BA annotationItem.setKind(CompletionItemKind.Property); if (currentPkgID != null && currentPkgID.name.value.equals(packageID.name.value)) { // If the annotation resides within the current package, no need to set the additional text edits - return annotationItem; + return new SymbolCompletionItem(ctx, annotationSymbol, annotationItem); } List imports = ctx.get(DocumentServiceKeys.CURRENT_DOC_IMPORTS_KEY); - Optional pkgImport = imports.stream() + Optional pkgImport = imports.stream() .filter(bLangImportPackage -> { String orgName = bLangImportPackage.orgName.value; String importPkgName = (orgName.equals("") ? currentProjectOrgName : orgName) + "/" @@ -335,7 +307,7 @@ public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BA annotationItem.setAdditionalTextEdits(getAutoImportTextEdits(packageID.orgName.getValue(), packageID.name.getValue(), ctx)); } - return annotationItem; + return new SymbolCompletionItem(ctx, annotationSymbol, annotationItem); } /** @@ -347,7 +319,7 @@ public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BA * @param pkgAliasMap Package alias map for the file * @return {@link CompletionItem} Completion item for the annotation */ - public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol, + public static LSCompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol, LSContext ctx, Map pkgAliasMap) { return getAnnotationCompletionItem(packageID, annotationSymbol, ctx, null, pkgAliasMap); } @@ -535,11 +507,12 @@ public static boolean listContainsPackage(String pkg, List pkg /** * Get completion items list for struct fields. * + * @param context Language server operation context * @param fields List of struct fields * @return {@link List} List of completion items for the struct fields */ - public static List getRecordFieldCompletionItems(List fields) { - List completionItems = new ArrayList<>(); + public static List getRecordFieldCompletionItems(LSContext context, List fields) { + List completionItems = new ArrayList<>(); fields.forEach(field -> { String insertText = getRecordFieldCompletionInsertText(field, 0); CompletionItem fieldItem = new CompletionItem(); @@ -549,7 +522,7 @@ public static List getRecordFieldCompletionItems(List fi fieldItem.setDetail(ItemResolverConstants.FIELD_TYPE); fieldItem.setKind(CompletionItemKind.Field); fieldItem.setSortText(Priority.PRIORITY120.toString()); - completionItems.add(fieldItem); + completionItems.add(new FieldCompletionItem(context, field, fieldItem)); }); return completionItems; @@ -558,10 +531,11 @@ public static List getRecordFieldCompletionItems(List fi /** * Get the completion item to fill all the struct fields. * + * @param context Language Server Operation Context * @param fields List of struct fields - * @return {@link CompletionItem} Completion Item to fill all the options + * @return {@link LSCompletionItem} Completion Item to fill all the options */ - public static CompletionItem getFillAllStructFieldsItem(List fields) { + public static LSCompletionItem getFillAllStructFieldsItem(LSContext context, List fields) { List fieldEntries = new ArrayList<>(); for (BField bStructField : fields) { @@ -580,7 +554,7 @@ public static CompletionItem getFillAllStructFieldsItem(List fields) { completionItem.setKind(CompletionItemKind.Property); completionItem.setSortText(Priority.PRIORITY110.toString()); - return completionItem; + return new StaticCompletionItem(context, completionItem); } /** @@ -613,6 +587,18 @@ public static String getBTypeName(BType bType, LSContext ctx, boolean doSimplify return getShallowBTypeName(bType, ctx); } + /** + * Get the Symbol Name. + * + * @param bSymbol BSymbol to evaluate + * @return captured symbol name + */ + public static String getSymbolName(BSymbol bSymbol) { + String nameValue = bSymbol.name.getValue(); + String[] split = nameValue.split("\\."); + return split[split.length - 1]; + } + private static String getShallowBTypeName(BType bType, LSContext ctx) { if (bType.tsymbol == null) { return bType.toString(); @@ -983,10 +969,10 @@ public static Pair getFunctionInvocationSignature(BInvokableSymb * @param context Language Server operation conext * @return {@link List} filtered visible symbols */ - public static List getWorkerSymbols(LSContext context) { - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - return visibleSymbols.stream().filter(symbolInfo -> { - BType bType = symbolInfo.getScopeEntry().symbol.type; + public static List getWorkerSymbols(LSContext context) { + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + return visibleSymbols.stream().filter(scopeEntry -> { + BType bType = scopeEntry.symbol.type; return bType instanceof BFutureType && ((BFutureType) bType).workerDerivative; }).collect(Collectors.toList()); } @@ -1059,10 +1045,8 @@ public static List getCurrentModuleImports(LSContext ctx) { * * @return {@link Predicate} Predicate for the check */ - public static Predicate invalidSymbolsPredicate() { - return symbolInfo -> !symbolInfo.isCustomOperation() - && symbolInfo.getScopeEntry() != null - && isInvalidSymbol(symbolInfo.getScopeEntry().symbol); + public static Predicate invalidSymbolsPredicate() { + return scopeEntry -> scopeEntry != null && isInvalidSymbol(scopeEntry.symbol); } /** diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/FilterUtils.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/FilterUtils.java index 4cd9547f12ea..479ea90cf10b 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/FilterUtils.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/FilterUtils.java @@ -1,20 +1,20 @@ /* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ + * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.ballerinalang.langserver.common.utils; import com.google.common.collect.Lists; @@ -23,7 +23,6 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.compiler.DocumentServiceKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; import org.ballerinalang.model.symbols.SymbolKind; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import org.wso2.ballerinalang.compiler.semantics.analyzer.Types; @@ -70,30 +69,32 @@ public class FilterUtils { /** * Get the invocations and fields against an identifier (functions, actions and fields). * - * @param context Text Document Service context (Completion Context) - * @param varName Variable name to evaluate against (Can be package alias or defined variable) - * @param delimiter delimiter type either dot or action invocation symbol - * @param defaultTokens List of Default tokens - * @param delimIndex Delimiter index + * @param context Text Document Service context (Completion Context) + * @param varName Variable name to evaluate against (Can be package alias or defined variable) + * @param delimiter delimiter type either dot or action invocation symbol + * @param defaultTokens List of Default tokens + * @param delimIndex Delimiter index * @return {@link ArrayList} List of filtered symbol info */ - public static List filterVariableEntriesOnDelimiter(LSContext context, String varName, int delimiter, - List defaultTokens, int delimIndex) { - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + public static List filterVariableEntriesOnDelimiter(LSContext context, String varName, + int delimiter, + List defaultTokens, + int delimIndex) { + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); visibleSymbols.removeIf(CommonUtil.invalidSymbolsPredicate()); if (BallerinaParser.RARROW == delimiter) { - SymbolInfo variable = getVariableByName(varName, visibleSymbols); - if (variable != null && CommonUtil.isClientObject(variable.getScopeEntry().symbol)) { + Scope.ScopeEntry variable = getVariableByName(varName, visibleSymbols); + if (variable != null && CommonUtil.isClientObject(variable.symbol)) { // Handling action invocations ep -> ... - return getClientActions((BObjectTypeSymbol) variable.getScopeEntry().symbol.type.tsymbol); + return getClientActions((BObjectTypeSymbol) variable.symbol.type.tsymbol); } // Handling worker-interactions eg. msg -> ... - visibleSymbols.removeIf(symbolInfo -> symbolInfo.getScopeEntry().symbol instanceof BTypeSymbol); + visibleSymbols.removeIf(scopeEntry -> scopeEntry.symbol instanceof BTypeSymbol); return visibleSymbols; } if (BallerinaParser.LARROW == delimiter) { // Handling worker-interaction msg <- ... - visibleSymbols.removeIf(symbolInfo -> symbolInfo.getScopeEntry().symbol instanceof BTypeSymbol); + visibleSymbols.removeIf(scopeEntry -> scopeEntry.symbol instanceof BTypeSymbol); return visibleSymbols; } if (BallerinaParser.DOT == delimiter || BallerinaParser.OPTIONAL_FIELD_ACCESS == delimiter @@ -101,16 +102,16 @@ public static List filterVariableEntriesOnDelimiter(LSContext contex return getInvocationsAndFields(context, defaultTokens, delimIndex); } if (BallerinaParser.COLON == delimiter) { - Optional pkgSymbol = visibleSymbols.stream() - .filter(item -> item.getSymbolName().equals(varName) - && item.getScopeEntry().symbol instanceof BPackageSymbol) + Optional pkgSymbol = visibleSymbols.stream() + .filter(item -> CommonUtil.getSymbolName(item.symbol).equals(varName) + && item.symbol instanceof BPackageSymbol) .findFirst(); if (!pkgSymbol.isPresent()) { return new ArrayList<>(); } - Map scopeEntryMap = pkgSymbol.get().getScopeEntry().symbol.scope.entries; + Map scopeEntryMap = pkgSymbol.get().symbol.scope.entries; return loadActionsFunctionsAndTypesFromScope(scopeEntryMap); } @@ -119,17 +120,13 @@ public static List filterVariableEntriesOnDelimiter(LSContext contex /** * Get the actions defined over and endpoint. - * @param bObjectTypeSymbol Endpoint variable symbol to evaluate - * @return {@link List} List of extracted actions as Symbol Info + * + * @param objectTypeSymbol Endpoint variable symbol to evaluate + * @return {@link List} List of extracted actions as Symbol Info */ - public static List getClientActions(BObjectTypeSymbol bObjectTypeSymbol) { - return bObjectTypeSymbol.methodScope.entries.entrySet().stream() - .filter(entry -> (entry.getValue().symbol.flags & Flags.REMOTE) == Flags.REMOTE) - .map(entry -> { - String actionName = entry.getKey().getValue(); - String[] nameComponents = actionName.split("\\."); - return new SymbolInfo(nameComponents[nameComponents.length - 1], entry.getValue()); - }) + public static List getClientActions(BObjectTypeSymbol objectTypeSymbol) { + return objectTypeSymbol.methodScope.entries.values().stream() + .filter(scopeEntry -> (scopeEntry.symbol.flags & Flags.REMOTE) == Flags.REMOTE) .collect(Collectors.toList()); } @@ -138,20 +135,20 @@ public static List getClientActions(BObjectTypeSymbol bObjectTypeSym * Get the invocations and fields for a dot separated chained statement * Eg: int x = var1.field1.testFunction() * - * @param context Language server operation context + * @param ctx Language server operation context * @param defaultTokens List of default tokens removed (LHS Tokens) - * @param delimIndex Delimiter index + * @param delimIndex Delimiter index * @return {@link List} List of extracted symbols */ - private static List getInvocationsAndFields(LSContext context, List defaultTokens, - int delimIndex) { - List resultList = new ArrayList<>(); + private static List getInvocationsAndFields(LSContext ctx, List defaultTokens, + int delimIndex) { + List resultList = new ArrayList<>(); List invocationFieldList = getInvocationFieldList(defaultTokens, delimIndex); - SymbolTable symbolTable = SymbolTable.getInstance(context.get(DocumentServiceKeys.COMPILER_CONTEXT_KEY)); + SymbolTable symbolTable = SymbolTable.getInstance(ctx.get(DocumentServiceKeys.COMPILER_CONTEXT_KEY)); ChainedFieldModel startField = invocationFieldList.get(0); - List symbolList = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - BSymbol bSymbol = getVariableByName(startField.name.getText(), symbolList).getScopeEntry().symbol; + List symbolList = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + BSymbol bSymbol = getVariableByName(startField.name.getText(), symbolList).symbol; if (bSymbol instanceof BPackageSymbol) { /* Above common filter extract package symbols as well. Hence we skip since dot delimiter is not valid over a @@ -159,9 +156,9 @@ private static List getInvocationsAndFields(LSContext context, List< */ return resultList; } - BType modifiedBType = getModifiedBType(bSymbol, context, startField.fieldType); + BType modifiedBType = getModifiedBType(bSymbol, ctx, startField.fieldType); Map scopeEntries = getInvocationsAndFieldsForSymbol(startField.name.getText(), - modifiedBType, context); + modifiedBType, ctx); for (int itr = 1; itr < invocationFieldList.size(); itr++) { ChainedFieldModel fieldModel = invocationFieldList.get(itr); @@ -171,7 +168,7 @@ private static List getInvocationsAndFields(LSContext context, List< Eg: myJson.test_field.toString() */ modifiedBType = BUnionType.create(null, modifiedBType, symbolTable.errorType); - scopeEntries = getInvocationsAndFieldsForSymbol(fieldModel.name.getText(), modifiedBType, context); + scopeEntries = getInvocationsAndFieldsForSymbol(fieldModel.name.getText(), modifiedBType, ctx); continue; } if (scopeEntries == null) { @@ -182,14 +179,13 @@ private static List getInvocationsAndFields(LSContext context, List< break; } bSymbol = entry.get().symbol; - modifiedBType = getModifiedBType(bSymbol, context, fieldModel.fieldType); - scopeEntries = getInvocationsAndFieldsForSymbol(fieldModel.name.getText(), modifiedBType, context); + modifiedBType = getModifiedBType(bSymbol, ctx, fieldModel.fieldType); + scopeEntries = getInvocationsAndFieldsForSymbol(fieldModel.name.getText(), modifiedBType, ctx); } if (scopeEntries == null) { return new ArrayList<>(); } - scopeEntries.forEach((entryName, fieldEntry) -> - resultList.add(new SymbolInfo(fieldEntry.symbol.getName().value, fieldEntry))); + scopeEntries.forEach((entryName, fieldEntry) -> resultList.add(fieldEntry)); return resultList; } @@ -199,11 +195,11 @@ private static List getInvocationsAndFields(LSContext context, List< * * @param name name of the variable * @param symbols list of symbol info - * @return {@link SymbolInfo} Symbol Info extracted + * @return {@link org.wso2.ballerinalang.compiler.semantics.model.Scope.ScopeEntry} Scope Entry extracted */ - public static SymbolInfo getVariableByName(String name, List symbols) { + public static Scope.ScopeEntry getVariableByName(String name, List symbols) { return symbols.stream() - .filter(symbolInfo -> symbolInfo.getSymbolName().equals(name)) + .filter(scopeEntry -> scopeEntry.symbol.name.getValue().equals(name)) .findFirst() .orElse(null); } @@ -223,11 +219,11 @@ public static Optional getBTypeEntry(Scope.ScopeEntry entry) { public static boolean isBTypeEntry(Scope.ScopeEntry entry) { return getBTypeEntry(entry).isPresent(); } - + /////////////////////////// ///// Private Methods ///// /////////////////////////// - + private static BType getBTypeForUnionType(BUnionType bType) { List memberTypeList = new ArrayList<>(bType.getMemberTypes()); memberTypeList.removeIf(type -> type.tsymbol instanceof BErrorTypeSymbol || type instanceof BNilType); @@ -235,33 +231,32 @@ private static BType getBTypeForUnionType(BUnionType bType) { if (memberTypeList.size() == 1) { return memberTypeList.get(0); } - + return bType; } - private static List loadActionsFunctionsAndTypesFromScope(Map entryMap) { - List actionFunctionList = new ArrayList<>(); + private static List loadActionsFunctionsAndTypesFromScope(Map entryMap) { + List actionFunctionList = new ArrayList<>(); entryMap.forEach((name, scopeEntry) -> { BSymbol symbol = scopeEntry.symbol; if (((symbol instanceof BInvokableSymbol && ((BInvokableSymbol) symbol).receiverSymbol == null) || isBTypeEntry(scopeEntry) || symbol instanceof BVarSymbol) && (symbol.flags & Flags.PUBLIC) == Flags.PUBLIC) { - SymbolInfo entry = new SymbolInfo(name.toString(), scopeEntry); - actionFunctionList.add(entry); + actionFunctionList.add(scopeEntry); } }); return actionFunctionList; } - + private static BType getModifiedBType(BSymbol bSymbol, LSContext context, InvocationFieldType fieldType) { Integer invocationType = context.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); BType actualType; if ((bSymbol.tag & SymTag.TYPE) == SymTag.TYPE) { actualType = new BTypedescType(bSymbol.type, null); } else if (bSymbol instanceof BInvokableSymbol) { - actualType = ((BInvokableSymbol) bSymbol).retType; + actualType = ((BInvokableSymbol) bSymbol).retType; } else if (bSymbol.type instanceof BArrayType && fieldType == InvocationFieldType.ARRAY_ACCESS) { return ((BArrayType) bSymbol.type).eType; } else { @@ -346,7 +341,7 @@ private static List getInvocationFieldList(List * * @param symbolName symbol name to evaluate * @param symbolType BType to evaluate - * @param context Language Server Operation Context + * @param context Language Server Operation Context * @return {@link Map} Scope Entry Map */ private static Map getInvocationsAndFieldsForSymbol(String symbolName, BType symbolType, @@ -368,7 +363,7 @@ private static Map getInvocationsAndFieldsForSymbol(Stri BSymbol entrySymbol = entry.getValue().symbol; boolean isPrivate = (entrySymbol.flags & Flags.PRIVATE) == Flags.PRIVATE; return !(entrySymbol.getName().getValue().contains(".__init") - && !"self".equals(symbolName)) && !(isPrivate && !"self".equals(symbolName)); + && !"self".equals(symbolName)) && !(isPrivate && !"self".equals(symbolName)); }) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); Map fieldEntries = objectTypeSymbol.scope.entries.entrySet().stream() @@ -409,9 +404,9 @@ private static Map getInvocationsAndFieldsForSymbol(Stri /** * When given a union of record types, iterate over the member types to extract the fields with the same name. * If a certain field with the same name contains in all records we extract the field entries - * + * * @param unionType union type to evaluate - * @param context Language server operation context + * @param context Language server operation context * @return {@link Map} map of scope entries */ private static Map getInvocationsAndFieldsForUnionType(BUnionType unionType, @@ -493,10 +488,10 @@ private static Optional getScopeEntryWithName(Map getLangLibScopeEntries(BType bType, SymbolTable symTable, Types types) { Map entries = new HashMap<>(symTable.langValueModuleSymbol.scope.entries); @@ -553,7 +548,7 @@ public static Map getLangLibScopeEntries(BType bType, Sy return symbol.kind != null && symbol.kind != SymbolKind.OBJECT; }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } - + private static Predicate> optionalFieldFilter(BType symbolType, Integer invocationTkn) { return entry -> { diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/completion/BLangRecordLiteralUtil.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/completion/BLangRecordLiteralUtil.java index 978654008664..b8699b9d3ab1 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/completion/BLangRecordLiteralUtil.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/common/utils/completion/BLangRecordLiteralUtil.java @@ -18,7 +18,8 @@ package org.ballerinalang.langserver.common.utils.completion; import org.ballerinalang.langserver.common.utils.CommonUtil; -import org.eclipse.lsp4j.CompletionItem; +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.wso2.ballerinalang.compiler.semantics.model.types.BField; import org.wso2.ballerinalang.compiler.semantics.model.types.BRecordType; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; @@ -39,12 +40,14 @@ private BLangRecordLiteralUtil() { } /** - * Get the record field completion itmes. + * Get the record field completion items. * + * @param context Language server operation Context * @param recordLiteral Record Literal - * @return {@link CompletionItem} List of Completion Items + * @return {@link LSCompletionItem} List of Completion Items */ - public static ArrayList getFieldsForMatchingRecord(BLangRecordLiteral recordLiteral) { + public static List getFieldsForMatchingRecord(LSContext context, + BLangRecordLiteral recordLiteral) { BType expectedType = recordLiteral.expectedType; Optional evalType = expectedType instanceof BUnionType ? getRecordTypeFromUnionType(expectedType) : Optional.ofNullable(expectedType); @@ -52,8 +55,8 @@ public static ArrayList getFieldsForMatchingRecord(BLangRecordLi return new ArrayList<>(); } List fields = ((BRecordType) evalType.get()).fields; - ArrayList completionItems = new ArrayList<>(CommonUtil.getRecordFieldCompletionItems(fields)); - completionItems.add(CommonUtil.getFillAllStructFieldsItem(fields)); + List completionItems = CommonUtil.getRecordFieldCompletionItems(context, fields); + completionItems.add(CommonUtil.getFillAllStructFieldsItem(context, fields)); return completionItems; } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/FieldCompletionItem.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/FieldCompletionItem.java new file mode 100644 index 000000000000..b371b6584e0c --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/FieldCompletionItem.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.langserver.completions; + +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.eclipse.lsp4j.CompletionItem; +import org.wso2.ballerinalang.compiler.semantics.model.types.BField; + +/** + * Represents a BField Completion Item. + * + * @since 1.2.0 + */ +public class FieldCompletionItem implements LSCompletionItem { + private LSContext lsContext; + private CompletionItem completionItem; + private BField bField; + + public FieldCompletionItem(LSContext lsContext, BField bField, CompletionItem completionItem) { + this.lsContext = lsContext; + this.completionItem = completionItem; + this.bField = bField; + } + + @Override + public CompletionItem getCompletionItem() { + return this.completionItem; + } + + public LSContext getLsContext() { + return lsContext; + } + + public BField getBField() { + return bField; + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SnippetCompletionItem.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SnippetCompletionItem.java new file mode 100644 index 000000000000..b12b38e989b7 --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SnippetCompletionItem.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.langserver.completions; + +import org.ballerinalang.langserver.SnippetBlock; +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.eclipse.lsp4j.CompletionItem; + +/** + * Represents a snippet Completion Item. + * Eg: Code Snippet + * + * @since 1.2.0 + */ +public class SnippetCompletionItem implements LSCompletionItem { + private CompletionItem completionItem; + private SnippetBlock.SnippetType snippetType; + + public SnippetCompletionItem(LSContext lsContext, SnippetBlock snippetBlock) { + this.completionItem = snippetBlock.build(lsContext); + this.snippetType = snippetBlock.getSnippetType(); + } + + @Override + public CompletionItem getCompletionItem() { + return this.completionItem; + } + + public SnippetBlock.SnippetType getSnippetType() { + return snippetType; + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/StaticCompletionItem.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/StaticCompletionItem.java new file mode 100644 index 000000000000..4726796d2b83 --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/StaticCompletionItem.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.langserver.completions; + +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.eclipse.lsp4j.CompletionItem; + +/** + * Represents a static Completion Item. + * Eg: Code Snippet + * + * @since 1.2.0 + */ +public class StaticCompletionItem implements LSCompletionItem { + LSContext lsContext; + CompletionItem completionItem; + + public StaticCompletionItem(LSContext lsContext, CompletionItem completionItem) { + this.lsContext = lsContext; + this.completionItem = completionItem; + } + + @Override + public CompletionItem getCompletionItem() { + return this.completionItem; + } + + public LSContext getLsContext() { + return lsContext; + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SymbolCompletionItem.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SymbolCompletionItem.java new file mode 100644 index 000000000000..729b8171b520 --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SymbolCompletionItem.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.langserver.completions; + +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.eclipse.lsp4j.CompletionItem; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol; + +import javax.annotation.Nullable; + +/** + * Represents a Symbol Based Completion Item. + * Eg: Invocation Symbol + * + * @since 1.2.0 + */ +public class SymbolCompletionItem implements LSCompletionItem { + private LSContext lsContext; + private BSymbol bSymbol; + private CompletionItem completionItem; + + public SymbolCompletionItem(LSContext lsContext, @Nullable BSymbol bSymbol, CompletionItem completionItem) { + this.lsContext = lsContext; + this.bSymbol = bSymbol; + this.completionItem = completionItem; + } + + public BSymbol getSymbol() { + return bSymbol; + } + + @Override + public CompletionItem getCompletionItem() { + return this.completionItem; + } + + public LSContext getLsContext() { + return lsContext; + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SymbolInfo.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SymbolInfo.java deleted file mode 100644 index 9734f564298d..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/SymbolInfo.java +++ /dev/null @@ -1,88 +0,0 @@ -/* -* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ - -package org.ballerinalang.langserver.completions; - -import org.wso2.ballerinalang.compiler.semantics.model.Scope; - -/** - * Represents the symbol information. - */ -public class SymbolInfo { - private String symbolName; - private Scope.ScopeEntry scopeEntry; - private boolean isCustomOperation; - private CustomOperationSignature customOperationSignature; - - public SymbolInfo(String symbolName, Scope.ScopeEntry scopeEntry) { - this.symbolName = symbolName; - this.scopeEntry = scopeEntry; - } - - public SymbolInfo() { - } - - public String getSymbolName() { - return symbolName; - } - - public void setSymbolName(String symbolName) { - this.symbolName = symbolName; - } - - public Scope.ScopeEntry getScopeEntry() { - return scopeEntry; - } - - public boolean isCustomOperation() { - return isCustomOperation; - } - - public void setCustomOperation(boolean customOperation) { - isCustomOperation = customOperation; - } - - public CustomOperationSignature getCustomOperationSignature() { - return customOperationSignature; - } - - public void setCustomOperationSignature(CustomOperationSignature customOperationSignature) { - this.customOperationSignature = customOperationSignature; - } - - /** - * Holds the iterable operation signature information. - */ - public static class CustomOperationSignature { - String label; - String insertText; - - public CustomOperationSignature(String label, String insertText) { - this.label = label; - this.insertText = insertText; - } - - public String getLabel() { - return label; - } - - public String getInsertText() { - return insertText; - } - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/TreeVisitor.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/TreeVisitor.java index 253a1f425f98..c0f1ffed551d 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/TreeVisitor.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/TreeVisitor.java @@ -868,13 +868,9 @@ public Map> resolveAllVisibleSymbols(SymbolEnv symb * @param symbolEnv Symbol environment */ public void populateSymbols(Map> symbolEntries, @Nonnull SymbolEnv symbolEnv) { - List visibleSymbols = new ArrayList<>(); + List visibleSymbols = new ArrayList<>(); this.populateSymbolEnvNode(symbolEnv.node); - symbolEntries.forEach((name, entryHolders) -> - visibleSymbols.addAll( - entryHolders.stream() - .map(scopeEntry -> new SymbolInfo(name.value, scopeEntry)) - .collect(Collectors.toList()))); + symbolEntries.values().forEach(visibleSymbols::addAll); lsContext.put(CommonKeys.VISIBLE_SYMBOLS_KEY, visibleSymbols); } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/AbstractCompletionProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/AbstractCompletionProvider.java index d1d99dbb3298..978d1867dcd7 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/AbstractCompletionProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/AbstractCompletionProvider.java @@ -27,6 +27,7 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.commons.completion.spi.LSCompletionProvider; import org.ballerinalang.langserver.compiler.DocumentServiceKeys; import org.ballerinalang.langserver.compiler.ExtendedLSCompiler; @@ -34,7 +35,9 @@ import org.ballerinalang.langserver.compiler.common.modal.BallerinaPackage; import org.ballerinalang.langserver.compiler.exception.CompilationFailedException; import org.ballerinalang.langserver.completions.LSCompletionProviderHolder; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; +import org.ballerinalang.langserver.completions.StaticCompletionItem; +import org.ballerinalang.langserver.completions.SymbolCompletionItem; import org.ballerinalang.langserver.completions.builder.BConstantCompletionItemBuilder; import org.ballerinalang.langserver.completions.builder.BFunctionCompletionItemBuilder; import org.ballerinalang.langserver.completions.builder.BTypeCompletionItemBuilder; @@ -85,6 +88,8 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import static org.ballerinalang.langserver.common.utils.CommonUtil.getFunctionInvocationSignature; + /** * Interface for completion item providers. * @@ -100,7 +105,7 @@ public abstract class AbstractCompletionProvider implements LSCompletionProvider * {@inheritDoc} */ @Override - public abstract List getCompletions(LSContext context) throws LSCompletionException; + public abstract List getCompletions(LSContext context) throws LSCompletionException; /** * {@inheritDoc} @@ -129,33 +134,35 @@ public Optional getContextProvider(LSContext ctx) { /** * Populate the completion item list by considering the. * - * @param symbolInfoList list of symbol information + * @param scopeEntries list of symbol information * @param context Language server operation context * @return {@link List} list of completion items */ - protected List getCompletionItemList(List symbolInfoList, LSContext context) { + protected List getCompletionItemList(List scopeEntries, LSContext context) { List processedSymbols = new ArrayList<>(); - List completionItems = new ArrayList<>(); - symbolInfoList.removeIf(CommonUtil.invalidSymbolsPredicate()); - symbolInfoList.forEach(symbolInfo -> { - BSymbol symbol = symbolInfo.getScopeEntry().symbol; + List completionItems = new ArrayList<>(); + scopeEntries.removeIf(CommonUtil.invalidSymbolsPredicate()); + scopeEntries.forEach(scopeEntry -> { + BSymbol symbol = scopeEntry.symbol; if (processedSymbols.contains(symbol)) { return; } Optional bTypeSymbol; - BSymbol bSymbol = symbolInfo.isCustomOperation() ? null : symbol; - if (CommonUtil.isValidInvokableSymbol(bSymbol) || symbolInfo.isCustomOperation()) { - completionItems.add(populateBallerinaFunctionCompletionItem(symbolInfo, context)); - } else if (bSymbol instanceof BConstantSymbol) { - completionItems.add(BConstantCompletionItemBuilder.build((BConstantSymbol) bSymbol, context)); - } else if (!(bSymbol instanceof BInvokableSymbol) && bSymbol instanceof BVarSymbol) { + if (CommonUtil.isValidInvokableSymbol(symbol)) { + completionItems.add(populateBallerinaFunctionCompletionItem(scopeEntry, context)); + } else if (symbol instanceof BConstantSymbol) { + CompletionItem constantCItem = BConstantCompletionItemBuilder.build((BConstantSymbol) symbol, context); + completionItems.add(new SymbolCompletionItem(context, symbol, constantCItem)); + } else if (!(symbol instanceof BInvokableSymbol) && symbol instanceof BVarSymbol) { String typeName = CommonUtil.getBTypeName(symbol.type, context, false); - completionItems.add( - BVariableCompletionItemBuilder.build((BVarSymbol) bSymbol, symbolInfo.getSymbolName(), typeName) - ); - } else if ((bTypeSymbol = FilterUtils.getBTypeEntry(symbolInfo.getScopeEntry())).isPresent()) { + CompletionItem variableCItem = BVariableCompletionItemBuilder + .build((BVarSymbol) symbol, scopeEntry.symbol.name.value, typeName); + completionItems.add(new SymbolCompletionItem(context, symbol, variableCItem)); + } else if ((bTypeSymbol = FilterUtils.getBTypeEntry(scopeEntry)).isPresent()) { // Here skip all the package symbols since the package is added separately - completionItems.add(BTypeCompletionItemBuilder.build(bTypeSymbol.get(), symbolInfo.getSymbolName())); + CompletionItem typeCItem = BTypeCompletionItemBuilder.build(bTypeSymbol.get(), + scopeEntry.symbol.name.value); + completionItems.add(new SymbolCompletionItem(context, bTypeSymbol.get(), typeCItem)); } processedSymbols.add(symbol); }); @@ -169,7 +176,7 @@ protected List getCompletionItemList(List symbolInfo * @param context LS Operation Context * @return {@link List} Completion Items List */ - protected List getCompletionItemList(Either, List> list, + protected List getCompletionItemList(Either, List> list, LSContext context) { return list.isLeft() ? list.getLeft() : this.getCompletionItemList(list.getRight(), context); } @@ -177,21 +184,23 @@ protected List getCompletionItemList(Either /** * Get the basic types. * + * @param context LS Operation Context * @param visibleSymbols List of visible symbols * @return {@link List} List of completion items */ - protected List getBasicTypes(List visibleSymbols) { + protected List getBasicTypesItems(LSContext context, List visibleSymbols) { visibleSymbols.removeIf(CommonUtil.invalidSymbolsPredicate()); - List completionItems = new ArrayList<>(); - visibleSymbols.forEach(symbolInfo -> { - BSymbol bSymbol = symbolInfo.getScopeEntry().symbol; + List completionItems = new ArrayList<>(); + visibleSymbols.forEach(scopeEntry -> { + BSymbol bSymbol = scopeEntry.symbol; if (((bSymbol instanceof BConstructorSymbol && Names.ERROR.equals(bSymbol.name))) || (bSymbol instanceof BTypeSymbol && !(bSymbol instanceof BPackageSymbol))) { BSymbol symbol = bSymbol; if (bSymbol instanceof BConstructorSymbol) { symbol = ((BConstructorSymbol) bSymbol).type.tsymbol; } - completionItems.add(BTypeCompletionItemBuilder.build(symbol, symbolInfo.getSymbolName())); + CompletionItem cItem = BTypeCompletionItemBuilder.build(symbol, scopeEntry.symbol.name.getValue()); + completionItems.add(new SymbolCompletionItem(context, symbol, cItem)); } }); @@ -206,22 +215,21 @@ protected List getBasicTypes(List visibleSymbols) { * @param ctx language server context * @return {@link List} list of Type completion items */ - protected List getTypesInPackage(List visibleSymbols, String pkgName, LSContext ctx) { - List filteredList = new ArrayList<>(); - Optional pkgSymbolInfo = visibleSymbols.stream() - .filter(symbolInfo -> { - BSymbol symbol = symbolInfo.getScopeEntry().symbol; - return symbol instanceof BPackageSymbol && symbolInfo.getSymbolName().equals(pkgName); + protected List getTypeItemsInPackage(List visibleSymbols, String pkgName, + LSContext ctx) { + List filteredList = new ArrayList<>(); + Optional pkgSymbolInfo = visibleSymbols.stream() + .filter(scopeEntry -> { + BSymbol symbol = scopeEntry.symbol; + return symbol instanceof BPackageSymbol && scopeEntry.symbol.name.getValue().equals(pkgName); }) .findAny(); - pkgSymbolInfo.ifPresent(symbolInfo -> { - BSymbol pkgSymbol = symbolInfo.getScopeEntry().symbol; + pkgSymbolInfo.ifPresent(pkgEntry -> { + BSymbol pkgSymbol = pkgEntry.symbol; pkgSymbol.scope.entries.forEach((name, scopeEntry) -> { - if (scopeEntry.symbol instanceof BTypeSymbol) { - filteredList.add(new SymbolInfo(name.getValue(), scopeEntry)); - } else if (scopeEntry.symbol instanceof BConstructorSymbol && Names.ERROR.equals( - scopeEntry.symbol.name)) { - filteredList.add(new SymbolInfo(name.getValue(), scopeEntry)); + if (scopeEntry.symbol instanceof BTypeSymbol || (scopeEntry.symbol instanceof BConstructorSymbol + && Names.ERROR.equals(scopeEntry.symbol.name))) { + filteredList.add(scopeEntry); } }); }); @@ -235,43 +243,32 @@ protected List getTypesInPackage(List visibleSymbols * @param context LS Context * @return {@link List} List of populated completion items */ - protected List addTopLevelItems(LSContext context) { - ArrayList completionItems = new ArrayList<>(); - completionItems.add(getStaticItem(context, Snippet.KW_IMPORT)); - completionItems.add(getStaticItem(context, Snippet.KW_FUNCTION)); - completionItems.add(getStaticItem(context, Snippet.DEF_FUNCTION)); - completionItems.add(getStaticItem(context, Snippet.DEF_MAIN_FUNCTION)); - completionItems.add(getStaticItem(context, Snippet.DEF_SERVICE)); - completionItems.add(getStaticItem(context, Snippet.DEF_SERVICE_WEBSOCKET)); - completionItems.add(getStaticItem(context, Snippet.DEF_SERVICE_WS_CLIENT)); -// completionItems.add(getStaticItem(context, Snippet.DEF_SERVICE_WEBSUB)); - completionItems.add(getStaticItem(context, Snippet.DEF_SERVICE_GRPC)); - completionItems.add(getStaticItem(context, Snippet.DEF_ANNOTATION)); - completionItems.add(getStaticItem(context, Snippet.STMT_NAMESPACE_DECLARATION)); - completionItems.add(getStaticItem(context, Snippet.DEF_OBJECT_SNIPPET)); - completionItems.add(getStaticItem(context, Snippet.DEF_RECORD)); - completionItems.add(getStaticItem(context, Snippet.DEF_CLOSED_RECORD)); - completionItems.add(getStaticItem(context, Snippet.KW_TYPE)); - completionItems.add(getStaticItem(context, Snippet.KW_PUBLIC)); - completionItems.add(getStaticItem(context, Snippet.KW_FINAL)); - completionItems.add(getStaticItem(context, Snippet.KW_CONST)); - completionItems.add(getStaticItem(context, Snippet.DEF_ERROR)); - completionItems.add(getStaticItem(context, Snippet.KW_LISTENER)); - completionItems.add(getStaticItem(context, Snippet.KW_VAR)); + protected List addTopLevelItems(LSContext context) { + ArrayList completionItems = new ArrayList<>(); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_IMPORT.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_MAIN_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_SERVICE.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_SERVICE_WEBSOCKET.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_SERVICE_WS_CLIENT.get())); +// completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_SERVICE_WEBSUB)); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_SERVICE_GRPC.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_ANNOTATION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_NAMESPACE_DECLARATION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_OBJECT_SNIPPET.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_RECORD.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_CLOSED_RECORD.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_TYPE.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_PUBLIC.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_FINAL.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_CONST.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_ERROR.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_LISTENER.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_VAR.get())); return completionItems; } - /** - * Get a static completion Item for the given snippet. - * - * @param ctx Language Server Context - * @param snippet Snippet to generate the static completion item - * @return {@link CompletionItem} Generated static completion Item - */ - protected CompletionItem getStaticItem(LSContext ctx, Snippet snippet) { - return snippet.get().build(ctx); - } - /** * Get the completion item for a package import. * If the package is already imported, additional text edit for the import statement will not be added. @@ -279,12 +276,12 @@ protected CompletionItem getStaticItem(LSContext ctx, Snippet snippet) { * @param ctx LS Operation context * @return {@link List} List of packages completion items */ - protected List getPackagesCompletionItems(LSContext ctx) { + protected List getPackagesCompletionItems(LSContext ctx) { // First we include the packages from the imported list. List populatedList = new ArrayList<>(); BLangPackage currentPkg = ctx.get(DocumentServiceKeys.CURRENT_BLANG_PACKAGE_CONTEXT_KEY); List currentModuleImports = ctx.get(DocumentServiceKeys.CURRENT_DOC_IMPORTS_KEY); - List completionItems = currentModuleImports.stream() + List completionItems = currentModuleImports.stream() .map(pkg -> { String orgName = pkg.orgName.value; String pkgName = pkg.pkgNameComps.stream() @@ -304,21 +301,21 @@ protected List getPackagesCompletionItems(LSContext ctx) { item.setDetail(ItemResolverConstants.PACKAGE_TYPE); item.setKind(CompletionItemKind.Module); populatedList.add(orgName + "/" + pkgName); - return item; + return new SymbolCompletionItem(ctx, pkg.symbol, item); }).collect(Collectors.toList()); List packages = LSPackageLoader.getSdkPackages(); packages.addAll(LSPackageLoader.getHomeRepoPackages()); packages.addAll(LSPackageLoader.getCurrentProjectModules(currentPkg, ctx)); - packages.forEach(ballerinaPackage -> { - String name = ballerinaPackage.getPackageName(); - String orgName = ballerinaPackage.getOrgName(); + packages.forEach(pkg -> { + String name = pkg.getPackageName(); + String orgName = pkg.getOrgName(); boolean pkgAlreadyImported = currentModuleImports.stream() .anyMatch(importPkg -> importPkg.orgName.value.equals(orgName) && importPkg.alias.value.equals(name)); if (!pkgAlreadyImported && !populatedList.contains(orgName + "/" + name)) { CompletionItem item = new CompletionItem(); - item.setLabel(ballerinaPackage.getFullPackageNameAlias()); + item.setLabel(pkg.getFullPackageNameAlias()); String[] pkgNameComps = name.split("\\."); String insertText = pkgNameComps[pkgNameComps.length - 1]; // Check for the lang lib module insert text @@ -330,7 +327,7 @@ protected List getPackagesCompletionItems(LSContext ctx) { item.setDetail(ItemResolverConstants.PACKAGE_TYPE); item.setKind(CompletionItemKind.Module); item.setAdditionalTextEdits(CommonUtil.getAutoImportTextEdits(orgName, name, ctx)); - completionItems.add(item); + completionItems.add(new StaticCompletionItem(ctx, item)); } }); @@ -343,8 +340,9 @@ protected List getPackagesCompletionItems(LSContext ctx) { * @param context Language Server Service Operation Context * @return {@link List} Completion Item List */ - protected List getDelimiterBasedCompletionItems(LSContext context) { - Either, List> itemList = SymbolFilters.get(DelimiterBasedContentFilter.class) + protected List getDelimiterBasedCompletionItems(LSContext context) { + Either, List> itemList = + SymbolFilters.get(DelimiterBasedContentFilter.class) .filterItems(context); return this.getCompletionItemList(itemList, context); } @@ -354,9 +352,9 @@ protected List getDelimiterBasedCompletionItems(LSContext contex * * @return {@link Predicate} Symbol filter predicate */ - protected Predicate attachedSymbolFilter() { - return symbolInfo -> { - BSymbol bSymbol = symbolInfo.getScopeEntry().symbol; + protected Predicate attachedSymbolFilter() { + return scopeEntry -> { + BSymbol bSymbol = scopeEntry.symbol; return bSymbol instanceof BInvokableSymbol && ((bSymbol.flags & Flags.ATTACHED) == Flags.ATTACHED); }; } @@ -378,11 +376,12 @@ protected LSCompletionProvider getProvider(Class providerKey) { return LSCompletionProviderHolder.getInstance().getProvider(providerKey); } - protected List getCompletionItemsAfterOnKeyword(LSContext ctx) { - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - List filtered = this.filterListenerVariables(visibleSymbols); - List completionItems = new ArrayList<>(this.getCompletionItemList(filtered, ctx)); - completionItems.add(Snippet.KW_NEW.get().build(ctx)); + protected List getCompletionItemsAfterOnKeyword(LSContext ctx) { + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List filtered = this.filterListenerVariables(visibleSymbols); + List completionItems = + new ArrayList<>(this.getCompletionItemList(new ArrayList<>(filtered), ctx)); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_NEW.get())); return completionItems; } @@ -395,15 +394,15 @@ protected List getCompletionItemsAfterOnKeyword(LSContext ctx) { * @param onGlobal whether global variable definition * @return {@link List} List of completion Items */ - protected List getVarDefExpressionCompletions(LSContext context, boolean onGlobal) { - List completionItems = new ArrayList<>(); + protected List getVarDefExpressionCompletions(LSContext context, boolean onGlobal) { + List completionItems = new ArrayList<>(); Integer invocationType = context.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); try { Optional assignmentType = getAssignmentType(context, onGlobal); if (assignmentType.isPresent() && !(assignmentType.get() instanceof BLangUserDefinedType) && invocationType > -1) { - Either, List> filteredList = + Either, List> filteredList = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(context); completionItems.addAll(this.getCompletionItemList(filteredList, context)); return completionItems; @@ -420,15 +419,15 @@ protected List getVarDefExpressionCompletions(LSContext context, fillArrowFunctionSnippet((BLangFunctionTypeNode) assignmentType.get(), context, completionItems); } else if (assignmentType.isPresent() && assignmentType.get().type instanceof BServiceType) { completionItems.addAll(this.getVarDefCompletions(context)); - completionItems.add(Snippet.DEF_SERVICE_VAR.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_SERVICE_VAR.get())); } else if (assignmentType.isPresent() && assignmentType.get() instanceof BLangUserDefinedType) { completionItems.addAll( getUserDefinedTypeCompletions(context, (BLangUserDefinedType) assignmentType.get())); } else if (isTypeDesc) { - completionItems.add(Snippet.KW_TYPEOF.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_TYPEOF.get())); completionItems.addAll(getVarDefCompletions(context)); } else if (invocationType > -1) { - Either, List> filteredList = + Either, List> filteredList = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(context); return this.getCompletionItemList(filteredList, context); } else { @@ -441,10 +440,10 @@ protected List getVarDefExpressionCompletions(LSContext context, return completionItems; } - protected List getUserDefinedTypeCompletions(LSContext context, BLangUserDefinedType type) { + protected List getUserDefinedTypeCompletions(LSContext context, BLangUserDefinedType type) { List defaultTokenTypes = context.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); Integer invocationType = context.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); - List completionItems = new ArrayList<>(); + List completionItems = new ArrayList<>(); int newTokenIndex = defaultTokenTypes.indexOf(BallerinaParser.NEW); int lastColonIndex = defaultTokenTypes.lastIndexOf(BallerinaParser.COLON); int firstColonIndex = defaultTokenTypes.indexOf(BallerinaParser.COLON); @@ -452,9 +451,9 @@ protected List getUserDefinedTypeCompletions(LSContext context, String pkgAlias = type.pkgAlias.value; BSymbol bSymbol; - Optional pkgSymbol = this.getPackageSymbolFromAlias(context, pkgAlias); + Optional pkgSymbol = this.getPackageSymbolFromAlias(context, pkgAlias); if (pkgSymbol.isPresent()) { - Optional entry = pkgSymbol.get().getScopeEntry().symbol.scope.entries.values().stream() + Optional entry = pkgSymbol.get().symbol.scope.entries.values().stream() .filter(scopeEntry -> scopeEntry.symbol.getName().getValue().equals(typeName)).findAny(); if (!entry.isPresent()) { @@ -462,11 +461,11 @@ protected List getUserDefinedTypeCompletions(LSContext context, } bSymbol = entry.get().symbol; } else { - List typeSymbol = getSymbolByName(typeName, context); + List typeSymbol = getSymbolByName(typeName, context); if (typeSymbol.isEmpty()) { return completionItems; } - bSymbol = typeSymbol.get(0).getScopeEntry().symbol; + bSymbol = typeSymbol.get(0).symbol; } if (bSymbol == null) { @@ -475,7 +474,7 @@ protected List getUserDefinedTypeCompletions(LSContext context, if (bSymbol instanceof BRecordTypeSymbol) { if (invocationType > -1) { - Either, List> filteredList = + Either, List> filteredList = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(context); return this.getCompletionItemList(filteredList, context); } @@ -483,7 +482,7 @@ protected List getUserDefinedTypeCompletions(LSContext context, } if (!(bSymbol instanceof BObjectTypeSymbol)) { if (invocationType > -1) { - Either, List> filteredList = + Either, List> filteredList = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(context); return this.getCompletionItemList(filteredList, context); } @@ -504,14 +503,14 @@ protected List getUserDefinedTypeCompletions(LSContext context, ex: modName:ObjectName = new modName: ObjectName = new */ - Pair newWithTypeSign = CommonUtil.getFunctionInvocationSignature(initFunction.symbol, - typeName, - context); - completionItems.add(BFunctionCompletionItemBuilder.build(initFunction.symbol, newWithTypeSign.getRight(), - newWithTypeSign.getLeft(), context)); + Pair newWithTypeSign = getFunctionInvocationSignature(initFunction.symbol, typeName, + context); + CompletionItem cItem = BFunctionCompletionItemBuilder.build(initFunction.symbol, newWithTypeSign.getRight(), + newWithTypeSign.getLeft(), context); + completionItems.add(new SymbolCompletionItem(context, initFunction.symbol, cItem)); return completionItems; } else if (invocationType > -1) { - Either, List> filteredList = + Either, List> filteredList = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(context); return this.getCompletionItemList(filteredList, context); } @@ -522,6 +521,8 @@ protected List getUserDefinedTypeCompletions(LSContext context, newCItem = BFunctionCompletionItemBuilder.build(null, "new()", "new();", context); typeCItem = BFunctionCompletionItemBuilder.build(null, typeName + "()", typeName + "();", context); + completionItems.add(new SymbolCompletionItem(context, null, newCItem)); + completionItems.add(new SymbolCompletionItem(context, null, typeCItem)); } else { Pair newSign = CommonUtil.getFunctionInvocationSignature(initFunction.symbol, CommonKeys.NEW_KEYWORD_KEY, @@ -535,11 +536,11 @@ protected List getUserDefinedTypeCompletions(LSContext context, typeCItem = BFunctionCompletionItemBuilder.build(initFunction.symbol, newWithTypeSign.getRight(), newWithTypeSign.getLeft(), context); + completionItems.add(new SymbolCompletionItem(context, initFunction.symbol, newCItem)); + completionItems.add(new SymbolCompletionItem(context, initFunction.symbol, typeCItem)); } completionItems.addAll(getVarDefCompletions(context)); - completionItems.add(newCItem); - completionItems.add(Snippet.KW_NEW.get().build(context)); - completionItems.add(typeCItem); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_NEW.get())); return completionItems; } @@ -550,9 +551,9 @@ protected List getUserDefinedTypeCompletions(LSContext context, * @param ctx Language Server Context * @return {@link Optional} Completion List */ - protected List getResourceSnippets(LSContext ctx) { + protected List getResourceSnippets(LSContext ctx) { BLangNode symbolEnvNode = ctx.get(CompletionKeys.SCOPE_NODE_KEY); - List items = new ArrayList<>(); + List items = new ArrayList<>(); if (!(symbolEnvNode instanceof BLangService)) { return items; } @@ -570,8 +571,8 @@ protected List getResourceSnippets(LSContext ctx) { } } else { // Is ambiguous, suggest for all 'ws', 'ws-client' and 'http' services - items.add(Snippet.DEF_RESOURCE_HTTP.get().build(ctx)); - items.add(Snippet.DEF_RESOURCE_COMMON.get().build(ctx)); + items.add(new SnippetCompletionItem(ctx, Snippet.DEF_RESOURCE_HTTP.get())); + items.add(new SnippetCompletionItem(ctx, Snippet.DEF_RESOURCE_COMMON.get())); addAllWSClientResources(ctx, items, service); addAllWSResources(ctx, items, service); } @@ -592,24 +593,24 @@ protected List getResourceSnippets(LSContext ctx) { addAllWSResources(ctx, items, service); } else { // Is a 'http' service - items.add(Snippet.DEF_RESOURCE_HTTP.get().build(ctx)); + items.add(new SnippetCompletionItem(ctx, Snippet.DEF_RESOURCE_HTTP.get())); } } else { // Is ambiguous, suggest both 'ws' and 'http' addAllWSResources(ctx, items, service); - items.add(Snippet.DEF_RESOURCE_HTTP.get().build(ctx)); + items.add(new SnippetCompletionItem(ctx, Snippet.DEF_RESOURCE_HTTP.get())); } break; } return items; case "grpc": - items.add(Snippet.DEF_RESOURCE_GRPC.get().build(ctx)); + items.add(new SnippetCompletionItem(ctx, Snippet.DEF_RESOURCE_GRPC.get())); break; // case "websub": // addAllWebsubResources(ctx, items, service); // break; default: - items.add(Snippet.DEF_RESOURCE_COMMON.get().build(ctx)); + items.add(new SnippetCompletionItem(ctx, Snippet.DEF_RESOURCE_COMMON.get())); return items; } return items; @@ -620,7 +621,7 @@ protected List getResourceSnippets(LSContext ctx) { // addIfNotExists(Snippet.DEF_RESOURCE_WEBSUB_NOTIFY.get(), service, items, ctx); // } - private void addAllWSClientResources(LSContext ctx, List items, BLangService service) { + private void addAllWSClientResources(LSContext ctx, List items, BLangService service) { addIfNotExists(Snippet.DEF_RESOURCE_WS_CS_TEXT.get(), service, items, ctx); addIfNotExists(Snippet.DEF_RESOURCE_WS_CS_BINARY.get(), service, items, ctx); addIfNotExists(Snippet.DEF_RESOURCE_WS_CS_PING.get(), service, items, ctx); @@ -630,7 +631,7 @@ private void addAllWSClientResources(LSContext ctx, List items, addIfNotExists(Snippet.DEF_RESOURCE_WS_CS_CLOSE.get(), service, items, ctx); } - private void addAllWSResources(LSContext ctx, List items, BLangService service) { + private void addAllWSResources(LSContext ctx, List items, BLangService service) { addIfNotExists(Snippet.DEF_RESOURCE_WS_OPEN.get(), service, items, ctx); addIfNotExists(Snippet.DEF_RESOURCE_WS_TEXT.get(), service, items, ctx); addIfNotExists(Snippet.DEF_RESOURCE_WS_BINARY.get(), service, items, ctx); @@ -642,23 +643,26 @@ private void addAllWSResources(LSContext ctx, List items, BLangS } - protected Optional getPackageSymbolFromAlias(LSContext context, String alias) { - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - if (alias.isEmpty()) { + protected Optional getPackageSymbolFromAlias(LSContext context, String alias) { + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + Optional pkgForAlias = context.get(DocumentServiceKeys.CURRENT_DOC_IMPORTS_KEY).stream() + .filter(pkg -> pkg.alias.value.equals(alias)) + .findAny(); + if (alias.isEmpty() || !pkgForAlias.isPresent()) { return Optional.empty(); } return visibleSymbols.stream() - .filter(symbolInfo -> { - BSymbol symbol = symbolInfo.getScopeEntry().symbol; - return symbol instanceof BPackageSymbol && alias.equals(symbolInfo.getSymbolName()); + .filter(scopeEntry -> { + BSymbol symbol = scopeEntry.symbol; + return symbol == pkgForAlias.get().symbol; }) .findAny(); } - - protected List getSymbolByName(String name, LSContext context) { - List symbolInfos = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - return symbolInfos.parallelStream() - .filter(symbolInfo -> symbolInfo.getScopeEntry().symbol.getName().getValue().equals(name)) + + protected List getSymbolByName(String name, LSContext context) { + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + return visibleSymbols.parallelStream() + .filter(scopeEntry -> scopeEntry.symbol.getName().getValue().equals(name)) .collect(Collectors.toList()); } @@ -709,26 +713,22 @@ protected boolean isAnnotationAccessExpression(LSContext context) { /** * Populate the Ballerina Function Completion Item. * - * @param symbolInfo - symbol information + * @param scopeEntry - symbol Entry * @return completion item */ - private CompletionItem populateBallerinaFunctionCompletionItem(SymbolInfo symbolInfo, LSContext context) { - if (symbolInfo.isCustomOperation()) { - SymbolInfo.CustomOperationSignature signature = - symbolInfo.getCustomOperationSignature(); - return BFunctionCompletionItemBuilder.build(null, signature.getLabel(), signature.getInsertText(), context); - } - BSymbol bSymbol = symbolInfo.getScopeEntry().symbol; + private LSCompletionItem populateBallerinaFunctionCompletionItem(Scope.ScopeEntry scopeEntry, LSContext context) { + BSymbol bSymbol = scopeEntry.symbol; if (!(bSymbol instanceof BInvokableSymbol)) { return null; } - return BFunctionCompletionItemBuilder.build((BInvokableSymbol) bSymbol, context); + CompletionItem completionItem = BFunctionCompletionItemBuilder.build((BInvokableSymbol) bSymbol, context); + return new SymbolCompletionItem(context, bSymbol, completionItem); } - private List filterListenerVariables(List symbolInfos) { - return symbolInfos.stream() - .filter(symbolInfo -> { - BSymbol symbol = symbolInfo.getScopeEntry().symbol; + private List filterListenerVariables(List scopeEntries) { + return scopeEntries.stream() + .filter(scopeEntry -> { + BSymbol symbol = scopeEntry.symbol; return symbol instanceof BVarSymbol && CommonUtil.isListenerObject(symbol.type.tsymbol); }) .collect(Collectors.toList()); @@ -786,7 +786,7 @@ public static Optional getAssignmentType(LSContext context, boolean o } private void fillFunctionWithBodySnippet(BLangFunctionTypeNode functionTypeNode, LSContext context, - List completionItems) + List completionItems) throws LSCompletionException { List params = functionTypeNode.getParams(); @@ -799,7 +799,7 @@ private void fillFunctionWithBodySnippet(BLangFunctionTypeNode functionTypeNode, SnippetBlock.SnippetType.SNIPPET); // Populate the anonymous function signature completion item - completionItems.add(snippetBlock.build(context)); + completionItems.add(new SnippetCompletionItem(context, snippetBlock)); } private String getFunctionSignature(List paramTypes, BLangType returnType, LSContext context) @@ -817,7 +817,7 @@ private String getFunctionSignature(List paramTypes, BLangType re } private void fillArrowFunctionSnippet(BLangFunctionTypeNode functionTypeNode, LSContext context, - List completionItems) throws LSCompletionException { + List completionItems) throws LSCompletionException { List params = functionTypeNode.getParams(); BLangType returnBLangType = functionTypeNode.getReturnTypeNode(); String paramSignature = this.getDynamicParamsSnippet(params, false, context); @@ -840,7 +840,7 @@ private void fillArrowFunctionSnippet(BLangFunctionTypeNode functionTypeNode, LS SnippetBlock.SnippetType.SNIPPET); // Populate the anonymous function signature completion item - completionItems.add(snippetBlock.build(context)); + completionItems.add(new SnippetCompletionItem(context, snippetBlock)); } private String getAnonFunctionSnippetBody(BLangType returnType, int numberOfParams) { @@ -918,45 +918,37 @@ private String getDynamicParamsSnippet(List paramTypes, boolean w * @param context Completion context * @return {@link List} List of resolved completion items */ - public List getVarDefCompletions(LSContext context) { - ArrayList completionItems = new ArrayList<>(); - List filteredList = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + public List getVarDefCompletions(LSContext context) { + ArrayList completionItems = new ArrayList<>(); + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); // Remove the functions without a receiver symbol, bTypes not being packages and attached functions - filteredList.removeIf(symbolInfo -> { - BSymbol bSymbol = symbolInfo.getScopeEntry().symbol; + visibleSymbols.removeIf(scopeEntry -> { + BSymbol bSymbol = scopeEntry.symbol; return (bSymbol instanceof BInvokableSymbol && ((BInvokableSymbol) bSymbol).receiverSymbol != null && CommonUtil.isValidInvokableSymbol(bSymbol)) - || (FilterUtils.isBTypeEntry(symbolInfo.getScopeEntry())) + || (FilterUtils.isBTypeEntry(scopeEntry)) || (bSymbol instanceof BInvokableSymbol && ((bSymbol.flags & Flags.ATTACHED) == Flags.ATTACHED)); }); - completionItems.addAll(getCompletionItemList(filteredList, context)); + completionItems.addAll(getCompletionItemList(visibleSymbols, context)); // Add the packages completion items. completionItems.addAll(getPackagesCompletionItems(context)); // Add the check keyword - CompletionItem checkKeyword = Snippet.KW_CHECK.get().build(context); - completionItems.add(checkKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_CHECK.get())); // Add the checkpanic keyword - CompletionItem checkPanicKeyword = Snippet.KW_CHECK_PANIC.get().build(context); - completionItems.add(checkPanicKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_CHECK_PANIC.get())); // Add the wait keyword - CompletionItem waitKeyword = Snippet.KW_WAIT.get().build(context); - completionItems.add(waitKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_WAIT.get())); // Add the start keyword - CompletionItem startKeyword = Snippet.KW_START.get().build(context); - completionItems.add(startKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_START.get())); // Add the flush keyword - CompletionItem flushKeyword = Snippet.KW_FLUSH.get().build(context); - completionItems.add(flushKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_FLUSH.get())); // Add the untaint keyword - CompletionItem untaintKeyword = Snippet.KW_UNTAINT.get().build(context); - completionItems.add(untaintKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_UNTAINT.get())); // Add But keyword item - CompletionItem butKeyword = Snippet.EXPR_MATCH.get().build(context); - completionItems.add(butKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.EXPR_MATCH.get())); // Add the trap expression keyword - CompletionItem trapExpression = Snippet.STMT_TRAP.get().build(context); - completionItems.add(trapExpression); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_TRAP.get())); return completionItems; } @@ -1047,7 +1039,8 @@ private boolean appendSingleQuoteForPackageInsertText(LSContext context) { return !lastToken.getText().startsWith("'"); } - private void addIfNotExists(SnippetBlock snippet, BLangService service, List items, LSContext ctx) { + private void addIfNotExists(SnippetBlock snippet, BLangService service, List items, + LSContext ctx) { boolean found = false; for (BLangFunction resource : service.getResources()) { if (snippet.getLabel().endsWith(resource.name.value + " " + ItemResolverConstants.RESOURCE)) { @@ -1055,7 +1048,7 @@ private void addIfNotExists(SnippetBlock snippet, BLangService service, List getCompletions(LSContext ctx) { + public List getCompletions(LSContext ctx) { return filterAnnotations(ctx); } /** * Filter the annotations. * - * @return {@link List} + * @return {@link List} list of filtered completion items */ - private List filterAnnotations(LSContext ctx) { - List completionItems = new ArrayList<>(); + private List filterAnnotations(LSContext ctx) { + List completionItems = new ArrayList<>(); List defaultTokenTypes = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); List defaultTokens = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); int annotationAccessIndex = defaultTokenTypes.indexOf(BallerinaParser.ANNOTATION_ACCESS); @@ -103,9 +105,9 @@ private List filterAnnotations(LSContext ctx) { return completionItems; } - private List getAnnotationsInModule(LSContext ctx) { + private List getAnnotationsInModule(LSContext ctx) { BLangPackage bLangPackage = ctx.get(DocumentServiceKeys.CURRENT_BLANG_PACKAGE_CONTEXT_KEY); - List completionItems = new ArrayList<>(); + List completionItems = new ArrayList<>(); List annotations = bLangPackage.topLevelNodes.stream() .filter(topLevelNode -> topLevelNode instanceof BLangAnnotation) .map(topLevelNode -> (BLangAnnotation) topLevelNode) @@ -119,13 +121,13 @@ private List getAnnotationsInModule(LSContext ctx) { annotationItem.setInsertTextFormat(InsertTextFormat.Snippet); annotationItem.setDetail(ItemResolverConstants.ANNOTATION_TYPE); annotationItem.setKind(CompletionItemKind.Property); - completionItems.add(annotationItem); + completionItems.add(new SymbolCompletionItem(ctx, symbol, annotationItem)); }); return completionItems; } - private CompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol, + private LSCompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol, LSContext ctx, CommonToken pkgAlias, Map pkgAliasMap) { PackageID currentPkgID = ctx.get(DocumentServiceKeys.CURRENT_PACKAGE_ID_KEY); @@ -151,7 +153,7 @@ private CompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotat annotationItem.setKind(CompletionItemKind.Property); if (currentPkgID != null && currentPkgID.name.value.equals(packageID.name.value)) { // If the annotation resides within the current package, no need to set the additional text edits - return annotationItem; + return new SymbolCompletionItem(ctx, annotationSymbol, annotationItem); } List imports = ctx.get(DocumentServiceKeys.CURRENT_DOC_IMPORTS_KEY); Optional pkgImport = imports.stream() @@ -172,7 +174,7 @@ private CompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotat annotationItem.setAdditionalTextEdits(CommonUtil.getAutoImportTextEdits(packageID.orgName.getValue(), packageID.name.getValue(), ctx)); } - return annotationItem; + return new SymbolCompletionItem(ctx, annotationSymbol, annotationItem); } private String getInsertText(String aliasComponent, BAnnotationSymbol annotationSymbol, boolean withAlias) { diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/AnnotationAttachmentContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/AnnotationAttachmentContextProvider.java index ebc5d271bedf..cbd57463615a 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/AnnotationAttachmentContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/AnnotationAttachmentContextProvider.java @@ -24,12 +24,12 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.AnnotationNodeKind; import org.ballerinalang.langserver.commons.completion.CompletionKeys; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.compiler.DocumentServiceKeys; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; import org.ballerinalang.model.elements.PackageID; import org.ballerinalang.model.tree.NodeKind; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BAnnotationSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.Symbols; @@ -54,7 +54,7 @@ public AnnotationAttachmentContextProvider() { } @Override - public List getCompletions(LSContext ctx) { + public List getCompletions(LSContext ctx) { List rhsTokenTypes = ctx.get(SourcePruneKeys.RHS_DEFAULT_TOKEN_TYPES_KEY); AnnotationNodeKind annotationNodeKind = ctx.get(CompletionKeys.NEXT_NODE_KEY); if (annotationNodeKind == null && rhsTokenTypes.contains(BallerinaParser.EXTERNAL)) { @@ -70,8 +70,8 @@ public List getCompletions(LSContext ctx) { * * @return {@link List} */ - private ArrayList filterAnnotations(AnnotationNodeKind attachmentPoint, LSContext ctx) { - ArrayList completionItems = new ArrayList<>(); + private List filterAnnotations(AnnotationNodeKind attachmentPoint, LSContext ctx) { + List completionItems = new ArrayList<>(); List lhsTokenTypes = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); List lhsDefaultTokens = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); Map pkgAliasMap = ctx.get(DocumentServiceKeys.CURRENT_DOC_IMPORTS_KEY).stream() @@ -108,10 +108,10 @@ private ArrayList filterAnnotations(AnnotationNodeKind attachmen return completionItems; } - private List getAnnotationsInModule(LSContext ctx, AnnotationNodeKind kind, + private List getAnnotationsInModule(LSContext ctx, AnnotationNodeKind kind, Map pkgAliasMap) { BLangPackage bLangPackage = ctx.get(DocumentServiceKeys.CURRENT_BLANG_PACKAGE_CONTEXT_KEY); - List completionItems = new ArrayList<>(); + List completionItems = new ArrayList<>(); List annotations = bLangPackage.topLevelNodes.stream() .filter(topLevelNode -> topLevelNode instanceof BLangAnnotation) .map(topLevelNode -> (BLangAnnotation) topLevelNode) diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/AssignmentStatementContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/AssignmentStatementContextProvider.java index b35486a62b8c..4e375cffa6ae 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/AssignmentStatementContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/AssignmentStatementContextProvider.java @@ -24,13 +24,16 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; +import org.ballerinalang.langserver.completions.SymbolCompletionItem; import org.ballerinalang.langserver.completions.builder.BFunctionCompletionItemBuilder; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BObjectTypeSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol; @@ -56,15 +59,15 @@ public AssignmentStatementContextProvider() { } @Override - public List getCompletions(LSContext ctx) throws LSCompletionException { - List completionItems = new ArrayList<>(); + public List getCompletions(LSContext ctx) throws LSCompletionException { + List completionItems = new ArrayList<>(); List defaultTokenTypes = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); List defaultTokens = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); int assignTokenIndex = defaultTokenTypes.indexOf(BallerinaParser.ASSIGN); int newTokenIndex = defaultTokenTypes.indexOf(BallerinaParser.NEW); String lhsToken = defaultTokens.get(assignTokenIndex - 1).getText(); Optional lhsTokenSymbol = this.getSymbolByName(lhsToken, ctx).stream() - .map(symbolInfo -> symbolInfo.getScopeEntry().symbol) + .map(scopeEntry -> scopeEntry.symbol) .filter(symbol -> symbol instanceof BVarSymbol) .findFirst(); @@ -87,32 +90,29 @@ public List getCompletions(LSContext ctx) throws LSCompletionExc ctx); CompletionItem cItem = BFunctionCompletionItemBuilder.build(initFunction, newSign.getRight(), newSign.getLeft(), ctx); - completionItems.add(cItem); + completionItems.add(new SymbolCompletionItem(ctx, initFunction, cItem)); } - List filteredList = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List filteredList = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); filteredList.removeIf(this.attachedSymbolFilter()); - filteredList.removeIf(symbolInfo -> symbolInfo.getScopeEntry().symbol instanceof BTypeSymbol); - completionItems.addAll(this.getCompletionItemList(filteredList, ctx)); + filteredList.removeIf(scopeEntry -> scopeEntry.symbol instanceof BTypeSymbol); + completionItems.addAll(this.getCompletionItemList(new ArrayList<>(filteredList), ctx)); completionItems.addAll(this.getPackagesCompletionItems(ctx)); - fillStaticItems(completionItems, ctx); + fillStaticSnippetItems(completionItems, ctx); return completionItems; } - - private void fillStaticItems(List completionItems, LSContext context) { + + private void fillStaticSnippetItems(List completionItems, LSContext context) { // Add the wait keyword - CompletionItem waitKeyword = Snippet.KW_WAIT.get().build(context); - completionItems.add(waitKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_WAIT.get())); // Add the start keyword - CompletionItem startKeyword = Snippet.KW_START.get().build(context); - completionItems.add(startKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_START.get())); // Add the flush keyword - CompletionItem flushKeyword = Snippet.KW_FLUSH.get().build(context); - completionItems.add(flushKeyword); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_FLUSH.get())); } - private List getCompletionsAfterNewKW(BSymbol lhsSymbol, LSContext context) { - List completionItems = new ArrayList<>(); + private List getCompletionsAfterNewKW(BSymbol lhsSymbol, LSContext context) { + List completionItems = new ArrayList<>(); if (!(lhsSymbol.type.tsymbol instanceof BObjectTypeSymbol)) { return completionItems; } @@ -126,8 +126,8 @@ private List getCompletionsAfterNewKW(BSymbol lhsSymbol, LSConte context); CompletionItem cItem = BFunctionCompletionItemBuilder.build(initFunction, newSign.getRight(), newSign.getLeft(), context); - completionItems.add(cItem); - + completionItems.add(new SymbolCompletionItem(context, initFunction, cItem)); + return completionItems; } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/DefinitionContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/DefinitionContextProvider.java index a974b54fee35..b6e0764d4ee6 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/DefinitionContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/DefinitionContextProvider.java @@ -22,12 +22,13 @@ import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.common.CommonKeys; import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.ArrayList; import java.util.List; @@ -46,8 +47,8 @@ public DefinitionContextProvider() { } @Override - public List getCompletions(LSContext context) { - List completionItems = new ArrayList<>(); + public List getCompletions(LSContext context) { + List completionItems = new ArrayList<>(); List lhsDefaultTokens = context.get(SourcePruneKeys.LHS_TOKENS_KEY).stream() .filter(commonToken -> commonToken.getChannel() == Token.DEFAULT_CHANNEL) .map(CommonToken::getType) @@ -59,7 +60,7 @@ public List getCompletions(LSContext context) { break; case BallerinaParser.FINAL: case BallerinaParser.CONST: - completionItems.addAll(this.getTypesAndPackages(context)); + completionItems.addAll(this.getTypesAndPackagesItems(context)); break; default: break; @@ -67,24 +68,24 @@ public List getCompletions(LSContext context) { return completionItems; } - private List getItemsAfterPublic(LSContext context) { - ArrayList completionItems = new ArrayList<>(); - completionItems.add(getStaticItem(context, Snippet.DEF_FUNCTION)); - completionItems.add(getStaticItem(context, Snippet.DEF_ANNOTATION)); - completionItems.add(getStaticItem(context, Snippet.DEF_OBJECT_SNIPPET)); - completionItems.add(getStaticItem(context, Snippet.DEF_RECORD)); - completionItems.add(getStaticItem(context, Snippet.DEF_CLOSED_RECORD)); - completionItems.add(getStaticItem(context, Snippet.KW_LISTENER)); - completionItems.add(getStaticItem(context, Snippet.KW_TYPE)); - completionItems.add(getStaticItem(context, Snippet.KW_CONST)); - completionItems.add(getStaticItem(context, Snippet.KW_ANNOTATION)); - completionItems.add(getStaticItem(context, Snippet.KW_FUNCTION)); + private List getItemsAfterPublic(LSContext context) { + ArrayList completionItems = new ArrayList<>(); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_ANNOTATION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_OBJECT_SNIPPET.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_RECORD.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_CLOSED_RECORD.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_LISTENER.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_TYPE.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_CONST.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_ANNOTATION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_FUNCTION.get())); return completionItems; } - private List getTypesAndPackages(LSContext ctx) { - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - List completionItems = new ArrayList<>(this.getBasicTypes(visibleSymbols)); + private List getTypesAndPackagesItems(LSContext ctx) { + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List completionItems = new ArrayList<>(this.getBasicTypesItems(ctx, visibleSymbols)); completionItems.addAll(this.getPackagesCompletionItems(ctx)); return completionItems; diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ExternalFunctionBodyContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ExternalFunctionBodyContextProvider.java index 896860be38fb..69744ae9ea5a 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ExternalFunctionBodyContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ExternalFunctionBodyContextProvider.java @@ -22,10 +22,11 @@ import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import java.util.ArrayList; @@ -46,8 +47,8 @@ public ExternalFunctionBodyContextProvider() { } @Override - public List getCompletions(LSContext context) { - List completionItems = new ArrayList<>(); + public List getCompletions(LSContext context) { + List completionItems = new ArrayList<>(); List lhsDefaultTokens = context.get(SourcePruneKeys.LHS_TOKENS_KEY).stream() .filter(commonToken -> commonToken.getChannel() == Token.DEFAULT_CHANNEL) .collect(Collectors.toList()); @@ -61,7 +62,7 @@ public List getCompletions(LSContext context) { function x = ex Suggest the external keyword */ - return Collections.singletonList(Snippet.KW_EXTERNAL.get().build(context)); + return Collections.singletonList(new SnippetCompletionItem(context, Snippet.KW_EXTERNAL.get())); } return completionItems; } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/GlobalVarDefContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/GlobalVarDefContextProvider.java index 3e4cee30daf6..6b7e4f9a527b 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/GlobalVarDefContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/GlobalVarDefContextProvider.java @@ -24,14 +24,14 @@ import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.filters.DelimiterBasedContentFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BPackageSymbol; import java.util.ArrayList; @@ -49,15 +49,15 @@ public GlobalVarDefContextProvider() { } @Override - public List getCompletions(LSContext ctx) { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext ctx) { + ArrayList completionItems = new ArrayList<>(); List lhsDefaultTokens = ctx.get(SourcePruneKeys.LHS_TOKENS_KEY).stream() .filter(commonToken -> commonToken.getChannel() == Token.DEFAULT_CHANNEL) .collect(Collectors.toList()); Optional assignToken = lhsDefaultTokens.stream() .filter(commonToken -> commonToken.getType() == BallerinaParser.ASSIGN) .findAny(); - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); if (lhsDefaultTokens.isEmpty()) { return completionItems; @@ -65,18 +65,30 @@ public List getCompletions(LSContext ctx) { int firstToken = lhsDefaultTokens.get(0).getType(); int invocationOrDelimiterTokenType = ctx.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); - Optional listenerKWToken = lhsDefaultTokens.stream() - .filter(commonToken -> commonToken.getType() == BallerinaParser.LISTENER) - .findAny(); + + // Consider the Listener keyword and suggest the listener type completions + if (this.suggestListeners(lhsDefaultTokens)) { + if (invocationOrDelimiterTokenType > -1) { + int pkgDelimiterIndex = lhsDefaultTokens.stream() + .map(CommonToken::getType) + .collect(Collectors.toList()) + .indexOf(BallerinaParser.COLON); + String pkgAlias = lhsDefaultTokens.get(pkgDelimiterIndex - 1).getText(); + completionItems.addAll(this.getListenersFromPackage(ctx, pkgAlias)); + + return completionItems; + } + completionItems.addAll(this.getListenersAndPackagesItems(ctx)); + + return completionItems; + } if (lhsDefaultTokens.size() <= 2) { - if (listenerKWToken.isPresent()) { - completionItems.addAll(this.getListenersAndPackages(ctx)); - } else if (firstToken == BallerinaParser.FINAL) { - completionItems.addAll(this.getBasicTypes(visibleSymbols)); + if (firstToken == BallerinaParser.FINAL) { + completionItems.addAll(this.getBasicTypesItems(ctx, visibleSymbols)); completionItems.addAll(this.getPackagesCompletionItems(ctx)); } else if (BallerinaParser.COLON == invocationOrDelimiterTokenType) { - Either, List> pkgContent = SymbolFilters + Either, List> pkgContent = SymbolFilters .get(DelimiterBasedContentFilter.class).filterItems(ctx); completionItems.addAll(this.getCompletionItemList(pkgContent, ctx)); } else { @@ -84,19 +96,9 @@ public List getCompletions(LSContext ctx) { completionItems.addAll(this.getPackagesCompletionItems(ctx)); } } else if (invocationOrDelimiterTokenType > -1) { - if (listenerKWToken.isPresent()) { - int pkgDelimiterIndex = lhsDefaultTokens.stream() - .map(CommonToken::getType) - .collect(Collectors.toList()) - .indexOf(BallerinaParser.COLON); - String pkgAlias = lhsDefaultTokens.get(pkgDelimiterIndex - 1).getText(); - completionItems.addAll(this.getListenersFromPackage(ctx, pkgAlias)); - } else { - Either, List> filteredList = - SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(ctx); - completionItems.addAll(this.getCompletionItemList(filteredList, ctx)); - } - // TODO: usage of index + Either, List> filteredList = + SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(ctx); + completionItems.addAll(this.getCompletionItemList(filteredList, ctx)); } else if (assignToken.isPresent()) { completionItems.addAll(this.getVarDefExpressionCompletions(ctx, true)); } else { @@ -105,45 +107,52 @@ public List getCompletions(LSContext ctx) { } return completionItems; } - - private List getListenersAndPackages(LSContext context) { - ArrayList completionItems = new ArrayList<>(this.getPackagesCompletionItems(context)); - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - List listeners = visibleSymbols.stream() - .filter(symbolInfo -> CommonUtil.isListenerObject(symbolInfo.getScopeEntry().symbol)) + + private List getListenersAndPackagesItems(LSContext context) { + List completionItems = new ArrayList<>(this.getPackagesCompletionItems(context)); + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List listeners = visibleSymbols.stream() + .filter(scopeEntry -> CommonUtil.isListenerObject(scopeEntry.symbol)) .collect(Collectors.toList()); - completionItems.addAll(this.getCompletionItemList(listeners, context)); + completionItems.addAll(this.getCompletionItemList(new ArrayList<>(listeners), context)); return completionItems; } - private List getListenersFromPackage(LSContext context, String alias) { - ArrayList completionItems = new ArrayList<>(); - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - Optional packageSymbolInfo = visibleSymbols.stream() - .filter(symbolInfo -> symbolInfo.getScopeEntry().symbol instanceof BPackageSymbol - && symbolInfo.getSymbolName().equals(alias)) + private List getListenersFromPackage(LSContext context, String alias) { + ArrayList completionItems = new ArrayList<>(); + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + Optional packageSymbolInfo = visibleSymbols.stream() + .filter(scopeEntry -> scopeEntry.symbol instanceof BPackageSymbol + && scopeEntry.symbol.name.getValue().equals(alias)) .findAny(); - if (!packageSymbolInfo.isPresent() - || !(packageSymbolInfo.get().getScopeEntry().symbol instanceof BPackageSymbol)) { + if (!packageSymbolInfo.isPresent() || !(packageSymbolInfo.get().symbol instanceof BPackageSymbol)) { return completionItems; } - List listeners = new ArrayList<>(); - ((BPackageSymbol) packageSymbolInfo.get().getScopeEntry().symbol).scope.entries.forEach((name, scopeEntry) -> { - if (CommonUtil.isListenerObject(scopeEntry.symbol)) { - listeners.add(new SymbolInfo(scopeEntry.symbol.getName().getValue(), scopeEntry)); - } - }); + List listeners = ((BPackageSymbol) packageSymbolInfo.get().symbol).scope.entries.values() + .stream() + .filter(scopeEntry -> CommonUtil.isListenerObject(scopeEntry.symbol)) + .collect(Collectors.toList()); completionItems.addAll(this.getCompletionItemList(listeners, context)); return completionItems; } - private List getAllTopLevelItems(LSContext ctx) { - ArrayList completionItems = new ArrayList<>(); - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + private List getAllTopLevelItems(LSContext ctx) { + ArrayList completionItems = new ArrayList<>(); + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); completionItems.addAll(this.addTopLevelItems(ctx)); - completionItems.addAll(this.getBasicTypes(visibleSymbols)); + completionItems.addAll(this.getBasicTypesItems(ctx, visibleSymbols)); return completionItems; } + + private boolean suggestListeners(List lhsDefaultTokens) { + List tokenTypes = lhsDefaultTokens.stream() + .map(CommonToken::getType) + .collect(Collectors.toList()); + int assignToken = tokenTypes.indexOf(BallerinaParser.ASSIGN); + int listenerToken = tokenTypes.indexOf(BallerinaParser.LISTENER); + + return assignToken == -1 && listenerToken > -1; + } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/IfWhileConditionContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/IfWhileConditionContextProvider.java index acd5852f2689..a002a199a870 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/IfWhileConditionContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/IfWhileConditionContextProvider.java @@ -24,14 +24,14 @@ import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.filters.DelimiterBasedContentFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.ArrayList; import java.util.List; @@ -50,9 +50,9 @@ public IfWhileConditionContextProvider() { } @Override - public List getCompletions(LSContext context) { + public List getCompletions(LSContext context) { List lhsTokens = context.get(SourcePruneKeys.LHS_TOKENS_KEY); - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); if (lhsTokens == null) { return this.getExpressionCompletions(context, visibleSymbols); @@ -70,14 +70,14 @@ public List getCompletions(LSContext context) { if (invocationOrDelimiterTokenType > -1) { if (invocationOrDelimiterTokenType == BallerinaParser.COLON && isTypeGuardCondition) { String pkgName = lhsDefaultTokens.get(tokenTypes.indexOf(invocationOrDelimiterTokenType) - 1).getText(); - return this.getTypesInPackage(visibleSymbols, pkgName, context); + return this.getTypeItemsInPackage(visibleSymbols, pkgName, context); } - Either, List> items = SymbolFilters.get(DelimiterBasedContentFilter.class) - .filterItems(context); + Either, List> items = + SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(context); return this.getCompletionItemList(items, context); } if (isTypeGuardCondition) { - return this.getBasicTypes(visibleSymbols); + return this.getBasicTypesItems(context, visibleSymbols); } return this.getExpressionCompletions(context, visibleSymbols); @@ -87,8 +87,8 @@ private boolean isTypeGuardCondition(List tokenTypes) { return tokenTypes.contains(BallerinaParser.IS); } - private List getExpressionCompletions(LSContext context, List visibleSymbols) { - List completionItems = new ArrayList<>(this.getCompletionItemList(visibleSymbols, context)); + private List getExpressionCompletions(LSContext context, List visibleSymbols) { + List completionItems = this.getCompletionItemList(new ArrayList<>(visibleSymbols), context); completionItems.addAll(this.getPackagesCompletionItems(context)); return completionItems; diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ImportDeclarationContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ImportDeclarationContextProvider.java index 6e6f1e39e0cc..601e7367ed96 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ImportDeclarationContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ImportDeclarationContextProvider.java @@ -22,13 +22,14 @@ import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.commons.workspace.LSDocumentIdentifier; import org.ballerinalang.langserver.compiler.DocumentServiceKeys; import org.ballerinalang.langserver.compiler.LSPackageLoader; import org.ballerinalang.langserver.compiler.common.modal.BallerinaPackage; +import org.ballerinalang.langserver.completions.StaticCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.ItemResolverConstants; -import org.ballerinalang.langserver.completions.util.Priority; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; @@ -50,8 +51,8 @@ public ImportDeclarationContextProvider() { } @Override - public List getCompletions(LSContext ctx) { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext ctx) { + ArrayList completionItems = new ArrayList<>(); List packagesList = new ArrayList<>(); Stream.of(LSPackageLoader.getSdkPackages(), LSPackageLoader.getHomeRepoPackages()) .forEach(packagesList::addAll); @@ -65,22 +66,22 @@ public List getCompletions(LSContext ctx) { if (divIndex > -1 && (divIndex == lhsDefaultTokenTypes.size() - 1 || divIndex == lhsDefaultTokenTypes.size() - 2)) { String orgName = lhsDefaultTokens.get(lhsDefaultTokenTypes.indexOf(BallerinaParser.DIV) - 1).getText(); - completionItems.addAll(this.getPackageNameCompletions(orgName, packagesList)); + completionItems.addAll(this.getPackageNameCompletions(ctx, orgName, packagesList)); } else if (importTokenIndex > -1 && (importTokenIndex == lhsDefaultTokenTypes.size() - 1 || importTokenIndex == lhsDefaultTokenTypes.size() - 2)) { completionItems.addAll(this.getItemsIncludingOrgName(packagesList, ctx)); } else if (importTokenIndex > -1 && lhsDefaultTokenTypes.size() >= 2 && (lastToken.getChannel() == Token.HIDDEN_CHANNEL || lhsTokens.get(lhsTokens.size() - 2).getChannel() == Token.HIDDEN_CHANNEL)) { - completionItems.add(getAsKeyword()); + completionItems.add(getAsKeyword(ctx)); } return completionItems; } - private ArrayList getItemsIncludingOrgName(List packagesList, LSContext ctx) { + private ArrayList getItemsIncludingOrgName(List packagesList, LSContext ctx) { List orgNames = new ArrayList<>(); - ArrayList completionItems = new ArrayList<>(); + ArrayList completionItems = new ArrayList<>(); packagesList.forEach(pkg -> { String fullPkgNameLabel = pkg.getOrgName() + "/" + pkg.getPackageName(); @@ -92,12 +93,10 @@ private ArrayList getItemsIncludingOrgName(List getItemsIncludingOrgName(List projectModules = lsDocument.getProjectModules(); projectModules.forEach(module -> { if (!module.equals(ownerModule)) { - completionItems.add(getImportCompletion(module, module)); + completionItems.add(getImportCompletion(ctx, module, module)); } }); } @@ -124,8 +123,9 @@ private String getLangLibModuleNameInsertText(String pkgName) { return pkgName.replace(".", ".'") + ";"; } - private ArrayList getPackageNameCompletions(String orgName, List packagesList) { - ArrayList completionItems = new ArrayList<>(); + private ArrayList getPackageNameCompletions(LSContext context, String orgName, + List packagesList) { + ArrayList completionItems = new ArrayList<>(); List pkgNameLabels = new ArrayList<>(); packagesList.forEach(ballerinaPackage -> { @@ -140,30 +140,30 @@ private ArrayList getPackageNameCompletions(String orgName, List } pkgNameLabels.add(packageName); // Do not add the semi colon at the end of the insert text since the user might type the as keyword - completionItems.add(getImportCompletion(packageName, insertText)); + completionItems.add(getImportCompletion(context, packageName, insertText)); } }); return completionItems; } - private static CompletionItem getImportCompletion(String label, String insertText) { + private static LSCompletionItem getImportCompletion(LSContext context, String label, String insertText) { CompletionItem item = new CompletionItem(); item.setLabel(label); item.setInsertText(insertText); item.setKind(CompletionItemKind.Module); item.setDetail(ItemResolverConstants.PACKAGE_TYPE); - return item; + return new StaticCompletionItem(context, item); } - private static CompletionItem getAsKeyword() { + private static LSCompletionItem getAsKeyword(LSContext context) { CompletionItem item = new CompletionItem(); item.setLabel("as"); item.setInsertText("as "); item.setKind(CompletionItemKind.Keyword); item.setDetail(ItemResolverConstants.KEYWORD_TYPE); - return item; + return new StaticCompletionItem(context, item); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/InvocationArgsContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/InvocationArgsContextProvider.java index 5a5e25c408f6..3cb50d7dea6e 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/InvocationArgsContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/InvocationArgsContextProvider.java @@ -23,13 +23,14 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.completions.util.filters.DelimiterBasedContentFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol; import org.wso2.ballerinalang.util.Flags; @@ -50,8 +51,8 @@ public InvocationArgsContextProvider() { } @Override - public List getCompletions(LSContext context) throws LSCompletionException { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext context) throws LSCompletionException { + ArrayList completionItems = new ArrayList<>(); int invocationOrDelimiterTokenType = context.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); if (this.isAnnotationAccessExpression(context)) { @@ -59,14 +60,14 @@ public List getCompletions(LSContext context) throws LSCompletio } if (invocationOrDelimiterTokenType > -1) { - Either, List> filtered = SymbolFilters + Either, List> filtered = SymbolFilters .get(DelimiterBasedContentFilter.class).filterItems(context); return this.getCompletionItemList(filtered, context); } - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); // Remove the functions without a receiver symbol, bTypes not being packages and attached functions - visibleSymbols.removeIf(symbolInfo -> { - BSymbol bSymbol = symbolInfo.getScopeEntry().symbol; + visibleSymbols.removeIf(scopeEntry -> { + BSymbol bSymbol = scopeEntry.symbol; return (bSymbol instanceof BInvokableSymbol && ((BInvokableSymbol) bSymbol).receiverSymbol != null && CommonUtil.isValidInvokableSymbol(bSymbol)) @@ -75,7 +76,7 @@ public List getCompletions(LSContext context) throws LSCompletio completionItems.addAll(getCompletionItemList(visibleSymbols, context)); completionItems.addAll(this.getPackagesCompletionItems(context)); // Add the untaint keyword - CompletionItem untaintKeyword = Snippet.KW_UNTAINT.get().build(context); + LSCompletionItem untaintKeyword = new SnippetCompletionItem(context, Snippet.KW_UNTAINT.get()); completionItems.add(untaintKeyword); return completionItems; diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/InvocationOrFieldAccessContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/InvocationOrFieldAccessContextProvider.java index 96e295db4852..faab0b8d8a64 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/InvocationOrFieldAccessContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/InvocationOrFieldAccessContextProvider.java @@ -19,12 +19,12 @@ import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.filters.DelimiterBasedContentFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.List; @@ -39,9 +39,9 @@ public InvocationOrFieldAccessContextProvider() { } @Override - public List getCompletions(LSContext context) { - Either, List> content = SymbolFilters.get(DelimiterBasedContentFilter.class) - .filterItems(context); + public List getCompletions(LSContext context) { + Either, List> content = + SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(context); return this.getCompletionItemList(content, context); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/MatchStatementContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/MatchStatementContextProvider.java index 24d1ffa86fdc..ba328bec89cf 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/MatchStatementContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/MatchStatementContextProvider.java @@ -25,19 +25,20 @@ import org.ballerinalang.langserver.common.utils.FilterUtils; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SymbolCompletionItem; import org.ballerinalang.langserver.completions.builder.BFunctionCompletionItemBuilder; import org.ballerinalang.langserver.completions.builder.BTypeCompletionItemBuilder; import org.ballerinalang.langserver.completions.builder.BVariableCompletionItemBuilder; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.filters.DelimiterBasedContentFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; -import org.ballerinalang.langserver.completions.util.sorters.MatchContextItemSorter; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.InsertTextFormat; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BPackageSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol; @@ -67,58 +68,59 @@ public MatchStatementContextProvider() { } @Override - public List getCompletions(LSContext ctx) { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext ctx) { + ArrayList completionItems = new ArrayList<>(); List defaultTokens = ctx.get(SourcePruneKeys.LHS_TOKENS_KEY).stream() .filter(commonToken -> commonToken.getChannel() == Token.DEFAULT_CHANNEL) .collect(Collectors.toList()); List defaultTokenTypes = defaultTokens.stream().map(CommonToken::getType).collect(Collectors.toList()); - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); int delimiter = ctx.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); if (delimiter == BallerinaParser.COLON) { - Either, List> moduleContent = + Either, List> moduleContent = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(ctx); return this.getCompletionItemList(moduleContent, ctx); } else if (delimiter > -1) { String varName = defaultTokens.get(defaultTokenTypes.indexOf(delimiter) - 1).getText(); - List filteredList = FilterUtils.filterVariableEntriesOnDelimiter(ctx, varName, delimiter + List filteredList = FilterUtils.filterVariableEntriesOnDelimiter(ctx, varName, delimiter , defaultTokens, defaultTokenTypes.lastIndexOf(delimiter)); filteredList.removeIf(CommonUtil.invalidSymbolsPredicate()); - filteredList.forEach(symbolInfo -> { - if (CommonUtil.isValidInvokableSymbol(symbolInfo.getScopeEntry().symbol)) { - BSymbol scopeEntrySymbol = symbolInfo.getScopeEntry().symbol; + filteredList.forEach(scopeEntry -> { + if (CommonUtil.isValidInvokableSymbol(scopeEntry.symbol)) { + BSymbol scopeEntrySymbol = scopeEntry.symbol; completionItems.add(this.fillInvokableSymbolMatchSnippet((BInvokableSymbol) scopeEntrySymbol, ctx)); } }); } else { visibleSymbols.removeIf(CommonUtil.invalidSymbolsPredicate()); - visibleSymbols.forEach(symbolInfo -> { - BSymbol bSymbol = symbolInfo.getScopeEntry().symbol; - if (CommonUtil.isValidInvokableSymbol(symbolInfo.getScopeEntry().symbol) + visibleSymbols.forEach(scopeEntry -> { + BSymbol bSymbol = scopeEntry.symbol; + if (CommonUtil.isValidInvokableSymbol(scopeEntry.symbol) && ((bSymbol.flags & Flags.ATTACHED) != Flags.ATTACHED)) { completionItems.add(this.fillInvokableSymbolMatchSnippet((BInvokableSymbol) bSymbol, ctx)); - } else if (!(symbolInfo.getScopeEntry().symbol instanceof BInvokableSymbol) + } else if (!(scopeEntry.symbol instanceof BInvokableSymbol) && bSymbol instanceof BVarSymbol) { - fillVarSymbolMatchSnippet((BVarSymbol) bSymbol, completionItems); - String typeName = symbolInfo.getScopeEntry().symbol.type.toString(); - completionItems.add(BVariableCompletionItemBuilder.build((BVarSymbol) bSymbol, - symbolInfo.getSymbolName(), typeName)); + fillVarSymbolMatchSnippet(ctx, (BVarSymbol) bSymbol, completionItems); + String typeName = scopeEntry.symbol.type.toString(); + CompletionItem cItem = BVariableCompletionItemBuilder.build((BVarSymbol) bSymbol, + scopeEntry.symbol.name.value, typeName); + completionItems.add(new SymbolCompletionItem(ctx, scopeEntry.symbol, cItem)); } else if (bSymbol instanceof BPackageSymbol) { - completionItems.add(BTypeCompletionItemBuilder.build(bSymbol, symbolInfo.getSymbolName())); + CompletionItem cItem = BTypeCompletionItemBuilder.build(bSymbol, scopeEntry.symbol.name.getValue()); + completionItems.add(new SymbolCompletionItem(ctx, scopeEntry.symbol, cItem)); } }); } - ctx.put(CompletionKeys.ITEM_SORTER_KEY, MatchContextItemSorter.class); - return completionItems; } - private CompletionItem getVariableCompletionItem(BVarSymbol varSymbol, String matchFieldSnippet, String label) { + private LSCompletionItem getVariableCompletionItem(LSContext context, BVarSymbol varSymbol, + String matchFieldSnippet, String label) { CompletionItem completionItem = BVariableCompletionItemBuilder.build(varSymbol, label, varSymbol.type.toString()); completionItem.setInsertText(varSymbol.getName().getValue() + " " + matchFieldSnippet); completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - return completionItem; + return new SymbolCompletionItem(context, varSymbol, completionItem); } private String getFunctionSignature(BInvokableSymbol func) { @@ -132,26 +134,29 @@ private String getFunctionSignature(BInvokableSymbol func) { return signature.toString(); } - private CompletionItem fillInvokableSymbolMatchSnippet(BInvokableSymbol func, LSContext ctx) { + private LSCompletionItem fillInvokableSymbolMatchSnippet(BInvokableSymbol func, LSContext ctx) { String functionSignature = getFunctionSignature(func); String variableValuePattern = getVariableValueDestructurePattern(); String variableValueSnippet = this.generateMatchSnippet(variableValuePattern); - return BFunctionCompletionItemBuilder.build(func, functionSignature, - functionSignature + " " + variableValueSnippet, ctx); + CompletionItem completionItem = BFunctionCompletionItemBuilder.build(func, functionSignature, + functionSignature + " " + variableValueSnippet, ctx); + + return new SymbolCompletionItem(ctx, func, completionItem); } - private void fillVarSymbolMatchSnippet(BVarSymbol varSymbol, List completionItems) { + private void fillVarSymbolMatchSnippet(LSContext context, BVarSymbol varSymbol, + List completionItems) { BType symbolType = varSymbol.getType(); String varName = varSymbol.getName().getValue(); if (symbolType instanceof BTupleType || symbolType instanceof BRecordType) { String fixedValuePattern = "\t" + generateMatchPattern(getStructuredFixedValueMatch(symbolType)); String fixedValueSnippet = this.generateMatchSnippet(fixedValuePattern); - completionItems.add(this.getVariableCompletionItem(varSymbol, fixedValueSnippet, varName)); + completionItems.add(this.getVariableCompletionItem(context, varSymbol, fixedValueSnippet, varName)); } else { String variableValuePattern = "\t" + getVariableValueDestructurePattern(); String variableValueSnippet = this.generateMatchSnippet(variableValuePattern); - completionItems.add(this.getVariableCompletionItem(varSymbol, variableValueSnippet, varName)); + completionItems.add(this.getVariableCompletionItem(context, varSymbol, variableValueSnippet, varName)); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/NamespaceDeclarationContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/NamespaceDeclarationContextProvider.java index e8717848abf4..566d8565c238 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/NamespaceDeclarationContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/NamespaceDeclarationContextProvider.java @@ -21,6 +21,8 @@ import org.antlr.v4.runtime.Token; import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.StaticCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.ItemResolverConstants; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; @@ -45,8 +47,8 @@ public NamespaceDeclarationContextProvider() { } @Override - public List getCompletions(LSContext ctx) { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext ctx) { + ArrayList completionItems = new ArrayList<>(); List lhsTokens = ctx.get(SourcePruneKeys.LHS_TOKENS_KEY); List lhsDefaultTokens = lhsTokens.stream() .filter(commonToken -> commonToken.getChannel() == Token.DEFAULT_CHANNEL) @@ -56,19 +58,19 @@ public List getCompletions(LSContext ctx) { .collect(Collectors.toList()); if (lhsDefaultTokens.size() >= 2 && !lhsDefaultTokenTypes.contains(BallerinaParser.AS)) { - completionItems.add(getAsKeyword()); + completionItems.add(getAsKeyword(ctx)); } return completionItems; } - private static CompletionItem getAsKeyword() { + private static LSCompletionItem getAsKeyword(LSContext context) { CompletionItem item = new CompletionItem(); item.setLabel("as"); item.setInsertText("as "); item.setKind(CompletionItemKind.Keyword); item.setDetail(ItemResolverConstants.KEYWORD_TYPE); - return item; + return new StaticCompletionItem(context, item); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ObjectFieldDefinitionContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ObjectFieldDefinitionContextProvider.java index 4124982c6987..116dfcc049c1 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ObjectFieldDefinitionContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ObjectFieldDefinitionContextProvider.java @@ -23,13 +23,13 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; -import org.ballerinalang.langserver.completions.util.sorters.ActionAndFieldAccessContextItemSorter; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.ArrayList; import java.util.List; @@ -44,11 +44,11 @@ public ObjectFieldDefinitionContextProvider() { } @Override - public List getCompletions(LSContext ctx) throws LSCompletionException { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext ctx) throws LSCompletionException { + ArrayList completionItems = new ArrayList<>(); List lhsTokens = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); List lhsTokenTypes = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); int invocationOrDelimiterTokenType = ctx.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); if (lhsTokenTypes.contains(BallerinaParser.ASSIGN)) { @@ -57,25 +57,24 @@ public List getCompletions(LSContext ctx) throws LSCompletionExc if (invocationOrDelimiterTokenType == BallerinaParser.COLON) { String pkgName = lhsTokens.get(lhsTokenTypes.indexOf(invocationOrDelimiterTokenType) - 1).getText(); - completionItems.addAll(this.getTypesInPackage(visibleSymbols, pkgName, ctx)); - ctx.put(CompletionKeys.ITEM_SORTER_KEY, ActionAndFieldAccessContextItemSorter.class); + completionItems.addAll(this.getTypeItemsInPackage(visibleSymbols, pkgName, ctx)); return completionItems; } - completionItems.addAll(this.getBasicTypes(visibleSymbols)); + completionItems.addAll(this.getBasicTypesItems(ctx, visibleSymbols)); completionItems.addAll(this.getPackagesCompletionItems(ctx)); - completionItems.add(Snippet.DEF_FUNCTION_SIGNATURE.get().build(ctx)); - completionItems.add(Snippet.DEF_FUNCTION.get().build(ctx)); - completionItems.add(Snippet.DEF_REMOTE_FUNCTION.get().build(ctx)); - completionItems.add(Snippet.DEF_INIT_FUNCTION.get().build(ctx)); - completionItems.add(Snippet.DEF_ATTACH_FUNCTION.get().build(ctx)); - completionItems.add(Snippet.DEF_DETACH_FUNCTION.get().build(ctx)); - completionItems.add(Snippet.DEF_START_FUNCTION.get().build(ctx)); - completionItems.add(Snippet.DEF_GRACEFUL_STOP_FUNCTION.get().build(ctx)); - completionItems.add(Snippet.DEF_IMMEDIATE_STOP_FUNCTION.get().build(ctx)); - completionItems.add(Snippet.KW_PUBLIC.get().build(ctx)); - completionItems.add(Snippet.KW_PRIVATE.get().build(ctx)); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_FUNCTION_SIGNATURE.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_REMOTE_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_INIT_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_ATTACH_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_DETACH_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_START_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_GRACEFUL_STOP_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_IMMEDIATE_STOP_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_PUBLIC.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_PRIVATE.get())); return completionItems; } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/PanicStatementContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/PanicStatementContextProvider.java index a43d3d7af2c8..95e70670d041 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/PanicStatementContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/PanicStatementContextProvider.java @@ -20,10 +20,10 @@ import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.common.CommonKeys; import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.types.BErrorType; import java.util.ArrayList; @@ -40,12 +40,12 @@ public PanicStatementContextProvider() { } @Override - public List getCompletions(LSContext context) { - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - List filteredList = visibleSymbols.stream() - .filter(symbolInfo -> symbolInfo.getScopeEntry().symbol.type instanceof BErrorType) + public List getCompletions(LSContext context) { + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List filteredList = visibleSymbols.stream() + .filter(scopeEntry -> scopeEntry.symbol.type instanceof BErrorType) .collect(Collectors.toList()); - return this.getCompletionItemList(filteredList, context); + return this.getCompletionItemList(new ArrayList<>(filteredList), context); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ReturnParameterContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ReturnParameterContextProvider.java index 4e8275438382..59f566725124 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ReturnParameterContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ReturnParameterContextProvider.java @@ -22,12 +22,13 @@ import org.ballerinalang.langserver.common.CommonKeys; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.ArrayList; import java.util.List; @@ -50,27 +51,27 @@ public ReturnParameterContextProvider() { } @Override - public List getCompletions(LSContext ctx) { - List completionItems = new ArrayList<>(); + public List getCompletions(LSContext ctx) { + List completionItems = new ArrayList<>(); List defaultTokenTypes = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); List defaultTokens = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); Integer invocationTokenType = ctx.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); - List visibleSymbols = ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY); + List visibleSymbols = ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY); if (invocationTokenType == BallerinaParser.COLON) { String pkgName = defaultTokens.get(defaultTokenTypes.lastIndexOf(invocationTokenType) - 1).getText(); - return this.getTypesInPackage(visibleSymbols, pkgName, ctx); + return this.getTypeItemsInPackage(visibleSymbols, pkgName, ctx); } if (defaultTokenTypes.contains(BallerinaParser.RETURNS)) { /* suggest visible types and modules */ completionItems.addAll(this.getPackagesCompletionItems(ctx)); - completionItems.addAll(this.getBasicTypes(visibleSymbols)); + completionItems.addAll(this.getBasicTypesItems(ctx, visibleSymbols)); } else { - completionItems.add(Snippet.KW_RETURNS.get().build(ctx)); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_RETURNS.get())); } - + return completionItems; } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ReturnStatementContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ReturnStatementContextProvider.java index bb4c50b24754..31c340f0a72f 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ReturnStatementContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ReturnStatementContextProvider.java @@ -22,14 +22,15 @@ import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.completions.util.filters.DelimiterBasedContentFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BPackageSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol; @@ -53,19 +54,19 @@ public ReturnStatementContextProvider() { } @Override - public List getCompletions(LSContext ctx) { - ArrayList completionItems = new ArrayList<>(); - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + public List getCompletions(LSContext ctx) { + ArrayList completionItems = new ArrayList<>(); + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); Integer invocationType = ctx.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); if (invocationType > -1) { - Either, List> filteredItems = + Either, List> filteredItems = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(ctx); return this.getCompletionItemList(filteredItems, ctx); } // Remove the functions without a receiver symbol, bTypes not being packages and attached functions - List filteredList = visibleSymbols.stream().filter(symbolInfo -> { - BSymbol bSymbol = symbolInfo.getScopeEntry().symbol; + List filteredList = visibleSymbols.stream().filter(scopeEntry -> { + BSymbol bSymbol = scopeEntry.symbol; return !((bSymbol instanceof BInvokableSymbol && ((BInvokableSymbol) bSymbol).receiverSymbol != null && CommonUtil.isValidInvokableSymbol(bSymbol)) @@ -75,8 +76,8 @@ public List getCompletions(LSContext ctx) { && ((bSymbol.flags & Flags.ATTACHED) == Flags.ATTACHED))); }).collect(Collectors.toList()); - completionItems.add(Snippet.KW_CHECK_PANIC.get().build(ctx)); - completionItems.add(Snippet.KW_CHECK.get().build(ctx)); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_CHECK_PANIC.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_CHECK.get())); completionItems.addAll(getCompletionItemList(filteredList, ctx)); completionItems.addAll(this.getPackagesCompletionItems(ctx)); diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ServiceDefinitionContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ServiceDefinitionContextProvider.java index eee6e32c3cd1..6e06ff1d0b56 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ServiceDefinitionContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/ServiceDefinitionContextProvider.java @@ -23,12 +23,13 @@ import org.ballerinalang.langserver.common.CommonKeys; import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BPackageSymbol; import java.util.ArrayList; @@ -49,8 +50,8 @@ public ServiceDefinitionContextProvider() { } @Override - public List getCompletions(LSContext context) { - List completionItems = new ArrayList<>(); + public List getCompletions(LSContext context) { + List completionItems = new ArrayList<>(); List lhsTokens = context.get(SourcePruneKeys.LHS_TOKENS_KEY); List lhsDefaultTokens = lhsTokens.stream() .filter(commonToken -> commonToken.getChannel() == Token.DEFAULT_CHANNEL) @@ -90,36 +91,36 @@ public List getCompletions(LSContext context) { Ideally this should be a syntax error and current grammar do not support it Also Issue #18729 is also broken */ - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - List filteredSymbols = this.filterListenerTypes(visibleSymbols); - completionItems.addAll(this.getCompletionItemList(filteredSymbols, context)); + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List filteredSymbols = this.filterListenerTypes(visibleSymbols); + completionItems.addAll(this.getCompletionItemList(new ArrayList<>(filteredSymbols), context)); completionItems.addAll(this.getPackagesCompletionItems(context)); break; } case BallerinaParser.COLON: { - List listeners = this.filterListenersFromPackage(context); + List listeners = this.filterListenersFromPackage(context); completionItems.addAll(this.getCompletionItemList(listeners, context)); break; } default: { // Fill the on keyword completion item - completionItems.add(Snippet.KW_ON.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_ON.get())); break; } } return completionItems; } - private List filterListenerTypes(List symbolInfos) { - return symbolInfos.stream() - .filter(symbolInfo -> CommonUtil.isListenerObject(symbolInfo.getScopeEntry().symbol)) + private List filterListenerTypes(List scopeEntries) { + return scopeEntries.stream() + .filter(scopeEntry -> CommonUtil.isListenerObject(scopeEntry.symbol)) .collect(Collectors.toList()); } - private List filterListenersFromPackage(LSContext context) { + private List filterListenersFromPackage(LSContext context) { List defaultTokens = context.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); List tokenTypes = context.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); if (tokenTypes == null) { return new ArrayList<>(); } @@ -130,17 +131,16 @@ private List filterListenersFromPackage(LSContext context) { } String pkgName = defaultTokens.get(colonIndex - 1).getText(); - Optional symbolWithName = visibleSymbols.stream() - .filter(symbolInfo -> symbolInfo.getSymbolName().equals(pkgName)) + Optional symbolWithName = visibleSymbols.stream() + .filter(scopeEntry -> scopeEntry.symbol.name.getValue().equals(pkgName)) .findAny(); - if (!symbolWithName.isPresent() || !(symbolWithName.get().getScopeEntry().symbol instanceof BPackageSymbol)) { + if (!symbolWithName.isPresent() || !(symbolWithName.get().symbol instanceof BPackageSymbol)) { return new ArrayList<>(); } - BPackageSymbol pkgSymbol = ((BPackageSymbol) symbolWithName.get().getScopeEntry().symbol); + BPackageSymbol pkgSymbol = ((BPackageSymbol) symbolWithName.get().symbol); return pkgSymbol.scope.entries.values().stream() .filter(scopeEntry -> CommonUtil.isListenerObject(scopeEntry.symbol)) - .map(scopeEntry -> new SymbolInfo(scopeEntry.symbol.getName().getValue(), scopeEntry)) .collect(Collectors.toList()); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/StatementContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/StatementContextProvider.java index e2ca69a00d2d..a88e7e38a243 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/StatementContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/StatementContextProvider.java @@ -26,16 +26,17 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.CompletionSubRuleParser; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.completions.util.filters.StatementTemplateFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import org.wso2.ballerinalang.compiler.semantics.model.types.BUnionType; import org.wso2.ballerinalang.compiler.util.TypeTags; @@ -57,7 +58,7 @@ public StatementContextProvider() { } @Override - public List getCompletions(LSContext context) throws LSCompletionException { + public List getCompletions(LSContext context) throws LSCompletionException { List lhsTokens = context.get(SourcePruneKeys.LHS_TOKENS_KEY); Boolean inWorkerReturn = context.get(CompletionKeys.IN_WORKER_RETURN_CONTEXT_KEY); int invocationOrDelimiterTokenType = context.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); @@ -95,69 +96,67 @@ public List getCompletions(LSContext context) throws LSCompletio } Boolean forceRemovedStmt = context.get(SourcePruneKeys.FORCE_REMOVED_STATEMENT_WITH_PARENTHESIS_KEY); - ArrayList completionItems = new ArrayList<>(); - List filteredList = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + ArrayList completionItems; + List filteredList = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); if (forceRemovedStmt == null || !forceRemovedStmt) { // Add the visible static completion items - completionItems.addAll(getStaticCompletionItems(context)); + completionItems = new ArrayList<>(getStaticCompletionItems(context)); // Add the statement templates - Either, List> itemList = SymbolFilters.get(StatementTemplateFilter.class) - .filterItems(context); + Either, List> itemList = + SymbolFilters.get(StatementTemplateFilter.class).filterItems(context); completionItems.addAll(this.getCompletionItemList(itemList, context)); - completionItems.addAll(this.getTypeguardDestructuredItems(filteredList, context)); + completionItems.addAll(this.getTypeguardDestructedItems(filteredList, context)); } else { return this.getProvider(InvocationArgsContextProvider.class).getCompletions(context); } filteredList.removeIf(this.attachedSymbolFilter()); - completionItems.addAll(this.getCompletionItemList(filteredList, context)); + completionItems.addAll(this.getCompletionItemList(new ArrayList<>(filteredList), context)); completionItems.addAll(this.getPackagesCompletionItems(context)); // Now we need to sort the completion items and populate the completion items specific to the scope owner // as an example, resource, action, function scopes are different from the if-else, while, and etc - Class itemSorter = context.get(CompletionKeys.BLOCK_OWNER_KEY).getClass(); - context.put(CompletionKeys.ITEM_SORTER_KEY, itemSorter); return completionItems; } - private List getStaticCompletionItems(LSContext context) { + private List getStaticCompletionItems(LSContext context) { - ArrayList completionItems = new ArrayList<>(); + ArrayList completionItems = new ArrayList<>(); // Add the xmlns snippet - completionItems.add(Snippet.STMT_NAMESPACE_DECLARATION.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_NAMESPACE_DECLARATION.get())); // Add the var keyword - completionItems.add(Snippet.KW_VAR.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_VAR.get())); // Add the wait keyword - completionItems.add(Snippet.KW_WAIT.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_WAIT.get())); // Add the start keyword - completionItems.add(Snippet.KW_START.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_START.get())); // Add the flush keyword - completionItems.add(Snippet.KW_FLUSH.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_FLUSH.get())); // Add the function keyword - completionItems.add(Snippet.KW_FUNCTION.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_FUNCTION.get())); // Add the error snippet - completionItems.add(Snippet.DEF_ERROR.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_ERROR.get())); // Add the checkpanic keyword - completionItems.add(Snippet.KW_CHECK_PANIC.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_CHECK_PANIC.get())); // Add the final keyword - completionItems.add(Snippet.KW_FINAL.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_FINAL.get())); return completionItems; } - private List getTypeguardDestructuredItems(List symbolInfoList, LSContext ctx) { + private List getTypeguardDestructedItems(List scopeEntries, + LSContext ctx) { List capturedSymbols = new ArrayList<>(); // In the case of type guarded variables multiple symbols with the same symbol name and we ignore those - return symbolInfoList.stream() - .filter(symbolInfo -> (symbolInfo.getScopeEntry().symbol.type instanceof BUnionType) - && !capturedSymbols.contains(symbolInfo.getScopeEntry().symbol.name.value)) - .map(symbolInfo -> { - capturedSymbols.add(symbolInfo.getSymbolName()); + return scopeEntries.stream() + .filter(scopeEntry -> (scopeEntry.symbol.type instanceof BUnionType) + && !capturedSymbols.contains(scopeEntry.symbol.name.value)) + .map(entry -> { + capturedSymbols.add(entry.symbol.name.getValue()); List errorTypes = new ArrayList<>(); List resultTypes = new ArrayList<>(); - List members = - new ArrayList<>(((BUnionType) symbolInfo.getScopeEntry().symbol.type).getMemberTypes()); + List members = new ArrayList<>(((BUnionType) entry.symbol.type).getMemberTypes()); members.forEach(bType -> { if (bType.tag == TypeTags.ERROR) { errorTypes.add(bType); @@ -168,7 +167,7 @@ private List getTypeguardDestructuredItems(List symb if (errorTypes.size() == 1) { resultTypes.addAll(errorTypes); } - String symbolName = symbolInfo.getScopeEntry().symbol.name.getValue(); + String symbolName = entry.symbol.name.getValue(); String label = symbolName + " - typeguard " + symbolName; String detail = "Destructure the variable " + symbolName + " with typeguard"; StringBuilder snippet = new StringBuilder(); @@ -197,8 +196,9 @@ private List getTypeguardDestructuredItems(List symb snippet.append(restSnippet); - return new SnippetBlock(label, snippet.toString(), detail, - SnippetBlock.SnippetType.SNIPPET).build(ctx); + SnippetBlock cItemSnippet = new SnippetBlock(label, snippet.toString(), detail, + SnippetBlock.SnippetType.SNIPPET); + return new SnippetCompletionItem(ctx, cItemSnippet); }).collect(Collectors.toList()); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/TypeDefinitionContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/TypeDefinitionContextProvider.java index e5221b0a9a02..18283e76023c 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/TypeDefinitionContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/TypeDefinitionContextProvider.java @@ -21,10 +21,11 @@ import org.antlr.v4.runtime.Token; import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import java.util.ArrayList; @@ -45,9 +46,10 @@ public TypeDefinitionContextProvider() { } @Override - public List getCompletions(LSContext ctx) { + public List getCompletions(LSContext ctx) { if (this.isObjectTypeDefinition(ctx)) { - return Arrays.asList(Snippet.KW_ABSTRACT.get().build(ctx), Snippet.KW_CLIENT.get().build(ctx)); + return Arrays.asList(new SnippetCompletionItem(ctx, Snippet.KW_ABSTRACT.get()), + new SnippetCompletionItem(ctx, Snippet.KW_CLIENT.get())); } return new ArrayList<>(); diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/VarDefContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/VarDefContextProvider.java index c3c34057b36c..1df9d5f88c19 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/VarDefContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/VarDefContextProvider.java @@ -19,10 +19,8 @@ import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.commons.completion.CompletionKeys; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; -import org.ballerinalang.langserver.completions.util.sorters.ActionAndFieldAccessContextItemSorter; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import java.util.ArrayList; @@ -39,16 +37,7 @@ public VarDefContextProvider() { @Override @SuppressWarnings("unchecked") - public List getCompletions(LSContext context) { - int invocationOrDelimiterTokenType = context.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); - - Class sorterKey; - if (invocationOrDelimiterTokenType > -1) { - sorterKey = ActionAndFieldAccessContextItemSorter.class; - } else { - sorterKey = context.get(CompletionKeys.PARSER_RULE_CONTEXT_KEY).getClass(); - } - context.put(CompletionKeys.ITEM_SORTER_KEY, sorterKey); + public List getCompletions(LSContext context) { return new ArrayList<>(this.getVarDefExpressionCompletions(context, false)); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerDeclarationContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerDeclarationContextProvider.java index cd74ee0b23c4..b7ba1cf69ce3 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerDeclarationContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerDeclarationContextProvider.java @@ -23,11 +23,12 @@ import org.ballerinalang.langserver.common.CommonKeys; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.ArrayList; import java.util.List; @@ -43,9 +44,9 @@ public WorkerDeclarationContextProvider() { @Override @SuppressWarnings("unchecked") - public List getCompletions(LSContext context) { - ArrayList completionItems = new ArrayList<>(); - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + public List getCompletions(LSContext context) { + ArrayList completionItems = new ArrayList<>(); + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); Boolean inWorkerReturnCtx = context.get(CompletionKeys.IN_WORKER_RETURN_CONTEXT_KEY); int invocationOrDelimiterTokenType = context.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); if (invocationOrDelimiterTokenType == BallerinaParser.COLON) { @@ -53,12 +54,12 @@ public List getCompletions(LSContext context) { List defaultTokenTypes = context.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); int pkgDelimIndex = defaultTokenTypes.indexOf(BallerinaParser.COLON); String pkgName = defaultTokens.get(pkgDelimIndex - 1).getText(); - completionItems.addAll(this.getTypesInPackage(visibleSymbols, pkgName, context)); + completionItems.addAll(this.getTypeItemsInPackage(visibleSymbols, pkgName, context)); } else if (inWorkerReturnCtx != null && inWorkerReturnCtx) { - completionItems.addAll(this.getBasicTypes(visibleSymbols)); + completionItems.addAll(this.getBasicTypesItems(context, visibleSymbols)); completionItems.addAll(this.getPackagesCompletionItems(context)); } else { - completionItems.add(SnippetGenerator.getReturnsKeywordSnippet().build(context)); + completionItems.add(new SnippetCompletionItem(context, SnippetGenerator.getReturnsKeywordSnippet())); } return completionItems; diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerReceiveExpressionContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerReceiveExpressionContextProvider.java index 179d3578f5d2..8df69820909a 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerReceiveExpressionContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerReceiveExpressionContextProvider.java @@ -20,8 +20,8 @@ import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import java.util.List; @@ -36,7 +36,7 @@ public WorkerReceiveExpressionContextProvider() { this.attachmentPoints.add(BallerinaParser.WorkerReceiveExpressionContext.class); } @Override - public List getCompletions(LSContext context) { + public List getCompletions(LSContext context) { return this.getCompletionItemList(CommonUtil.getWorkerSymbols(context), context); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerSendSyncExpressionContextProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerSendSyncExpressionContextProvider.java index f5ca2ba3d0e6..bb33a4bd5d07 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerSendSyncExpressionContextProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/contextproviders/WorkerSendSyncExpressionContextProvider.java @@ -20,8 +20,8 @@ import org.ballerinalang.annotation.JavaSPIService; import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import java.util.List; @@ -36,7 +36,7 @@ public WorkerSendSyncExpressionContextProvider() { this.attachmentPoints.add(BallerinaParser.WorkerSendSyncExpressionContext.class); } @Override - public List getCompletions(LSContext context) { + public List getCompletions(LSContext context) { return this.getCompletionItemList(CommonUtil.getWorkerSymbols(context), context); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/BlockStatementScopeProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/BlockStatementScopeProvider.java index c57d8250e7aa..001d00cbfc02 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/BlockStatementScopeProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/BlockStatementScopeProvider.java @@ -22,13 +22,13 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.commons.completion.spi.LSCompletionProvider; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.providers.contextproviders.IfWhileConditionContextProvider; import org.ballerinalang.langserver.completions.providers.contextproviders.InvocationArgsContextProvider; import org.ballerinalang.langserver.completions.providers.contextproviders.StatementContextProvider; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.tree.statements.BLangBlockStmt; import java.util.List; @@ -46,7 +46,7 @@ public BlockStatementScopeProvider() { } @Override - public List getCompletions(LSContext context) throws LSCompletionException { + public List getCompletions(LSContext context) throws LSCompletionException { Optional contextProvider = getContextProvider(context); if (contextProvider.isPresent()) { return contextProvider.get().getCompletions(context); diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ForkJoinStatementScopeProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ForkJoinStatementScopeProvider.java index a2d56a0689d5..3e94399f61d0 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ForkJoinStatementScopeProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ForkJoinStatementScopeProvider.java @@ -22,11 +22,12 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.CompletionSubRuleParser; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import org.wso2.ballerinalang.compiler.tree.statements.BLangForkJoin; @@ -45,7 +46,7 @@ public ForkJoinStatementScopeProvider() { } @Override - public List getCompletions(LSContext context) throws LSCompletionException { + public List getCompletions(LSContext context) throws LSCompletionException { Boolean inWorkerReturn = context.get(CompletionKeys.IN_WORKER_RETURN_CONTEXT_KEY); List lhsTokens = context.get(SourcePruneKeys.LHS_TOKENS_KEY); if (inWorkerReturn != null && inWorkerReturn) { @@ -58,6 +59,6 @@ public List getCompletions(LSContext context) throws LSCompletio && this.getProvider(parserRuleContext.getClass()) != null) { return this.getProvider(parserRuleContext.getClass()).getCompletions(context); } - return Collections.singletonList(Snippet.DEF_WORKER.get().build(context)); + return Collections.singletonList(new SnippetCompletionItem(context, Snippet.DEF_WORKER.get())); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ObjectTypeNodeScopeProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ObjectTypeNodeScopeProvider.java index bb664195d45f..0bcefa68d024 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ObjectTypeNodeScopeProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ObjectTypeNodeScopeProvider.java @@ -27,16 +27,14 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.CompletionSubRuleParser; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.providers.contextproviders.AnnotationAttachmentContextProvider; import org.ballerinalang.langserver.completions.util.Snippet; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; import org.ballerinalang.model.tree.NodeKind; -import org.eclipse.lsp4j.CompletionItem; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BObjectTypeSymbol; @@ -55,14 +53,13 @@ @JavaSPIService("org.ballerinalang.langserver.commons.completion.spi.LSCompletionProvider") public class ObjectTypeNodeScopeProvider extends AbstractCompletionProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(ObjectTypeNodeScopeProvider.class); public ObjectTypeNodeScopeProvider() { this.attachmentPoints.add(BLangObjectTypeNode.class); } @Override - public List getCompletions(LSContext context) throws LSCompletionException { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext context) throws LSCompletionException { + ArrayList completionItems = new ArrayList<>(); BLangNode objectNode = context.get(CompletionKeys.SCOPE_NODE_KEY); if (!objectNode.getKind().equals(NodeKind.OBJECT_TYPE)) { @@ -93,50 +90,49 @@ public List getCompletions(LSContext context) throws LSCompletio this.fillObjectReferences(completionItems, lhsDefaultTokens, context); } else { fillTypes(context, completionItems); - completionItems.add(Snippet.DEF_FUNCTION_SIGNATURE.get().build(context)); - completionItems.add(Snippet.DEF_FUNCTION.get().build(context)); - completionItems.add(Snippet.DEF_REMOTE_FUNCTION.get().build(context)); - completionItems.add(Snippet.DEF_INIT_FUNCTION.get().build(context)); - completionItems.add(Snippet.DEF_ATTACH_FUNCTION.get().build(context)); - completionItems.add(Snippet.DEF_DETACH_FUNCTION.get().build(context)); - completionItems.add(Snippet.DEF_START_FUNCTION.get().build(context)); - completionItems.add(Snippet.DEF_GRACEFUL_STOP_FUNCTION.get().build(context)); - completionItems.add(Snippet.DEF_IMMEDIATE_STOP_FUNCTION.get().build(context)); - completionItems.add(Snippet.KW_PUBLIC.get().build(context)); - completionItems.add(Snippet.KW_PRIVATE.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_FUNCTION_SIGNATURE.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_REMOTE_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_INIT_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_ATTACH_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_DETACH_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_START_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_GRACEFUL_STOP_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_IMMEDIATE_STOP_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_PUBLIC.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.KW_PRIVATE.get())); } return completionItems; } - private void fillTypes(LSContext context, List completionItems) { - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - List filteredTypes = visibleSymbols.stream() - .filter(symbolInfo -> FilterUtils.isBTypeEntry(symbolInfo.getScopeEntry())) + private void fillTypes(LSContext context, List completionItems) { + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List filteredTypes = visibleSymbols.stream() + .filter(FilterUtils::isBTypeEntry) .collect(Collectors.toList()); - completionItems.addAll(this.getCompletionItemList(filteredTypes, context)); + completionItems.addAll(this.getCompletionItemList(new ArrayList<>(filteredTypes), context)); completionItems.addAll(this.getPackagesCompletionItems(context)); } - private void fillObjectReferences(List completionItems, List lhsDefaultTokens, + private void fillObjectReferences(List completionItems, List lhsDefaultTokens, LSContext ctx) { CommonToken lastItem = CommonUtil.getLastItem(lhsDefaultTokens); if (lastItem != null && lastItem.getType() == BallerinaParser.COLON) { String pkgName = lhsDefaultTokens.get(1).getText(); - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - Optional pkgSymbolInfo = visibleSymbols.stream() - .filter(symbolInfo -> symbolInfo.getScopeEntry().symbol instanceof BPackageSymbol - && symbolInfo.getScopeEntry().symbol.pkgID.getName().getValue().equals(pkgName)) + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + Optional pkgSymbolInfo = visibleSymbols.stream() + .filter(scopeEntry -> scopeEntry.symbol instanceof BPackageSymbol + && scopeEntry.symbol.pkgID.getName().getValue().equals(pkgName)) .findAny(); if (pkgSymbolInfo.isPresent()) { - List filteredSymbolInfo = pkgSymbolInfo.get().getScopeEntry().symbol.scope.entries.values() - .stream() + List filteredSymbolInfo = pkgSymbolInfo.get().symbol.scope.entries.values().stream() .filter(scopeEntry -> scopeEntry.symbol instanceof BObjectTypeSymbol && (scopeEntry.symbol.flags & Flags.ABSTRACT) == Flags.ABSTRACT) .map(scopeEntry -> { BObjectTypeSymbol oSymbol = (BObjectTypeSymbol) scopeEntry.symbol; - return new SymbolInfo(oSymbol.getName().getValue(), new Scope.ScopeEntry(oSymbol, null)); + return new Scope.ScopeEntry(oSymbol, null); }) .collect(Collectors.toList()); completionItems.addAll(this.getCompletionItemList(filteredSymbolInfo, ctx)); @@ -146,13 +142,13 @@ private void fillObjectReferences(List completionItems, List completionItems, LSContext ctx) { - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - List filteredList = visibleSymbols.stream() - .filter(symbolInfo -> symbolInfo.getScopeEntry().symbol instanceof BObjectTypeSymbol - && (symbolInfo.getScopeEntry().symbol.flags & Flags.ABSTRACT) == Flags.ABSTRACT) + private void fillVisibleObjectsAndPackages(List completionItems, LSContext ctx) { + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List filteredList = visibleSymbols.stream() + .filter(scopeEntry -> scopeEntry.symbol instanceof BObjectTypeSymbol + && (scopeEntry.symbol.flags & Flags.ABSTRACT) == Flags.ABSTRACT) .collect(Collectors.toList()); - completionItems.addAll(this.getCompletionItemList(filteredList, ctx)); + completionItems.addAll(this.getCompletionItemList(new ArrayList<>(filteredList), ctx)); completionItems.addAll(this.getPackagesCompletionItems(ctx)); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/RecordLiteralScopeProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/RecordLiteralScopeProvider.java index a86028b922c5..15a66c63d7ba 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/RecordLiteralScopeProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/RecordLiteralScopeProvider.java @@ -23,14 +23,14 @@ import org.ballerinalang.langserver.common.utils.completion.BLangRecordLiteralUtil; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.util.filters.DelimiterBasedContentFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.tree.BLangNode; import org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral; @@ -48,7 +48,7 @@ public RecordLiteralScopeProvider() { } @Override - public List getCompletions(LSContext ctx) { + public List getCompletions(LSContext ctx) { BLangNode scopeNode = ctx.get(CompletionKeys.SCOPE_NODE_KEY); List lhsDefaultTokens = ctx.get(SourcePruneKeys.LHS_TOKENS_KEY).stream() .filter(commonToken -> commonToken.getChannel() == Token.DEFAULT_CHANNEL) @@ -68,7 +68,7 @@ public List getCompletions(LSContext ctx) { } */ BLangRecordLiteral recordLiteral = (BLangRecordLiteral) scopeNode; - return BLangRecordLiteralUtil.getFieldsForMatchingRecord(recordLiteral); + return BLangRecordLiteralUtil.getFieldsForMatchingRecord(ctx, recordLiteral); } if (firstColonIndex >= 0 && firstColonIndex == invocationTokenTypeIndex) { /* @@ -89,7 +89,7 @@ public List getCompletions(LSContext ctx) { f1: a:b } */ - Either, List> filteredItems = + Either, List> filteredItems = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(ctx); return this.getCompletionItemList(filteredItems, ctx); } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/RecordTypeNodeScopeProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/RecordTypeNodeScopeProvider.java index edeb0e4fadd0..2c627c3ed515 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/RecordTypeNodeScopeProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/RecordTypeNodeScopeProvider.java @@ -25,11 +25,11 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.CompletionSubRuleParser; -import org.ballerinalang.langserver.completions.SymbolInfo; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.tree.types.BLangRecordTypeNode; import java.util.ArrayList; @@ -48,8 +48,8 @@ public RecordTypeNodeScopeProvider() { } @Override - public List getCompletions(LSContext context) throws LSCompletionException { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext context) throws LSCompletionException { + ArrayList completionItems = new ArrayList<>(); List lhsTokens = context.get(SourcePruneKeys.LHS_TOKENS_KEY); Optional subRule = this.getSubRule(lhsTokens); subRule.ifPresent(rule -> CompletionSubRuleParser.parseWithinFunctionDefinition(rule, context)); @@ -59,11 +59,11 @@ public List getCompletions(LSContext context) throws LSCompletio return this.getProvider(parserRuleContext.getClass()).getCompletions(context); } - List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - List filteredTypes = visibleSymbols.stream() - .filter(symbolInfo -> FilterUtils.isBTypeEntry(symbolInfo.getScopeEntry())) + List visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List filteredTypes = visibleSymbols.stream() + .filter(FilterUtils::isBTypeEntry) .collect(Collectors.toList()); - completionItems.addAll(this.getCompletionItemList(filteredTypes, context)); + completionItems.addAll(this.getCompletionItemList(new ArrayList<>(filteredTypes), context)); completionItems.addAll(this.getPackagesCompletionItems(context)); return completionItems; diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ServiceScopeProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ServiceScopeProvider.java index 3ead749dd490..153cffa27947 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ServiceScopeProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/ServiceScopeProvider.java @@ -22,11 +22,12 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.compiler.DocumentServiceKeys; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.providers.contextproviders.AnnotationAttachmentContextProvider; import org.ballerinalang.langserver.completions.util.Snippet; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.Position; import org.wso2.ballerinalang.compiler.tree.BLangNode; import org.wso2.ballerinalang.compiler.tree.BLangService; @@ -47,8 +48,8 @@ public ServiceScopeProvider() { } @Override - public List getCompletions(LSContext ctx) throws LSCompletionException { - ArrayList completionItems = new ArrayList<>(); + public List getCompletions(LSContext ctx) throws LSCompletionException { + ArrayList completionItems = new ArrayList<>(); if (this.isWithinAttachedExpressions(ctx)) { // suggest all the visible, defined listeners return this.getCompletionItemsAfterOnKeyword(ctx); @@ -57,11 +58,11 @@ public List getCompletions(LSContext ctx) throws LSCompletionExc return this.getProvider(AnnotationAttachmentContextProvider.class).getCompletions(ctx); } - completionItems.add(Snippet.KW_PUBLIC.get().build(ctx)); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_PUBLIC.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_FUNCTION.get())); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.KW_RESOURCE.get())); completionItems.addAll(this.getResourceSnippets(ctx)); - completionItems.add(Snippet.DEF_FUNCTION.get().build(ctx)); - - ctx.put(CompletionKeys.ITEM_SORTER_KEY, BLangService.class); + completionItems.add(new SnippetCompletionItem(ctx, Snippet.DEF_FUNCTION.get())); return completionItems; } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/TopLevelScopeProvider.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/TopLevelScopeProvider.java index 27de6cddbaf1..bccaa5965da8 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/TopLevelScopeProvider.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/providers/scopeproviders/TopLevelScopeProvider.java @@ -23,18 +23,17 @@ import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; import org.ballerinalang.langserver.commons.completion.LSCompletionException; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.commons.completion.spi.LSCompletionProvider; import org.ballerinalang.langserver.completions.CompletionSubRuleParser; -import org.ballerinalang.langserver.completions.SymbolInfo; import org.ballerinalang.langserver.completions.providers.AbstractCompletionProvider; import org.ballerinalang.langserver.completions.providers.contextproviders.AnnotationAttachmentContextProvider; import org.ballerinalang.langserver.completions.util.filters.DelimiterBasedContentFilter; import org.ballerinalang.langserver.completions.util.filters.SymbolFilters; -import org.ballerinalang.langserver.completions.util.sorters.TopLevelContextSorter; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.tree.BLangPackage; import org.wso2.ballerinalang.compiler.tree.BLangTestablePackage; @@ -55,9 +54,12 @@ public TopLevelScopeProvider() { } @Override - public List getCompletions(LSContext ctx) throws LSCompletionException { - ArrayList completionItems = new ArrayList<>(); - + public List getCompletions(LSContext ctx) throws LSCompletionException { + ArrayList completionItems = new ArrayList<>(); + List lhsTokens = ctx.get(SourcePruneKeys.LHS_TOKENS_KEY); + Optional subRule = this.getSubRule(lhsTokens); + subRule.ifPresent(rule -> CompletionSubRuleParser.parseWithinCompilationUnit(rule, ctx)); + if (this.inFunctionReturnParameterContext(ctx)) { return this.getProvider(BallerinaParser.ReturnParameterContext.class).getCompletions(ctx); } @@ -81,23 +83,22 @@ public List getCompletions(LSContext ctx) throws LSCompletionExc && BallerinaParser.LT == lhsDefaultTokens.get(lhsDefaultTokens.size() - 1).getType())) { completionItems.addAll(addTopLevelItems(ctx)); } - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - completionItems.addAll(getBasicTypes(visibleSymbols)); + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + completionItems.addAll(getBasicTypesItems(ctx, visibleSymbols)); completionItems.addAll(this.getPackagesCompletionItems(ctx)); - ctx.put(CompletionKeys.ITEM_SORTER_KEY, TopLevelContextSorter.class); return completionItems; } - private List getCompletionOnParameterContext(LSContext lsContext) { + private List getCompletionOnParameterContext(LSContext lsContext) { List defaultTokenTypes = lsContext.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); List defaultTokens = lsContext.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); - List visibleSymbols = new ArrayList<>(lsContext.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + List visibleSymbols = new ArrayList<>(lsContext.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); Integer invocationType = lsContext.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); if (defaultTokenTypes.contains(BallerinaParser.FUNCTION)) { if (invocationType == BallerinaParser.COLON) { String pkgAlias = defaultTokens.get(defaultTokenTypes.indexOf(invocationType) - 1).getText(); - return this.getTypesInPackage(visibleSymbols, pkgAlias, lsContext); + return this.getTypeItemsInPackage(new ArrayList<>(visibleSymbols), pkgAlias, lsContext); } if (invocationType > -1) { return new ArrayList<>(); @@ -105,22 +106,22 @@ private List getCompletionOnParameterContext(LSContext lsContext /* Within the function definition's parameter context and we only suggest the packages and types */ - List completionItems = new ArrayList<>(); - completionItems.addAll(getBasicTypes(visibleSymbols)); + List completionItems = new ArrayList<>(); + completionItems.addAll(getBasicTypesItems(lsContext, visibleSymbols)); completionItems.addAll(this.getPackagesCompletionItems(lsContext)); return completionItems; } if (invocationType > -1) { - Either, List> filteredSymbols = + Either, List> filteredSymbols = SymbolFilters.get(DelimiterBasedContentFilter.class).filterItems(lsContext); return this.getCompletionItemList(filteredSymbols, lsContext); } - List completionItems = new ArrayList<>(); + List completionItems = new ArrayList<>(); visibleSymbols.removeIf(this.attachedSymbolFilter()); - completionItems.addAll(getBasicTypes(visibleSymbols)); + completionItems.addAll(getBasicTypesItems(lsContext, visibleSymbols)); completionItems.addAll(this.getPackagesCompletionItems(lsContext)); return completionItems; } @@ -128,7 +129,6 @@ private List getCompletionOnParameterContext(LSContext lsContext @Override public Optional getContextProvider(LSContext ctx) { List lhsTokensTypes = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); - List lhsTokens = ctx.get(SourcePruneKeys.LHS_TOKENS_KEY); Boolean forcedRemoved = ctx.get(SourcePruneKeys.FORCE_REMOVED_STATEMENT_WITH_PARENTHESIS_KEY); if (lhsTokensTypes == null || lhsTokensTypes.isEmpty() || (forcedRemoved != null && forcedRemoved)) { return Optional.empty(); @@ -139,13 +139,11 @@ public Optional getContextProvider(LSContext ctx) { // Handle with the parser rule context int serviceTokenIndex = lhsTokensTypes.indexOf(BallerinaParser.SERVICE); int assignTokenIndex = lhsTokensTypes.indexOf(BallerinaParser.ASSIGN); + ParserRuleContext parserRuleContext = ctx.get(CompletionKeys.PARSER_RULE_CONTEXT_KEY); if (serviceTokenIndex > -1 && assignTokenIndex == -1) { return Optional.ofNullable(this.getProvider(BallerinaParser.ServiceDefinitionContext.class)); } - Optional subRule = this.getSubRule(lhsTokens); - subRule.ifPresent(rule -> CompletionSubRuleParser.parseWithinCompilationUnit(rule, ctx)); - ParserRuleContext parserRuleContext = ctx.get(CompletionKeys.PARSER_RULE_CONTEXT_KEY); if (parserRuleContext != null) { return Optional.ofNullable(this.getProvider(parserRuleContext.getClass())); diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/CompletionUtil.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/CompletionUtil.java index 5ddec8001d2b..9c2f974387b1 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/CompletionUtil.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/CompletionUtil.java @@ -20,6 +20,7 @@ import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.commons.completion.spi.LSCompletionProvider; import org.ballerinalang.langserver.commons.workspace.WorkspaceDocumentException; import org.ballerinalang.langserver.commons.workspace.WorkspaceDocumentManager; @@ -73,9 +74,9 @@ public static void resolveSymbols(LSContext completionContext) { * @return {@link List} List of resolved completion Items */ public static List getCompletionItems(LSContext ctx) { - List items = new ArrayList<>(); + List items = new ArrayList<>(); if (ctx == null) { - return items; + return new ArrayList<>(); } // Set the invocation or field access token type setInvocationOrInteractionOrFieldAccessToken(ctx); @@ -88,18 +89,28 @@ public static List getCompletionItems(LSContext ctx) { LOGGER.error("Error while retrieving completions from: " + completionProvider.getClass()); } - boolean isSnippetSupported = ctx.get(CompletionKeys.CLIENT_CAPABILITIES_KEY).getCompletionItem() + return getPreparedCompletionItems(ctx, items); + } + + private static List getPreparedCompletionItems(LSContext context, List items) { + List completionItems = new ArrayList<>(); + boolean isSnippetSupported = context.get(CompletionKeys.CLIENT_CAPABILITIES_KEY).getCompletionItem() .getSnippetSupport(); - ItemSorters.get(ctx.get(CompletionKeys.ITEM_SORTER_KEY)).sortItems(ctx, items); - for (CompletionItem item : items) { + List sortedItems = ItemSorters.get(context.get(CompletionKeys.SCOPE_NODE_KEY).getClass()) + .sortItems(context, items); + + // TODO: Remove this + for (CompletionItem item : sortedItems) { if (!isSnippetSupported) { item.setInsertText(CommonUtil.getPlainTextSnippet(item.getInsertText())); item.setInsertTextFormat(InsertTextFormat.PlainText); } else { item.setInsertTextFormat(InsertTextFormat.Snippet); } + completionItems.add(item); } - return items; + + return completionItems; } /** diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/Snippet.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/Snippet.java index b19a61b0c5eb..9fa91db8a87e 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/Snippet.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/Snippet.java @@ -133,6 +133,8 @@ public enum Snippet { KW_FUNCTION(SnippetGenerator.getFunctionKeywordSnippet()), + KW_RESOURCE(SnippetGenerator.getResourceKeywordSnippet()), + KW_PUBLIC(SnippetGenerator.getPublicKeywordSnippet()), KW_PRIVATE(SnippetGenerator.getPrivateKeywordSnippet()), diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/AbstractSymbolFilter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/AbstractSymbolFilter.java index 4d2241d804cc..0b2dbf09807b 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/AbstractSymbolFilter.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/AbstractSymbolFilter.java @@ -18,9 +18,9 @@ package org.ballerinalang.langserver.completions.util.filters; import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.SymbolInfo; -import org.eclipse.lsp4j.CompletionItem; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.ArrayList; import java.util.List; @@ -35,5 +35,5 @@ public abstract class AbstractSymbolFilter { * @param completionContext - Completion operation context * @return {@link ArrayList} */ - public abstract Either, List> filterItems(LSContext completionContext); + public abstract Either, List> filterItems(LSContext completionContext); } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/DelimiterBasedContentFilter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/DelimiterBasedContentFilter.java index 27198e8663b5..e026936eda5b 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/DelimiterBasedContentFilter.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/DelimiterBasedContentFilter.java @@ -23,11 +23,11 @@ import org.ballerinalang.langserver.common.utils.FilterUtils; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import java.util.ArrayList; import java.util.List; @@ -38,25 +38,25 @@ public class DelimiterBasedContentFilter extends AbstractSymbolFilter { @Override - public Either, List> filterItems(LSContext ctx) { + public Either, List> filterItems(LSContext ctx) { List defaultTokens = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); List defaultTokenTypes = ctx.get(SourcePruneKeys.LHS_DEFAULT_TOKEN_TYPES_KEY); int delimiter = ctx.get(CompletionKeys.INVOCATION_TOKEN_TYPE_KEY); String symbolToken = defaultTokens.get(defaultTokenTypes.lastIndexOf(delimiter) - 1).getText().replace("'", ""); - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - SymbolInfo symbol = FilterUtils.getVariableByName(symbolToken, visibleSymbols); + List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); + Scope.ScopeEntry scopeEntry = FilterUtils.getVariableByName(symbolToken, visibleSymbols); boolean isActionInvocation = BallerinaParser.RARROW == delimiter - && CommonUtil.isClientObject(symbol.getScopeEntry().symbol); + && CommonUtil.isClientObject(scopeEntry.symbol); boolean isWorkerSend = !isActionInvocation && BallerinaParser.RARROW == delimiter; if (BallerinaParser.DOT == delimiter || BallerinaParser.NOT == delimiter || BallerinaParser.COLON == delimiter || BallerinaParser.OPTIONAL_FIELD_ACCESS == delimiter || isActionInvocation) { - List symbolInfos = FilterUtils.filterVariableEntriesOnDelimiter(ctx, symbolToken, delimiter, - defaultTokens, defaultTokenTypes.lastIndexOf(delimiter)); - return Either.forRight(symbolInfos); + List symbolCompletionItems = FilterUtils.filterVariableEntriesOnDelimiter(ctx, + symbolToken, delimiter, defaultTokens, defaultTokenTypes.lastIndexOf(delimiter)); + return Either.forRight(new ArrayList<>(symbolCompletionItems)); } if (isWorkerSend) { - List workerSymbols = CommonUtil.getWorkerSymbols(ctx); + List workerSymbols = new ArrayList<>(CommonUtil.getWorkerSymbols(ctx)); return Either.forRight(workerSymbols); } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/StatementTemplateFilter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/StatementTemplateFilter.java index 571c66810df4..b8b0010dc4fb 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/StatementTemplateFilter.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/filters/StatementTemplateFilter.java @@ -1,29 +1,30 @@ /* -* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.ballerinalang.langserver.completions.util.filters; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; import org.ballerinalang.langserver.completions.util.Snippet; -import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.InsertTextFormat; import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.tree.BLangFunction; import org.wso2.ballerinalang.compiler.tree.BLangNode; import org.wso2.ballerinalang.compiler.tree.statements.BLangBlockStmt; @@ -39,65 +40,66 @@ */ public class StatementTemplateFilter extends AbstractSymbolFilter { @Override - public Either, List> filterItems(LSContext context) { - ArrayList completionItems = new ArrayList<>(); + public Either, List> filterItems(LSContext context) { + ArrayList completionItems = new ArrayList<>(); BLangNode bLangNode = context.get(CompletionKeys.SCOPE_NODE_KEY); // Populate If Statement template - completionItems.add(Snippet.STMT_IF.get().build(context)); - + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_IF.get())); + if (context.get(CompletionKeys.PREVIOUS_NODE_KEY) instanceof BLangIf) { // Populate Else If Statement template - completionItems.add(Snippet.STMT_ELSE_IF.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_ELSE_IF.get())); // Populate Else Statement template - completionItems.add(Snippet.STMT_ELSE.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_ELSE.get())); } - + // Populate While Statement template - completionItems.add(Snippet.STMT_WHILE.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_WHILE.get())); // Populate Lock Statement template - completionItems.add(Snippet.STMT_LOCK.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_LOCK.get())); // Populate Foreach Statement template - completionItems.add(Snippet.STMT_FOREACH.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_FOREACH.get())); // Populate Fork Statement template - completionItems.add(Snippet.STMT_FORK.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_FORK.get())); // Populate Transaction Statement template - completionItems.add(Snippet.STMT_TRANSACTION.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_TRANSACTION.get())); // Populate Match statement template - completionItems.add(Snippet.STMT_MATCH.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_MATCH.get())); if (bLangNode instanceof BLangBlockStmt && (bLangNode.parent instanceof BLangFunction || bLangNode.parent instanceof BLangForkJoin)) { // Populate Worker Declaration statement template - completionItems.add(Snippet.DEF_WORKER.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.DEF_WORKER.get())); } - - if (context.get(CompletionKeys.LOOP_COUNT_KEY) > 0 + + if (context.get(CompletionKeys.LOOP_COUNT_KEY) > 0 && !context.get(CompletionKeys.CURRENT_NODE_TRANSACTION_KEY)) { /* Populate Continue Statement template only if enclosed within a looping construct and not in immediate transaction construct */ - completionItems.add(Snippet.STMT_CONTINUE.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_CONTINUE.get())); } - + if (context.get(CompletionKeys.LOOP_COUNT_KEY) > 0) { // Populate Break Statement template only if there is an enclosing looping construct such as while/ foreach - completionItems.add(Snippet.STMT_BREAK.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_BREAK.get())); } // Populate Return Statement template - completionItems.add(Snippet.STMT_RETURN.get().build(context)); - + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_RETURN.get())); + if (context.get(CompletionKeys.TRANSACTION_COUNT_KEY) > 0) { - completionItems.add(Snippet.STMT_ABORT.get().build(context)); - completionItems.add(Snippet.STMT_RETRY.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_ABORT.get())); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_RETRY.get())); } // Populate Throw Statement template - completionItems.add(Snippet.STMT_PANIC.get().build(context)); + completionItems.add(new SnippetCompletionItem(context, Snippet.STMT_PANIC.get())); - completionItems.sort(Comparator.comparing(CompletionItem::getLabel)); + completionItems.sort(Comparator.comparing(lsCompletionItem -> lsCompletionItem.getCompletionItem().getLabel())); // Set the insert text format to be snippet supported format - completionItems.forEach(completionItem -> completionItem.setInsertTextFormat(InsertTextFormat.Snippet)); + completionItems.forEach(completionItem -> completionItem.getCompletionItem() + .setInsertTextFormat(InsertTextFormat.Snippet)); return Either.forLeft(completionItems); } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ActionAndFieldAccessContextItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ActionAndFieldAccessContextItemSorter.java deleted file mode 100644 index 9b08b7b989dc..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ActionAndFieldAccessContextItemSorter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.util.ItemResolverConstants; -import org.ballerinalang.langserver.completions.util.Priority; -import org.eclipse.lsp4j.CompletionItem; - -import java.util.List; - -/** - * Item Sorter for the actions and field access items. - */ -public class ActionAndFieldAccessContextItemSorter extends CompletionItemSorter { - /** - * Sort Completion Items based on a particular criteria. - * - * @param ctx Completion context - * @param completionItems List of initial completion items - */ - @Override - public void sortItems(LSContext ctx, List completionItems) { - this.setPriorities(completionItems); - completionItems.forEach(this::decreasePriority); - } - - @Override - void setPriorities(List completionItems) { - completionItems.forEach(completionItem -> { - switch (completionItem.getDetail()) { - case ItemResolverConstants.NONE: - case ItemResolverConstants.KEYWORD_TYPE: - case ItemResolverConstants.STATEMENT_TYPE: - case ItemResolverConstants.SNIPPET_TYPE: - case ItemResolverConstants.FIELD_TYPE: - case ItemResolverConstants.B_TYPE: - case ItemResolverConstants.PACKAGE_TYPE: - case ItemResolverConstants.FUNCTION_TYPE: - super.setPriority(completionItem); - break; - default: - completionItem.setSortText(Priority.PRIORITY220.toString()); - break; - } - }); - } - - private void decreasePriority(CompletionItem completionItem) { - int sortText = Integer.parseInt(completionItem.getSortText()); - completionItem.setSortText(Integer.toString(sortText + 1)); - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/AssignmentStmtContextSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/AssignmentStmtContextSorter.java deleted file mode 100644 index 9df2d6dc31d9..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/AssignmentStmtContextSorter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.ballerinalang.langserver.common.CommonKeys; -import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; -import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol; -import org.wso2.ballerinalang.compiler.semantics.model.symbols.BVarSymbol; - -import java.util.ArrayList; -import java.util.List; - -/** - * Item Sorter for the Assignment statement context. - */ -class AssignmentStmtContextSorter extends VariableDefContextItemSorter { - /** - * Get the variable type. - * - * @param ctx Document Service context (Completion context) - * @return {@link String} type of the variable - */ - @Override - String getVariableType(LSContext ctx) { - String variableName = ctx.get(CompletionKeys.PARSER_RULE_CONTEXT_KEY).getStart().getText(); - List visibleSymbols = new ArrayList<>(ctx.get(CommonKeys.VISIBLE_SYMBOLS_KEY)); - SymbolInfo filteredSymbol = visibleSymbols.stream().filter(symbolInfo -> { - BSymbol bSymbol = symbolInfo.getScopeEntry().symbol; - String symbolName = symbolInfo.getSymbolName(); - return bSymbol instanceof BVarSymbol && symbolName.equals(variableName); - }).findFirst().orElse(null); - - if (filteredSymbol != null) { - return filteredSymbol.getScopeEntry().symbol.type.toString(); - } - - return ""; - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/CallableUnitBodyItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/CallableUnitBodyItemSorter.java deleted file mode 100644 index e3c2ad778546..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/CallableUnitBodyItemSorter.java +++ /dev/null @@ -1,33 +0,0 @@ -/* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.ballerinalang.langserver.commons.LSContext; -import org.eclipse.lsp4j.CompletionItem; - -import java.util.List; - -/** - * Completion Item sorter to sort items inside a callable unit body. This is used by functions and resources. - */ -class CallableUnitBodyItemSorter extends CompletionItemSorter { - @Override - public void sortItems(LSContext ctx, List completionItems) { - this.setPriorities(completionItems); - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/CompletionItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/CompletionItemSorter.java index c97be20a3245..3b84cb30a9fc 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/CompletionItemSorter.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/CompletionItemSorter.java @@ -18,11 +18,14 @@ package org.ballerinalang.langserver.completions.util.sorters; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.ballerinalang.langserver.completions.util.Priority; import org.eclipse.lsp4j.CompletionItem; import java.util.List; +import javax.annotation.Nonnull; + /** * Abstract implementation for the completion Item Sorter. */ @@ -30,18 +33,18 @@ public abstract class CompletionItemSorter { /** * Sort Completion Items based on a particular criteria. - * - * @param ctx Completion context + * @param ctx Completion context * @param completionItems List of initial completion items + * @return */ - public abstract void sortItems(LSContext ctx, List completionItems); + public abstract List sortItems(LSContext ctx, List completionItems); /** * Set the priorities in the default order. * * @param completionItems list of completion items */ - void setPriorities(List completionItems) { + protected void setPriorities(List completionItems) { completionItems.forEach(this::setPriority); } @@ -55,7 +58,7 @@ void removeCompletionsByType(List types, List completion completionItems.removeIf(completionItem -> types.contains(completionItem.getDetail())); } - void setPriority(CompletionItem completionItem) { + protected final void setPriority(CompletionItem completionItem) { if (completionItem.getKind() == null) { completionItem.setSortText(Priority.PRIORITY110.toString()); return; @@ -103,7 +106,8 @@ void setPriority(CompletionItem completionItem) { default: completionItem.setSortText(Priority.PRIORITY110.toString()); break; - } } + + protected abstract @Nonnull List getAttachedContexts(); } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ConditionalStatementItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ConditionalStatementItemSorter.java deleted file mode 100644 index c69c252f17cb..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ConditionalStatementItemSorter.java +++ /dev/null @@ -1,63 +0,0 @@ -/* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.util.ItemResolverConstants; -import org.ballerinalang.langserver.completions.util.Priority; -import org.eclipse.lsp4j.CompletionItem; - -import java.util.List; - -/** - * Completion item sorter for conditional statements such as if statement and while statement conditions. - * @since 0.965.0 - */ -public class ConditionalStatementItemSorter extends CompletionItemSorter { - - private static final String OPEN_BRACKET = "("; - - private static final String CLOSE_BRACKET = ")"; - /** - * Sort Completion Items based on a particular criteria. - * - * @param ctx Completion context - * @param completionItems List of initial completion items - */ - @Override - public void sortItems(LSContext ctx, List completionItems) { - this.setPriorities(completionItems); - completionItems.forEach(completionItem -> { - String detail = completionItem.getDetail(); - String label = completionItem.getLabel(); - if (detail.equals(ItemResolverConstants.FUNCTION_TYPE)) { - String signature = completionItem.getLabel(); - String returnType = signature - .substring(signature.lastIndexOf(OPEN_BRACKET), signature.lastIndexOf(CLOSE_BRACKET)).trim(); - if (returnType.endsWith(ItemResolverConstants.BOOLEAN_TYPE)) { - completionItem.setSortText(Priority.shiftPriority(completionItem.getSortText(), -1)); - } - } else if (detail.equals(ItemResolverConstants.BOOLEAN_TYPE)) { - completionItem.setSortText(Priority.shiftPriority(completionItem.getSortText(), -1)); - } else if (ItemResolverConstants.TRUE_KEYWORD.equals(label) - || ItemResolverConstants.FALSE_KEYWORD.equals(label)) { - completionItem.setSortText(Priority.PRIORITY110.toString()); - } - }); - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/DefaultItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/DefaultItemSorter.java index f03a92da5b45..fc8ff75d89e8 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/DefaultItemSorter.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/DefaultItemSorter.java @@ -18,16 +18,36 @@ package org.ballerinalang.langserver.completions.util.sorters; import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; import org.eclipse.lsp4j.CompletionItem; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; + /** * Default Item Sorter. */ public class DefaultItemSorter extends CompletionItemSorter { + /** + * {@inheritDoc} + */ + @Override + public List sortItems(LSContext ctx, List completionItems) { + List cItems = new ArrayList<>(); + for (LSCompletionItem lsCItem : completionItems) { + CompletionItem completionItem = lsCItem.getCompletionItem(); + this.setPriority(completionItem); + cItems.add(completionItem); + } + return cItems; + } + + @Nonnull @Override - public void sortItems(LSContext ctx, List completionItems) { - this.setPriorities(completionItems); + protected List getAttachedContexts() { + return Collections.singletonList(DefaultItemSorter.class); } } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ItemSorters.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ItemSorters.java index 9c2b672b3eb5..2e5a91b80deb 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ItemSorters.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ItemSorters.java @@ -17,9 +17,10 @@ */ package org.ballerinalang.langserver.completions.util.sorters; -import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; -import org.wso2.ballerinalang.compiler.tree.BLangFunction; -import org.wso2.ballerinalang.compiler.tree.BLangService; +import org.ballerinalang.langserver.completions.util.sorters.context.DefinitionContext; +import org.ballerinalang.langserver.completions.util.sorters.context.ImportDeclarationContext; +import org.ballerinalang.langserver.completions.util.sorters.scope.PackageScope; +import org.ballerinalang.langserver.completions.util.sorters.scope.ServiceScope; import java.util.Collections; import java.util.HashMap; @@ -29,43 +30,20 @@ * Item sorters to be used on sorting completion items, based on the scope. */ public enum ItemSorters { - ASSIGNMENT_STMT_ITEM_SORTER(BallerinaParser.AssignmentStatementContext.class, - new AssignmentStmtContextSorter()), - FUNCTION_BODY_ITEM_SORTER(BLangFunction.class, - new CallableUnitBodyItemSorter()), - DEFAULT_ITEM_SORTER(DefaultItemSorter.class, - new DefaultItemSorter()), - SERVICE_BODY_ITEM_SORTER(BLangService.class, - new ServiceContextItemSorter()), - STATEMENT_CONTEXT_ITEM_SORTER(StatementContextItemSorter.class, - new StatementContextItemSorter()), - VAR_DEF_CONTEXT_ITEM_SORTER(BallerinaParser.VariableDefinitionStatementContext.class, - new VariableDefContextItemSorter()), - GLOBAL_VAR_DEF_CONTEXT_ITEM_SORTER(BallerinaParser.GlobalVariableDefinitionContext.class, - new VariableDefContextItemSorter()), - CONDITIONAL_STMT_CONTEXT_ITEM_SORTER(ConditionalStatementItemSorter.class, - new ConditionalStatementItemSorter()), - MATCH_STMT_CONTEXT_ITEM_SORTER(MatchContextItemSorter.class, - new MatchContextItemSorter()), - TOP_LEVEL_MATCH_STMT_CONTEXT_ITEM_SORTER(TopLevelContextSorter.class, - new TopLevelContextSorter()), - ACTION_AND_FIELD_ITEM_SORTER(ActionAndFieldAccessContextItemSorter.class, - new ActionAndFieldAccessContextItemSorter()); - - private final Class context; + DEFAULT_ITEM_SORTER(new DefaultItemSorter()), + SERVICE_SCOPE_ITEM_SORTER(new ServiceScope()), + DEFINITION_CTX_ITEM_SORTER(new DefinitionContext()), + PACKAGE_SCOPE_ITEM_SORTER(new PackageScope()), + IMPORT_DECL_CTX_ITEM_SORTER(new ImportDeclarationContext()); + private final CompletionItemSorter itemSorter; private static final Map resolverMap = Collections.unmodifiableMap(initializeMapping()); - ItemSorters(Class context, CompletionItemSorter itemSorter) { - this.context = context; + ItemSorters(CompletionItemSorter itemSorter) { this.itemSorter = itemSorter; } - private Class getContext() { - return context; - } - private CompletionItemSorter getItemSorter() { return itemSorter; } @@ -85,7 +63,9 @@ public static CompletionItemSorter get(Class context) { private static Map initializeMapping() { Map map = new HashMap<>(); for (ItemSorters resolver : ItemSorters.values()) { - map.put(resolver.getContext(), resolver.getItemSorter()); + for (Class attachedContext : resolver.itemSorter.getAttachedContexts()) { + map.put(attachedContext, resolver.getItemSorter()); + } } return map; } diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/MatchContextItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/MatchContextItemSorter.java deleted file mode 100644 index 517b348a969e..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/MatchContextItemSorter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.util.ItemResolverConstants; -import org.ballerinalang.langserver.completions.util.Priority; -import org.eclipse.lsp4j.CompletionItem; -import org.eclipse.lsp4j.InsertTextFormat; - -import java.util.List; - -/** - * Completion Item sorter for the match statement completions. - */ -public class MatchContextItemSorter extends CompletionItemSorter { - /** - * Sort Completion Items based on a particular criteria. - * - * @param ctx Completion context - * @param completionItems List of initial completion items - */ - @Override - public void sortItems(LSContext ctx, List completionItems) { - completionItems.forEach(completionItem -> { - if (completionItem.getDetail().equals(ItemResolverConstants.B_TYPE)) { - completionItem.setSortText(Priority.PRIORITY150.toString()); - } else if (completionItem.getDetail().equals(ItemResolverConstants.FUNCTION_TYPE) - && InsertTextFormat.Snippet.equals(completionItem.getInsertTextFormat())) { - completionItem.setDetail(ItemResolverConstants.SNIPPET_TYPE); - completionItem.setSortText(Priority.PRIORITY120.toString()); - } else if (completionItem.getDetail().equals(ItemResolverConstants.FUNCTION_TYPE)) { - completionItem.setSortText(Priority.PRIORITY140.toString()); - } else if (InsertTextFormat.Snippet.equals(completionItem.getInsertTextFormat())) { - completionItem.setDetail(ItemResolverConstants.SNIPPET_TYPE); - completionItem.setSortText(Priority.PRIORITY110.toString()); - } else { - completionItem.setSortText(Priority.PRIORITY130.toString()); - } - }); - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ServiceContextItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ServiceContextItemSorter.java deleted file mode 100644 index b10915544124..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/ServiceContextItemSorter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.util.ItemResolverConstants; -import org.ballerinalang.langserver.completions.util.Priority; -import org.eclipse.lsp4j.CompletionItem; - -import java.util.List; - -/** - * Item sorter for the service context. - */ -public class ServiceContextItemSorter extends CompletionItemSorter { - @Override - public void sortItems(LSContext ctx, List completionItems) { - this.setPriorities(completionItems); - } - - @Override - void setPriority(CompletionItem completionItem) { - String detail = completionItem.getDetail(); - switch (detail) { - case ItemResolverConstants.B_TYPE: - completionItem.setSortText(Priority.PRIORITY150.toString()); - break; - case ItemResolverConstants.PACKAGE_TYPE: - completionItem.setSortText(Priority.PRIORITY140.toString()); - break; - case ItemResolverConstants.KEYWORD_TYPE: - completionItem.setSortText(Priority.PRIORITY120.toString()); - break; - case ItemResolverConstants.FUNCTION_TYPE: - completionItem.setSortText(Priority.PRIORITY130.toString()); - break; - case ItemResolverConstants.SNIPPET_TYPE: - completionItem.setSortText(Priority.PRIORITY110.toString()); - break; - default: - completionItem.setSortText(Priority.PRIORITY160.toString()); - break; - } - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/StatementContextItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/StatementContextItemSorter.java deleted file mode 100644 index f3d75b4e8497..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/StatementContextItemSorter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.commons.completion.CompletionKeys; -import org.eclipse.lsp4j.CompletionItem; - -import java.util.List; - -/** - * Item Sorter for the statement context. - */ -public class StatementContextItemSorter extends CompletionItemSorter { - /** - * Sort Completion Items based on a particular criteria. - * - * @param ctx Completion context - * @param completionItems List of initial completion items - */ - @Override - public void sortItems(LSContext ctx, List completionItems) { - int startTokenIndex = ctx.get(CompletionKeys.PARSER_RULE_CONTEXT_KEY).getStart().getTokenIndex(); - int stopTokenIndex = ctx.get(CompletionKeys.PARSER_RULE_CONTEXT_KEY).getStop().getTokenIndex(); - if (startTokenIndex > 0 && stopTokenIndex < 0) { - completionItems.clear(); - } - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/TopLevelContextSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/TopLevelContextSorter.java deleted file mode 100644 index 926cd969c931..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/TopLevelContextSorter.java +++ /dev/null @@ -1,62 +0,0 @@ -/* -* Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.util.ItemResolverConstants; -import org.ballerinalang.langserver.completions.util.Priority; -import org.eclipse.lsp4j.CompletionItem; - -import java.util.List; - -/** - * Item Sorter for the Top Level context. - * - * @since 1.0 - */ -public class TopLevelContextSorter extends VariableDefContextItemSorter { - @Override - public void sortItems(LSContext ctx, List completionItems) { - this.setPriorities(completionItems); - } - - @Override - void setPriority(CompletionItem completionItem) { - String detail = completionItem.getDetail(); - switch (detail) { - case ItemResolverConstants.B_TYPE: - completionItem.setSortText(Priority.PRIORITY150.toString()); - break; - case ItemResolverConstants.PACKAGE_TYPE: - completionItem.setSortText(Priority.PRIORITY140.toString()); - break; - case ItemResolverConstants.FUNCTION_TYPE: - completionItem.setSortText(Priority.PRIORITY130.toString()); - break; - case ItemResolverConstants.KEYWORD_TYPE: - completionItem.setSortText(Priority.PRIORITY120.toString()); - break; - case ItemResolverConstants.SNIPPET_TYPE: - completionItem.setSortText(Priority.PRIORITY110.toString()); - break; - default: - completionItem.setSortText(Priority.PRIORITY160.toString()); - break; - } - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/VariableDefContextItemSorter.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/VariableDefContextItemSorter.java deleted file mode 100644 index 6c72f4e717cd..000000000000 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/VariableDefContextItemSorter.java +++ /dev/null @@ -1,79 +0,0 @@ -/* -* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. -* -* WSO2 Inc. licenses this file to you under the Apache License, -* Version 2.0 (the "License"); you may not use this file except -* in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ -package org.ballerinalang.langserver.completions.util.sorters; - -import org.antlr.v4.runtime.CommonToken; -import org.antlr.v4.runtime.Token; -import org.ballerinalang.langserver.commons.LSContext; -import org.ballerinalang.langserver.completions.util.ItemResolverConstants; -import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; -import org.eclipse.lsp4j.CompletionItem; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * Item Sorter for the Variable Definition context. - */ -public class VariableDefContextItemSorter extends CompletionItemSorter { - /** - * Sort Completion Items based on a particular criteria. - * - * @param ctx Completion context - * @param completionItems List of initial completion items - */ - @Override - public void sortItems(LSContext ctx, List completionItems) { - this.setPriorities(completionItems); - String variableType = this.getVariableType(ctx); - // TODO: Revamp with the latest token analyzing - List poppedTokens = ctx.get(SourcePruneKeys.LHS_TOKENS_KEY).stream() - .filter(commonToken -> commonToken.getChannel() == Token.DEFAULT_CHANNEL) - .map(CommonToken::getText) - .collect(Collectors.toList()); - - if (poppedTokens.contains("=")) { - completionItems.forEach(completionItem -> { - if (completionItem.getDetail().equals(ItemResolverConstants.FUNCTION_TYPE)) { - String label = completionItem.getLabel(); - String functionReturnType = label.substring(label.lastIndexOf("(") + 1, label.lastIndexOf(")")); - - if (variableType.equals(functionReturnType)) { - this.increasePriority(completionItem); - } - } - }); - } - } - - private void increasePriority(CompletionItem completionItem) { - int sortText = Integer.parseInt(completionItem.getSortText()); - completionItem.setSortText(Integer.toString(sortText - 1)); - } - - /** - * Get the variable type. - * @param ctx Document Service context (Completion context) - * @return {@link String} type of the variable - */ - String getVariableType(LSContext ctx) { - // TODO: Use the content parsing to determine the rule - List lhsTokens = ctx.get(SourcePruneKeys.LHS_TOKENS_KEY); - return lhsTokens.get(0).getText(); - } -} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/DefinitionContext.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/DefinitionContext.java new file mode 100644 index 000000000000..c9774db1e9cc --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/DefinitionContext.java @@ -0,0 +1,65 @@ +/* +* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except +* in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ +package org.ballerinalang.langserver.completions.util.sorters.context; + +import org.ballerinalang.langserver.SnippetBlock; +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; +import org.ballerinalang.langserver.completions.util.Priority; +import org.ballerinalang.langserver.completions.util.sorters.CompletionItemSorter; +import org.eclipse.lsp4j.CompletionItem; +import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nonnull; + +/** + * Item sorter for Definition Context. + * + * @since 1.2.0 + */ +public class DefinitionContext extends CompletionItemSorter { + @Override + public List sortItems(LSContext ctx, List completionItems) { + List cItems = new ArrayList<>(); + completionItems.forEach(lsCItem -> { + CompletionItem completionItem = lsCItem.getCompletionItem(); + if (lsCItem instanceof SnippetCompletionItem + && ((SnippetCompletionItem) lsCItem).getSnippetType().equals(SnippetBlock.SnippetType.SNIPPET)) { + completionItem.setSortText(Priority.PRIORITY110.toString()); + } else if (lsCItem instanceof SnippetCompletionItem + && ((SnippetCompletionItem) lsCItem).getSnippetType().equals(SnippetBlock.SnippetType.KEYWORD)) { + completionItem.setSortText(Priority.PRIORITY120.toString()); + } else { + completionItem.setSortText(Priority.PRIORITY130.toString()); + } + cItems.add(completionItem); + }); + return cItems; + } + + @Nonnull + @Override + protected List getAttachedContexts() { + return Collections.singletonList(BallerinaParser.DefinitionContext.class); + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/ExpressionListContext.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/ExpressionListContext.java new file mode 100644 index 000000000000..1952a1ba03e2 --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/ExpressionListContext.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.langserver.completions.util.sorters.context; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.CompletionKeys; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SymbolCompletionItem; +import org.ballerinalang.langserver.completions.util.Priority; +import org.ballerinalang.langserver.completions.util.sorters.CompletionItemSorter; +import org.eclipse.lsp4j.CompletionItem; +import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nonnull; + +/** + * Item sorter for expression List context. + * + * @since 1.2.0 + */ +public class ExpressionListContext extends CompletionItemSorter { + @Override + public List sortItems(LSContext ctx, List completionItems) { + List cItems = new ArrayList<>(); + ParserRuleContext parserRuleContext = ctx.get(CompletionKeys.PARSER_RULE_CONTEXT_KEY); + boolean serviceExprCtx = parserRuleContext.getParent() instanceof BallerinaParser.ServiceDefinitionContext; + completionItems.forEach(lsCItem -> { + CompletionItem completionItem = lsCItem.getCompletionItem(); + /* + Captured context is as follows + Ex: service serviceName on + */ + if (serviceExprCtx && lsCItem instanceof SymbolCompletionItem) { + completionItem.setSortText(Priority.PRIORITY110.toString()); + } else { + completionItem.setSortText(Priority.PRIORITY120.toString()); + } + cItems.add(completionItem); + }); + return cItems; + } + + @Nonnull + @Override + protected List getAttachedContexts() { + return Collections.singletonList(BallerinaParser.ExpressionListContext.class); + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/ImportDeclarationContext.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/ImportDeclarationContext.java new file mode 100644 index 000000000000..ff9cc098e871 --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/context/ImportDeclarationContext.java @@ -0,0 +1,65 @@ +/* +* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except +* in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ +package org.ballerinalang.langserver.completions.util.sorters.context; + +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.util.Priority; +import org.ballerinalang.langserver.completions.util.sorters.CompletionItemSorter; +import org.eclipse.lsp4j.CompletionItem; +import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nonnull; + +/** + * Item sorter for Import Declaration Context. + * + * @since 1.2.0 + */ +public class ImportDeclarationContext extends CompletionItemSorter { + @Override + public List sortItems(LSContext ctx, List completionItems) { + List cItems = new ArrayList<>(); + completionItems.forEach(lsCItem -> { + CompletionItem completionItem = lsCItem.getCompletionItem(); + if (completionItem.getLabel().contains("/")) { + // Ex: import a + completionItem.setSortText(Priority.PRIORITY120.toString()); + } else { + /* + Address both of the following usecases + import o - Priority is given to the org names + import orgName/ + */ + completionItem.setSortText(Priority.PRIORITY110.toString()); + } + cItems.add(completionItem); + }); + return cItems; + } + + @Nonnull + @Override + protected List getAttachedContexts() { + return Collections.singletonList(BallerinaParser.ImportDeclarationContext.class); + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/scope/PackageScope.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/scope/PackageScope.java new file mode 100644 index 000000000000..98343887c6ca --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/scope/PackageScope.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.langserver.completions.util.sorters.scope; + +import org.antlr.v4.runtime.CommonToken; +import org.antlr.v4.runtime.ParserRuleContext; +import org.ballerinalang.langserver.SnippetBlock; +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.CompletionKeys; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; +import org.ballerinalang.langserver.completions.StaticCompletionItem; +import org.ballerinalang.langserver.completions.SymbolCompletionItem; +import org.ballerinalang.langserver.completions.util.Priority; +import org.ballerinalang.langserver.completions.util.sorters.CompletionItemSorter; +import org.ballerinalang.langserver.completions.util.sorters.ItemSorters; +import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionItemKind; +import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.BTypeSymbol; +import org.wso2.ballerinalang.compiler.tree.BLangPackage; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +/** + * Item sorter for Package Context. + * + * @since 1.2.0 + */ +public class PackageScope extends CompletionItemSorter { + @Override + public List sortItems(LSContext ctx, List completionItems) { + ParserRuleContext parserRuleCtx = ctx.get(CompletionKeys.PARSER_RULE_CONTEXT_KEY); + + if (this.isTopLevel(ctx, parserRuleCtx)) { + return this.sortInTopLevelScope(completionItems); + } else if (isGlobalVarDef(parserRuleCtx)) { + return this.getGlobalVarDefCompletions(ctx, completionItems); + } + CompletionItemSorter sorter = ItemSorters.get(parserRuleCtx.getClass()); + return sorter.sortItems(ctx, completionItems); + } + + @Nonnull + @Override + protected List getAttachedContexts() { + return Collections.singletonList(BLangPackage.class); + } + + private List sortInTopLevelScope(List completionItems) { + List cItems = new ArrayList<>(); + for (LSCompletionItem completionItem : completionItems) { + CompletionItem cItem = completionItem.getCompletionItem(); + cItems.add(cItem); + if (completionItem instanceof SnippetCompletionItem && ((SnippetCompletionItem) completionItem) + .getSnippetType().equals(SnippetBlock.SnippetType.SNIPPET)) { + cItem.setSortText(Priority.PRIORITY110.toString()); + } else if (completionItem instanceof SnippetCompletionItem && ((SnippetCompletionItem) completionItem) + .getSnippetType().equals(SnippetBlock.SnippetType.KEYWORD)) { + cItem.setSortText(Priority.PRIORITY120.toString()); + } else if (completionItem instanceof StaticCompletionItem + && cItem.getKind().equals(CompletionItemKind.Module)) { + cItem.setSortText(Priority.PRIORITY130.toString()); + } else if (completionItem instanceof SymbolCompletionItem + && ((SymbolCompletionItem) completionItem).getSymbol() instanceof BTypeSymbol) { + cItem.setSortText(Priority.PRIORITY140.toString()); + } else { + cItem.setSortText(Priority.PRIORITY150.toString()); + } + } + + return cItems; + } + + private List getGlobalVarDefCompletions(LSContext context, List completionItems) { + List defaultTokenTypes = context.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY).stream() + .map(CommonToken::getType) + .collect(Collectors.toList()); + List cItems = new ArrayList<>(); + + int listenerKWIndex = defaultTokenTypes.indexOf(BallerinaParser.LISTENER); + // Listener Types are sorted + /* + Ex: public listener + public listener h + */ + boolean suggestListeners = listenerKWIndex > 0 && (listenerKWIndex == defaultTokenTypes.size() - 1 + || listenerKWIndex == defaultTokenTypes.size() - 2); + for (LSCompletionItem lsCItem : completionItems) { + CompletionItem cItem = lsCItem.getCompletionItem(); + if (suggestListeners && lsCItem instanceof SymbolCompletionItem + && ((SymbolCompletionItem) lsCItem).getSymbol() instanceof BTypeSymbol) { + cItem.setSortText(Priority.PRIORITY110.toString()); + } else { + cItem.setSortText(Priority.PRIORITY120.toString()); + } + cItems.add(cItem); + } + + return cItems; + } + + private boolean isTopLevel(LSContext context, ParserRuleContext parserRuleCtx) { + List commonTokens = context.get(SourcePruneKeys.LHS_DEFAULT_TOKENS_KEY); + return parserRuleCtx == null || (parserRuleCtx instanceof BallerinaParser.GlobalVariableDefinitionContext + && commonTokens.size() < 2); + } + + private boolean isGlobalVarDef(ParserRuleContext context) { + return context instanceof BallerinaParser.GlobalVariableDefinitionContext; + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/scope/ServiceScope.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/scope/ServiceScope.java new file mode 100644 index 000000000000..d8d5d30aec83 --- /dev/null +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/completions/util/sorters/scope/ServiceScope.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ballerinalang.langserver.completions.util.sorters.scope; + +import org.ballerinalang.langserver.SnippetBlock; +import org.ballerinalang.langserver.commons.LSContext; +import org.ballerinalang.langserver.commons.completion.LSCompletionItem; +import org.ballerinalang.langserver.completions.SnippetCompletionItem; +import org.ballerinalang.langserver.completions.util.Priority; +import org.ballerinalang.langserver.completions.util.sorters.CompletionItemSorter; +import org.eclipse.lsp4j.CompletionItem; +import org.wso2.ballerinalang.compiler.tree.BLangService; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nonnull; + +/** + * Item Sorter for service scope. + * + * @since 1.2.0 + */ +public class ServiceScope extends CompletionItemSorter { + @Override + public List sortItems(LSContext ctx, List lsCItems) { + List cItems = new ArrayList<>(); + + for (LSCompletionItem lsCItem : lsCItems) { + CompletionItem cItem = lsCItem.getCompletionItem(); + if (lsCItem instanceof SnippetCompletionItem && ((SnippetCompletionItem) lsCItem) + .getSnippetType().equals(SnippetBlock.SnippetType.SNIPPET)) { + cItem.setSortText(Priority.PRIORITY110.toString()); + } else if (lsCItem instanceof SnippetCompletionItem && ((SnippetCompletionItem) lsCItem) + .getSnippetType().equals(SnippetBlock.SnippetType.KEYWORD)) { + cItem.setSortText(Priority.PRIORITY120.toString()); + } else { + cItem.setSortText(Priority.PRIORITY130.toString()); + } + cItems.add(cItem); + } + return cItems; + } + + @Nonnull + @Override + protected List getAttachedContexts() { + return Collections.singletonList(BLangService.class); + } +} diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/signature/SignatureHelpUtil.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/signature/SignatureHelpUtil.java index 3a951c4e0a3b..dea97ef7414b 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/signature/SignatureHelpUtil.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/signature/SignatureHelpUtil.java @@ -27,7 +27,6 @@ import org.ballerinalang.langserver.compiler.DocumentServiceKeys; import org.ballerinalang.langserver.compiler.ExtendedLSCompiler; import org.ballerinalang.langserver.compiler.exception.CompilationFailedException; -import org.ballerinalang.langserver.completions.SymbolInfo; import org.ballerinalang.langserver.completions.util.SourcePruneException; import org.ballerinalang.langserver.signature.sourceprune.SignatureTokenTraverserFactory; import org.ballerinalang.langserver.sourceprune.SourcePruneKeys; @@ -44,6 +43,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser; import org.wso2.ballerinalang.compiler.semantics.analyzer.Types; +import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BObjectTypeSymbol; @@ -323,37 +323,34 @@ private static BLangExpression getInnerExpression(BLangNode node) { } } - public static Optional getFuncSymbolInfo(LSContext context, String funcName, - List visibleSymbols) { + public static Optional getFuncScopeEntry(LSContext context, String funcName, + List visibleSymbols) { CompilerContext compilerContext = context.get(DocumentServiceKeys.COMPILER_CONTEXT_KEY); SymbolTable symbolTable = SymbolTable.getInstance(compilerContext); Types types = Types.getInstance(compilerContext); String[] nameComps = funcName.split("\\."); int index = 0; - Optional searchSymbol = Optional.empty(); + Optional searchSymbol = Optional.empty(); while (index < nameComps.length) { String name = nameComps[index]; int pkgPrefix = name.indexOf(":"); boolean hasPkgPrefix = pkgPrefix > -1; if (!hasPkgPrefix) { searchSymbol = visibleSymbols.stream() - .filter(s -> name.equals(getLastItem(s.getSymbolName().split("\\.")))) + .filter(symbol -> + name.equals(getLastItem(symbol.symbol.name.getValue().split("\\.")))) .findFirst(); } else { String[] moduleComps = name.substring(0, pkgPrefix).split("/"); String alias = moduleComps[1].split(" ")[0]; - - Optional moduleSymbol = visibleSymbols.stream() - .filter(s -> s.getSymbolName().equals(alias)) + Optional moduleSymbol = visibleSymbols.stream() + .filter(entry -> entry.symbol.name.getValue().equals(alias)) .findFirst(); - - visibleSymbols = moduleSymbol.get().getScopeEntry().symbol.scope.entries.entrySet().stream() - .map(e -> new SymbolInfo(e.getKey().value, e.getValue())) - .collect(Collectors.toList()); - + visibleSymbols = new ArrayList<>(moduleSymbol.get().symbol.scope.entries.values()); searchSymbol = visibleSymbols.stream() - .filter(s -> name.substring(pkgPrefix + 1).equals(getLastItem(s.getSymbolName().split("\\.")))) + .filter(entry -> name.substring(pkgPrefix + 1) + .equals(getLastItem(entry.symbol.name.getValue().split("\\.")))) .findFirst(); } // If search symbol not found, return @@ -361,30 +358,26 @@ public static Optional getFuncSymbolInfo(LSContext context, String f break; } // The `searchSymbol` found, resolve further - boolean isInvocation = searchSymbol.get().getScopeEntry().symbol instanceof BInvokableSymbol; - boolean isObject = searchSymbol.get().getScopeEntry().symbol instanceof BObjectTypeSymbol; - boolean isVariable = searchSymbol.get().getScopeEntry().symbol instanceof BVarSymbol; + boolean isInvocation = searchSymbol.get().symbol instanceof BInvokableSymbol; + boolean isObject = searchSymbol.get().symbol instanceof BObjectTypeSymbol; + boolean isVariable = searchSymbol.get().symbol instanceof BVarSymbol; boolean hasNextNameComp = index + 1 < nameComps.length; if (isInvocation && hasNextNameComp) { - BInvokableSymbol invokableSymbol = (BInvokableSymbol) searchSymbol.get().getScopeEntry().symbol; + BInvokableSymbol invokableSymbol = (BInvokableSymbol) searchSymbol.get().symbol; BTypeSymbol returnTypeSymbol = invokableSymbol.getReturnType().tsymbol; if (returnTypeSymbol instanceof BObjectTypeSymbol) { BObjectTypeSymbol objectTypeSymbol = (BObjectTypeSymbol) returnTypeSymbol; - visibleSymbols = objectTypeSymbol.methodScope.entries.entrySet().stream() - .map(e -> new SymbolInfo(e.getKey().value, e.getValue())) - .collect(Collectors.toList()); + visibleSymbols = new ArrayList<>(objectTypeSymbol.methodScope.entries.values()); } } else if (isObject && hasNextNameComp) { - BObjectTypeSymbol bObjectTypeSymbol = (BObjectTypeSymbol) searchSymbol.get().getScopeEntry().symbol; + BObjectTypeSymbol bObjectTypeSymbol = (BObjectTypeSymbol) searchSymbol.get().symbol; BTypeSymbol typeSymbol = bObjectTypeSymbol.type.tsymbol; if (typeSymbol instanceof BObjectTypeSymbol) { BObjectTypeSymbol objectTypeSymbol = (BObjectTypeSymbol) typeSymbol; - visibleSymbols = objectTypeSymbol.methodScope.entries.entrySet().stream() - .map(e -> new SymbolInfo(e.getKey().value, e.getValue())) - .collect(Collectors.toList()); + visibleSymbols = new ArrayList<>(objectTypeSymbol.methodScope.entries.values()); } } else if (isVariable && hasNextNameComp) { - BVarSymbol bVarSymbol = (BVarSymbol) searchSymbol.get().getScopeEntry().symbol; + BVarSymbol bVarSymbol = (BVarSymbol) searchSymbol.get().symbol; BTypeSymbol typeSymbol = bVarSymbol.type.tsymbol; if (typeSymbol.type instanceof BUnionType) { // Check for optional field accesses. @@ -401,21 +394,14 @@ public static Optional getFuncSymbolInfo(LSContext context, String f } if (typeSymbol instanceof BObjectTypeSymbol) { BObjectTypeSymbol objectTypeSymbol = (BObjectTypeSymbol) typeSymbol; - visibleSymbols = objectTypeSymbol.methodScope.entries.entrySet().stream() - .map(e -> new SymbolInfo(e.getKey().value, e.getValue())) - .collect(Collectors.toList()); - visibleSymbols.addAll(objectTypeSymbol.scope.entries.entrySet().stream() - .map(e -> new SymbolInfo(e.getKey().value, e.getValue())) - .collect(Collectors.toList())); + visibleSymbols = new ArrayList<>(objectTypeSymbol.methodScope.entries.values()); + visibleSymbols.addAll(objectTypeSymbol.scope.entries.values()); } else if (typeSymbol instanceof BRecordTypeSymbol) { BRecordTypeSymbol bRecordTypeSymbol = (BRecordTypeSymbol) typeSymbol; - visibleSymbols = bRecordTypeSymbol.scope.entries.entrySet().stream() - .map(e -> new SymbolInfo(e.getKey().value, e.getValue())) - .collect(Collectors.toList()); + visibleSymbols = new ArrayList<>(bRecordTypeSymbol.scope.entries.values()); } else { - visibleSymbols = getLangLibScopeEntries(typeSymbol.type, symbolTable, types).entrySet().stream() - .map(e -> new SymbolInfo(e.getKey().value, e.getValue())) - .collect(Collectors.toList()); + visibleSymbols = new ArrayList<>(getLangLibScopeEntries(typeSymbol.type, symbolTable, types) + .values()); } } index++; diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/signature/SignatureTreeVisitor.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/signature/SignatureTreeVisitor.java index a4920a21d112..dd9af4fa0ad4 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/signature/SignatureTreeVisitor.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/signature/SignatureTreeVisitor.java @@ -22,7 +22,6 @@ import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.commons.LSContext; import org.ballerinalang.langserver.compiler.DocumentServiceKeys; -import org.ballerinalang.langserver.completions.SymbolInfo; import org.ballerinalang.model.elements.Flag; import org.ballerinalang.model.elements.PackageID; import org.ballerinalang.model.tree.TopLevelNode; @@ -291,19 +290,17 @@ private boolean isCursorWithinBlock() { /** * Populate the symbols. + * * @param symbolEntries symbol entries */ private void populateSymbols(Map> symbolEntries) { this.terminateVisitor = true; - List visibleSymbols = new ArrayList<>(); + List visibleSymbols = new ArrayList<>(); for (Map.Entry> entry : symbolEntries.entrySet()) { - Name name = entry.getKey(); List entryList = entry.getValue(); - List filteredSymbolInfos = entryList.stream() - .map(scopeEntry -> new SymbolInfo(name.value, scopeEntry)) - .collect(Collectors.toList()); - visibleSymbols.addAll(filteredSymbolInfos); + List symbolCompletionItems = new ArrayList<>(entryList); + visibleSymbols.addAll(symbolCompletionItems); } lsContext.put(CommonKeys.VISIBLE_SYMBOLS_KEY, visibleSymbols); } diff --git a/language-server/modules/langserver-core/src/test/java/org/ballerinalang/langserver/codeaction/CodeActionTest.java b/language-server/modules/langserver-core/src/test/java/org/ballerinalang/langserver/codeaction/CodeActionTest.java index 40931ca4f434..500740b8a4a6 100644 --- a/language-server/modules/langserver-core/src/test/java/org/ballerinalang/langserver/codeaction/CodeActionTest.java +++ b/language-server/modules/langserver-core/src/test/java/org/ballerinalang/langserver/codeaction/CodeActionTest.java @@ -244,6 +244,7 @@ public Object[][] codeActionQuickFixesDataProvider() { {"variableAssignmentRequiredCodeAction2.json", "createVariable.bal"}, {"variableAssignmentRequiredCodeAction3.json", "createVariable.bal"}, {"variableAssignmentRequiredCodeAction4.json", "createVariable.bal"}, + {"variableAssignmentRequiredCodeAction5.json", "createVariable2.bal"}, {"ignoreReturnValueCodeAction.json", "createVariable.bal"}, {"typeGuardCodeAction1.json", "typeGuard.bal"}, {"typeGuardCodeAction2.json", "typeGuard.bal"}, diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/source/createVariable2.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/source/createVariable2.bal new file mode 100644 index 000000000000..e42504e71de8 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/source/createVariable2.bal @@ -0,0 +1,5 @@ +import ballerina/crypto; + +function getCacheId(string str) { + crypto:hashMd5(str.toBytes()); +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/variableAssignmentRequiredCodeAction5.json b/language-server/modules/langserver-core/src/test/resources/codeaction/variableAssignmentRequiredCodeAction5.json new file mode 100644 index 000000000000..8bcb421f2554 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/variableAssignmentRequiredCodeAction5.json @@ -0,0 +1,20 @@ +{ + "line": 3, + "character": 26, + "expected": { + "title": "Create Local Variable", + "edit": { + "range": { + "start": { + "line": 3, + "character": 4 + }, + "end": { + "line": 3, + "character": 4 + } + }, + "newText": "byte[] hashMd5 = " + } + } +} diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/actionInvocationSuggestion1.json b/language-server/modules/langserver-core/src/test/resources/completion/function/actionInvocationSuggestion1.json index c5e3404d9c1c..97f70ee6fd1a 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/actionInvocationSuggestion1.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/actionInvocationSuggestion1.json @@ -6,13 +6,13 @@ "source": "function/source/actionInvocationSuggestion1.bal", "items": [ { - "label": "post(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "post(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.post()` function can be used to send HTTP POST requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.post()` function can be used to send HTTP POST requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -24,13 +24,13 @@ } }, { - "label": "head(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "head(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.head()` function can be used to send HTTP HEAD requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.head()` function can be used to send HTTP HEAD requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -42,13 +42,13 @@ } }, { - "label": "put(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "put(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.put()` function can be used to send HTTP PUT requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.put()` function can be used to send HTTP PUT requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -60,13 +60,13 @@ } }, { - "label": "execute(string httpVerb, string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "execute(string httpVerb, string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nInvokes an HTTP call with the specified HTTP verb.\n \n**Params** \n- `string` httpVerb: HTTP verb value \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nInvokes an HTTP call with the specified HTTP verb.\n \n**Params** \n- `string` httpVerb: HTTP verb value \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -78,13 +78,13 @@ } }, { - "label": "patch(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "patch(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.patch()` function can be used to send HTTP PATCH requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.patch()` function can be used to send HTTP PATCH requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -96,13 +96,13 @@ } }, { - "label": "delete(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "delete(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.delete()` function can be used to send HTTP DELETE requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.delete()` function can be used to send HTTP DELETE requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -114,13 +114,13 @@ } }, { - "label": "get(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "get(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.get()` function can be used to send HTTP GET requests to HTTP endpoints.\n \n**Params** \n- `string` path: Request path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.get()` function can be used to send HTTP GET requests to HTTP endpoints.\n \n**Params** \n- `string` path: Request path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -132,13 +132,13 @@ } }, { - "label": "options(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "options(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.options()` function can be used to send HTTP OPTIONS requests to HTTP endpoints.\n \n**Params** \n- `string` path: Request path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.options()` function can be used to send HTTP OPTIONS requests to HTTP endpoints.\n \n**Params** \n- `string` path: Request path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -150,13 +150,13 @@ } }, { - "label": "forward(string path, http:Request request)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "forward(string path, http:Request request)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.forward()` function can be used to invoke an HTTP call with inbound request's HTTP verb\n \n**Params** \n- `string` path: Request path \n- `http:Request` request: An HTTP inbound request message \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.forward()` function can be used to invoke an HTTP call with inbound request\u0027s HTTP verb\n \n**Params** \n- `string` path: Request path \n- `http:Request` request: An HTTP inbound request message \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -168,13 +168,13 @@ } }, { - "label": "submit(string httpVerb, string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "submit(string httpVerb, string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSubmits an HTTP request to a service with the specified HTTP verb.\nThe `Client.submit()` function does not give out a `Response` as the result,\nrather it returns an `HttpFuture` which can be used to do further interactions with the endpoint.\n \n**Params** \n- `string` httpVerb: The HTTP verb value \n- `string` path: The resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An `HttpFuture` that represents an asynchronous service invocation, or an `http:ClientError` if the submission fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nSubmits an HTTP request to a service with the specified HTTP verb.\nThe `Client.submit()` function does not give out a `Response` as the result,\nrather it returns an `HttpFuture` which can be used to do further interactions with the endpoint.\n \n**Params** \n- `string` httpVerb: The HTTP verb value \n- `string` path: The resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An `HttpFuture` that represents an asynchronous service invocation, or an `http:ClientError` if the submission fails \n \n" } }, "sortText": "120", @@ -186,13 +186,13 @@ } }, { - "label": "getResponse(http:HttpFuture httpFuture)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getResponse(http:HttpFuture httpFuture)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:HttpFuture` httpFuture: The `HttpFuture` relates to a previous asynchronous invocation \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An HTTP response message, or an error if the invocation fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:HttpFuture` httpFuture: The `HttpFuture` relates to a previous asynchronous invocation \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An HTTP response message, or an error if the invocation fails \n \n" } }, "sortText": "120", @@ -222,13 +222,13 @@ } }, { - "label": "getNextPromise(http:HttpFuture httpFuture)((http:PushPromise|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getNextPromise(http:HttpFuture httpFuture)((http:PushPromise|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:HttpFuture` httpFuture: The `HttpFuture` relates to a previous asynchronous invocation \n \n**Returns** `(http:PushPromise|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An HTTP Push Promise message, or an error if the invocation fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:HttpFuture` httpFuture: The `HttpFuture` relates to a previous asynchronous invocation \n \n**Returns** `(http:PushPromise|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An HTTP Push Promise message, or an error if the invocation fails \n \n" } }, "sortText": "120", @@ -240,13 +240,13 @@ } }, { - "label": "getPromisedResponse(http:PushPromise promise)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getPromisedResponse(http:PushPromise promise)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:PushPromise` promise: The related `PushPromise` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- A promised HTTP `Response` message, or an error if the invocation fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:PushPromise` promise: The related `PushPromise` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- A promised HTTP `Response` message, or an error if the invocation fails \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/actionInvocationSuggestion2.json b/language-server/modules/langserver-core/src/test/resources/completion/function/actionInvocationSuggestion2.json index 1066f0c04a20..477f9acedac6 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/actionInvocationSuggestion2.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/actionInvocationSuggestion2.json @@ -6,13 +6,13 @@ "source": "function/source/actionInvocationSuggestion2.bal", "items": [ { - "label": "post(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "post(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.post()` function can be used to send HTTP POST requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.post()` function can be used to send HTTP POST requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -24,13 +24,13 @@ } }, { - "label": "head(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "head(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.head()` function can be used to send HTTP HEAD requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.head()` function can be used to send HTTP HEAD requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -42,13 +42,13 @@ } }, { - "label": "put(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "put(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.put()` function can be used to send HTTP PUT requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.put()` function can be used to send HTTP PUT requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -60,13 +60,13 @@ } }, { - "label": "execute(string httpVerb, string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "execute(string httpVerb, string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nInvokes an HTTP call with the specified HTTP verb.\n \n**Params** \n- `string` httpVerb: HTTP verb value \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nInvokes an HTTP call with the specified HTTP verb.\n \n**Params** \n- `string` httpVerb: HTTP verb value \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -78,13 +78,13 @@ } }, { - "label": "patch(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "patch(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.patch()` function can be used to send HTTP PATCH requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.patch()` function can be used to send HTTP PATCH requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -96,13 +96,13 @@ } }, { - "label": "delete(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "delete(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.delete()` function can be used to send HTTP DELETE requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.delete()` function can be used to send HTTP DELETE requests to HTTP endpoints.\n \n**Params** \n- `string` path: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -114,13 +114,13 @@ } }, { - "label": "get(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "get(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.get()` function can be used to send HTTP GET requests to HTTP endpoints.\n \n**Params** \n- `string` path: Request path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.get()` function can be used to send HTTP GET requests to HTTP endpoints.\n \n**Params** \n- `string` path: Request path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -132,13 +132,13 @@ } }, { - "label": "options(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "options(string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.options()` function can be used to send HTTP OPTIONS requests to HTTP endpoints.\n \n**Params** \n- `string` path: Request path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.options()` function can be used to send HTTP OPTIONS requests to HTTP endpoints.\n \n**Params** \n- `string` path: Request path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An optional HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -150,13 +150,13 @@ } }, { - "label": "forward(string path, http:Request request)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "forward(string path, http:Request request)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe `Client.forward()` function can be used to invoke an HTTP call with inbound request's HTTP verb\n \n**Params** \n- `string` path: Request path \n- `http:Request` request: An HTTP inbound request message \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe `Client.forward()` function can be used to invoke an HTTP call with inbound request\u0027s HTTP verb\n \n**Params** \n- `string` path: Request path \n- `http:Request` request: An HTTP inbound request message \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -168,13 +168,13 @@ } }, { - "label": "submit(string httpVerb, string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "submit(string httpVerb, string path, (http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSubmits an HTTP request to a service with the specified HTTP verb.\nThe `Client.submit()` function does not give out a `Response` as the result,\nrather it returns an `HttpFuture` which can be used to do further interactions with the endpoint.\n \n**Params** \n- `string` httpVerb: The HTTP verb value \n- `string` path: The resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An `HttpFuture` that represents an asynchronous service invocation, or an `http:ClientError` if the submission fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nSubmits an HTTP request to a service with the specified HTTP verb.\nThe `Client.submit()` function does not give out a `Response` as the result,\nrather it returns an `HttpFuture` which can be used to do further interactions with the endpoint.\n \n**Params** \n- `string` httpVerb: The HTTP verb value \n- `string` path: The resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An `HttpFuture` that represents an asynchronous service invocation, or an `http:ClientError` if the submission fails \n \n" } }, "sortText": "120", @@ -186,13 +186,13 @@ } }, { - "label": "getResponse(http:HttpFuture httpFuture)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getResponse(http:HttpFuture httpFuture)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:HttpFuture` httpFuture: The `HttpFuture` relates to a previous asynchronous invocation \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An HTTP response message, or an error if the invocation fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:HttpFuture` httpFuture: The `HttpFuture` relates to a previous asynchronous invocation \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An HTTP response message, or an error if the invocation fails \n \n" } }, "sortText": "120", @@ -222,13 +222,13 @@ } }, { - "label": "getNextPromise(http:HttpFuture httpFuture)((http:PushPromise|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getNextPromise(http:HttpFuture httpFuture)((http:PushPromise|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:HttpFuture` httpFuture: The `HttpFuture` relates to a previous asynchronous invocation \n \n**Returns** `(http:PushPromise|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An HTTP Push Promise message, or an error if the invocation fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:HttpFuture` httpFuture: The `HttpFuture` relates to a previous asynchronous invocation \n \n**Returns** `(http:PushPromise|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An HTTP Push Promise message, or an error if the invocation fails \n \n" } }, "sortText": "120", @@ -240,13 +240,13 @@ } }, { - "label": "getPromisedResponse(http:PushPromise promise)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getPromisedResponse(http:PushPromise promise)((http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:PushPromise` promise: The related `PushPromise` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- A promised HTTP `Response` message, or an error if the invocation fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nThis just pass the request to actual network call.\n \n**Params** \n- `http:PushPromise` promise: The related `PushPromise` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- A promised HTTP `Response` message, or an error if the invocation fails \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/completionWithinTransaction.json b/language-server/modules/langserver-core/src/test/resources/completion/function/completionWithinTransaction.json index b72543f2e41a..8d1122ce4327 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/completionWithinTransaction.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/completionWithinTransaction.json @@ -5,1453 +5,1453 @@ }, "source": "function/source/commonCompletionBlocks.bal", "items": [ - { - "label": "xmlns", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "240", - "insertText": "xmlns \"${1}\" as ${2:ns};", - "insertTextFormat": "Snippet" - }, - { - "label": "var", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "220", - "insertText": "var ", - "insertTextFormat": "Snippet" - }, - { - "label": "wait", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "220", - "insertText": "wait ", - "insertTextFormat": "Snippet" - }, - { - "label": "start", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "220", - "insertText": "start ", - "insertTextFormat": "Snippet" - }, - { - "label": "flush", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "220", - "insertText": "flush ", - "insertTextFormat": "Snippet" - }, - { - "label": "function", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "220", - "insertText": "function ", - "insertTextFormat": "Snippet" - }, - { - "label": "error", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "240", - "insertText": "error ${1:name} = error(\"${2:errorCode}\", message = \"${3}\");", - "insertTextFormat": "Snippet" - }, - { - "label": "checkpanic", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "220", - "insertText": "checkpanic ", - "insertTextFormat": "Snippet" - }, - { - "label": "final", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "220", - "insertText": "final ", - "insertTextFormat": "Snippet" - }, - { - "label": "abort", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "abort;", - "insertTextFormat": "Snippet" - }, - { - "label": "foreach", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "foreach ${1:var} ${2:item} in ${3:itemList} {\n\t${4}\n}", - "insertTextFormat": "Snippet" - }, - { - "label": "fork", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "fork {\n\t${1}\n}", - "insertTextFormat": "Snippet" - }, - { - "label": "if", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "if (${1:true}) {\n\t${2}\n}", - "insertTextFormat": "Snippet" - }, - { - "label": "lock", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "lock {\n\t${1}\n}", - "insertTextFormat": "Snippet" - }, - { - "label": "match", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "match ", - "insertTextFormat": "Snippet" - }, - { - "label": "panic", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "panic ", - "insertTextFormat": "Snippet" - }, - { - "label": "retry", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "retry;", - "insertTextFormat": "Snippet" - }, - { - "label": "return", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "return ", - "insertTextFormat": "Snippet" - }, - { - "label": "transaction", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "transaction with retries = ${1:0} {\n\t${2}\n} onretry {\n\t${3}\n} committed {\n\t${4}\n} aborted {\n\t${5}\n}", - "insertTextFormat": "Snippet" - }, - { - "label": "while", - "kind": "Snippet", - "detail": "Statement", - "sortText": "240", - "insertText": "while (${1:true}) {\n\t${2}\n}", - "insertTextFormat": "Snippet" - }, - { - "label": "resp - typeguard resp", - "kind": "Snippet", - "detail": "Destructure the variable resp with typeguard", - "sortText": "240", - "insertText": "if (resp is error) {\n\t${1}\n} else {\n\t${20}\n}", - "insertTextFormat": "Snippet" - }, - { - "label": "initiateNestedTransactionInRemote(string nestingMethod)(string)", - "kind": "Function", - "detail": "Function", - "documentation": { - "right": { - "kind": "markdown", - "value": "**Package:** _._ \n \n \n**Params** \n- `string` nestingMethod \n \n**Returns** `string` \n \n" - } - }, - "sortText": "120", - "insertText": "initiateNestedTransactionInRemote(${1})", - "insertTextFormat": "Snippet", - "command": { - "title": "editor.action.triggerParameterHints", - "command": "editor.action.triggerParameterHints" - } - }, - { - "label": "float", - "kind": "Unit", - "detail": "Float", - "sortText": "230", - "insertText": "float", - "insertTextFormat": "Snippet" - }, - { - "label": "nestingMethod", - "kind": "Variable", - "detail": "string", - "sortText": "130", - "insertText": "nestingMethod", - "insertTextFormat": "Snippet" - }, - { - "label": "xml", - "kind": "Unit", - "detail": "Xml", - "sortText": "230", - "insertText": "xml", - "insertTextFormat": "Snippet" - }, - { - "label": "byte", - "kind": "Unit", - "detail": "Byte", - "sortText": "230", - "insertText": "byte", - "insertTextFormat": "Snippet" - }, - { - "label": "handle", - "kind": "Unit", - "detail": "Handle", - "sortText": "230", - "insertText": "handle", - "insertTextFormat": "Snippet" - }, - { - "label": "ArgsData", - "kind": "Struct", - "detail": "Record", - "documentation": { - "left": "Defaultable argument names. This is for internal use.\n" - }, - "sortText": "180", - "insertText": "ArgsData", - "insertTextFormat": "Snippet" - }, - { - "label": "divideNumbers(int a, int b)((int|error))", - "kind": "Function", - "detail": "Function", - "documentation": { - "right": { - "kind": "markdown", - "value": "**Package:** _._ \n \n \n**Params** \n- `int` a \n- `int` b \n \n**Returns** `(int|error)` \n \n" - } - }, - "sortText": "120", - "insertText": "divideNumbers(${1})", - "insertTextFormat": "Snippet", - "command": { - "title": "editor.action.triggerParameterHints", - "command": "editor.action.triggerParameterHints" - } - }, - { - "label": "null", - "kind": "Unit", - "detail": "Nil", - "sortText": "230", - "insertText": "null", - "insertTextFormat": "Snippet" - }, - { - "label": "decimal", - "kind": "Unit", - "detail": "Decimal", - "sortText": "230", - "insertText": "decimal", - "insertTextFormat": "Snippet" - }, - { - "label": "string", - "kind": "Unit", - "detail": "String", - "sortText": "230", - "insertText": "string", - "insertTextFormat": "Snippet" - }, - { - "label": "error", - "kind": "Event", - "detail": "Error", - "documentation": { - "left": "Default error type.\nThe first type parameter discribe reason type which must be a subtype of string,\nand the second type parameter is for the error detail.\nThe error detail record type may contain an optional message, optional cause,\nand any other pure constrained mapping values." - }, - "sortText": "200", - "insertText": "error", - "insertTextFormat": "Snippet" - }, - { - "label": "json", - "kind": "Unit", - "detail": "Json", - "sortText": "230", - "insertText": "json", - "insertTextFormat": "Snippet" - }, - { - "label": "functionForkJoin()(int)", - "kind": "Function", - "detail": "Function", - "documentation": { - "right": { - "kind": "markdown", - "value": "**Package:** _._ \n \n \n \n \n**Returns** `int` \n \n" - } - }, - "sortText": "120", - "insertText": "functionForkJoin()", - "insertTextFormat": "Snippet" - }, - { - "label": "StrandData", - "kind": "Struct", - "detail": "Record", - "documentation": { - "left": "Describes Strand execution details for the runtime.\n" - }, - "sortText": "180", - "insertText": "StrandData", - "insertTextFormat": "Snippet" - }, - { - "label": "map", - "kind": "Unit", - "detail": "Map", - "sortText": "230", - "insertText": "map", - "insertTextFormat": "Snippet" - }, - { - "label": "table", - "kind": "Unit", - "detail": "Table", - "sortText": "230", - "insertText": "table", - "insertTextFormat": "Snippet" - }, - { - "label": "anydata", - "kind": "Unit", - "detail": "Anydata", - "sortText": "230", - "insertText": "anydata", - "insertTextFormat": "Snippet" - }, - { - "label": "resp", - "kind": "Variable", - "detail": "(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)", - "sortText": "130", - "insertText": "resp", - "insertTextFormat": "Snippet" - }, - { - "label": "any", - "kind": "Unit", - "detail": "Any", - "sortText": "230", - "insertText": "any", - "insertTextFormat": "Snippet" - }, - { - "label": "int", - "kind": "Unit", - "detail": "Int", - "sortText": "230", - "insertText": "int", - "insertTextFormat": "Snippet" - }, - { - "label": "Thread", - "kind": "TypeParameter", - "detail": "Finite", - "sortText": "170", - "insertText": "Thread", - "insertTextFormat": "Snippet" - }, - { - "label": "s", - "kind": "Variable", - "detail": "string", - "sortText": "130", - "insertText": "s", - "insertTextFormat": "Snippet" - }, - { - "label": "boolean", - "kind": "Unit", - "detail": "Boolean", - "sortText": "230", - "insertText": "boolean", - "insertTextFormat": "Snippet" - }, - { - "label": "sampleService", - "kind": "Variable", - "detail": "sampleService", - "sortText": "130", - "insertText": "sampleService", - "insertTextFormat": "Snippet" - }, - { - "label": "future", - "kind": "Unit", - "detail": "Future", - "sortText": "230", - "insertText": "future", - "insertTextFormat": "Snippet" - }, - { - "label": "service", - "kind": "Unit", - "detail": "Service", - "sortText": "230", - "insertText": "service", - "insertTextFormat": "Snippet" - }, - { - "label": "typedesc", - "kind": "Unit", - "detail": "Typedesc", - "sortText": "230", - "insertText": "typedesc", - "insertTextFormat": "Snippet" - }, - { - "label": "remoteEp", - "kind": "Variable", - "detail": "http:Client", - "sortText": "130", - "insertText": "remoteEp", - "insertTextFormat": "Snippet" - }, - { - "label": "io", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "io", - "insertTextFormat": "Snippet" - }, - { - "label": "http", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "http", - "insertTextFormat": "Snippet" - }, - { - "label": "log", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "log", - "insertTextFormat": "Snippet" - }, - { - "label": "ballerinax/java.jdbc", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "jdbc", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerinax/java.jdbc;\n" - } - ] - }, - { - "label": "ballerinax/java", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "java", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerinax/java;\n" - } - ] - }, - { - "label": "ballerina/lang.object", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'object", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'object;\n" - } - ] - }, - { - "label": "ballerina/jwt", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "jwt", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/jwt;\n" - } - ] - }, - { - "label": "ballerina/lang.xml", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'xml", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'xml;\n" - } - ] - }, - { - "label": "ballerina/crypto", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "crypto", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/crypto;\n" - } - ] - }, - { - "label": "ballerina/lang.array", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'array", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'array;\n" - } - ] - }, - { - "label": "ballerina/stringutils", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "stringutils", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/stringutils;\n" - } - ] - }, - { - "label": "ballerina/cache", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "cache", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/cache;\n" - } - ] - }, - { - "label": "ballerina/test", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "test", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/test;\n" - } - ] - }, - { - "label": "ballerina/file", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "file", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/file;\n" - } - ] - }, - { - "label": "ballerina/grpc", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "grpc", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/grpc;\n" - } - ] - }, - { - "label": "ballerina/bir", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "bir", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/bir;\n" - } - ] - }, - { - "label": "ballerina/config", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "config", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/config;\n" - } - ] - }, - { - "label": "ballerina/auth", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "auth", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/auth;\n" - } - ] - }, - { - "label": "ballerina/filepath", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "filepath", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/filepath;\n" - } - ] - }, - { - "label": "ballerina/ldap", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "ldap", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/ldap;\n" - } - ] - }, - { - "label": "ballerina/reflect", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "reflect", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/reflect;\n" - } - ] - }, - { - "label": "ballerina/lang.string", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'string", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'string;\n" - } - ] - }, - { - "label": "ballerina/runtime", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "runtime", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/runtime;\n" - } - ] - }, - { - "label": "ballerina/oauth2", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "oauth2", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/oauth2;\n" - } - ] - }, - { - "label": "ballerina/jvm", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "jvm", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/jvm;\n" - } - ] - }, - { - "label": "ballerina/encoding", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "encoding", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/encoding;\n" - } - ] - }, - { - "label": "ballerina/rabbitmq", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "rabbitmq", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/rabbitmq;\n" - } - ] - }, - { - "label": "ballerina/lang.future", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'future", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'future;\n" - } - ] - }, - { - "label": "ballerina/lang.value", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'value", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'value;\n" - } - ] - }, - { - "label": "ballerina/openapi", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "openapi", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/openapi;\n" - } - ] - }, - { - "label": "ballerina/math", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "math", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/math;\n" - } - ] - }, - { - "label": "ballerina/time", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "time", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/time;\n" - } - ] - }, - { - "label": "ballerina/observe", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "observe", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/observe;\n" - } - ] - }, - { - "label": "ballerina/system", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "system", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/system;\n" - } - ] - }, - { - "label": "ballerina/lang.float", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'float", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'float;\n" - } - ] - }, - { - "label": "ballerina/transactions", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "transactions", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/transactions;\n" - } - ] - }, - { - "label": "ballerina/nats", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "nats", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/nats;\n" - } - ] - }, - { - "label": "ballerina/lang.decimal", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'decimal", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'decimal;\n" - } - ] - }, - { - "label": "ballerina/task", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "task", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/task;\n" - } - ] - }, - { - "label": "ballerina/lang.table", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'table", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } - }, - "newText": "import ballerina/lang.'table;\n" - } - ] - }, - { - "label": "ballerina/mime", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "mime", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } + { + "label": "xmlns", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "240", + "insertText": "xmlns \"${1}\" as ${2:ns};", + "insertTextFormat": "Snippet" + }, + { + "label": "var", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "220", + "insertText": "var ", + "insertTextFormat": "Snippet" + }, + { + "label": "wait", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "220", + "insertText": "wait ", + "insertTextFormat": "Snippet" + }, + { + "label": "start", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "220", + "insertText": "start ", + "insertTextFormat": "Snippet" + }, + { + "label": "flush", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "220", + "insertText": "flush ", + "insertTextFormat": "Snippet" + }, + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "220", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "error", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "240", + "insertText": "error ${1:name} \u003d error(\"${2:errorCode}\", message \u003d \"${3}\");", + "insertTextFormat": "Snippet" + }, + { + "label": "checkpanic", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "220", + "insertText": "checkpanic ", + "insertTextFormat": "Snippet" + }, + { + "label": "final", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "220", + "insertText": "final ", + "insertTextFormat": "Snippet" + }, + { + "label": "abort", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "abort;", + "insertTextFormat": "Snippet" + }, + { + "label": "foreach", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "foreach ${1:var} ${2:item} in ${3:itemList} {\n\t${4}\n}", + "insertTextFormat": "Snippet" + }, + { + "label": "fork", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "fork {\n\t${1}\n}", + "insertTextFormat": "Snippet" + }, + { + "label": "if", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "if (${1:true}) {\n\t${2}\n}", + "insertTextFormat": "Snippet" + }, + { + "label": "lock", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "lock {\n\t${1}\n}", + "insertTextFormat": "Snippet" + }, + { + "label": "match", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "match ", + "insertTextFormat": "Snippet" + }, + { + "label": "panic", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "panic ", + "insertTextFormat": "Snippet" + }, + { + "label": "retry", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "retry;", + "insertTextFormat": "Snippet" + }, + { + "label": "return", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "return ", + "insertTextFormat": "Snippet" + }, + { + "label": "transaction", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "transaction with retries \u003d ${1:0} {\n\t${2}\n} onretry {\n\t${3}\n} committed {\n\t${4}\n} aborted {\n\t${5}\n}", + "insertTextFormat": "Snippet" + }, + { + "label": "while", + "kind": "Snippet", + "detail": "Statement", + "sortText": "240", + "insertText": "while (${1:true}) {\n\t${2}\n}", + "insertTextFormat": "Snippet" + }, + { + "label": "resp - typeguard resp", + "kind": "Snippet", + "detail": "Destructure the variable resp with typeguard", + "sortText": "240", + "insertText": "if (resp is error) {\n\t${1}\n} else {\n\t${21}\n}", + "insertTextFormat": "Snippet" + }, + { + "label": "initiateNestedTransactionInRemote(string nestingMethod)(string)", + "kind": "Function", + "detail": "Function", + "documentation": { + "right": { + "kind": "markdown", + "value": "**Package:** _._ \n \n \n**Params** \n- `string` nestingMethod \n \n**Returns** `string` \n \n" + } }, - "newText": "import ballerina/mime;\n" - } - ] - }, - { - "label": "ballerina/lang.error", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'error", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } + "sortText": "120", + "insertText": "initiateNestedTransactionInRemote(${1})", + "insertTextFormat": "Snippet", + "command": { + "title": "editor.action.triggerParameterHints", + "command": "editor.action.triggerParameterHints" + } + }, + { + "label": "float", + "kind": "Unit", + "detail": "Float", + "sortText": "230", + "insertText": "float", + "insertTextFormat": "Snippet" + }, + { + "label": "nestingMethod", + "kind": "Variable", + "detail": "string", + "sortText": "130", + "insertText": "nestingMethod", + "insertTextFormat": "Snippet" + }, + { + "label": "xml", + "kind": "Unit", + "detail": "Xml", + "sortText": "230", + "insertText": "xml", + "insertTextFormat": "Snippet" + }, + { + "label": "byte", + "kind": "Unit", + "detail": "Byte", + "sortText": "230", + "insertText": "byte", + "insertTextFormat": "Snippet" + }, + { + "label": "handle", + "kind": "Unit", + "detail": "Handle", + "sortText": "230", + "insertText": "handle", + "insertTextFormat": "Snippet" + }, + { + "label": "ArgsData", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Defaultable argument names. This is for internal use.\n" }, - "newText": "import ballerina/lang.'error;\n" - } - ] - }, - { - "label": "ballerina/lang.typedesc", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'typedesc", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } + "sortText": "180", + "insertText": "ArgsData", + "insertTextFormat": "Snippet" + }, + { + "label": "divideNumbers(int a, int b)((int|error))", + "kind": "Function", + "detail": "Function", + "documentation": { + "right": { + "kind": "markdown", + "value": "**Package:** _._ \n \n \n**Params** \n- `int` a \n- `int` b \n \n**Returns** `(int|error)` \n \n" + } }, - "newText": "import ballerina/lang.'typedesc;\n" - } - ] - }, - { - "label": "ballerina/lang.map", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'map", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } + "sortText": "120", + "insertText": "divideNumbers(${1})", + "insertTextFormat": "Snippet", + "command": { + "title": "editor.action.triggerParameterHints", + "command": "editor.action.triggerParameterHints" + } + }, + { + "label": "null", + "kind": "Unit", + "detail": "Nil", + "sortText": "230", + "insertText": "null", + "insertTextFormat": "Snippet" + }, + { + "label": "decimal", + "kind": "Unit", + "detail": "Decimal", + "sortText": "230", + "insertText": "decimal", + "insertTextFormat": "Snippet" + }, + { + "label": "string", + "kind": "Unit", + "detail": "String", + "sortText": "230", + "insertText": "string", + "insertTextFormat": "Snippet" + }, + { + "label": "error", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Default error type.\nThe first type parameter discribe reason type which must be a subtype of string,\nand the second type parameter is for the error detail.\nThe error detail record type may contain an optional message, optional cause,\nand any other pure constrained mapping values." }, - "newText": "import ballerina/lang.'map;\n" - } - ] - }, - { - "label": "ballerina/lang.int", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "'int", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } + "sortText": "200", + "insertText": "error", + "insertTextFormat": "Snippet" + }, + { + "label": "json", + "kind": "Unit", + "detail": "Json", + "sortText": "230", + "insertText": "json", + "insertTextFormat": "Snippet" + }, + { + "label": "functionForkJoin()(int)", + "kind": "Function", + "detail": "Function", + "documentation": { + "right": { + "kind": "markdown", + "value": "**Package:** _._ \n \n \n \n \n**Returns** `int` \n \n" + } }, - "newText": "import ballerina/lang.'int;\n" - } - ] - }, - { - "label": "ballerina/socket", - "kind": "Module", - "detail": "Package", - "sortText": "140", - "insertText": "socket", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 3, - "character": 0 - } + "sortText": "120", + "insertText": "functionForkJoin()", + "insertTextFormat": "Snippet" + }, + { + "label": "StrandData", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Describes Strand execution details for the runtime.\n" }, - "newText": "import ballerina/socket;\n" - } - ] - } + "sortText": "180", + "insertText": "StrandData", + "insertTextFormat": "Snippet" + }, + { + "label": "map", + "kind": "Unit", + "detail": "Map", + "sortText": "230", + "insertText": "map", + "insertTextFormat": "Snippet" + }, + { + "label": "table", + "kind": "Unit", + "detail": "Table", + "sortText": "230", + "insertText": "table", + "insertTextFormat": "Snippet" + }, + { + "label": "anydata", + "kind": "Unit", + "detail": "Anydata", + "sortText": "230", + "insertText": "anydata", + "insertTextFormat": "Snippet" + }, + { + "label": "resp", + "kind": "Variable", + "detail": "(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)", + "sortText": "130", + "insertText": "resp", + "insertTextFormat": "Snippet" + }, + { + "label": "any", + "kind": "Unit", + "detail": "Any", + "sortText": "230", + "insertText": "any", + "insertTextFormat": "Snippet" + }, + { + "label": "int", + "kind": "Unit", + "detail": "Int", + "sortText": "230", + "insertText": "int", + "insertTextFormat": "Snippet" + }, + { + "label": "Thread", + "kind": "TypeParameter", + "detail": "Finite", + "sortText": "170", + "insertText": "Thread", + "insertTextFormat": "Snippet" + }, + { + "label": "s", + "kind": "Variable", + "detail": "string", + "sortText": "130", + "insertText": "s", + "insertTextFormat": "Snippet" + }, + { + "label": "boolean", + "kind": "Unit", + "detail": "Boolean", + "sortText": "230", + "insertText": "boolean", + "insertTextFormat": "Snippet" + }, + { + "label": "sampleService", + "kind": "Variable", + "detail": "sampleService", + "sortText": "130", + "insertText": "sampleService", + "insertTextFormat": "Snippet" + }, + { + "label": "future", + "kind": "Unit", + "detail": "Future", + "sortText": "230", + "insertText": "future", + "insertTextFormat": "Snippet" + }, + { + "label": "service", + "kind": "Unit", + "detail": "Service", + "sortText": "230", + "insertText": "service", + "insertTextFormat": "Snippet" + }, + { + "label": "typedesc", + "kind": "Unit", + "detail": "Typedesc", + "sortText": "230", + "insertText": "typedesc", + "insertTextFormat": "Snippet" + }, + { + "label": "remoteEp", + "kind": "Variable", + "detail": "http:Client", + "sortText": "130", + "insertText": "remoteEp", + "insertTextFormat": "Snippet" + }, + { + "label": "io", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "io", + "insertTextFormat": "Snippet" + }, + { + "label": "http", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "http", + "insertTextFormat": "Snippet" + }, + { + "label": "log", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "log", + "insertTextFormat": "Snippet" + }, + { + "label": "ballerina/bir", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "bir", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/bir;\n" + } + ] + }, + { + "label": "ballerina/transactions", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "transactions", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/transactions;\n" + } + ] + }, + { + "label": "ballerina/lang.value", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027value", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027value;\n" + } + ] + }, + { + "label": "ballerina/openapi", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "openapi", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/openapi;\n" + } + ] + }, + { + "label": "ballerina/test", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "test", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/test;\n" + } + ] + }, + { + "label": "ballerina/lang.future", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027future", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027future;\n" + } + ] + }, + { + "label": "ballerina/filepath", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "filepath", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/filepath;\n" + } + ] + }, + { + "label": "ballerina/cache", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "cache", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/cache;\n" + } + ] + }, + { + "label": "ballerina/mime", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "mime", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/mime;\n" + } + ] + }, + { + "label": "ballerina/lang.map", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027map", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027map;\n" + } + ] + }, + { + "label": "ballerina/jwt", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "jwt", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/jwt;\n" + } + ] + }, + { + "label": "ballerina/reflect", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "reflect", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/reflect;\n" + } + ] + }, + { + "label": "ballerina/ldap", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "ldap", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/ldap;\n" + } + ] + }, + { + "label": "ballerina/lang.table", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027table", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027table;\n" + } + ] + }, + { + "label": "ballerina/socket", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "socket", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/socket;\n" + } + ] + }, + { + "label": "ballerina/time", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "time", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/time;\n" + } + ] + }, + { + "label": "ballerina/crypto", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "crypto", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/crypto;\n" + } + ] + }, + { + "label": "ballerina/system", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "system", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/system;\n" + } + ] + }, + { + "label": "ballerina/lang.float", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027float", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027float;\n" + } + ] + }, + { + "label": "ballerina/lang.int", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027int", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027int;\n" + } + ] + }, + { + "label": "ballerina/lang.typedesc", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027typedesc", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027typedesc;\n" + } + ] + }, + { + "label": "ballerina/nats", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "nats", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/nats;\n" + } + ] + }, + { + "label": "ballerina/lang.xml", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027xml", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027xml;\n" + } + ] + }, + { + "label": "ballerina/lang.object", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027object", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027object;\n" + } + ] + }, + { + "label": "ballerina/lang.error", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027error", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027error;\n" + } + ] + }, + { + "label": "ballerina/lang.string", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027string", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027string;\n" + } + ] + }, + { + "label": "ballerina/observe", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "observe", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/observe;\n" + } + ] + }, + { + "label": "ballerina/stringutils", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "stringutils", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/stringutils;\n" + } + ] + }, + { + "label": "ballerina/file", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "file", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/file;\n" + } + ] + }, + { + "label": "ballerina/task", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "task", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/task;\n" + } + ] + }, + { + "label": "ballerina/lang.decimal", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027decimal", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027decimal;\n" + } + ] + }, + { + "label": "ballerina/jvm", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "jvm", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/jvm;\n" + } + ] + }, + { + "label": "ballerina/runtime", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "runtime", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/runtime;\n" + } + ] + }, + { + "label": "ballerina/config", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "config", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/config;\n" + } + ] + }, + { + "label": "ballerina/grpc", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "grpc", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/grpc;\n" + } + ] + }, + { + "label": "ballerina/lang.array", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "\u0027array", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/lang.\u0027array;\n" + } + ] + }, + { + "label": "ballerina/oauth2", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "oauth2", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/oauth2;\n" + } + ] + }, + { + "label": "ballerina/rabbitmq", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "rabbitmq", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/rabbitmq;\n" + } + ] + }, + { + "label": "ballerina/math", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "math", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/math;\n" + } + ] + }, + { + "label": "ballerina/auth", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "auth", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/auth;\n" + } + ] + }, + { + "label": "ballerina/encoding", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "encoding", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerina/encoding;\n" + } + ] + }, + { + "label": "ballerinax/java", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "java", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerinax/java;\n" + } + ] + }, + { + "label": "ballerinax/java.jdbc", + "kind": "Module", + "detail": "Package", + "sortText": "140", + "insertText": "jdbc", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 0 + } + }, + "newText": "import ballerinax/java.jdbc;\n" + } + ] + } ] -} \ No newline at end of file +} diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/delimiterBasedCompletionForCompleteSource1.json b/language-server/modules/langserver-core/src/test/resources/completion/function/delimiterBasedCompletionForCompleteSource1.json index 237df4a214d4..4e9b7f0a86aa 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/delimiterBasedCompletionForCompleteSource1.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/delimiterBasedCompletionForCompleteSource1.json @@ -957,6 +957,20 @@ "insertText": "WRITING_100_CONTINUE_RESPONSE_FAILED", "insertTextFormat": "Snippet" }, + { + "label": "INVALID_COOKIE_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:InvalidCookieError`" + } + }, + "sortText": "130", + "insertText": "INVALID_COOKIE_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "GENERIC_CLIENT_ERROR", "kind": "Variable", @@ -1041,6 +1055,20 @@ "insertText": "SSL_ERROR", "insertTextFormat": "Snippet" }, + { + "label": "COOKIE_HANDLING_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:CookieHandlingError`" + } + }, + "sortText": "130", + "insertText": "COOKIE_HANDLING_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "AGE", "kind": "Variable", @@ -2575,6 +2603,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -2988,6 +3027,17 @@ "insertText": "Writing100ContinueResponseError", "insertTextFormat": "Snippet" }, + { + "label": "InvalidCookieError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when sending cookies in the response" + }, + "sortText": "200", + "insertText": "InvalidCookieError", + "insertTextFormat": "Snippet" + }, { "label": "GenericClientError", "kind": "Event", @@ -3054,6 +3104,17 @@ "insertText": "SslError", "insertTextFormat": "Snippet" }, + { + "label": "CookieHandlingError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when using the cookies" + }, + "sortText": "200", + "insertText": "CookieHandlingError", + "insertTextFormat": "Snippet" + }, { "label": "ResiliencyError", "kind": "Event", @@ -3588,6 +3649,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WsConnectionClosureError", "kind": "Event", @@ -3676,6 +3748,28 @@ "insertText": "WebSocketError", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketFailoverClient", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "A WebSocket client endpoint, which provides failover support for multiple WebSocket targets." + }, + "sortText": "190", + "insertText": "WebSocketFailoverClient", + "insertTextFormat": "Snippet", + }, + { + "label": "WebSocketFailoverClientConfiguration", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Configurations for the WebSocket client endpoint.\n" + }, + "sortText": "180", + "insertText": "WebSocketFailoverClientConfiguration", + "insertTextFormat": "Snippet" + }, { "label": "BasicAuthHandler", "kind": "Interface", @@ -3698,6 +3792,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "190", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", @@ -3739,13 +3844,13 @@ } }, { - "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" } }, "sortText": "120", @@ -3757,13 +3862,13 @@ } }, { - "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns a tuple containing the value and its parameter map \n \n" + "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns a tuple containing the value and its parameter map \n \n" } }, "sortText": "120", @@ -3775,13 +3880,13 @@ } }, { - "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -3793,13 +3898,13 @@ } }, { - "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Created secure HTTP client \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Created secure HTTP client \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/errorLiftingSuggestions1.json b/language-server/modules/langserver-core/src/test/resources/completion/function/errorLiftingSuggestions1.json index fe3517439caf..8441b933aaa5 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/errorLiftingSuggestions1.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/errorLiftingSuggestions1.json @@ -150,13 +150,13 @@ } }, { - "label": "getBinaryPayload()((byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getBinaryPayload()((byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `byte[]`.\n \n \n \n**Returns** `(byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The byte[] representation of the message payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `byte[]`.\n \n \n \n**Returns** `(byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The byte[] representation of the message payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "121", @@ -232,13 +232,13 @@ } }, { - "label": "getXmlPayload()((xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getXmlPayload()((xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `xml` payload from the response.\n \n \n \n**Returns** `(xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `xml` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `xml` payload from the response.\n \n \n \n**Returns** `(xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `xml` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "121", @@ -264,13 +264,13 @@ } }, { - "label": "getByteChannel()((io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getByteChannel()((io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `ByteChannel`, except in the case of multiparts. To retrieve multiparts, use\n`Response.getBodyParts()`.\n \n \n \n**Returns** `(io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- A byte channel from which the message payload can be read or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `ByteChannel`, except in the case of multiparts. To retrieve multiparts, use\n`Response.getBodyParts()`.\n \n \n \n**Returns** `(io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- A byte channel from which the message payload can be read or `http:ClientError` in case of errors \n \n" } }, "sortText": "121", @@ -278,13 +278,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getEntity()((mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getEntity()((mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the `Entity` associated with the response.\n \n \n \n**Returns** `(mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `Entity` of the response. An `http:ClientError` is returned, if entity construction fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the `Entity` associated with the response.\n \n \n \n**Returns** `(mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `Entity` of the response. An `http:ClientError` is returned, if entity construction fails \n \n" } }, "sortText": "121", @@ -402,13 +402,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getBodyParts()((mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getBodyParts()((mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts body parts from the response. If the content type is not a composite media type, an error is returned.\n \n \n \n**Returns** `(mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns the body parts as an array of entities or an `http:ClientError` if there were any errors in \n constructing the body parts from the response \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts body parts from the response. If the content type is not a composite media type, an error is returned.\n \n \n \n**Returns** `(mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns the body parts as an array of entities or an `http:ClientError` if there were any errors in \n constructing the body parts from the response \n \n" } }, "sortText": "121", @@ -452,13 +452,13 @@ } }, { - "label": "getJsonPayload()((json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getJsonPayload()((json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtract `json` payload from the response. If the content type is not JSON, an `http:ClientError` is returned.\n \n \n \n**Returns** `(json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `json` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtract `json` payload from the response. If the content type is not JSON, an `http:ClientError` is returned.\n \n \n \n**Returns** `(json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `json` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "121", @@ -586,13 +586,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getTextPayload()((string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getTextPayload()((string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `text` payload from the response.\n \n \n \n**Returns** `(string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The string representation of the message payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `text` payload from the response.\n \n \n \n**Returns** `(string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The string representation of the message payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "121", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/ifWhileConditionContextCompletion4.json b/language-server/modules/langserver-core/src/test/resources/completion/function/ifWhileConditionContextCompletion4.json index 4cf9333231b7..5655b8ad812a 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/ifWhileConditionContextCompletion4.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/ifWhileConditionContextCompletion4.json @@ -377,6 +377,14 @@ "insertText": "CookieStore", "insertTextFormat": "Snippet" }, + { + "label": "myCookie", + "kind": "Struct", + "detail": "Record", + "sortText": "180", + "insertText": "myCookie", + "insertTextFormat": "Snippet" + }, { "label": "CookieClient", "kind": "Interface", @@ -388,6 +396,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -1109,6 +1128,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WebSocketConnector", "kind": "Interface", @@ -1131,6 +1161,28 @@ "insertText": "WebSocketError", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketFailoverClient", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "A WebSocket client endpoint, which provides failover support for multiple WebSocket targets." + }, + "sortText": "190", + "insertText": "WebSocketFailoverClient", + "insertTextFormat": "Snippet" + }, + { + "label": "WebSocketFailoverClientConfiguration", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Configurations for the WebSocket client endpoint.\n" + }, + "sortText": "180", + "insertText": "WebSocketFailoverClientConfiguration", + "insertTextFormat": "Snippet" + }, { "label": "BasicAuthHandler", "kind": "Interface", @@ -1153,6 +1205,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "190", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions1.json b/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions1.json index 2b3180292269..ddada1237657 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions1.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions1.json @@ -8,14 +8,13 @@ { "label": "bar(i)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _._ \n \n \n**Params** \n- `(string|int|boolean)` i \n \n**Returns** `(string|int|boolean)` \n \n" } }, - "sortText": "120", "insertText": "bar(i) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -27,7 +26,6 @@ "label": "io", "kind": "Module", "detail": "Package", - "sortText": "130", "insertText": "io", "insertTextFormat": "Snippet" }, @@ -35,15 +33,13 @@ "label": "http", "kind": "Module", "detail": "Package", - "sortText": "130", "insertText": "http", "insertTextFormat": "Snippet" }, { "label": "var5", "kind": "Variable", - "detail": "Snippet", - "sortText": "110", + "detail": "string", "insertText": "var5 {\n\t${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, @@ -51,15 +47,13 @@ "label": "var5", "kind": "Variable", "detail": "string", - "sortText": "130", "insertText": "var5", "insertTextFormat": "Snippet" }, { "label": "var4", "kind": "Variable", - "detail": "Snippet", - "sortText": "110", + "detail": "int", "insertText": "var4 {\n\t${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, @@ -67,15 +61,13 @@ "label": "var4", "kind": "Variable", "detail": "int", - "sortText": "130", "insertText": "var4", "insertTextFormat": "Snippet" }, { "label": "var2", "kind": "Variable", - "detail": "Snippet", - "sortText": "110", + "detail": "[string,int,boolean]", "insertText": "var2 {\n\t${1:[\"\", 0, false]} => {${2}}\n}", "insertTextFormat": "Snippet" }, @@ -83,15 +75,13 @@ "label": "var2", "kind": "Variable", "detail": "[string,int,boolean]", - "sortText": "130", "insertText": "var2", "insertTextFormat": "Snippet" }, { "label": "var1", "kind": "Variable", - "detail": "Snippet", - "sortText": "110", + "detail": "(string|int|boolean)", "insertText": "var1 {\n\t${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, @@ -99,15 +89,13 @@ "label": "var1", "kind": "Variable", "detail": "(string|int|boolean)", - "sortText": "130", "insertText": "var1", "insertTextFormat": "Snippet" }, { "label": "i", "kind": "Variable", - "detail": "Snippet", - "sortText": "110", + "detail": "(string|int|boolean)", "insertText": "i {\n\t${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, @@ -115,15 +103,13 @@ "label": "i", "kind": "Variable", "detail": "(string|int|boolean)", - "sortText": "130", "insertText": "i", "insertTextFormat": "Snippet" }, { "label": "p", "kind": "Variable", - "detail": "Snippet", - "sortText": "110", + "detail": "Person", "insertText": "p {\n\t${1:{name:\"\", age:0}} => {${2}}\n}", "insertTextFormat": "Snippet" }, @@ -131,7 +117,6 @@ "label": "p", "kind": "Variable", "detail": "Person", - "sortText": "130", "insertText": "p", "insertTextFormat": "Snippet" } diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions3.json b/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions3.json index d6dbd6f185f2..a1666d434729 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions3.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions3.json @@ -8,28 +8,26 @@ { "label": "fromJsonString(str)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.value_ \n \nParses a string in JSON format and returns the the value that it represents.\nAll numbers in the JSON will be represented as float values.\nReturns an error if the string cannot be parsed.\n \n \n \n**Returns** `(json|error)` \n- `str` parsed to json or error \n \n" } }, - "sortText": "120", "insertText": "fromJsonString(str) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "getCodePoint(str,index)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nReturns the code point of a character in a string.\n \n**Params** \n- `int` index: an index in `str` \n \n**Returns** `int` \n- the Unicode code point of the character at `index` in `str` \n \n" } }, - "sortText": "120", "insertText": "getCodePoint(str,index) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -40,42 +38,39 @@ { "label": "toCodePointInts(str)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nConverts a string to an array of code points.\n \n \n \n**Returns** `int[]` \n- an array with a code point for each character of `str` \n \n" } }, - "sortText": "120", "insertText": "toCodePointInts(str) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "toUpperAscii(str)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nConverts occurrences of a-z to A-Z.\nOther characters are left unchanged.\n \n \n \n**Returns** `string` \n- `str` with any occurrences of a-z converted to A-Z \n \n" } }, - "sortText": "120", "insertText": "toUpperAscii(str) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "substring(str,startIndex,endIndex)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nReturns a substring of a string.\n \n**Params** \n- `int` startIndex: the starting index, inclusive \n- `int` endIndex: the ending index, exclusive(Defaultable) \n \n**Returns** `string` \n- substring consisting of characters with index >= startIndex and < endIndex \n \n" } }, - "sortText": "120", "insertText": "substring(str,startIndex,endIndex) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -86,56 +81,52 @@ { "label": "iterator(str)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nReturns an iterator over the string.\nThe iterator will yield the substrings of length 1 in order.\n \n \n \n**Returns** `` \n- a new iterator object \n \n" } }, - "sortText": "120", "insertText": "iterator(str) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "isReadOnly(v)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.value_ \n \nTests whether `v` is read-only, i.e. immutable\nReturns true if read-only, false otherwise.\n \n \n \n**Returns** `boolean` \n- true if read-only, false otherwise \n \n" } }, - "sortText": "120", "insertText": "isReadOnly(v) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "trim(str)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nRemoves ASCII white space characters from the start and end of a string.\nThe ASCII white space characters are 0x9...0xD, 0x20.\n \n \n \n**Returns** `string` \n- `str` with leading or trailing ASCII white space characters removed \n \n" } }, - "sortText": "120", "insertText": "trim(str) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "join(separator)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nJoins zero or more strings together with a separator.\n \n**Params** \n- `string[]` strs: strings to be joined \n \n**Returns** `string` \n- a string consisting of all of `strs` concatenated in order \n with `separator` in between them \n \n" } }, - "sortText": "120", "insertText": "join(separator) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -146,14 +137,13 @@ { "label": "indexOf(str,substr,startIndex)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nSearches for one string in another string.\n \n**Params** \n- `string` substr: the string to search for \n- `int` startIndex: index to start searching from(Defaultable) \n \n**Returns** `(int|())` \n- index of the first occurrence of `substr` in `str` that is >= `startIndex`, \n or `()` if there is no such occurrence \n \n" } }, - "sortText": "120", "insertText": "indexOf(str,substr,startIndex) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -164,84 +154,78 @@ { "label": "toLowerAscii(str)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nConverts occurrences of A-Z to a-z.\nOther characters are left unchanged.\n \n \n \n**Returns** `string` \n- `str` with any occurrences of A-Z converted to a-z \n \n" } }, - "sortText": "120", "insertText": "toLowerAscii(str) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "toJsonString(v)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.value_ \n \nReturns the string that represents `v` in JSON format.\n \n \n \n**Returns** `string` \n- string representation of json \n \n" } }, - "sortText": "120", "insertText": "toJsonString(v) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "toBytes(str)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nRepresents `str` as an array of bytes using UTF-8.\n \n \n \n**Returns** `byte[]` \n- UTF-8 byte array \n \n" } }, - "sortText": "120", "insertText": "toBytes(str) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "cloneReadOnly(v)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.value_ \n \nReturns a clone of `v` that is read-only, i.e. immutable.\nIt corresponds to the ImmutableClone(v) abstract operation,\ndefined in the Ballerina Language Specification.\n \n" } }, - "sortText": "120", "insertText": "cloneReadOnly(v) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "length(str)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nReturns the length of the string.\n \n \n \n**Returns** `int` \n- the number of characters (code points) in `str` \n \n" } }, - "sortText": "120", "insertText": "length(str) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "concat()", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nConcatenates zero or more strings.\n \n \n \n**Returns** `string` \n- concatenation of all of the `strs`; empty string if `strs` is empty \n \n" } }, - "sortText": "120", "insertText": "concat() {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -252,14 +236,13 @@ { "label": "mergeJson(j1,j2)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.value_ \n \nMerges two json values.\n \n**Params** \n- `json` j2: json value \n \n**Returns** `(json|error)` \n- the merge of `j1` with `j2` or an error if the merge fails \n \nThe merge of `j1` with `j2` is defined as follows: \n- if `j1` is `()`, then the result is `j2` \n- if `j2` is `()`, then the result is `j1` \n- if `j1` is a mapping and `j2` is a mapping, then for each entry [k, j] in j2, \n set `j1[k]` to the merge of `j1[k]` with `j` \n - if `j1[k]` is undefined, then set `j1[k]` to `j` \n - if any merge fails, then the merge of `j1` with `j2` fails \n - otherwise, the result is `j1`. \n- otherwise, the merge fails \nIf the merge fails, then `j1` is unchanged. \n \n" } }, - "sortText": "120", "insertText": "mergeJson(j1,j2) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -270,28 +253,26 @@ { "label": "clone(v)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.value_ \n \nReturns a clone of `v`.\nA clone is a deep copy that does not copy immutable subtrees.\nA clone can therefore safely be used concurrently with the original.\nIt corresponds to the Clone(v) abstract operation,\ndefined in the Ballerina Language Specification.\n \n" } }, - "sortText": "120", "insertText": "clone(v) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "endsWith(str,substr)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nTests whether a string ends with another string.\n \n**Params** \n- `string` substr: the ending string \n \n**Returns** `boolean` \n- true if `str` ends with `substr`; false otherwise \n \n" } }, - "sortText": "120", "insertText": "endsWith(str,substr) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -302,28 +283,26 @@ { "label": "toString(v)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.value_ \n \nPerforms a minimal conversion of a value to a string.\nThe conversion is minimal in particular in the sense\nthat the conversion applied to a value that is already\na string does nothing. \n \n \n**Returns** `string` \n- a string resulting from the conversion \n \nThe result of `toString(v)` is as follows: \n \n- if `v` is a string, then returns `v` \n- if `v` is `()`, then returns an empty string \n- if `v` is boolean, then the string `true` or `false` \n- if `v` is an int, then return `v` represented as a decimal string \n- if `v` is a float or decimal, then return `v` represented as a decimal string, \n with a decimal point only if necessary, but without any suffix indicating the type of `v`; \n return `NaN`, `Infinity` for positive infinity, and `-Infinity` for negative infinity \n- if `v` is a list, then returns the results toString on each member of the list \n separated by a space character \n- if `v` is a map, then returns key=value for each member separated by a space character \n- if `v` is xml, then returns `v` in XML format (as if it occurred within an XML element) \n- if `v` is table, TBD \n- if `v` is an error, then a string consisting of the following in order \n 1. the string `error` \n 2. a space character \n 3. the reason string \n 4. if the detail record is non-empty \n 1. a space character \n 2. the result of calling toString on the detail record \n- if `v` is an object, then \n - if `v` provides a `toString` method with a string return type and no required methods, \n then the result of calling that method on `v` \n - otherwise, `object` followed by some implementation-dependent string \n- if `v` is any other behavioral type, then the identifier for the behavioral type \n (`function`, `future`, `service`, `typedesc` or `handle`) \n followed by some implementation-dependent string \n \nNote that `toString` may produce the same string for two Ballerina values \nthat are not equal (in the sense of the `==` operator). \n \n" } }, - "sortText": "120", "insertText": "toString(v) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet" }, { "label": "codePointCompare(str1,str2)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nLexicographically compares strings using their Unicode code points.\nThis orders strings in a consistent and well-defined way,\nbut the ordering will often not be consistent with cultural expectations\nfor sorted order.\n \n**Params** \n- `string` str2: the second string to be compared \n \n**Returns** `int` \n- an int that is less than, equal to or greater than zero, \n according as `str1` is less than, equal to or greater than `str2` \n \n" } }, - "sortText": "120", "insertText": "codePointCompare(str1,str2) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { @@ -334,14 +313,13 @@ { "label": "startsWith(str,substr)", "kind": "Function", - "detail": "Snippet", + "detail": "Function", "documentation": { "right": { "kind": "markdown", "value": "**Package:** _ballerina/lang.string_ \n \nTests whether a string starts with another string.\n \n**Params** \n- `string` substr: the starting string \n \n**Returns** `boolean` \n- true if `str` starts with `substr`; false otherwise \n \n" } }, - "sortText": "120", "insertText": "startsWith(str,substr) {\n${1:value} => {${2}}\n}", "insertTextFormat": "Snippet", "command": { diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions4.json b/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions4.json index 9e658ac6fd41..3c8b6296a42e 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions4.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/matchStatementSuggestions4.json @@ -957,6 +957,20 @@ "insertText": "WRITING_100_CONTINUE_RESPONSE_FAILED", "insertTextFormat": "Snippet" }, + { + "label": "INVALID_COOKIE_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:InvalidCookieError`" + } + }, + "sortText": "130", + "insertText": "INVALID_COOKIE_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "GENERIC_CLIENT_ERROR", "kind": "Variable", @@ -1041,6 +1055,20 @@ "insertText": "SSL_ERROR", "insertTextFormat": "Snippet" }, + { + "label": "COOKIE_HANDLING_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:CookieHandlingError`" + } + }, + "sortText": "130", + "insertText": "COOKIE_HANDLING_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "AGE", "kind": "Variable", @@ -2575,6 +2603,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -2988,6 +3027,17 @@ "insertText": "Writing100ContinueResponseError", "insertTextFormat": "Snippet" }, + { + "label": "InvalidCookieError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when sending cookies in the response" + }, + "sortText": "200", + "insertText": "InvalidCookieError", + "insertTextFormat": "Snippet" + }, { "label": "GenericClientError", "kind": "Event", @@ -3054,6 +3104,17 @@ "insertText": "SslError", "insertTextFormat": "Snippet" }, + { + "label": "CookieHandlingError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when using the cookies" + }, + "sortText": "200", + "insertText": "CookieHandlingError", + "insertTextFormat": "Snippet" + }, { "label": "ResiliencyError", "kind": "Event", @@ -3588,6 +3649,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WsConnectionClosureError", "kind": "Event", @@ -3676,6 +3748,28 @@ "insertText": "WebSocketError", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketFailoverClient", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "A WebSocket client endpoint, which provides failover support for multiple WebSocket targets." + }, + "sortText": "190", + "insertText": "WebSocketFailoverClient", + "insertTextFormat": "Snippet" + }, + { + "label": "WebSocketFailoverClientConfiguration", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Configurations for the WebSocket client endpoint.\n" + }, + "sortText": "180", + "insertText": "WebSocketFailoverClientConfiguration", + "insertTextFormat": "Snippet" + }, { "label": "BasicAuthHandler", "kind": "Interface", @@ -3698,6 +3792,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "190", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", @@ -3739,13 +3844,13 @@ } }, { - "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" } }, "sortText": "120", @@ -3757,13 +3862,13 @@ } }, { - "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns a tuple containing the value and its parameter map \n \n" + "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns a tuple containing the value and its parameter map \n \n" } }, "sortText": "120", @@ -3775,13 +3880,13 @@ } }, { - "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -3793,13 +3898,13 @@ } }, { - "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Created secure HTTP client \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Created secure HTTP client \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/typeGuardSuggestions3.json b/language-server/modules/langserver-core/src/test/resources/completion/function/typeGuardSuggestions3.json index 779d148d93ca..e1e72637a59f 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/typeGuardSuggestions3.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/typeGuardSuggestions3.json @@ -150,13 +150,13 @@ } }, { - "label": "getBinaryPayload()((byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getBinaryPayload()((byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `byte[]`.\n \n \n \n**Returns** `(byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The byte[] representation of the message payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `byte[]`.\n \n \n \n**Returns** `(byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The byte[] representation of the message payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -232,13 +232,13 @@ } }, { - "label": "getXmlPayload()((xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getXmlPayload()((xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `xml` payload from the response.\n \n \n \n**Returns** `(xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `xml` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `xml` payload from the response.\n \n \n \n**Returns** `(xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `xml` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -264,13 +264,13 @@ } }, { - "label": "getByteChannel()((io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getByteChannel()((io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `ByteChannel`, except in the case of multiparts. To retrieve multiparts, use\n`Response.getBodyParts()`.\n \n \n \n**Returns** `(io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- A byte channel from which the message payload can be read or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `ByteChannel`, except in the case of multiparts. To retrieve multiparts, use\n`Response.getBodyParts()`.\n \n \n \n**Returns** `(io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- A byte channel from which the message payload can be read or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -278,13 +278,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getEntity()((mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getEntity()((mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the `Entity` associated with the response.\n \n \n \n**Returns** `(mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `Entity` of the response. An `http:ClientError` is returned, if entity construction fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the `Entity` associated with the response.\n \n \n \n**Returns** `(mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `Entity` of the response. An `http:ClientError` is returned, if entity construction fails \n \n" } }, "sortText": "120", @@ -402,13 +402,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getBodyParts()((mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getBodyParts()((mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts body parts from the response. If the content type is not a composite media type, an error is returned.\n \n \n \n**Returns** `(mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns the body parts as an array of entities or an `http:ClientError` if there were any errors in \n constructing the body parts from the response \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts body parts from the response. If the content type is not a composite media type, an error is returned.\n \n \n \n**Returns** `(mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns the body parts as an array of entities or an `http:ClientError` if there were any errors in \n constructing the body parts from the response \n \n" } }, "sortText": "120", @@ -452,13 +452,13 @@ } }, { - "label": "getJsonPayload()((json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getJsonPayload()((json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtract `json` payload from the response. If the content type is not JSON, an `http:ClientError` is returned.\n \n \n \n**Returns** `(json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `json` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtract `json` payload from the response. If the content type is not JSON, an `http:ClientError` is returned.\n \n \n \n**Returns** `(json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `json` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -586,13 +586,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getTextPayload()((string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getTextPayload()((string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `text` payload from the response.\n \n \n \n**Returns** `(string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The string representation of the message payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `text` payload from the response.\n \n \n \n**Returns** `(string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The string representation of the message payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/variableBoundItemSuggestions3.json b/language-server/modules/langserver-core/src/test/resources/completion/function/variableBoundItemSuggestions3.json index 92c402fec6c5..fcdf4ade9709 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/variableBoundItemSuggestions3.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/variableBoundItemSuggestions3.json @@ -150,13 +150,13 @@ } }, { - "label": "getBinaryPayload()((byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getBinaryPayload()((byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `byte[]`.\n \n \n \n**Returns** `(byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The byte[] representation of the message payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `byte[]`.\n \n \n \n**Returns** `(byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The byte[] representation of the message payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -232,13 +232,13 @@ } }, { - "label": "getXmlPayload()((xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getXmlPayload()((xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `xml` payload from the response.\n \n \n \n**Returns** `(xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `xml` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `xml` payload from the response.\n \n \n \n**Returns** `(xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `xml` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -264,13 +264,13 @@ } }, { - "label": "getByteChannel()((io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getByteChannel()((io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `ByteChannel`, except in the case of multiparts. To retrieve multiparts, use\n`Response.getBodyParts()`.\n \n \n \n**Returns** `(io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- A byte channel from which the message payload can be read or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the response payload as a `ByteChannel`, except in the case of multiparts. To retrieve multiparts, use\n`Response.getBodyParts()`.\n \n \n \n**Returns** `(io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- A byte channel from which the message payload can be read or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -278,13 +278,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getEntity()((mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getEntity()((mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the `Entity` associated with the response.\n \n \n \n**Returns** `(mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `Entity` of the response. An `http:ClientError` is returned, if entity construction fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the `Entity` associated with the response.\n \n \n \n**Returns** `(mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `Entity` of the response. An `http:ClientError` is returned, if entity construction fails \n \n" } }, "sortText": "120", @@ -402,13 +402,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getBodyParts()((mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getBodyParts()((mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts body parts from the response. If the content type is not a composite media type, an error is returned.\n \n \n \n**Returns** `(mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns the body parts as an array of entities or an `http:ClientError` if there were any errors in \n constructing the body parts from the response \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts body parts from the response. If the content type is not a composite media type, an error is returned.\n \n \n \n**Returns** `(mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns the body parts as an array of entities or an `http:ClientError` if there were any errors in \n constructing the body parts from the response \n \n" } }, "sortText": "120", @@ -452,13 +452,13 @@ } }, { - "label": "getJsonPayload()((json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getJsonPayload()((json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtract `json` payload from the response. If the content type is not JSON, an `http:ClientError` is returned.\n \n \n \n**Returns** `(json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `json` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtract `json` payload from the response. If the content type is not JSON, an `http:ClientError` is returned.\n \n \n \n**Returns** `(json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `json` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -586,13 +586,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getTextPayload()((string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getTextPayload()((string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `text` payload from the response.\n \n \n \n**Returns** `(string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The string representation of the message payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `text` payload from the response.\n \n \n \n**Returns** `(string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The string representation of the message payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/function/workerDeclarationContext4.json b/language-server/modules/langserver-core/src/test/resources/completion/function/workerDeclarationContext4.json index 77dc6b4da5a7..18cf59891047 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/function/workerDeclarationContext4.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/function/workerDeclarationContext4.json @@ -377,6 +377,14 @@ "insertText": "CookieStore", "insertTextFormat": "Snippet" }, + { + "label": "myCookie", + "kind": "Struct", + "detail": "Record", + "sortText": "180", + "insertText": "myCookie", + "insertTextFormat": "Snippet" + }, { "label": "CookieClient", "kind": "Interface", @@ -388,6 +396,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -1109,6 +1128,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation":{ + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WebSocketConnector", "kind": "Interface", @@ -1131,6 +1161,28 @@ "insertText": "WebSocketError", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketFailoverClient", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "A WebSocket client endpoint, which provides failover support for multiple WebSocket targets." + }, + "sortText": "190", + "insertText": "WebSocketFailoverClient", + "insertTextFormat": "Snippet" + }, + { + "label": "WebSocketFailoverClientConfiguration", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Configurations for the WebSocket client endpoint.\n" + }, + "sortText": "180", + "insertText": "WebSocketFailoverClientConfiguration", + "insertTextFormat": "Snippet" + }, { "label": "BasicAuthHandler", "kind": "Interface", @@ -1153,6 +1205,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "190", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/object/objectTest13.json b/language-server/modules/langserver-core/src/test/resources/completion/object/objectTest13.json index ba6eac02f7bb..37f0afea535f 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/object/objectTest13.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/object/objectTest13.json @@ -377,6 +377,14 @@ "insertText": "CookieStore", "insertTextFormat": "Snippet" }, + { + "label": "myCookie", + "kind": "Struct", + "detail": "Record", + "sortText": "221", + "insertText": "myCookie", + "insertTextFormat": "Snippet" + }, { "label": "CookieClient", "kind": "Interface", @@ -388,6 +396,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "221", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -1109,6 +1128,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "221", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WebSocketConnector", "kind": "Interface", @@ -1131,6 +1161,28 @@ "insertText": "WebSocketError", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketFailoverClient", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "A WebSocket client endpoint, which provides failover support for multiple WebSocket targets." + }, + "sortText": "221", + "insertText": "WebSocketFailoverClient", + "insertTextFormat": "Snippet" + }, + { + "label": "WebSocketFailoverClientConfiguration", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Configurations for the WebSocket client endpoint.\n" + }, + "sortText": "221", + "insertText": "WebSocketFailoverClientConfiguration", + "insertTextFormat": "Snippet" + }, { "label": "BasicAuthHandler", "kind": "Interface", @@ -1153,6 +1205,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "221", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/object/objectTest15.json b/language-server/modules/langserver-core/src/test/resources/completion/object/objectTest15.json index f6378c6be732..49ba75ef7672 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/object/objectTest15.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/object/objectTest15.json @@ -5,60 +5,71 @@ }, "source": "object/source/objectTest15.bal", "items": [ - { - "label": "InboundAuthHandler", - "kind": "Interface", - "detail": "Object", - "documentation": { - "left": "The representation of an inbound authentication handler for HTTP traffic." + { + "label": "InboundAuthHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of an inbound authentication handler for HTTP traffic." + }, + "sortText": "190", + "insertText": "InboundAuthHandler", + "insertTextFormat": "Snippet" }, - "sortText": "190", - "insertText": "InboundAuthHandler", - "insertTextFormat": "Snippet" - }, - { - "label": "OutboundAuthHandler", - "kind": "Interface", - "detail": "Object", - "documentation": { - "left": "The representation of an outbound authentication handler for HTTP traffic." + { + "label": "OutboundAuthHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of an outbound authentication handler for HTTP traffic." + }, + "sortText": "190", + "insertText": "OutboundAuthHandler", + "insertTextFormat": "Snippet" }, - "sortText": "190", - "insertText": "OutboundAuthHandler", - "insertTextFormat": "Snippet" - }, - { - "label": "RequestFilter", - "kind": "Interface", - "detail": "Object", - "documentation": { - "left": "Abstract Representation of a HTTP Request Filter.\nThis filter will be applied before the request is dispatched to the relevant resource.\nAny RequestFilter implementation should be structurally similar to or implement the RequestFilter object." + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" }, - "sortText": "190", - "insertText": "RequestFilter", - "insertTextFormat": "Snippet" - }, - { - "label": "ResponseFilter", - "kind": "Interface", - "detail": "Object", - "documentation": { - "left": "Abstract Representation of a HTTP Response Filter.\nThis filter will be applied in the response path.\nAny ResponseFilter implementation should be structurally similar to or implement the ResponseFilter object." + { + "label": "RequestFilter", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Abstract Representation of a HTTP Request Filter.\nThis filter will be applied before the request is dispatched to the relevant resource.\nAny RequestFilter implementation should be structurally similar to or implement the RequestFilter object." + }, + "sortText": "190", + "insertText": "RequestFilter", + "insertTextFormat": "Snippet" }, - "sortText": "190", - "insertText": "ResponseFilter", - "insertTextFormat": "Snippet" - }, - { - "label": "LoadBalancerRule", - "kind": "Interface", - "detail": "Object", - "documentation": { - "left": "\nLoadBalancerRule provides a required interfaces to implement different algorithms.\n" + { + "label": "ResponseFilter", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Abstract Representation of a HTTP Response Filter.\nThis filter will be applied in the response path.\nAny ResponseFilter implementation should be structurally similar to or implement the ResponseFilter object." + }, + "sortText": "190", + "insertText": "ResponseFilter", + "insertTextFormat": "Snippet" }, - "sortText": "190", - "insertText": "LoadBalancerRule", - "insertTextFormat": "Snippet" - } + { + "label": "LoadBalancerRule", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "\nLoadBalancerRule provides a required interfaces to implement different algorithms.\n" + }, + "sortText": "190", + "insertText": "LoadBalancerRule", + "insertTextFormat": "Snippet" + } ] -} \ No newline at end of file +} diff --git a/language-server/modules/langserver-core/src/test/resources/completion/packageimport/packageImport1.json b/language-server/modules/langserver-core/src/test/resources/completion/packageimport/packageImport1.json index 4aad0cf4b256..7ad9a82309a1 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/packageimport/packageImport1.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/packageimport/packageImport1.json @@ -957,6 +957,20 @@ "insertText": "WRITING_100_CONTINUE_RESPONSE_FAILED", "insertTextFormat": "Snippet" }, + { + "label": "INVALID_COOKIE_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:InvalidCookieError`" + } + }, + "sortText": "130", + "insertText": "INVALID_COOKIE_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "GENERIC_CLIENT_ERROR", "kind": "Variable", @@ -1041,6 +1055,20 @@ "insertText": "SSL_ERROR", "insertTextFormat": "Snippet" }, + { + "label": "COOKIE_HANDLING_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:CookieHandlingError`" + } + }, + "sortText": "130", + "insertText": "COOKIE_HANDLING_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "AGE", "kind": "Variable", @@ -2575,6 +2603,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -2988,6 +3027,17 @@ "insertText": "Writing100ContinueResponseError", "insertTextFormat": "Snippet" }, + { + "label": "InvalidCookieError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when sending cookies in the response" + }, + "sortText": "200", + "insertText": "InvalidCookieError", + "insertTextFormat": "Snippet" + }, { "label": "GenericClientError", "kind": "Event", @@ -3054,6 +3104,17 @@ "insertText": "SslError", "insertTextFormat": "Snippet" }, + { + "label": "CookieHandlingError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when using the cookies" + }, + "sortText": "200", + "insertText": "CookieHandlingError", + "insertTextFormat": "Snippet" + }, { "label": "ResiliencyError", "kind": "Event", @@ -3588,6 +3649,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WsConnectionClosureError", "kind": "Event", @@ -3676,6 +3748,28 @@ "insertText": "WebSocketError", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketFailoverClient", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "A WebSocket client endpoint, which provides failover support for multiple WebSocket targets." + }, + "sortText": "190", + "insertText": "WebSocketFailoverClient", + "insertTextFormat": "Snippet" + }, + { + "label": "WebSocketFailoverClientConfiguration", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Configurations for the WebSocket client endpoint.\n" + }, + "sortText": "180", + "insertText": "WebSocketFailoverClientConfiguration", + "insertTextFormat": "Snippet" + }, { "label": "BasicAuthHandler", "kind": "Interface", @@ -3698,6 +3792,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "190", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", @@ -3739,13 +3844,13 @@ } }, { - "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" } }, "sortText": "120", @@ -3757,13 +3862,13 @@ } }, { - "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns a tuple containing the value and its parameter map \n \n" + "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns a tuple containing the value and its parameter map \n \n" } }, "sortText": "120", @@ -3775,13 +3880,13 @@ } }, { - "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -3793,13 +3898,13 @@ } }, { - "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Created secure HTTP client \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Created secure HTTP client \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/resource/actionInvocationSuggestion1.json b/language-server/modules/langserver-core/src/test/resources/completion/resource/actionInvocationSuggestion1.json index 2fb944cecaf4..af8cc14fd10e 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/resource/actionInvocationSuggestion1.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/resource/actionInvocationSuggestion1.json @@ -6,13 +6,13 @@ "source": "resource/source/actionInvocationSuggestion1.bal", "items": [ { - "label": "respond((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "respond((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" } }, "sortText": "120", @@ -24,13 +24,13 @@ } }, { - "label": "promise(http:PushPromise promise)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "promise(http:PushPromise promise)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nPushes a promise to the caller.\n \n**Params** \n- `http:PushPromise` promise: Push promise message \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- An `http:ListenerError` in case of failures \n \n" + "value": "**Package:** _ballerina/http_ \n \nPushes a promise to the caller.\n \n**Params** \n- `http:PushPromise` promise: Push promise message \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- An `http:ListenerError` in case of failures \n \n" } }, "sortText": "120", @@ -42,13 +42,13 @@ } }, { - "label": "pushPromisedResponse(http:PushPromise promise, http:Response response)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "pushPromisedResponse(http:PushPromise promise, http:Response response)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends a promised push response to the caller.\n \n**Params** \n- `http:PushPromise` promise: Push promise message \n- `http:Response` response: The outbound response \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- An `http:ListenerError` in case of failures while responding with the promised response \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends a promised push response to the caller.\n \n**Params** \n- `http:PushPromise` promise: Push promise message \n- `http:Response` response: The outbound response \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- An `http:ListenerError` in case of failures while responding with the promised response \n \n" } }, "sortText": "120", @@ -60,13 +60,13 @@ } }, { - "label": "acceptWebSocketUpgrade(map headers)((http:WebSocketCaller|http:WsConnectionClosureError|http:WsInvalidHandshakeError|http:WsPayloadTooBigError|http:WsProtocolError|http:WsConnectionError|http:WsInvalidContinuationFrameError|http:WsGenericError))", + "label": "acceptWebSocketUpgrade(map\u003cstring\u003e headers)((http:WebSocketCaller|http:WsConnectionClosureError|http:WsInvalidHandshakeError|http:WsPayloadTooBigError|http:WsProtocolError|http:WsConnectionError|http:WsInvalidContinuationFrameError|http:WsGenericError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends an upgrade request with custom headers.\n \n**Params** \n- `map` headers: A `map` of custom headers for handshake \n \n**Returns** `(http:WebSocketCaller|http:WsConnectionClosureError|http:WsInvalidHandshakeError|http:WsPayloadTooBigError|http:WsProtocolError|http:WsConnectionError|http:WsInvalidContinuationFrameError|http:WsGenericError)` \n- `WebSocketCaller` or error on failure to upgrade \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends an upgrade request with custom headers.\n \n**Params** \n- `map\u003cstring\u003e` headers: A `map` of custom headers for handshake \n \n**Returns** `(http:WebSocketCaller|http:WsConnectionClosureError|http:WsInvalidHandshakeError|http:WsPayloadTooBigError|http:WsProtocolError|http:WsConnectionError|http:WsInvalidContinuationFrameError|http:WsGenericError)` \n- `WebSocketCaller` or error on failure to upgrade \n \n" } }, "sortText": "120", @@ -96,13 +96,13 @@ } }, { - "label": "continue()((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "continue()((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends a `100-continue` response to the caller.\n \n \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to send the `100-continue` response \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends a `100-continue` response to the caller.\n \n \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to send the `100-continue` response \n \n" } }, "sortText": "120", @@ -110,13 +110,13 @@ "insertTextFormat": "Snippet" }, { - "label": "redirect(http:Response response, (300|301|302|303|304|305|307|308) code, string[] locations)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "redirect(http:Response response, (300|301|302|303|304|305|307|308) code, string[] locations)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends a redirect response to the user with the specified redirection status code.\n \n**Params** \n- `http:Response` response: Response to be sent to the caller \n- `(300|301|302|303|304|305|307|308)` code: The redirect status code to be sent \n- `string[]` locations: An array of URLs to which the caller can redirect to \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to send the redirect response \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends a redirect response to the user with the specified redirection status code.\n \n**Params** \n- `http:Response` response: Response to be sent to the caller \n- `(300|301|302|303|304|305|307|308)` code: The redirect status code to be sent \n- `string[]` locations: An array of URLs to which the caller can redirect to \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to send the redirect response \n \n" } }, "sortText": "120", @@ -128,13 +128,13 @@ } }, { - "label": "ok((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "ok((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 200 OK.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 200 OK.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" } }, "sortText": "120", @@ -146,13 +146,13 @@ } }, { - "label": "created(string uri, (http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "created(string uri, (http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 201 Created.\n \n**Params** \n- `string` uri: Represents the most specific URI for the newly created resource \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`. This message is optional.(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 201 Created.\n \n**Params** \n- `string` uri: Represents the most specific URI for the newly created resource \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`. This message is optional.(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" } }, "sortText": "120", @@ -164,13 +164,13 @@ } }, { - "label": "accepted((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "accepted((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 202 Accepted.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`. This message is optional.(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 202 Accepted.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`. This message is optional.(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/resource/actionInvocationSuggestion2.json b/language-server/modules/langserver-core/src/test/resources/completion/resource/actionInvocationSuggestion2.json index 815b340bbd3f..f45bf6b4a818 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/resource/actionInvocationSuggestion2.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/resource/actionInvocationSuggestion2.json @@ -6,13 +6,13 @@ "source": "resource/source/actionInvocationSuggestion2.bal", "items": [ { - "label": "respond((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "respond((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`,\n `io:ReadableByteChannel` or `mime:Entity[]`(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" } }, "sortText": "120", @@ -24,13 +24,13 @@ } }, { - "label": "promise(http:PushPromise promise)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "promise(http:PushPromise promise)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nPushes a promise to the caller.\n \n**Params** \n- `http:PushPromise` promise: Push promise message \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- An `http:ListenerError` in case of failures \n \n" + "value": "**Package:** _ballerina/http_ \n \nPushes a promise to the caller.\n \n**Params** \n- `http:PushPromise` promise: Push promise message \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- An `http:ListenerError` in case of failures \n \n" } }, "sortText": "120", @@ -42,13 +42,13 @@ } }, { - "label": "pushPromisedResponse(http:PushPromise promise, http:Response response)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "pushPromisedResponse(http:PushPromise promise, http:Response response)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends a promised push response to the caller.\n \n**Params** \n- `http:PushPromise` promise: Push promise message \n- `http:Response` response: The outbound response \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- An `http:ListenerError` in case of failures while responding with the promised response \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends a promised push response to the caller.\n \n**Params** \n- `http:PushPromise` promise: Push promise message \n- `http:Response` response: The outbound response \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- An `http:ListenerError` in case of failures while responding with the promised response \n \n" } }, "sortText": "120", @@ -60,13 +60,13 @@ } }, { - "label": "acceptWebSocketUpgrade(map headers)((http:WebSocketCaller|http:WsConnectionClosureError|http:WsInvalidHandshakeError|http:WsPayloadTooBigError|http:WsProtocolError|http:WsConnectionError|http:WsInvalidContinuationFrameError|http:WsGenericError))", + "label": "acceptWebSocketUpgrade(map\u003cstring\u003e headers)((http:WebSocketCaller|http:WsConnectionClosureError|http:WsInvalidHandshakeError|http:WsPayloadTooBigError|http:WsProtocolError|http:WsConnectionError|http:WsInvalidContinuationFrameError|http:WsGenericError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends an upgrade request with custom headers.\n \n**Params** \n- `map` headers: A `map` of custom headers for handshake \n \n**Returns** `(http:WebSocketCaller|http:WsConnectionClosureError|http:WsInvalidHandshakeError|http:WsPayloadTooBigError|http:WsProtocolError|http:WsConnectionError|http:WsInvalidContinuationFrameError|http:WsGenericError)` \n- `WebSocketCaller` or error on failure to upgrade \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends an upgrade request with custom headers.\n \n**Params** \n- `map\u003cstring\u003e` headers: A `map` of custom headers for handshake \n \n**Returns** `(http:WebSocketCaller|http:WsConnectionClosureError|http:WsInvalidHandshakeError|http:WsPayloadTooBigError|http:WsProtocolError|http:WsConnectionError|http:WsInvalidContinuationFrameError|http:WsGenericError)` \n- `WebSocketCaller` or error on failure to upgrade \n \n" } }, "sortText": "120", @@ -96,13 +96,13 @@ } }, { - "label": "continue()((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "continue()((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends a `100-continue` response to the caller.\n \n \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to send the `100-continue` response \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends a `100-continue` response to the caller.\n \n \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to send the `100-continue` response \n \n" } }, "sortText": "120", @@ -110,13 +110,13 @@ "insertTextFormat": "Snippet" }, { - "label": "redirect(http:Response response, (300|301|302|303|304|305|307|308) code, string[] locations)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "redirect(http:Response response, (300|301|302|303|304|305|307|308) code, string[] locations)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends a redirect response to the user with the specified redirection status code.\n \n**Params** \n- `http:Response` response: Response to be sent to the caller \n- `(300|301|302|303|304|305|307|308)` code: The redirect status code to be sent \n- `string[]` locations: An array of URLs to which the caller can redirect to \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to send the redirect response \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends a redirect response to the user with the specified redirection status code.\n \n**Params** \n- `http:Response` response: Response to be sent to the caller \n- `(300|301|302|303|304|305|307|308)` code: The redirect status code to be sent \n- `string[]` locations: An array of URLs to which the caller can redirect to \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to send the redirect response \n \n" } }, "sortText": "120", @@ -128,13 +128,13 @@ } }, { - "label": "ok((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "ok((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 200 OK.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 200 OK.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" } }, "sortText": "120", @@ -146,13 +146,13 @@ } }, { - "label": "created(string uri, (http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "created(string uri, (http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 201 Created.\n \n**Params** \n- `string` uri: Represents the most specific URI for the newly created resource \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`. This message is optional.(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 201 Created.\n \n**Params** \n- `string` uri: Represents the most specific URI for the newly created resource \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`. This message is optional.(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" } }, "sortText": "120", @@ -164,13 +164,13 @@ } }, { - "label": "accepted((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError))", + "label": "accepted((http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[]) message)((()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 202 Accepted.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`. This message is optional.(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" + "value": "**Package:** _ballerina/http_ \n \nSends the outbound response to the caller with the status 202 Accepted.\n \n**Params** \n- `(http:Response|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` message: The outbound response or any payload of type `string`, `xml`, `json`, `byte[]`, `io:ReadableByteChannel`\n or `mime:Entity[]`. This message is optional.(Defaultable) \n \n**Returns** `(()|http:GenericListenerError|http:InitializingInboundRequestError|http:ReadingInboundRequestHeadersError|http:ReadingInboundRequestBodyError|http:InitializingOutboundResponseError|http:WritingOutboundResponseHeadersError|http:WritingOutboundResponseBodyError|http:Initiating100ContinueResponseError|http:Writing100ContinueResponseError|http:InvalidCookieError)` \n- Returns an `http:ListenerError` if failed to respond \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/resource/completionBeforeUnderscore2.json b/language-server/modules/langserver-core/src/test/resources/completion/resource/completionBeforeUnderscore2.json index 2d4f59e7d7fd..31ddb28b800d 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/resource/completionBeforeUnderscore2.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/resource/completionBeforeUnderscore2.json @@ -14,13 +14,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getXmlPayload()((xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getXmlPayload()((xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `xml` payload from the request. If the content type is not XML, an `http:ClientError` is returned.\n \n \n \n**Returns** `(xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `xml` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `xml` payload from the request. If the content type is not XML, an `http:ClientError` is returned.\n \n \n \n**Returns** `(xml|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `xml` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -46,13 +46,13 @@ } }, { - "label": "getJsonPayload()((json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getJsonPayload()((json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `json` payload from the request. If the content type is not JSON, an `http:ClientError` is returned.\n \n \n \n**Returns** `(json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `json` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `json` payload from the request. If the content type is not JSON, an `http:ClientError` is returned.\n \n \n \n**Returns** `(json|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `json` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -60,13 +60,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getBinaryPayload()((byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getBinaryPayload()((byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the request payload as a `byte[]`.\n \n \n \n**Returns** `(byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The byte[] representation of the message payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the request payload as a `byte[]`.\n \n \n \n**Returns** `(byte[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The byte[] representation of the message payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -102,13 +102,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getTextPayload()((string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getTextPayload()((string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts `text` payload from the request. If the content type is not of type text, an `http:ClientError` is returned.\n \n \n \n**Returns** `(string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `text` payload or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts `text` payload from the request. If the content type is not of type text, an `http:ClientError` is returned.\n \n \n \n**Returns** `(string|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `text` payload or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -134,13 +134,13 @@ } }, { - "label": "getByteChannel()((io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getByteChannel()((io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the request payload as a `ByteChannel` except in the case of multiparts. To retrieve multiparts, use\n`Request.getBodyParts()`.\n \n \n \n**Returns** `(io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- A byte channel from which the message payload can be read or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the request payload as a `ByteChannel` except in the case of multiparts. To retrieve multiparts, use\n`Request.getBodyParts()`.\n \n \n \n**Returns** `(io:ReadableByteChannel|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- A byte channel from which the message payload can be read or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", @@ -280,13 +280,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getEntity()((mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getEntity()((mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the `Entity` associated with the request.\n \n \n \n**Returns** `(mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The `Entity` of the request. An `http:ClientError` is returned, if entity construction fails \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the `Entity` associated with the request.\n \n \n \n**Returns** `(mime:Entity|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The `Entity` of the request. An `http:ClientError` is returned, if entity construction fails \n \n" } }, "sortText": "120", @@ -370,13 +370,13 @@ } }, { - "label": "getBodyParts()((mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getBodyParts()((mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nExtracts body parts from the request. If the content type is not a composite media type, an error\nis returned. \n \n \n**Returns** `(mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns the body parts as an array of entities or an `http:ClientError` if there were any errors in \n constructing the body parts from the request \n \n" + "value": "**Package:** _ballerina/http_ \n \nExtracts body parts from the request. If the content type is not a composite media type, an error\nis returned. \n \n \n**Returns** `(mime:Entity[]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns the body parts as an array of entities or an `http:ClientError` if there were any errors in \n constructing the body parts from the request \n \n" } }, "sortText": "120", @@ -384,13 +384,13 @@ "insertTextFormat": "Snippet" }, { - "label": "getFormParams()((map\u003cstring\u003e|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "getFormParams()((map\u003cstring\u003e|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nGets the form parameters from the HTTP request as a `map` when content type is application/x-www-form-urlencoded.\n \n \n \n**Returns** `(map\u003cstring\u003e|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The map of form params or `http:ClientError` in case of errors \n \n" + "value": "**Package:** _ballerina/http_ \n \nGets the form parameters from the HTTP request as a `map` when content type is application/x-www-form-urlencoded.\n \n \n \n**Returns** `(map\u003cstring\u003e|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The map of form params or `http:ClientError` in case of errors \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/grpcServiceBodyResourceCompletion.json b/language-server/modules/langserver-core/src/test/resources/completion/service/grpcServiceBodyResourceCompletion.json index 32c3c684862f..68aef0617d23 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/grpcServiceBodyResourceCompletion.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/grpcServiceBodyResourceCompletion.json @@ -13,6 +13,22 @@ "insertText": "public ", "insertTextFormat": "Snippet" }, + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "resource", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "resource ", + "insertTextFormat": "Snippet" + }, { "label": "resource", "kind": "Snippet", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/httpServiceBodyResourceCompletion.json b/language-server/modules/langserver-core/src/test/resources/completion/service/httpServiceBodyResourceCompletion.json index 1bf0d38ac724..022bc332c877 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/httpServiceBodyResourceCompletion.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/httpServiceBodyResourceCompletion.json @@ -1,106 +1,122 @@ { - "position": { - "line": 3, - "character": 4 + "position": { + "line": 3, + "character": 4 + }, + "source": "service/source/httpServiceBodyResourceCompletion.bal", + "items": [ + { + "label": "public", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "public ", + "insertTextFormat": "Snippet" }, - "source": "service/source/httpServiceBodyResourceCompletion.bal", - "items": [ - { - "label": "public", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "120", - "insertText": "public ", - "insertTextFormat": "Snippet" - }, - { - "label": "websocket onOpen resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onOpen(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onText resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onText(http:WebSocketCaller ${1:caller},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onBinary resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onBinary(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onPing resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPing(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onPong resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPong(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onIdleTimeout resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onIdleTimeout(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onError resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onError(http:WebSocketCaller ${1:caller},error ${2:err}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onClose resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onClose(http:WebSocketCaller ${1:caller},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "http resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "function", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", - "insertTextFormat": "Snippet" - } - ] + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "resource", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "resource ", + "insertTextFormat": "Snippet" + }, + { + "label": "websocket onOpen resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onOpen(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onText resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onText(http:WebSocketCaller ${1:caller},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onBinary resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onBinary(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onPing resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPing(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onPong resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPong(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onIdleTimeout resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onIdleTimeout(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onError resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onError(http:WebSocketCaller ${1:caller},error ${2:err}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onClose resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onClose(http:WebSocketCaller ${1:caller},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "http resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "function", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", + "insertTextFormat": "Snippet" + } + ] } diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion1.json b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion1.json index ed0841a9a6a6..ba60d0e86002 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion1.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion1.json @@ -1,34 +1,50 @@ { - "position": { - "line": 8, - "character": 4 + "position": { + "line": 8, + "character": 4 + }, + "source": "service/source/serviceBodyCompletion1.bal", + "items": [ + { + "label": "public", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "public ", + "insertTextFormat": "Snippet" }, - "source": "service/source/serviceBodyCompletion1.bal", - "items": [ - { - "label": "public", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "120", - "insertText": "public ", - "insertTextFormat": "Snippet" - }, - { - "label": "http resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "function", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", - "insertTextFormat": "Snippet" - } - ] + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "resource", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "resource ", + "insertTextFormat": "Snippet" + }, + { + "label": "http resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "function", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", + "insertTextFormat": "Snippet" + } + ] } diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion2.json b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion2.json index 7fe53860195b..30b9001958de 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion2.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion2.json @@ -1,34 +1,50 @@ { - "position": { - "line": 8, - "character": 5 + "position": { + "line": 8, + "character": 5 + }, + "source": "service/source/serviceBodyCompletion2.bal", + "items": [ + { + "label": "public", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "public ", + "insertTextFormat": "Snippet" }, - "source": "service/source/serviceBodyCompletion2.bal", - "items": [ - { - "label": "public", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "120", - "insertText": "public ", - "insertTextFormat": "Snippet" - }, - { - "label": "http resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "function", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", - "insertTextFormat": "Snippet" - } - ] + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "resource", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "resource ", + "insertTextFormat": "Snippet" + }, + { + "label": "http resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "function", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", + "insertTextFormat": "Snippet" + } + ] } diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion6.json b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion6.json index 1c063cdad1e8..8d9cf597a995 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion6.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion6.json @@ -1,401 +1,417 @@ { - "position": { - "line": 2, - "character": 4 + "position": { + "line": 2, + "character": 4 + }, + "source": "service/source/serviceBodyCompletion6.bal", + "items": [ + { + "label": "public", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "public ", + "insertTextFormat": "Snippet" }, - "source": "service/source/serviceBodyCompletion6.bal", - "items": [ - { - "label": "public", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "120", - "insertText": "public ", - "insertTextFormat": "Snippet" - }, - { - "label": "http resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, - { - "label": "resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function ${1:newResource}(${2}) {\n\t${3}\n}", - "insertTextFormat": "Snippet" - }, + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "resource", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "resource ", + "insertTextFormat": "Snippet" + }, + { + "label": "http resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocketClient onText resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onText(http:WebSocketClient ${1:wsEp},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function ${1:newResource}(${2}) {\n\t${3}\n}", + "insertTextFormat": "Snippet" + }, + { + "label": "websocketClient onText resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onText(http:WebSocketClient ${1:wsEp},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocketClient onBinary resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onBinary(http:WebSocketClient ${1:wsEp},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocketClient onBinary resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onBinary(http:WebSocketClient ${1:wsEp},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocketClient onPing resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPing(http:WebSocketClient ${1:wsEp},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocketClient onPing resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPing(http:WebSocketClient ${1:wsEp},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocketClient onPong resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPong(http:WebSocketClient ${1:wsEp},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocketClient onPong resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPong(http:WebSocketClient ${1:wsEp},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocketClient onIdleTimeout resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onIdleTimeout(http:WebSocketClient ${1:wsEp}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocketClient onIdleTimeout resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onIdleTimeout(http:WebSocketClient ${1:wsEp}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocketClient onError resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onError(http:WebSocketClient ${1:wsEp},error ${2:err}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocketClient onError resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onError(http:WebSocketClient ${1:wsEp},error ${2:err}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocketClient onClose resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onClose(http:WebSocketClient ${1:wsEp},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocketClient onClose resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onClose(http:WebSocketClient ${1:wsEp},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocket onOpen resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onOpen(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocket onOpen resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onOpen(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocket onText resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onText(http:WebSocketCaller ${1:caller},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocket onText resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onText(http:WebSocketCaller ${1:caller},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocket onBinary resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onBinary(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocket onBinary resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onBinary(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocket onPing resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPing(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocket onPing resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPing(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocket onPong resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPong(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocket onPong resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPong(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocket onIdleTimeout resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onIdleTimeout(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocket onIdleTimeout resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onIdleTimeout(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocket onError resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onError(http:WebSocketCaller ${1:caller},error ${2:err}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocket onError resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onError(http:WebSocketCaller ${1:caller},error ${2:err}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "websocket onClose resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onClose(http:WebSocketCaller ${1:caller},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [ - { - "range": { - "start": { - "line": 0, - "character": 0 - }, - "end": { - "line": 0, - "character": 0 - } - }, - "newText": "import ballerina/http;\n" - } - ] - }, + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, + { + "label": "websocket onClose resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onClose(http:WebSocketCaller ${1:caller},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ { - "label": "function", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", - "insertTextFormat": "Snippet" + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" } - ] + ] + }, + { + "label": "function", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", + "insertTextFormat": "Snippet" + } + ] } diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion7.json b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion7.json index d4b6bbc0f1ea..43d6af2d9096 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion7.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/serviceBodyCompletion7.json @@ -13,6 +13,22 @@ "insertText": "public ", "insertTextFormat": "Snippet" }, + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "resource", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "resource ", + "insertTextFormat": "Snippet" + }, { "label": "resource", "kind": "Snippet", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/websocketServiceBodyResourceCompletion1.json b/language-server/modules/langserver-core/src/test/resources/completion/service/websocketServiceBodyResourceCompletion1.json index 5a456ab94666..ce40e50c0209 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/websocketServiceBodyResourceCompletion1.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/websocketServiceBodyResourceCompletion1.json @@ -1,106 +1,122 @@ { - "position": { - "line": 3, - "character": 4 + "position": { + "line": 3, + "character": 4 + }, + "source": "service/source/websocketServiceBodyResourceCompletion1.bal", + "items": [ + { + "label": "public", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "public ", + "insertTextFormat": "Snippet" }, - "source": "service/source/websocketServiceBodyResourceCompletion1.bal", - "items": [ - { - "label": "public", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "120", - "insertText": "public ", - "insertTextFormat": "Snippet" - }, - { - "label": "websocket onOpen resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onOpen(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onText resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onText(http:WebSocketCaller ${1:caller},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onBinary resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onBinary(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onPing resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPing(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onPong resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPong(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onIdleTimeout resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onIdleTimeout(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onError resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onError(http:WebSocketCaller ${1:caller},error ${2:err}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onClose resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onClose(http:WebSocketCaller ${1:caller},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "http resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "function", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", - "insertTextFormat": "Snippet" - } - ] + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "resource", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "resource ", + "insertTextFormat": "Snippet" + }, + { + "label": "websocket onOpen resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onOpen(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onText resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onText(http:WebSocketCaller ${1:caller},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onBinary resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onBinary(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onPing resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPing(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onPong resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPong(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onIdleTimeout resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onIdleTimeout(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onError resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onError(http:WebSocketCaller ${1:caller},error ${2:err}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onClose resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onClose(http:WebSocketCaller ${1:caller},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "http resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "function", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", + "insertTextFormat": "Snippet" + } + ] } diff --git a/language-server/modules/langserver-core/src/test/resources/completion/service/websocketServiceBodyResourceCompletion2.json b/language-server/modules/langserver-core/src/test/resources/completion/service/websocketServiceBodyResourceCompletion2.json index a1b54a065a8e..74083ea9d122 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/service/websocketServiceBodyResourceCompletion2.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/service/websocketServiceBodyResourceCompletion2.json @@ -1,106 +1,122 @@ { - "position": { - "line": 3, - "character": 4 + "position": { + "line": 3, + "character": 4 + }, + "source": "service/source/websocketServiceBodyResourceCompletion2.bal", + "items": [ + { + "label": "public", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "public ", + "insertTextFormat": "Snippet" }, - "source": "service/source/websocketServiceBodyResourceCompletion2.bal", - "items": [ - { - "label": "public", - "kind": "Keyword", - "detail": "Keyword", - "sortText": "120", - "insertText": "public ", - "insertTextFormat": "Snippet" - }, - { - "label": "websocket onOpen resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onOpen(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onText resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onText(http:WebSocketCaller ${1:caller},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onBinary resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onBinary(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onPing resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPing(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onPong resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onPong(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onIdleTimeout resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onIdleTimeout(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onError resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onError(http:WebSocketCaller ${1:caller},error ${2:err}) {\n\t${3}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "websocket onClose resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function onClose(http:WebSocketCaller ${1:caller},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "http resource", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", - "insertTextFormat": "Snippet", - "additionalTextEdits": [] - }, - { - "label": "function", - "kind": "Snippet", - "detail": "Snippet", - "sortText": "110", - "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", - "insertTextFormat": "Snippet" - } - ] + { + "label": "function", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "function ", + "insertTextFormat": "Snippet" + }, + { + "label": "resource", + "kind": "Keyword", + "detail": "Keyword", + "sortText": "120", + "insertText": "resource ", + "insertTextFormat": "Snippet" + }, + { + "label": "websocket onOpen resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onOpen(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onText resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onText(http:WebSocketCaller ${1:caller},string ${2:data},boolean ${3:finalFrame}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onBinary resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onBinary(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onPing resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPing(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onPong resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onPong(http:WebSocketCaller ${1:caller},byte[] ${2:data}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onIdleTimeout resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onIdleTimeout(http:WebSocketCaller ${1:caller}) {\n\t${2}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onError resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onError(http:WebSocketCaller ${1:caller},error ${2:err}) {\n\t${3}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "websocket onClose resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function onClose(http:WebSocketCaller ${1:caller},int ${2:statusCode},string ${3:reason}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "http resource", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "resource function ${1:newResource}(http:Caller ${2:caller}, ${3:http:Request request}) {\n\t${4}\n}", + "insertTextFormat": "Snippet", + "additionalTextEdits": [] + }, + { + "label": "function", + "kind": "Snippet", + "detail": "Snippet", + "sortText": "110", + "insertText": "function ${1:name}(${2}) {\n\t${3}\n}", + "insertTextFormat": "Snippet" + } + ] } diff --git a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/globalVarDefPackageContent.json b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/globalVarDefPackageContent.json index 4a6deb1744b5..26290b102a64 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/globalVarDefPackageContent.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/globalVarDefPackageContent.json @@ -957,6 +957,20 @@ "insertText": "WRITING_100_CONTINUE_RESPONSE_FAILED", "insertTextFormat": "Snippet" }, + { + "label": "INVALID_COOKIE_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:InvalidCookieError`" + } + }, + "sortText": "130", + "insertText": "INVALID_COOKIE_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "GENERIC_CLIENT_ERROR", "kind": "Variable", @@ -1041,6 +1055,20 @@ "insertText": "SSL_ERROR", "insertTextFormat": "Snippet" }, + { + "label": "COOKIE_HANDLING_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:CookieHandlingError`" + } + }, + "sortText": "130", + "insertText": "COOKIE_HANDLING_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "AGE", "kind": "Variable", @@ -2575,6 +2603,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -2988,6 +3027,17 @@ "insertText": "Writing100ContinueResponseError", "insertTextFormat": "Snippet" }, + { + "label": "InvalidCookieError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when sending cookies in the response" + }, + "sortText": "200", + "insertText": "InvalidCookieError", + "insertTextFormat": "Snippet" + }, { "label": "GenericClientError", "kind": "Event", @@ -3054,6 +3104,17 @@ "insertText": "SslError", "insertTextFormat": "Snippet" }, + { + "label": "CookieHandlingError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when using the cookies" + }, + "sortText": "200", + "insertText": "CookieHandlingError", + "insertTextFormat": "Snippet" + }, { "label": "ResiliencyError", "kind": "Event", @@ -3588,6 +3649,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WsConnectionClosureError", "kind": "Event", @@ -3698,6 +3770,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "190", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", @@ -3739,13 +3822,13 @@ } }, { - "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" } }, "sortText": "120", @@ -3757,13 +3840,13 @@ } }, { - "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns a tuple containing the value and its parameter map \n \n" + "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns a tuple containing the value and its parameter map \n \n" } }, "sortText": "120", @@ -3775,13 +3858,13 @@ } }, { - "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -3793,13 +3876,13 @@ } }, { - "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Created secure HTTP client \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Created secure HTTP client \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/statementWithMissingSemiColon2.json b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/statementWithMissingSemiColon2.json index 7694e0d25376..565a4a7a8ec8 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/statementWithMissingSemiColon2.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/statementWithMissingSemiColon2.json @@ -377,6 +377,14 @@ "insertText": "CookieStore", "insertTextFormat": "Snippet" }, + { + "label": "myCookie", + "kind": "Struct", + "detail": "Record", + "sortText": "180", + "insertText": "myCookie", + "insertTextFormat": "Snippet" + }, { "label": "CookieClient", "kind": "Interface", @@ -388,6 +396,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -1109,6 +1128,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WebSocketConnector", "kind": "Interface", @@ -1153,6 +1183,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "190", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/statementWithMissingSemiColon3.json b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/statementWithMissingSemiColon3.json index f560db61d9be..1bc5b1d6e459 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/statementWithMissingSemiColon3.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/statementWithMissingSemiColon3.json @@ -957,6 +957,20 @@ "insertText": "WRITING_100_CONTINUE_RESPONSE_FAILED", "insertTextFormat": "Snippet" }, + { + "label": "INVALID_COOKIE_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:InvalidCookieError`" + } + }, + "sortText": "130", + "insertText": "INVALID_COOKIE_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "GENERIC_CLIENT_ERROR", "kind": "Variable", @@ -1041,6 +1055,20 @@ "insertText": "SSL_ERROR", "insertTextFormat": "Snippet" }, + { + "label": "COOKIE_HANDLING_ERROR", + "kind": "Variable", + "detail": "string", + "documentation": { + "right": { + "kind": "markdown", + "value": "Represents the reason string for the `http:CookieHandlingError`" + } + }, + "sortText": "130", + "insertText": "COOKIE_HANDLING_ERROR", + "insertTextFormat": "Snippet" + }, { "label": "AGE", "kind": "Variable", @@ -2575,6 +2603,17 @@ "insertText": "CookieClient", "insertTextFormat": "Snippet" }, + { + "label": "PersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "The representation of a persistent cookie handler for managing persistent cookies." + }, + "sortText": "190", + "insertText": "PersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "HttpFuture", "kind": "Interface", @@ -2988,6 +3027,17 @@ "insertText": "Writing100ContinueResponseError", "insertTextFormat": "Snippet" }, + { + "label": "InvalidCookieError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when sending cookies in the response" + }, + "sortText": "200", + "insertText": "InvalidCookieError", + "insertTextFormat": "Snippet" + }, { "label": "GenericClientError", "kind": "Event", @@ -3054,6 +3104,17 @@ "insertText": "SslError", "insertTextFormat": "Snippet" }, + { + "label": "CookieHandlingError", + "kind": "Event", + "detail": "Error", + "documentation": { + "left": "Represents a cookie error that occurred when using the cookies" + }, + "sortText": "200", + "insertText": "CookieHandlingError", + "insertTextFormat": "Snippet" + }, { "label": "ResiliencyError", "kind": "Event", @@ -3588,6 +3649,17 @@ "insertText": "WebSocketClientConfiguration", "insertTextFormat": "Snippet" }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Retry configurations for WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet" + }, { "label": "WsConnectionClosureError", "kind": "Event", @@ -3698,6 +3770,17 @@ "insertText": "BearerAuthHandler", "insertTextFormat": "Snippet" }, + { + "label": "CsvPersistentCookieHandler", + "kind": "Interface", + "detail": "Object", + "documentation": { + "left": "Represents a default persistent cookie handler, which stores persistent cookies in a CSV file.\n" + }, + "sortText": "190", + "insertText": "CsvPersistentCookieHandler", + "insertTextFormat": "Snippet" + }, { "label": "RequestMessage", "kind": "Enum", @@ -3739,13 +3822,13 @@ } }, { - "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpCachingClient(string url, http:ClientConfiguration config, http:CacheConfig cacheConfig)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of caching HTTP responses.\n \n**Params** \n- `string` url: The URL of the HTTP endpoint to connect to \n- `http:ClientConfiguration` config: The configurations for the client endpoint associated with the caching client \n- `http:CacheConfig` cacheConfig: The configurations for the HTTP cache to be used with the caching client \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- An `HttpCachingClient` instance which wraps the base `Client` with a caching layer \n \n" } }, "sortText": "120", @@ -3757,13 +3840,13 @@ } }, { - "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "parseHeader(string headerValue)(([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Returns a tuple containing the value and its parameter map \n \n" + "value": "**Package:** _ballerina/http_ \n \nParses the given header value to extract its value and parameter map.\n \n**Params** \n- `string` headerValue: The header value \n \n**Returns** `([string,map\u003cany\u003e]|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Returns a tuple containing the value and its parameter map \n \n" } }, "sortText": "120", @@ -3775,13 +3858,13 @@ } }, { - "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "invokeEndpoint(string path, http:Request outRequest, (FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE) requestAction, http:HttpClient httpClient, string verb)((http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "value": "**Package:** _ballerina/http_ \n \nThe HEAD remote function implementation of the Circuit Breaker. This wraps the `head` function of the underlying\nHTTP remote function provider. \n**Params** \n- `string` path: Resource path \n- `http:Request` outRequest: A Request struct \n- `(FORWARD|GET|POST|DELETE|OPTIONS|PUT|PATCH|HEAD|SUBMIT|NONE)` requestAction: `HttpOperation` related to the request \n- `http:HttpClient` httpClient: HTTP client which uses to call the relevant functions \n- `string` verb: HTTP verb used for submit method(Defaultable) \n \n**Returns** `(http:Response|http:HttpFuture|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "sortText": "120", @@ -3793,13 +3876,13 @@ } }, { - "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError))", + "label": "createHttpSecureClient(string url, http:ClientConfiguration config)((http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError))", "kind": "Function", "detail": "Function", "documentation": { "right": { "kind": "markdown", - "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- Created secure HTTP client \n \n" + "value": "**Package:** _ballerina/http_ \n \nCreates an HTTP client capable of securing HTTP requests with authentication.\n \n**Params** \n- `string` url: Base URL \n- `http:ClientConfiguration` config: Client endpoint configurations \n \n**Returns** `(http:HttpClient|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- Created secure HTTP client \n \n" } }, "sortText": "120", diff --git a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/topLevelPackageContentAccess.json b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/topLevelPackageContentAccess.json index 0ff9def95102..606e8358a457 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/toplevel/topLevelPackageContentAccess.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/toplevel/topLevelPackageContentAccess.json @@ -1366,6 +1366,32 @@ } ] }, + { + "label": "WebSocketRetryConfig", + "kind": "Struct", + "detail": "Record", + "documentation": { + "left": "Configurations for reconnecting to the WebSocket.\n" + }, + "sortText": "180", + "insertText": "WebSocketRetryConfig", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import ballerina/http;\n" + } + ] + }, { "label": "AuthnFilter", "kind": "Interface", diff --git a/language-server/modules/langserver-core/src/test/resources/hover/expected/hover-over-async-send.json b/language-server/modules/langserver-core/src/test/resources/hover/expected/hover-over-async-send.json index 2d5c38e9a120..7dd9b39e5356 100644 --- a/language-server/modules/langserver-core/src/test/resources/hover/expected/hover-over-async-send.json +++ b/language-server/modules/langserver-core/src/test/resources/hover/expected/hover-over-async-send.json @@ -1,8 +1,8 @@ { "result": { "contents": { - "kind": "markdown", - "value": "**Description** \n \nThe `Client.post()` function can be used to send HTTP POST requests to HTTP endpoints. \n \n**Params** \n- `string` **path**: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` **message**: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`, \n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" + "kind": "markdown", + "value": "**Description** \n \nThe `Client.post()` function can be used to send HTTP POST requests to HTTP endpoints. \n \n**Params** \n- `string` **path**: Resource path \n- `(http:Request|string|xml|json|byte[]|io:ReadableByteChannel|mime:Entity[])` **message**: An HTTP outbound request message or any payload of type `string`, `xml`, `json`, `byte[]`, \n `io:ReadableByteChannel` or `mime:Entity[]` \n \n**Returns** `(http:Response|http:FailoverAllEndpointsFailedError|http:FailoverActionFailedError|http:UpstreamServiceUnavailableError|http:AllLoadBalanceEndpointsFailedError|http:AllRetryAttemptsFailed|http:IdleTimeoutError|http:AuthenticationError|http:AuthorizationError|http:InitializingOutboundRequestError|http:WritingOutboundRequestHeadersError|http:WritingOutboundRequestBodyError|http:InitializingInboundResponseError|http:ReadingInboundResponseHeadersError|http:ReadingInboundResponseBodyError|http:UnsupportedActionError|http:Http2ClientError|http:MaximumWaitTimeExceededError|http:SslError|http:GenericClientError|http:CookieHandlingError)` \n- The response for the request or an `http:ClientError` if failed to establish communication with the upstream server \n \n" } }, "id": { diff --git a/stdlib/http/build.gradle b/stdlib/http/build.gradle index 7a4927a06e28..5f4832241d24 100644 --- a/stdlib/http/build.gradle +++ b/stdlib/http/build.gradle @@ -103,6 +103,7 @@ dependencies { testCompile project(':ballerina-core') testCompile 'org.apache.ws.commons.axiom:axiom-api' testCompile 'org.testng:testng' + testCompile 'com.h2database:h2' interopImports project(':ballerina-crypto') } diff --git a/stdlib/http/src/main/ballerina/src/http/client_endpoint.bal b/stdlib/http/src/main/ballerina/src/http/client_endpoint.bal index fef26446e33b..0a03df26daba 100644 --- a/stdlib/http/src/main/ballerina/src/http/client_endpoint.bal +++ b/stdlib/http/src/main/ballerina/src/http/client_endpoint.bal @@ -51,7 +51,7 @@ public type Client client object { var cookieConfigVal = self.config.cookieConfig; if (cookieConfigVal is CookieConfig) { if (cookieConfigVal.enabled) { - self.cookieStore = new; + self.cookieStore = new(cookieConfigVal?.persistentCookieHandler); } } var result = initialize(url, self.config, self.cookieStore); @@ -370,19 +370,17 @@ public type OutboundAuthConfig record {| # Client configuration for cookies. # # + enabled - User agents provide users with a mechanism for disabling or enabling cookies -# + maxSizePerCookie - Maximum number of bytes per cookie (as measured by the sum of the length of the cookie’s name, value, and attributes), which is 4096 bytes # + maxCookiesPerDomain - Maximum number of cookies per domain, which is 50 # + maxTotalCookieCount - Maximum number of total cookies allowed to be stored in cookie store, which is 3000 # + blockThirdPartyCookies - User can block cookies from third party responses and refuse to send cookies for third party requests, if needed -# + enablePersistence - Users are provided with a mechanism for enabling or disabling persistent cookies, which are stored until a specific expiration date. -# If false, only session cookies are used +# + persistentCookieHandler - To manage persistent cookies, users are provided with a mechanism for specifying a persistent cookie store with their own mechanism +# which references the persistent cookie handler or specifying the CSV persistent cookie handler. If not specified any, only the session cookies are used public type CookieConfig record {| boolean enabled = false; - int maxSizePerCookie = 4096; int maxCookiesPerDomain = 50; int maxTotalCookieCount = 3000; boolean blockThirdPartyCookies = true; - boolean enablePersistence = false; + PersistentCookieHandler persistentCookieHandler?; |}; function initialize(string serviceUrl, ClientConfiguration config, CookieStore? cookieStore) returns HttpClient|error { diff --git a/stdlib/http/src/main/ballerina/src/http/cookie/cookie.bal b/stdlib/http/src/main/ballerina/src/http/cookie/cookie.bal index 1bf14ee723a8..907fc657c1a9 100644 --- a/stdlib/http/src/main/ballerina/src/http/cookie/cookie.bal +++ b/stdlib/http/src/main/ballerina/src/http/cookie/cookie.bal @@ -28,7 +28,7 @@ import ballerina/time; # + expires - Maximum lifetime of the cookie represented as the date and time at which the cookie expires # + httpOnly - Cookie is sent only to HTTP requests # + secure - Cookie is sent only to secure channels -# + creationTime - Creation time of the cookie +# + createdTime - At what time the cookie was created # + lastAccessedTime - Last-accessed time of the cookie # + hostOnly - Cookie is sent only to the requested host public type Cookie object { @@ -41,7 +41,7 @@ public type Cookie object { public int maxAge = 0; public boolean httpOnly = false; public boolean secure = false; - public time:Time creationTime = time:currentTime(); + public time:Time createdTime = time:currentTime(); public time:Time lastAccessedTime = time:currentTime(); public boolean hostOnly = false; @@ -58,62 +58,55 @@ public type Cookie object { return true; } - // Returns true if the attributes of the cookie are in the correct format; false otherwise. - public function isValid() returns boolean | error { - error invalidCookieError; - var temp = self.name; - if (temp is string) { - temp = temp.trim(); - if (temp == "") { - invalidCookieError = error("Invalid name"); - return invalidCookieError; + // Returns true if the attributes of the cookie are in the correct format or else error is returned. + public function isValid() returns boolean|InvalidCookieError { + var name = self.name; + if (name is string) { + name = name.trim(); + if (name == "") { + return error(INVALID_COOKIE_ERROR, message = "Invalid name: Name cannot be empty"); } - self.name = temp; - } - temp = self.value; - if (temp is string) { - temp = temp.trim(); - if (temp == "") { - invalidCookieError = error("Invalid value"); - return invalidCookieError; + self.name = name; + } + var value = self.value; + if (value is string) { + value = value.trim(); + if (value == "") { + return error(INVALID_COOKIE_ERROR, message = "Invalid value: Value cannot be empty"); } - self.value = temp; - } - temp = self.domain; - if (temp is string) { - temp = temp.trim().toLowerAscii(); - if (temp == "") { - invalidCookieError = error("Invalid domain"); - return invalidCookieError; + self.value = value; + } + var domain = self.domain; + if (domain is string) { + domain = domain.trim().toLowerAscii(); + if (domain == "") { + return error(INVALID_COOKIE_ERROR, message = "Invalid domain: Domain cannot be empty"); } - if (temp.startsWith(".")) { - temp = temp.substring(1, temp.length()); + if (domain.startsWith(".")) { + domain = domain.substring(1, domain.length()); } - if (temp.endsWith(".")) { - temp = temp.substring(0, temp.length() - 1); + if (domain.endsWith(".")) { + domain = domain.substring(0, domain.length() - 1); } - self.domain = temp; - } - temp = self.path; - if (temp is string) { - temp = temp.trim(); - if (temp == "" || !temp.startsWith("/") || stringutils:contains(temp, "?")) { - invalidCookieError = error("Path is not in correct format "); - return invalidCookieError; + self.domain = domain; + } + var path = self.path; + if (path is string) { + path = path.trim(); + if (path == "" || !path.startsWith("/") || stringutils:contains(path, "?")) { + return error(INVALID_COOKIE_ERROR, message = "Invalid path: Path is not in correct format"); } - self.path = temp; - } - temp = self.expires; - if (temp is string) { - temp = temp.trim(); - if (!toGmtFormat(self, temp)) { - invalidCookieError = error("Time is not in correct format"); - return invalidCookieError; + self.path = path; + } + var expires = self.expires; + if (expires is string) { + expires = expires.trim(); + if (!toGmtFormat(self, expires)) { + return error(INVALID_COOKIE_ERROR, message = "Invalid time: Expiry-time is not in yyyy-mm-dd hh:mm:ss format"); } } if (self.maxAge < 0) { - invalidCookieError = error("Max Age is less than zero"); - return invalidCookieError; + return error(INVALID_COOKIE_ERROR, message = "Invalid max-age: Max Age can not be less than zero"); } return true; } @@ -154,9 +147,9 @@ public type Cookie object { // Converts the cookie's expiry time into the GMT format. function toGmtFormat(Cookie cookie, string expires) returns boolean { - time:Time | error t1 = time:parse(expires, "yyyy-MM-dd HH:mm:ss"); + time:Time|error t1 = time:parse(expires, "yyyy-MM-dd HH:mm:ss"); if (t1 is time:Time) { - string | error timeString = time:format(t1, "E, dd MMM yyyy HH:mm:ss "); + string|error timeString = time:format(t1, "E, dd MMM yyyy HH:mm:ss "); if (timeString is string) { cookie.expires = timeString + "GMT"; return true; @@ -203,7 +196,7 @@ function parseSetCookieHeader(string cookieStringValue) returns Cookie { cookie.path = nameValuePair[1]; } MAX_AGE_ATTRIBUTE => { - int | error age = ints:fromString(nameValuePair[1]); + int|error age = ints:fromString(nameValuePair[1]); if (age is int) { cookie.maxAge = age; } @@ -238,18 +231,18 @@ function parseCookieHeader(string cookieStringValue) returns Cookie[] { // Returns a value to be used for sorting an array of cookies in order to create the "Cookie" header in the request. // This value is returned according to the rules in [RFC-6265](https://tools.ietf.org/html/rfc6265#section-5.4). function comparator(Cookie c1, Cookie c2) returns int { - var temp1 = c1.path; - var temp2 = c2.path; + var cookiePath1 = c1.path; + var cookiePath2 = c2.path; int l1 = 0; int l2 = 0; - if (temp1 is string) { - l1 = temp1.length(); + if (cookiePath1 is string) { + l1 = cookiePath1.length(); } - if (temp2 is string) { - l2 = temp2.length(); + if (cookiePath2 is string) { + l2 = cookiePath2.length(); } if (l1 != l2) { return l2 - l1; } - return c1.creationTime.time - c2.creationTime.time; + return c1.createdTime.time - c2.createdTime.time; } diff --git a/stdlib/http/src/main/ballerina/src/http/cookie/cookieStore.bal b/stdlib/http/src/main/ballerina/src/http/cookie/cookieStore.bal index 111e512292d3..fec72348dabc 100644 --- a/stdlib/http/src/main/ballerina/src/http/cookie/cookieStore.bal +++ b/stdlib/http/src/main/ballerina/src/http/cookie/cookieStore.bal @@ -14,14 +14,21 @@ // specific language governing permissions and limitations // under the License. +import ballerina/log; import ballerina/time; # Represents the cookie store. # # + allSessionCookies - Array to store all the session cookies +# + persistentCookieHandler - Persistent cookie handler to manage persistent cookies public type CookieStore object { Cookie[] allSessionCookies = []; + PersistentCookieHandler? persistentCookieHandler; + + public function __init(PersistentCookieHandler? persistentCookieHandler = ()) { + self.persistentCookieHandler = persistentCookieHandler; + } # Adds a cookie to the cookie store according to the rules in [RFC-6265](https://tools.ietf.org/html/rfc6265#section-5.3). # @@ -29,15 +36,22 @@ public type CookieStore object { # + cookieConfig - Configurations associated with the cookies # + url - Target service URL # + requestPath - Resource path - public function addCookie(Cookie cookie, CookieConfig cookieConfig, string url, string requestPath) { + # + return - An error will be returned if there is any error occurred when adding a cookie or else nil is returned + public function addCookie(Cookie cookie, CookieConfig cookieConfig, string url, string requestPath) returns CookieHandlingError? { + if (self.getAllCookies().length() == cookieConfig.maxTotalCookieCount) { + return error(COOKIE_HANDLING_ERROR, message = "Number of total cookies in the cookie store can not exceed the maximum amount"); + } string domain = getDomain(url); + if (self.getCookiesByDomain(domain).length() == cookieConfig.maxCookiesPerDomain) { + return error(COOKIE_HANDLING_ERROR, message = "Number of total cookies for the domain: " + domain + " in the cookie store can not exceed the maximum amount per domain"); + } string path = requestPath; int? index = requestPath.indexOf("?"); if (index is int) { - path = requestPath.substring(0,index); + path = requestPath.substring(0, index); } lock { - Cookie? identicalCookie = getIdenticalCookie(cookie, self.allSessionCookies); + Cookie? identicalCookie = getIdenticalCookie(cookie, self); if (!isDomainMatched(cookie, domain, cookieConfig)) { return; } @@ -51,12 +65,20 @@ public type CookieStore object { return; } if (cookie.isPersistent()) { - if (!cookieConfig.enablePersistence) { - return; + var persistentCookieHandler = self.persistentCookieHandler; + if (persistentCookieHandler is PersistentCookieHandler) { + var result = addPersistentCookie(identicalCookie, cookie, url, persistentCookieHandler, self); + if (result is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in adding persistent cookies", cause = result); + } + } else if (isFirstRequest(self.allSessionCookies, domain)) { + log:printWarn("Client is not configured to use persistent cookies. Hence, persistent cookies from " + domain + " will be discarded."); } - addPersistentCookie(identicalCookie, cookie, url, self); } else { - addSessionCookie(identicalCookie, cookie, url, self); + var result = addSessionCookie(identicalCookie, cookie, url, self); + if (result is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in adding session cookie", cause = result); + } } } } @@ -69,7 +91,10 @@ public type CookieStore object { # + requestPath - Resource path public function addCookies(Cookie[] cookiesInResponse, CookieConfig cookieConfig, string url, string requestPath) { foreach var cookie in cookiesInResponse { - self.addCookie(cookie, cookieConfig, url, requestPath); + var result = self.addCookie(cookie, cookieConfig, url, requestPath); + if (result is error) { + log:printError("Error in adding cookies to cookie store: ", result); + } } } @@ -86,9 +111,12 @@ public type CookieStore object { if (index is int) { path = requestPath.substring(0,index); } + Cookie[] allCookies = self.getAllCookies(); lock { - // Gets the session cookies. - foreach var cookie in self.allSessionCookies { + foreach var cookie in allCookies { + if (isExpired(cookie)) { + continue; + } if (!((url.startsWith(HTTPS) && cookie.secure) || cookie.secure == false)) { continue; } @@ -100,8 +128,8 @@ public type CookieStore object { cookiesToReturn.push(cookie); } } else { - var temp = cookie.domain; - if (((temp is string && domain.endsWith("." + temp)) || cookie.domain == domain ) && checkPath(path, cookie)) { + var cookieDomain = cookie.domain; + if (((cookieDomain is string && domain.endsWith("." + cookieDomain)) || cookie.domain == domain ) && checkPath(path, cookie)) { cookiesToReturn.push(cookie); } } @@ -114,7 +142,52 @@ public type CookieStore object { # # + return - Array of all the cookie objects public function getAllCookies() returns Cookie[] { - return self.allSessionCookies; + var persistentCookieHandler = self.persistentCookieHandler; + Cookie[] allCookies = []; + foreach var cookie in self.allSessionCookies { + allCookies.push(cookie); + } + if (persistentCookieHandler is PersistentCookieHandler) { + var result = persistentCookieHandler.getAllCookies(); + if (result is error) { + log:printError("Error in getting persistent cookies: ", result); + } else { + foreach var cookie in result { + allCookies.push(cookie); + } + } + } + return allCookies; + } + + # Gets all the cookies, which have the given name as the name of the cookie. + # + # + cookieName - Name of the cookie + # + return - Array of all the matched cookie objects + public function getCookiesByName(string cookieName) returns Cookie[] { + Cookie[] cookiesToReturn = []; + Cookie[] allCookies = self.getAllCookies(); + foreach var cookie in allCookies { + if (cookie.name == cookieName) { + cookiesToReturn.push(cookie); + } + } + return cookiesToReturn; + } + + # Gets all the cookies, which have the given name as the domain of the cookie. + # + # + domain - Name of the domain + # + return - Array of all the matched cookie objects + public function getCookiesByDomain(string domain) returns Cookie[] { + Cookie[] cookiesToReturn = []; + Cookie[] allCookies = self.getAllCookies(); + foreach var cookie in allCookies { + if (cookie.domain == domain) { + cookiesToReturn.push(cookie); + } + } + return cookiesToReturn; } # Removes a specific cookie. @@ -122,31 +195,97 @@ public type CookieStore object { # + name - Name of the cookie to be removed # + domain - Domain of the cookie to be removed # + path - Path of the cookie to be removed - # + return - Return true if the relevant cookie is removed, false otherwise - public function removeCookie(string name, string domain, string path) returns boolean { - lock { - // Removes the session cookie in the cookie store, which is matched with the given name, domain and path. - int k = 0; - while (k < self.allSessionCookies.length()) { - if (name == self.allSessionCookies[k].name && domain == self.allSessionCookies[k].domain && path == self.allSessionCookies[k].path) { - int j = k; - while (j < self.allSessionCookies.length()-1) { - self.allSessionCookies[j] = self.allSessionCookies[j + 1]; - j = j + 1; - } - _ = self.allSessionCookies.pop(); - return true; - } - k = k + 1; - } - return false; - } + # + return - An error will be returned if there is any error occurred during the removal of the cookie or else nil is returned + public function removeCookie(string name, string domain, string path) returns CookieHandlingError? { + lock { + // Removes the session cookie if it is in the session cookies array, which is matched with the given name, domain, and path. + int k = 0; + while (k < self.allSessionCookies.length()) { + if (name == self.allSessionCookies[k].name && domain == self.allSessionCookies[k].domain && path == self.allSessionCookies[k].path) { + int j = k; + while (j < self.allSessionCookies.length() - 1) { + self.allSessionCookies[j] = self.allSessionCookies[j + 1]; + j = j + 1; + } + _ = self.allSessionCookies.pop(); + return; + } + k = k + 1; + } + // Removes the persistent cookie if it is in the persistent cookie store, which is matched with the given name, domain, and path. + var persistentCookieHandler = self.persistentCookieHandler; + if (persistentCookieHandler is PersistentCookieHandler) { + return persistentCookieHandler.removeCookie(name, domain, path); + } + return error(COOKIE_HANDLING_ERROR, message = "Error in removing cookie: No such cookie to remove"); + } + } + + # Removes cookies, which match with the given domain. + # + # + domain - Domain of the cookie to be removed + # + return - An error will be returned if there is any error occurred during the removal of cookies by domain or else nil is returned + public function removeCookiesByDomain(string domain) returns CookieHandlingError? { + Cookie[] allCookies = self.getAllCookies(); + lock { + foreach var cookie in allCookies { + if (cookie.domain != domain ) { + continue; + } + var cookieName = cookie.name; + var cookiePath = cookie.path; + if (cookieName is string && cookiePath is string) { + var result = self.removeCookie(cookieName, domain, cookiePath); + if (result is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in removing cookies", cause = result); + } + } + } + } + } + + # Removes all expired cookies. + # + # + return - An error will be returned if there is any error occurred during the removal of expired cookies or else nil is returned + public function removeExpiredCookies() returns CookieHandlingError? { + var persistentCookieHandler = self.persistentCookieHandler; + if (persistentCookieHandler is PersistentCookieHandler) { + var result = persistentCookieHandler.getAllCookies(); + if (result is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in removing expired cookies", cause = result); + } else { + lock { + foreach var cookie in result { + if (!isExpired(cookie)) { + continue; + } + var cookieName = cookie.name; + var cookieDomain = cookie.domain; + var cookiePath = cookie.path; + if (cookieName is string && cookieDomain is string && cookiePath is string) { + var removeResult = persistentCookieHandler.removeCookie(cookieName, cookieDomain, cookiePath); + if (removeResult is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in removing expired cookies", cause = removeResult); + } + } + } + } + } + } else { + return error(COOKIE_HANDLING_ERROR, message = "No persistent cookie store to remove expired cookies"); + } } # Removes all the cookies. - public function clear() { + # + # + return - An error will be returned if there is any error occurred during the removal of all the cookies or else nil is returned + public function removeAllCookies() returns CookieHandlingError? { + var persistentCookieHandler = self.persistentCookieHandler; lock { self.allSessionCookies = []; + if (persistentCookieHandler is PersistentCookieHandler) { + return persistentCookieHandler.removeAllCookies(); + } } } }; @@ -177,14 +316,15 @@ function getDomain(string url) returns string { # Identical cookie is the cookie, which has the same name, domain and path as the given cookie. # # + cookieToCompare - Cookie to be compared -# + allSessionCookies - Array which stores all the session cookies +# + cookieStore - Cookie store of the client # + return - Identical cookie if one exists, else `()` -function getIdenticalCookie(Cookie cookieToCompare, Cookie[] allSessionCookies) returns Cookie? { - // Searches for the session cookies. +function getIdenticalCookie(Cookie cookieToCompare, CookieStore cookieStore) returns Cookie? { + Cookie[] allCookies = cookieStore.getAllCookies(); int k = 0 ; - while (k < allSessionCookies.length()) { - if (cookieToCompare.name == allSessionCookies[k].name && cookieToCompare.domain == allSessionCookies[k].domain && cookieToCompare.path == allSessionCookies[k].path) { - return allSessionCookies[k]; + while (k < allCookies.length()) { + if (cookieToCompare.name == allCookies[k].name && cookieToCompare.domain == allCookies[k].domain + && cookieToCompare.path == allCookies[k].path) { + return allCookies[k]; } k = k + 1; } @@ -201,8 +341,8 @@ function isDomainMatched(Cookie cookie, string domain, CookieConfig cookieConfig if (!cookieConfig.blockThirdPartyCookies) { return true; } - var temp = cookie.domain; - if (cookie.domain == domain || (temp is string && domain.endsWith("." + temp))) { + var cookieDomain = cookie.domain; + if (cookieDomain == domain || (cookieDomain is string && domain.endsWith("." + cookieDomain))) { return true; } return false; @@ -227,11 +367,11 @@ function checkPath(string path, Cookie cookie) returns boolean { if (cookie.path == path) { return true; } - var temp = cookie.path; - if (temp is string && path.startsWith(temp) && temp.endsWith("/")) { + var cookiePath = cookie.path; + if (cookiePath is string && path.startsWith(cookiePath) && cookiePath.endsWith("/")) { return true; } - if (temp is string && path.startsWith(temp) && path[temp.length()] == "/" ) { + if (cookiePath is string && path.startsWith(cookiePath) && path[cookiePath.length()] == "/" ) { return true; } return false; @@ -239,11 +379,11 @@ function checkPath(string path, Cookie cookie) returns boolean { // Returns true if the cookie expires attribute value is valid according to [RFC-6265](https://tools.ietf.org/html/rfc6265#section-5.1.1). function isExpiresAttributeValid(Cookie cookie) returns boolean { - var temp = cookie.expires; - if (temp is ()) { + var expiryTime = cookie.expires; + if (expiryTime is ()) { return true; } else { - time:Time|error t1 = time:parse(temp.substring(0, temp.length() - 4), "E, dd MMM yyyy HH:mm:ss"); + time:Time|error t1 = time:parse(expiryTime.substring(0, expiryTime.length() - 4), "E, dd MMM yyyy HH:mm:ss"); if (t1 is time:Time) { int year = time:getYear(t1); if (year <= 69 && year >= 0) { @@ -261,29 +401,44 @@ function isExpiresAttributeValid(Cookie cookie) returns boolean { } } +// Checks whether the user has requested a particular domain or a sub-domain of it previously or not. +function isFirstRequest(Cookie[] allSessionCookies, string domain) returns boolean { + foreach var cookie in allSessionCookies { + var cookieDomain = cookie.domain; + if (((cookieDomain is string && (domain.endsWith("." + cookieDomain) || cookieDomain.endsWith("." + domain))) || cookie.domain == domain )) { + return false; + } + } + return true; +} + // Adds a persistent cookie to the cookie store according to the rules in [RFC-6265](https://tools.ietf.org/html/rfc6265#section-5.3 , https://tools.ietf.org/html/rfc6265#section-4.1.2). -function addPersistentCookie(Cookie? identicalCookie, Cookie cookie, string url, CookieStore cookieStore) { +function addPersistentCookie(Cookie? identicalCookie, Cookie cookie, string url, PersistentCookieHandler persistentCookieHandler, CookieStore cookieStore) returns error? { if (identicalCookie is Cookie) { - var temp1 = identicalCookie.name; - var temp2 = identicalCookie.domain; - var temp3 = identicalCookie.path; - if (isExpired(cookie) && temp1 is string && temp2 is string && temp3 is string) { - _ = cookieStore.removeCookie(temp1, temp2, temp3); + var identicalCookieName = identicalCookie.name; + var identicalCookieDomain = identicalCookie.domain; + var identicalCookiePath = identicalCookie.path; + if (isExpired(cookie) && identicalCookieName is string && identicalCookieDomain is string && identicalCookiePath is string) { + return cookieStore.removeCookie(identicalCookieName, identicalCookieDomain, identicalCookiePath); } else { // Removes the old cookie and adds the new persistent cookie. - if (((identicalCookie.httpOnly && url.startsWith(HTTP)) || identicalCookie.httpOnly == false) && temp1 is string && temp2 is string && temp3 is string) { - _ = cookieStore.removeCookie(temp1, temp2, temp3); - cookie.creationTime = identicalCookie.creationTime; + if (((identicalCookie.httpOnly && url.startsWith(HTTP)) || identicalCookie.httpOnly == false) + && identicalCookieName is string && identicalCookieDomain is string && identicalCookiePath is string) { + var removeResult = cookieStore.removeCookie(identicalCookieName, identicalCookieDomain, identicalCookiePath); + if (removeResult is error) { + return removeResult; + } + cookie.createdTime = identicalCookie.createdTime; cookie.lastAccessedTime = time:currentTime(); - // TODO:insert into the database. + return persistentCookieHandler.storeCookie(cookie); } } } else { - // If cookie is not expired adds that cookie. + // If cookie is not expired, adds that cookie. if (!isExpired(cookie)) { - cookie.creationTime = time:currentTime(); + cookie.createdTime = time:currentTime(); cookie.lastAccessedTime = time:currentTime(); - // TODO:insert into the database. + return persistentCookieHandler.storeCookie(cookie); } } } @@ -291,16 +446,13 @@ function addPersistentCookie(Cookie? identicalCookie, Cookie cookie, string url, // Returns true if the cookie is expired according to the rules in [RFC-6265](https://tools.ietf.org/html/rfc6265#section-4.1.2.2). function isExpired(Cookie cookie) returns boolean { if (cookie.maxAge > 0) { - time:Time exptime = time:addDuration(cookie.creationTime, 0, 0, 0, 0, 0, cookie.maxAge, 0); + time:Time expTime = time:addDuration(cookie.createdTime, 0, 0, 0, 0, 0, cookie.maxAge, 0); time:Time curTime = time:currentTime(); - if (exptime.time < curTime.time) { - return true; - } - return false; + return (expTime.time < curTime.time); } - var temp = cookie.expires; - if (temp is string) { - time:Time|error cookieExpires = time:parse(temp.substring(0, temp.length() - 4), "E, dd MMM yyyy HH:mm:ss"); + var expiryTime = cookie.expires; + if (expiryTime is string) { + time:Time|error cookieExpires = time:parse(expiryTime.substring(0, expiryTime.length() - 4), "E, dd MMM yyyy HH:mm:ss"); time:Time curTime = time:currentTime(); if ((cookieExpires is time:Time) && cookieExpires.time < curTime.time) { return true; @@ -311,21 +463,25 @@ function isExpired(Cookie cookie) returns boolean { } // Adds a session cookie to the cookie store according to the rules in [RFC-6265](https://tools.ietf.org/html/rfc6265#section-5.3 , https://tools.ietf.org/html/rfc6265#section-4.1.2). -function addSessionCookie(Cookie? identicalCookie, Cookie cookie, string url, CookieStore cookieStore) { +function addSessionCookie(Cookie? identicalCookie, Cookie cookie, string url, CookieStore cookieStore) returns error? { if (identicalCookie is Cookie) { - var temp1 = identicalCookie.name; - var temp2 = identicalCookie.domain; - var temp3 = identicalCookie.path; + var identicalCookieName = identicalCookie.name; + var identicalCookieDomain = identicalCookie.domain; + var identicalCookiePath = identicalCookie.path; // Removes the old cookie and adds the new session cookie. - if (((identicalCookie.httpOnly && url.startsWith(HTTP)) || identicalCookie.httpOnly == false) && temp1 is string && temp2 is string && temp3 is string) { - _ = cookieStore.removeCookie(temp1, temp2, temp3); - cookie.creationTime = identicalCookie.creationTime; + if (((identicalCookie.httpOnly && url.startsWith(HTTP)) || identicalCookie.httpOnly == false) + && identicalCookieName is string && identicalCookieDomain is string && identicalCookiePath is string) { + var removeResult = cookieStore.removeCookie(identicalCookieName, identicalCookieDomain, identicalCookiePath); + if (removeResult is error) { + return removeResult; + } + cookie.createdTime = identicalCookie.createdTime; cookie.lastAccessedTime = time:currentTime(); cookieStore.allSessionCookies.push(cookie); - } + } } else { // Adds the session cookie. - cookie.creationTime = time:currentTime(); + cookie.createdTime = time:currentTime(); cookie.lastAccessedTime = time:currentTime(); cookieStore.allSessionCookies.push(cookie); } diff --git a/stdlib/http/src/main/ballerina/src/http/cookie/csv_persistent_cookie_handler.bal b/stdlib/http/src/main/ballerina/src/http/cookie/csv_persistent_cookie_handler.bal new file mode 100644 index 000000000000..4bbaf44a1188 --- /dev/null +++ b/stdlib/http/src/main/ballerina/src/http/cookie/csv_persistent_cookie_handler.bal @@ -0,0 +1,238 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/file; +import ballerina/io; +import ballerina/log; +import ballerina/time; + +type myCookie record { + string name; + string value; + string domain; + string path; + string expires; + int maxAge; + boolean httpOnly; + boolean secure; + string createdTime; + string lastAccessedTime; + boolean hostOnly; +}; + +string? cookieNameToRemove = (); +string? cookieDomainToRemove = (); +string? cookiePathToRemove = (); + +# Represents a default persistent cookie handler, which stores persistent cookies in a CSV file. +# +# + fileName - Name of the CSV file to store persistent cookies +public type CsvPersistentCookieHandler object { + *PersistentCookieHandler; + + string fileName = ""; + table cookiesTable = table{}; + + public function __init(string fileName) { + self.fileName = checkpanic validateFileExtension(fileName); + } + + # Adds a persistent cookie to the cookie store. + # + # + cookie - Cookie to be added + # + return - An error will be returned if there is any error occurred during the storing process of the cookie or else nil is returned + public function storeCookie(Cookie cookie) returns @tainted CookieHandlingError? { + if (file:exists(self.fileName) && !self.cookiesTable.hasNext()) { + var tblResult = readFile(self.fileName); + if (tblResult is table) { + self.cookiesTable = tblResult; + } else { + return error(COOKIE_HANDLING_ERROR, message = "Error in reading the csv file", cause = tblResult); + } + } + var tableUpdateResult = addNewCookieToTable(self.cookiesTable, cookie); + if (tableUpdateResult is table) { + self.cookiesTable = tableUpdateResult; + } else { + return error(COOKIE_HANDLING_ERROR, message = "Error in updating the records in csv file", cause = tableUpdateResult); + } + var result = writeToFile(self.cookiesTable, <@untainted> self.fileName); + if (result is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in writing the csv file", cause = result); + } + } + + # Gets all the persistent cookies. + # + # + return - Array of persistent cookies stored in the cookie store or else an error is returned if one occurred during the retrieval of the cookies + public function getAllCookies() returns @tainted Cookie[]|CookieHandlingError { + Cookie[] cookies = []; + if (file:exists(self.fileName)) { + var tblResult = readFile(self.fileName); + if (tblResult is table) { + foreach var rec in tblResult { + Cookie cookie = new(rec.name, rec.value); + cookie.domain = rec.domain; + cookie.path = rec.path; + cookie.expires = rec.expires == "-" ? () : rec.expires; + cookie.maxAge = rec.maxAge; + cookie.httpOnly = rec.httpOnly; + cookie.secure = rec.secure; + time:Time|error t1 = time:parse(rec.createdTime, "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + if (t1 is time:Time) { + cookie.createdTime = t1; + } + time:Time|error t2 = time:parse(rec.lastAccessedTime, "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + if (t2 is time:Time) { + cookie.lastAccessedTime = t2; + } + cookie.hostOnly = rec.hostOnly; + cookies.push(cookie); + } + return cookies; + } else { + return error(COOKIE_HANDLING_ERROR, message = "Error in reading the csv file", cause = tblResult); + } + } + return cookies; + } + + # Removes a specific persistent cookie. + # + # + name - Name of the persistent cookie to be removed + # + domain - Domain of the persistent cookie to be removed + # + path - Path of the persistent cookie to be removed + # + return - An error will be returned if there is any error occurred during the removal of the cookie or else nil is returned + public function removeCookie(string name, string domain, string path) returns @tainted CookieHandlingError? { + cookieNameToRemove = name; + cookieDomainToRemove = domain; + cookiePathToRemove = path; + if (file:exists(self.fileName)) { + if(!self.cookiesTable.hasNext()) { + var tblResult = readFile(self.fileName); + if (tblResult is table) { + self.cookiesTable = tblResult; + } else { + return error(COOKIE_HANDLING_ERROR, message = "Error in reading the csv file", cause = tblResult); + } + } + int|error count = self.cookiesTable.remove(checkRemoveCriteria); + if (count is error || count <= 0) { + return error(COOKIE_HANDLING_ERROR, message = "Error in removing cookie: No such cookie to remove"); + } + error? removeResults = file:remove(<@untainted> self.fileName); + if (removeResults is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in removing the csv file", cause = removeResults); + } + var writeResult = writeToFile(self.cookiesTable, <@untainted> self.fileName); + if (writeResult is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in writing the csv file", cause = writeResult); + } + return; + } + return error(COOKIE_HANDLING_ERROR, message = "Error in removing cookie: No persistent cookie store file to remove"); + } + + # Removes all persistent cookies. + # + # + return - An error will be returned if there is any error occurred during the removal of all the cookies or else nil is returned + public function removeAllCookies() returns CookieHandlingError? { + error? removeResults = file:remove(self.fileName); + if (removeResults is error) { + return error(COOKIE_HANDLING_ERROR, message = "Error in removing the csv file", cause = removeResults); + } + } +}; + +function validateFileExtension(string fileName) returns string|CookieHandlingError { + if (fileName.toLowerAscii().endsWith(".csv")) { + return fileName; + } + return error(COOKIE_HANDLING_ERROR, message = "Invalid file format"); +} + +function readFile(string fileName) returns @tainted error|table { + io:ReadableCSVChannel rCsvChannel2 = check io:openReadableCsvFile(fileName); + var tblResult = rCsvChannel2.getTable(myCookie); + closeReadableCSVChannel(rCsvChannel2); + if (tblResult is table) { + return >tblResult; + } else { + return tblResult; + } +} + +function closeReadableCSVChannel(io:ReadableCSVChannel csvChannel) { + var result = csvChannel.close(); + if (result is error) { + log:printError("Error occurred while closing the channel: ", result); + } +} + +// Updates the table with new cookie. +function addNewCookieToTable(table cookiesTable, Cookie cookieToAdd) returns table|error { + table tableToReturn = cookiesTable; + var name = cookieToAdd.name; + var value = cookieToAdd.value; + var domain = cookieToAdd.domain; + var path = cookieToAdd.path; + var expires = cookieToAdd.expires; + var createdTime = time:format(cookieToAdd.createdTime, "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + var lastAccessedTime = time:format(cookieToAdd.lastAccessedTime, "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + if (name is string && value is string && domain is string && path is string && createdTime is string && lastAccessedTime is string) { + myCookie c1 = { name: name, value: value, domain: domain, path: path, expires: expires is string ? expires : "-", maxAge: cookieToAdd.maxAge, httpOnly: cookieToAdd.httpOnly, secure: cookieToAdd.secure, createdTime: createdTime, lastAccessedTime: lastAccessedTime, hostOnly: cookieToAdd.hostOnly }; + var result = tableToReturn.add(c1); + if (result is error) { + return result; + } + return tableToReturn; + } + CookieHandlingError err = error(COOKIE_HANDLING_ERROR, message = "Invalid data types for cookie attributes"); + return err; +} + +// Writes the updated table to the file. +function writeToFile(table cookiesTable, string fileName) returns @tainted error? { + io:WritableCSVChannel wCsvChannel2 = check io:openWritableCsvFile(fileName); + foreach var entry in cookiesTable { + string[] rec = [entry.name, entry.value, entry.domain, entry.path, entry.expires, entry.maxAge.toString(), entry.httpOnly.toString(), entry.secure.toString(), entry.createdTime, entry.lastAccessedTime, entry.hostOnly.toString()]; + var writeResult = writeDataToCSVChannel(wCsvChannel2, rec); + if (writeResult is error) { + return writeResult; + } + } + closeWritableCSVChannel(wCsvChannel2); +} + +function writeDataToCSVChannel(io:WritableCSVChannel csvChannel, string[]... data) returns error? { + foreach var rec in data { + var returnedVal = csvChannel.write(rec); + if (returnedVal is error) { + return returnedVal; + } + } +} + +function closeWritableCSVChannel(io:WritableCSVChannel csvChannel) { + var result = csvChannel.close(); + if (result is error) { + log:printError("Error occurred while closing the channel: ", result); + } +} + +function checkRemoveCriteria(myCookie rec) returns boolean { + return rec.name == cookieNameToRemove && rec.domain == cookieDomainToRemove && rec.path == cookiePathToRemove; +} diff --git a/stdlib/http/src/main/ballerina/src/http/cookie/persistent_cookie_handler.bal b/stdlib/http/src/main/ballerina/src/http/cookie/persistent_cookie_handler.bal new file mode 100644 index 000000000000..95d5b186e796 --- /dev/null +++ b/stdlib/http/src/main/ballerina/src/http/cookie/persistent_cookie_handler.bal @@ -0,0 +1,43 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +# The representation of a persistent cookie handler for managing persistent cookies. +public type PersistentCookieHandler abstract object { + + # Adds a persistent cookie to the cookie store. + # + # + cookie - Cookie to be added + # + return - An error will be returned if there is any error occurred during the storing process of the cookie or else nil is returned + public function storeCookie(Cookie cookie) returns CookieHandlingError?; + + # Gets all persistent cookies. + # + # + return - Array of persistent cookies stored in the cookie store or else error is returned if occurred during the retrieval of the cookies + public function getAllCookies() returns Cookie[]|CookieHandlingError; + + # Removes a specific persistent cookie. + # + # + name - Name of the persistent cookie to be removed + # + domain - Domain of the persistent cookie to be removed + # + path - Path of the persistent cookie to be removed + # + return - An error will be returned if there is any error occurred during the removal of the cookie or else nil is returned + public function removeCookie(string name, string domain, string path) returns CookieHandlingError?; + + # Removes all persistent cookies. + # + # + return - An error will be returned if there is any error occurred during the removal of all the cookies or else nil is returned + public function removeAllCookies() returns CookieHandlingError?; +}; diff --git a/stdlib/http/src/main/ballerina/src/http/http_errors.bal b/stdlib/http/src/main/ballerina/src/http/http_errors.bal index 76c02d1887e4..2df3a64de986 100644 --- a/stdlib/http/src/main/ballerina/src/http/http_errors.bal +++ b/stdlib/http/src/main/ballerina/src/http/http_errors.bal @@ -141,6 +141,11 @@ public const WRITING_100_CONTINUE_RESPONSE_FAILED = "{ballerina/http}Writing100C # Represents an error that occurred while writing 100 continue response public type Writing100ContinueResponseError error; +# Represents the reason string for the `http:InvalidCookieError` +public const INVALID_COOKIE_ERROR = "{ballerina/http}InvalidCookieError"; +# Represents a cookie error that occurred when sending cookies in the response +public type InvalidCookieError error; + // Generic errors (mostly to wrap errors from other modules) # Error reason for generic client error public const GENERIC_CLIENT_ERROR = "{ballerina/http}GenericClientError"; @@ -173,7 +178,12 @@ public const SSL_ERROR = "{ballerina/http}SslError"; # Represents a client error that occurred due to SSL failure public type SslError error; -// Ballerina Http Union Errors +# Represents the reason string for the `http:CookieHandlingError` +public const COOKIE_HANDLING_ERROR = "{ballerina/http}CookieHandlingError"; +# Represents a cookie error that occurred when using the cookies +public type CookieHandlingError error; + +// Ballerina HTTP Union Errors # Defines the resiliency error types that returned from client public type ResiliencyError FailoverAllEndpointsFailedError | FailoverActionFailedError | UpstreamServiceUnavailableError | AllLoadBalanceEndpointsFailedError | @@ -197,12 +207,12 @@ public type InboundRequestError InitializingInboundRequestError|ReadingInboundRe # Defines the listener error types that returned while sending outbound response public type OutboundResponseError InitializingOutboundResponseError|WritingOutboundResponseHeadersError| WritingOutboundResponseBodyError|Initiating100ContinueResponseError| - Writing100ContinueResponseError; + Writing100ContinueResponseError|InvalidCookieError; # Defines the possible client error types public type ClientError ResiliencyError|ClientAuthError|OutboundRequestError| InboundResponseError|UnsupportedActionError|Http2ClientError| - MaximumWaitTimeExceededError|SslError|GenericClientError; + MaximumWaitTimeExceededError|SslError|GenericClientError|CookieHandlingError; # Defines the possible listener error types public type ListenerError GenericListenerError|InboundRequestError|OutboundResponseError; diff --git a/stdlib/http/src/main/ballerina/src/http/http_request.bal b/stdlib/http/src/main/ballerina/src/http/http_request.bal index f9d636c531dd..403725410779 100644 --- a/stdlib/http/src/main/ballerina/src/http/http_request.bal +++ b/stdlib/http/src/main/ballerina/src/http/http_request.bal @@ -549,14 +549,12 @@ public type Request object { # + cookiesToAdd - Represents the cookies to be added public function addCookies(Cookie[] cookiesToAdd) { string cookieheader = ""; - string? temp1 = (); - string? temp2 = (); Cookie[] sortedCookies = cookiesToAdd.sort(comparator); foreach var cookie in sortedCookies { - temp1 = cookie.name; - temp2 = cookie.value; - if (temp1 is string && temp2 is string) { - cookieheader = cookieheader + temp1 + EQUALS + temp2 + SEMICOLON + SPACE; + var cookieName = cookie.name; + var cookieValue = cookie.value; + if (cookieName is string && cookieValue is string) { + cookieheader = cookieheader + cookieName + EQUALS + cookieValue + SEMICOLON + SPACE; } cookie.lastAccessedTime = time:currentTime(); } diff --git a/stdlib/http/src/main/ballerina/src/http/redirect/redirect_client.bal b/stdlib/http/src/main/ballerina/src/http/redirect/redirect_client.bal index 5d2e4ba92dce..e830216bd3f3 100644 --- a/stdlib/http/src/main/ballerina/src/http/redirect/redirect_client.bal +++ b/stdlib/http/src/main/ballerina/src/http/redirect/redirect_client.bal @@ -331,7 +331,7 @@ function performRedirection(string location, RedirectClient redirectClient, Http var cookieConfigVal = redirectClient.config.cookieConfig; if (cookieConfigVal is CookieConfig) { if (cookieConfigVal.enabled) { - cookieStore = new; + cookieStore = new(cookieConfigVal?.persistentCookieHandler); } } var retryClient = createRetryClient(location, createNewEndpointConfig(redirectClient.config), cookieStore); diff --git a/stdlib/http/src/main/ballerina/src/http/websocket/websocket_client.bal b/stdlib/http/src/main/ballerina/src/http/websocket/websocket_client.bal index b7502b6906c5..6ab7b9283abb 100644 --- a/stdlib/http/src/main/ballerina/src/http/websocket/websocket_client.bal +++ b/stdlib/http/src/main/ballerina/src/http/websocket/websocket_client.bal @@ -18,8 +18,6 @@ import ballerinax/java; # Represents a WebSocket client endpoint. public type WebSocketClient client object { - // This is to keep track if the ready() function has been called - private boolean isReady = false; private string id = ""; private string? negotiatedSubProtocol = (); @@ -46,12 +44,13 @@ public type WebSocketClient client object { return externWSInitEndpoint(self); } - # Push text to the connection. + # Pushes text to the connection. # - # + data - Data to be sent, if byte[] it is converted to a UTF-8 string for sending + # + data - Data to be sent. If it is a byte[], it is converted to a UTF-8 string for sending. # + finalFrame - Set to `true` if this is a final frame of a (long) message - # + return - `error` if an error occurs when sending - public remote function pushText(string|json|xml|boolean|int|float|byte|byte[] data, + # + return - Returns a`WebSocketError` if an error occurs while sending the text message to the server. + # The message will be lost if an error occurs. + public remote function pushText(string|json|xml|boolean|int|float|byte|byte[] data, public boolean finalFrame = true) returns WebSocketError? { return self.conn.pushText(data, finalFrame); } @@ -60,47 +59,51 @@ public type WebSocketClient client object { # # + data - Binary data to be sent # + finalFrame - Set to `true` if this is a final frame of a (long) message - # + return - `error` if an error occurs when sending + # + return - Returns a `WebSocketError` if an error occurs while sending the binary message to the server. + # The message will be lost if an error occurs. public remote function pushBinary(byte[] data, public boolean finalFrame = true) returns error? { return self.conn.pushBinary(data, finalFrame); } - # Ping the connection. + # Pings the connection. # # + data - Binary data to be sent. - # + return - `error` if an error occurs when sending + # + return - Returns a`WebSocketError` if an error occurs while sending the ping frame to the server. + # The frame will be lost if an error occurs. public remote function ping(byte[] data) returns WebSocketError? { return self.conn.ping(data); } - # Send pong message to the connection. + # Sends a pong message to the connection. # # + data - Binary data to be sent - # + return - `error` if an error occurs when sending + # + return - Returns a `WebSocketError` if an error occurs while sending the pong frame to the server. + # The frame will be lost if an error occurs. public remote function pong(byte[] data) returns WebSocketError? { return self.conn.pong(data); } - # Close the connection. + # Closes the connection. # - # + statusCode - Status code for closing the connection + # + statusCode - Status code for closing the connection. # + reason - Reason for closing the connection # + timeoutInSeconds - Time to wait for the close frame to be received from the remote endpoint before closing the # connection. If the timeout exceeds, then the connection is terminated even though a close frame - # is not received from the remote endpoint. If the value < 0 (e.g., -1), then the connection waits - # until a close frame is received. If WebSocket frame is received from the remote endpoint, - # within waiting period the connection is terminated immediately. - # + return - `error` if an error occurs when sending + # is not received from the remote endpoint. If the value is < 0 (e.g., -1), then the connection + # waits until a close frame is received. If the WebSocket frame is received from the remote endpoint + # within the waiting period, the connection is terminated immediately. + # + return - Returns a `WebSocketError` if an error occurs while closing the webSocket connection. public remote function close(public int? statusCode = 1000, public string? reason = (), public int timeoutInSeconds = 60) returns WebSocketError? { return self.conn.close(statusCode, reason, timeoutInSeconds); } - # Called when the client is ready to receive messages. Can be called only once. + # Called when the endpoint is ready to receive messages. Can be called only once per endpoint. For the + # WebSocketListener, it can be called only in the `upgrade` or `onOpen` resources. # - # + return - `error` if an error occurs when sending + # + return - Returns a`WebSocketError` if an error occurs while checking the connection state. public remote function ready() returns WebSocketError? { - return externWSReady(self); + return self.conn.ready(); } # Sets a connection related attribute. @@ -164,21 +167,25 @@ public type WebSocketClient client object { }; -# Configuration for the WebSocket client endpoint. +# Configurations for the WebSocket client endpoint. # -# + callbackService - The callback service for the client. Resources in this service gets called on receipt of messages -# from the server. -# + subProtocols - Negotiable sub protocols for the client -# + customHeaders - Custom headers which should be sent to the server -# + idleTimeoutInSeconds - Idle timeout of the client. Upon timeout, `onIdleTimeout` resource (if defined) in the client -# service will be triggered. -# + readyOnConnect - `true` if the client is ready to receive messages as soon as the connection is established. -# This is true by default. If changed to false the function ready() of the -# `WebSocketClient`needs to be called once to start receiving messages. -# + secureSocket - SSL/TLS related options +# + callbackService - The callback service for the client. Resources in this service gets called on the +# receipt of messages from the server. +# + subProtocols - Negotiable sub protocols for the client. +# + customHeaders - Custom headers, which should be sent to the server. +# + idleTimeoutInSeconds - Idle timeout of the client. Upon timeout, the `onIdleTimeout` resource (if defined) +# of the client service will be triggered. +# + readyOnConnect - Set to `true` if the client is ready to receive messages as soon as the connection is established. +# This is set to `true` by default. If changed to `false`, the ready() function of the +# `WebSocketClient` needs to be called once to start receiving messages. +# + secureSocket - SSL/TLS-related options. # + maxFrameSize - The maximum payload size of a WebSocket frame in bytes. -# If this is not set or is negative or zero the default frame size of 65536 will be used. -# + webSocketCompressionEnabled - Enable support for compression in WebSocket +# If this is not set, is negative, or is zero, the default frame size of 65536 will be used. +# + webSocketCompressionEnabled - Enable support for compression in the WebSocket. +# + handShakeTimeoutInSeconds - Time (in seconds) that a connection waits to get the response of +# the webSocket handshake. If the timeout exceeds, then the connection is terminated with +# an error.If the value < 0, then the value sets to the default value(300). +# + retryConfig - Retry related configurations. public type WebSocketClientConfiguration record {| service? callbackService = (); string[] subProtocols = []; @@ -188,14 +195,25 @@ public type WebSocketClientConfiguration record {| ClientSecureSocket? secureSocket = (); int maxFrameSize = 0; boolean webSocketCompressionEnabled = true; + int handShakeTimeoutInSeconds = 300; + WebSocketRetryConfig retryConfig?; +|}; + +# Retry configurations for WebSocket. +# +# + maxCount - The maximum number of retry attempts. If the count is zero, the client will retry indefinitely. +# + intervalInMillis - The number of milliseconds to delay before attempting to reconnect. +# + backOffFactor - The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems +# persist. +# + maxWaitIntervalInMillis - Maximum time of the retry interval in milliseconds. +public type WebSocketRetryConfig record {| + int maxCount = 0; + int intervalInMillis = 1000; + float backOffFactor = 1.0; + int maxWaitIntervalInMillis = 30000; |}; function externWSInitEndpoint(WebSocketClient wsClient) = @java:Method { class: "org.ballerinalang.net.http.websocket.client.InitEndpoint", name: "initEndpoint" } external; - -function externWSReady(WebSocketClient wsClient) returns WebSocketError? = @java:Method { - class: "org.ballerinalang.net.http.actions.websocketconnector.Ready", - name: "ready" -} external; diff --git a/stdlib/http/src/main/ballerina/src/http/websocket/websocket_connector.bal b/stdlib/http/src/main/ballerina/src/http/websocket/websocket_connector.bal index efe70f5182ac..9e1f5fd1869c 100644 --- a/stdlib/http/src/main/ballerina/src/http/websocket/websocket_connector.bal +++ b/stdlib/http/src/main/ballerina/src/http/websocket/websocket_connector.bal @@ -19,6 +19,7 @@ import ballerinax/java; # Represents a WebSocket connection in Ballerina. This includes all connection-oriented operations. type WebSocketConnector object { + private boolean isReady = false; # Push text to the connection. # @@ -68,6 +69,14 @@ type WebSocketConnector object { return externPong(self, data); } + # Calls when the endpoint is ready to receive messages. It can be called only once per endpoint. The + # WebSocketListener can be called only in `upgrade` or `onOpen` resources. + # + # + return - Returns `error` if an error occurs when sending. + public function ready() returns WebSocketError? { + return externReady(self); + } + # Close the connection. # # + statusCode - Status code for closing the connection @@ -121,3 +130,8 @@ function externClose(WebSocketConnector wsConnector, int statusCode, handle reas @java:Method { class: "org.ballerinalang.net.http.actions.websocketconnector.Close" } external; + +function externReady(WebSocketConnector wsConnector) returns WebSocketError? = @java:Method { + class: "org.ballerinalang.net.http.actions.websocketconnector.Ready", + name: "ready" +} external; diff --git a/stdlib/http/src/main/ballerina/src/http/websocket/websocket_failover_client.bal b/stdlib/http/src/main/ballerina/src/http/websocket/websocket_failover_client.bal new file mode 100644 index 000000000000..2ce494539a85 --- /dev/null +++ b/stdlib/http/src/main/ballerina/src/http/websocket/websocket_failover_client.bal @@ -0,0 +1,206 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerinax/java; + +# A WebSocket client endpoint, which provides failover support for multiple WebSocket targets. +public type WebSocketFailoverClient client object { + + private string id = ""; + private string? negotiatedSubProtocol = (); + private boolean secure = false; + private boolean open = false; + private Response? response = (); + private map attributes = {}; + + private WebSocketConnector conn = new; + private WebSocketFailoverClientConfiguration config = {}; + + # The failover caller action, which provides failover capabilities to a WebSocket client endpoint. + # + # + config - The `WebSocketFailoverClientConfiguration` of the endpoint. + public function __init(public WebSocketFailoverClientConfiguration? config = ()) { + self.config = config ?: {}; + self.init(); + } + + public function init() { + return externWSFailoverInit(self); + } + + # Pushes text to the connection. + # + # + data - Data to be sent. If it is a byte[], it is converted to a UTF-8 string for sending. + # + finalFrame - Set to `true` if this is a final frame of a (long) message. + # + return - Returns a`WebSocketError` if an error occurs while sending the text message to the server. + # The message will be lost if an error occurs. + public remote function pushText(string|json|xml|boolean|int|float|byte|byte[] data, + public boolean finalFrame = true) returns WebSocketError? { + return self.conn.pushText(data, finalFrame); + } + + # Pushes binary data to the connection. + # + # + data - Binary data to be sent. + # + finalFrame - Sets to `true` if this is a final frame of a (long) message. + # + return - Returns a `WebSocketError` if an error occurs while sending the binary message to the server. + # The message will be lost if an error occurs. + public remote function pushBinary(byte[] data, public boolean finalFrame = true) returns error? { + return self.conn.pushBinary(data, finalFrame); + } + + # Pings the connection. + # + # + data - Binary data to be sent. + # + return - Returns a`WebSocketError` if an error occurs while sending the ping frame to the server. + # The frame will be lost if an error occurs. + public remote function ping(byte[] data) returns WebSocketError? { + return self.conn.ping(data); + } + + # Sends a pong message to the connection. + # + # + data - Binary data to be sent. + # + return - Returns a `WebSocketError` if an error occurs while sending the pong frame to the server. + # The frame will be lost if an error occurs. + public remote function pong(byte[] data) returns WebSocketError? { + return self.conn.pong(data); + } + + # Closes the connection. + # + # + statusCode - Status code for closing the connection. + # + reason - Reason for closing the connection. + # + timeoutInSeconds - Time to wait for the close frame to be received from the remote endpoint before closing the + # connection. If the timeout exceeds, then the connection is terminated even though a close frame + # is not received from the remote endpoint. If the value is < 0 (e.g., -1), then the connection + # waits until a close frame is received. If the WebSocket frame is received from the remote + # endpoint within the waiting period, the connection is terminated immediately. + # + return - Returns a `WebSocketError` if an error occurs while closing the webSocket connection. + public remote function close(public int? statusCode = 1000, public string? reason = (), + public int timeoutInSeconds = 60) returns WebSocketError? { + return self.conn.close(statusCode, reason, timeoutInSeconds); + } + + # Called when the endpoint is ready to receive messages. Can be called only once per endpoint. For the + # WebSocketListener, it can be called only in the `upgrade` or `onOpen` resources. + # + # + return - Returns a`WebSocketError` if an error occurs while checking the connection state. + public remote function ready() returns WebSocketError? { + return self.conn.ready(); + } + + # Sets a connection-related attribute. + # + # + key - The key to identify the attribute. + # + value - Value of the attribute. + public function setAttribute(string key, any value) { + self.attributes[key] = value; + } + + # Gets connection-related attributes if any. + # + # + key - The key to identify the attribute. + # + return - The attribute related to the given key or `nil`. + public function getAttribute(string key) returns any { + return self.attributes[key]; + } + + # Removes connection-related attributes if any. + # + # + key - The key to identify the attribute. + # + return - The attribute related to the given key or `nil`. + public function removeAttribute(string key) returns any { + return self.attributes.remove(key); + } + + # Gives the connection ID associated with this connection. + # + # + return - The unique ID associated with the connection. + public function getConnectionId() returns string { + return self.id; + } + + # Gives the subprotocol if any that is negotiated with the client. + # + # + return - Returns the subprotocol if any that is negotiated with the client or `nil`. + public function getNegotiatedSubProtocol() returns string? { + return self.negotiatedSubProtocol; + } + + # Gives the secured status of the connection. + # + # + return - Returns `true` if the connection is secure. + public function isSecure() returns boolean { + return self.secure; + } + + # Gives the open or closed status of the connection. + # + # + return - Returns `true` if the connection is open. + public function isOpen() returns boolean { + return self.open; + } + + # Gives any HTTP response for the client handshake request if received. + # + # + return - Returns the HTTP response received for the client handshake request. + public function getHttpResponse() returns Response? { + return self.response; + } + +}; + +# Configurations for the WebSocket client endpoint. +# +# + callbackService - The callback service for the client. Resources in this service gets called on the +# receipt of messages from the server. +# + subProtocols - Negotiable sub protocols for the client. +# + customHeaders - Custom headers, which should be sent to the server. +# + idleTimeoutInSeconds - Idle timeout of the client. Upon timeout, the `onIdleTimeout` resource (if defined) +# of the client service will be triggered. +# + readyOnConnect - Set to `true` if the client is ready to receive messages as soon as the connection is established. +# This is set to `true` by default. If changed to `false`, the ready() function of the +# `WebSocketFailoverClient` needs to be called once to start receiving messages. +# + secureSocket - SSL/TLS-related options. +# + maxFrameSize - The maximum payload size of a WebSocket frame in bytes. +# If this is not set, is negative, or is zero, the default frame size of 65536 will be used. +# + targetUrls - The set of URLs, which are used to connect to the server. +# + failoverIntervalInMillis - The maximum number of milliseconds to delay a failover attempt. +# + webSocketCompressionEnabled - Enable support for compression in WebSocket. +# + handShakeTimeoutInSeconds - Time (in seconds) that a connection waits to get the response of +# the webSocket handshake. If the timeout exceeds, then the connection is terminated with +# an error.If the value < 0, then the value sets to the default value(300). +# + retryConfig - Configurations related to retrying. +public type WebSocketFailoverClientConfiguration record {| + service? callbackService = (); + string[] subProtocols = []; + map customHeaders = {}; + int idleTimeoutInSeconds = -1; + boolean readyOnConnect = true; + ClientSecureSocket? secureSocket = (); + int maxFrameSize = 0; + string[] targetUrls = []; + int failoverIntervalInMillis = 1000; + boolean webSocketCompressionEnabled = true; + int handShakeTimeoutInSeconds = 300; + WebSocketRetryConfig retryConfig?; +|}; + +function externWSFailoverInit(WebSocketFailoverClient wsClient) = @java:Method { + class: "org.ballerinalang.net.http.websocket.client.FailoverInitEndpoint", + name: "init" +} external; diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/actions/websocketconnector/Ready.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/actions/websocketconnector/Ready.java index 1468ac009210..67d3b6beaf08 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/actions/websocketconnector/Ready.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/actions/websocketconnector/Ready.java @@ -35,23 +35,23 @@ public class Ready { private static final Logger log = LoggerFactory.getLogger(Ready.class); - public static Object ready(ObjectValue wsClient) { - ObjectValue wsConnection = (ObjectValue) wsClient.get(WebSocketConstants.CLIENT_CONNECTOR_FIELD); - WebSocketConnectionInfo connectionInfo = (WebSocketConnectionInfo) wsConnection - .getNativeData(WebSocketConstants.NATIVE_DATA_WEBSOCKET_CONNECTION_INFO); + public static Object ready(ObjectValue wsConnector) { + WebSocketConnectionInfo connectionInfo = (WebSocketConnectionInfo) wsConnector + .getNativeData(WebSocketConstants.NATIVE_DATA_WEBSOCKET_CONNECTION_INFO); WebSocketObservabilityUtil.observeResourceInvocation(Scheduler.getStrand(), connectionInfo, - WebSocketConstants.RESOURCE_NAME_READY); + WebSocketConstants.RESOURCE_NAME_READY); try { - boolean isReady = wsClient.getBooleanValue(WebSocketConstants.CONNECTOR_IS_READY_FIELD); + boolean isReady = wsConnector.getBooleanValue(WebSocketConstants.CONNECTOR_IS_READY_FIELD); if (!isReady) { - WebSocketUtil.readFirstFrame(connectionInfo.getWebSocketConnection(), wsClient); + WebSocketUtil.readFirstFrame(connectionInfo.getWebSocketConnection(), wsConnector); + connectionInfo.getWebSocketEndpoint().getMapValue(WebSocketConstants.CLIENT_ENDPOINT_CONFIG). + put(WebSocketConstants.CLIENT_READY_ON_CONNECT, true); } else { return new WebSocketException("Already started reading frames"); } } catch (Exception e) { log.error("Error occurred when calling ready", e); - WebSocketObservabilityUtil.observeError(WebSocketObservabilityUtil.getConnectionInfo(wsConnection), - WebSocketObservabilityConstants.ERROR_TYPE_READY, + WebSocketObservabilityUtil.observeError(connectionInfo, WebSocketObservabilityConstants.ERROR_TYPE_READY, e.getMessage()); return WebSocketUtil.createErrorByType(e); } diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/compiler/websocket/WebSocketFailoverClientResourceValidator.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/compiler/websocket/WebSocketFailoverClientResourceValidator.java new file mode 100644 index 000000000000..ca96c830745e --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/compiler/websocket/WebSocketFailoverClientResourceValidator.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ballerinalang.net.http.compiler.websocket; + +import org.ballerinalang.net.http.websocket.WebSocketConstants; +import org.ballerinalang.util.diagnostic.Diagnostic; +import org.ballerinalang.util.diagnostic.DiagnosticLog; +import org.wso2.ballerinalang.compiler.tree.BLangFunction; + +/** + * Service validator for failover WebSocket. + * + * @since 1.2.0 + */ +class WebSocketFailoverClientResourceValidator extends WebSocketClientResourceValidator { + + WebSocketFailoverClientResourceValidator(DiagnosticLog dlog, BLangFunction resource) { + super(dlog, resource); + } + + @Override + void validateEndpointParameter() { + if (paramDetails != null && !paramDetails.isEmpty() && + !WebSocketConstants.FULL_FAILOVER_WEBSOCKET_CLIENT_NAME.equals(paramDetails.get(0).type.toString())) { + dlog.logDiagnostic(Diagnostic.Kind.ERROR, resource.pos, INVALID_RESOURCE_SIGNATURE_FOR + + resource.getName().getValue() + RESOURCE_IN_SERVICE + + ": The first parameter should be a " + WebSocketConstants.FAILOVER_WEBSOCKET_CLIENT); + } + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/compiler/websocket/WebSocketFailoverClientServiceCompilerPlugin.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/compiler/websocket/WebSocketFailoverClientServiceCompilerPlugin.java new file mode 100644 index 000000000000..ecda4fb2daba --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/compiler/websocket/WebSocketFailoverClientServiceCompilerPlugin.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ballerinalang.net.http.compiler.websocket; + +import org.ballerinalang.compiler.plugins.AbstractCompilerPlugin; +import org.ballerinalang.compiler.plugins.SupportedResourceParamTypes; +import org.ballerinalang.model.tree.AnnotationAttachmentNode; +import org.ballerinalang.model.tree.ServiceNode; +import org.ballerinalang.net.http.websocket.WebSocketConstants; +import org.ballerinalang.util.diagnostic.DiagnosticLog; +import org.wso2.ballerinalang.compiler.tree.BLangFunction; + +import java.util.List; + +import static org.ballerinalang.net.http.websocket.WebSocketConstants.FAILOVER_WEBSOCKET_CLIENT; + +/** + * Compiler plugin for validating failover WebSocket service. + * + * @since 1.2.0 + */ +@SupportedResourceParamTypes( + paramTypes = { + @SupportedResourceParamTypes.Type( + packageName = WebSocketConstants.PACKAGE_HTTP, + name = FAILOVER_WEBSOCKET_CLIENT + ) + } +) +public class WebSocketFailoverClientServiceCompilerPlugin extends AbstractCompilerPlugin { + + private DiagnosticLog dlog = null; + + @Override + public void init(DiagnosticLog diagnosticLog) { + dlog = diagnosticLog; + } + + @SuppressWarnings("unchecked") + @Override + public void process(ServiceNode serviceNode, List annotations) { + List resources = (List) serviceNode.getResources(); + resources.forEach( + res -> new WebSocketFailoverClientResourceValidator(dlog, res).validate()); + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketConstants.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketConstants.java index de13990b4a7e..e47e61db5269 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketConstants.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketConstants.java @@ -18,8 +18,8 @@ package org.ballerinalang.net.http.websocket; - -import static org.ballerinalang.jvm.util.BLangConstants.BALLERINA_PACKAGE_PREFIX; +import org.ballerinalang.jvm.types.BPackage; +import org.ballerinalang.jvm.util.BLangConstants; /** * Constants of WebSocket. @@ -28,7 +28,7 @@ public class WebSocketConstants { public static final String BALLERINA_ORG = "ballerina"; public static final String PACKAGE_HTTP = "http"; - public static final String FULL_PACKAGE_HTTP = BALLERINA_PACKAGE_PREFIX + PACKAGE_HTTP; + public static final String FULL_PACKAGE_HTTP = BLangConstants.BALLERINA_PACKAGE_PREFIX + PACKAGE_HTTP; public static final String SEPARATOR = ":"; public static final String LISTENER = "Listener"; public static final String WEBSOCKET_CONNECTOR = "WebSocketConnector"; @@ -38,9 +38,11 @@ public class WebSocketConstants { public static final String WEBSOCKET_CLIENT_SERVICE = "WebSocketClientService"; public static final String WSS_SCHEME = "wss"; public static final String WEBSOCKET_CALLER_NAME = PACKAGE_HTTP + SEPARATOR + WEBSOCKET_CALLER; - public static final String FULL_WEBSOCKET_CALLER_NAME = BALLERINA_PACKAGE_PREFIX + WEBSOCKET_CALLER_NAME; + public static final String FULL_WEBSOCKET_CALLER_NAME = BLangConstants.BALLERINA_PACKAGE_PREFIX + + WEBSOCKET_CALLER_NAME; public static final String WEBSOCKET_CLIENT_NAME = PACKAGE_HTTP + SEPARATOR + WEBSOCKET_CLIENT; - public static final String FULL_WEBSOCKET_CLIENT_NAME = BALLERINA_PACKAGE_PREFIX + WEBSOCKET_CLIENT_NAME; + public static final String FULL_WEBSOCKET_CLIENT_NAME = BLangConstants.BALLERINA_PACKAGE_PREFIX + + WEBSOCKET_CLIENT_NAME; public static final String WEBSOCKET_ANNOTATION_CONFIGURATION = "WebSocketServiceConfig"; @@ -76,6 +78,22 @@ public class WebSocketConstants { public static final String CLIENT_READY_ON_CONNECT = "readyOnConnect"; public static final String WEBSOCKET_UPGRADE_SERVICE_CONFIG = "upgradeService"; + public static final String RETRY_CONFIG = "retryConfig"; + public static final String COUNT_DOWN_LATCH = "countDownLatch"; + public static final String CLIENT_LISTENER = "clientListener"; + public static final String CLIENT_CONNECTOR = "clientConnector"; + public static final String LOG_MESSAGE = "{} {}"; + public static final String ERROR_MESSAGE = "Error occurred: "; + + public static final String CLIENT_ENDPOINT_CONFIG = "config"; + public static final String TARGET_URLS = "targetUrls"; + public static final String FAILOVER_CONFIG = "failoverConfig"; + public static final String CONNECTOR_FACTORY = "connectorFactory"; + public static final String FAILOVER_WEBSOCKET_CLIENT = "WebSocketFailoverClient"; + public static final String CONNECTED_TO = "Connected to "; + public static final String FULL_FAILOVER_WEBSOCKET_CLIENT_NAME = BLangConstants.BALLERINA_PACKAGE_PREFIX + + PACKAGE_HTTP + SEPARATOR + FAILOVER_WEBSOCKET_CLIENT; + public static final String COMPRESSION_ENABLED_CONFIG = "webSocketCompressionEnabled"; // WebSocketListener field names @@ -98,6 +116,8 @@ public class WebSocketConstants { public static final int STATUS_CODE_FOR_NO_STATUS_CODE_PRESENT = 1005; public static final int DEFAULT_MAX_FRAME_SIZE = 65536; + public static final BPackage PROTOCOL_HTTP_PKG_ID = new BPackage(BLangConstants.BALLERINA_BUILTIN_PKG_PREFIX, + "http"); // Warning suppression public static final String UNCHECKED = "unchecked"; diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketException.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketException.java index 64b28de45e0c..bc3c1a6fa0a3 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketException.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketException.java @@ -18,7 +18,10 @@ package org.ballerinalang.net.http.websocket; +import org.ballerinalang.jvm.BallerinaValues; import org.ballerinalang.jvm.values.ErrorValue; +import org.ballerinalang.jvm.values.MapValue; +import org.ballerinalang.net.http.HttpConstants; import static org.ballerinalang.net.http.websocket.WebSocketConstants.ErrorCode; @@ -39,16 +42,26 @@ public WebSocketException(String message) { } public WebSocketException(ErrorCode errorCode, String message) { - super(errorCode.errorCode(), WebSocketUtil.createDetailRecord(message)); + super(errorCode.errorCode(), createDetailRecord(message)); this.message = message; } public WebSocketException(ErrorCode errorCode, String message, ErrorValue cause) { - super(errorCode.errorCode(), WebSocketUtil.createDetailRecord(message, cause)); + super(errorCode.errorCode(), createDetailRecord(message, cause)); this.message = message; } public String detailMessage() { return message; } + + private static MapValue createDetailRecord(String errMsg) { + return createDetailRecord(errMsg, null); + } + + private static MapValue createDetailRecord(String errMsg, ErrorValue cause) { + MapValue detail = BallerinaValues.createRecordValue(HttpConstants.PROTOCOL_HTTP_PKG_ID, + WebSocketConstants.WEBSOCKET_ERROR_DETAILS); + return BallerinaValues.createRecord(detail, errMsg, cause); + } } diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketUtil.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketUtil.java index a7aa3a563c2a..e456527ebbd0 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketUtil.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/WebSocketUtil.java @@ -26,13 +26,24 @@ import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException; import org.ballerinalang.jvm.BallerinaErrors; import org.ballerinalang.jvm.BallerinaValues; +import org.ballerinalang.jvm.scheduling.Strand; import org.ballerinalang.jvm.types.BPackage; +import org.ballerinalang.jvm.types.BType; import org.ballerinalang.jvm.values.ErrorValue; import org.ballerinalang.jvm.values.MapValue; import org.ballerinalang.jvm.values.ObjectValue; import org.ballerinalang.jvm.values.connector.NonBlockingCallback; import org.ballerinalang.net.http.HttpConstants; import org.ballerinalang.net.http.HttpErrorType; +import org.ballerinalang.net.http.HttpUtil; +import org.ballerinalang.net.http.websocket.client.FailoverContext; +import org.ballerinalang.net.http.websocket.client.RetryContext; +import org.ballerinalang.net.http.websocket.client.WebSocketClientConnectorListener; +import org.ballerinalang.net.http.websocket.client.WebSocketClientConnectorListenerForRetry; +import org.ballerinalang.net.http.websocket.client.WebSocketClientHandshakeListener; +import org.ballerinalang.net.http.websocket.client.WebSocketClientHandshakeListenerForRetry; +import org.ballerinalang.net.http.websocket.client.WebSocketFailoverClientHandshakeListener; +import org.ballerinalang.net.http.websocket.client.WebSocketFailoverClientListener; import org.ballerinalang.net.http.websocket.observability.WebSocketObservabilityUtil; import org.ballerinalang.net.http.websocket.server.WebSocketConnectionInfo; import org.ballerinalang.net.http.websocket.server.WebSocketConnectionManager; @@ -40,28 +51,41 @@ import org.ballerinalang.stdlib.io.utils.IOConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.wso2.transport.http.netty.contract.HttpWsConnectorFactory; +import org.wso2.transport.http.netty.contract.websocket.ClientHandshakeFuture; +import org.wso2.transport.http.netty.contract.websocket.WebSocketClientConnector; +import org.wso2.transport.http.netty.contract.websocket.WebSocketClientConnectorConfig; +import org.wso2.transport.http.netty.contract.websocket.WebSocketCloseMessage; import org.wso2.transport.http.netty.contract.websocket.WebSocketConnection; +import org.wso2.transport.http.netty.message.HttpCarbonResponse; import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLException; -import static org.ballerinalang.net.http.websocket.WebSocketConstants.ErrorCode; -import static org.ballerinalang.stdlib.io.utils.IOConstants.IO_PACKAGE_ID; - /** * Utility class for WebSocket. */ public class WebSocketUtil { private static final Logger logger = LoggerFactory.getLogger(WebSocketUtil.class); + private static final String CLIENT_ENDPOINT_CONFIG = "config"; + private static final String WEBSOCKET_FAILOVER_CLIENT_NAME = WebSocketConstants.PACKAGE_HTTP + + WebSocketConstants.SEPARATOR + WebSocketConstants.FAILOVER_WEBSOCKET_CLIENT; public static ObjectValue createAndPopulateWebSocketCaller(WebSocketConnection webSocketConnection, WebSocketServerService wsService, WebSocketConnectionManager connectionManager) { ObjectValue webSocketCaller = BallerinaValues.createObjectValue(HttpConstants.PROTOCOL_HTTP_PKG_ID, - WebSocketConstants.WEBSOCKET_CALLER); + WebSocketConstants.WEBSOCKET_CALLER); ObjectValue webSocketConnector = BallerinaValues.createObjectValue( HttpConstants.PROTOCOL_HTTP_PKG_ID, WebSocketConstants.WEBSOCKET_CONNECTOR); @@ -92,7 +116,7 @@ public static void handleWebSocketCallback(NonBlockingCallback callback, webSocketChannelFuture.addListener(future -> { Throwable cause = future.cause(); if (!future.isSuccess() && cause != null) { - log.error("Error occurred ", cause); + log.error(WebSocketConstants.ERROR_MESSAGE, cause); callback.notifyFailure(WebSocketUtil.createErrorByType(cause)); } else { // This is needed because since the same strand is used in all actions if an action is called before @@ -103,15 +127,15 @@ public static void handleWebSocketCallback(NonBlockingCallback callback, }); } - public static void readFirstFrame(WebSocketConnection webSocketConnection, ObjectValue wsClient) { + public static void readFirstFrame(WebSocketConnection webSocketConnection, ObjectValue wsConnector) { webSocketConnection.readNextFrame(); - wsClient.set(WebSocketConstants.CONNECTOR_IS_READY_FIELD, true); + wsConnector.set(WebSocketConstants.CONNECTOR_IS_READY_FIELD, true); } /** * Closes the connection with the unexpected failure status code. * - * @param webSocketConnection the websocket connection to be closed. + * @param webSocketConnection - the webSocket connection to be closed. */ public static void closeDuringUnexpectedCondition(WebSocketConnection webSocketConnection) { webSocketConnection.terminateConnection(1011, "Unexpected condition"); @@ -137,16 +161,16 @@ public static int findMaxFrameSize(MapValue configs) { } - public static int findIdleTimeoutInSeconds(MapValue configs) { - long timeout = configs.getIntValue(WebSocketConstants.ANNOTATION_ATTR_IDLE_TIMEOUT); - if (timeout <= 0) { - return 0; + public static int findTimeoutInSeconds(MapValue config, String key, int defaultValue) { + long timeout = config.getIntValue(key); + if (timeout < 0) { + return defaultValue; } try { return Math.toIntExact(timeout); } catch (ArithmeticException e) { - logger.warn("The value set for idleTimeoutInSeconds needs to be less than" + Integer.MAX_VALUE + - ". The idleTimeoutInSeconds value is set to " + Integer.MAX_VALUE); + logger.warn("The value set for {} needs to be less than {} .The {} value is set to {} ", key, + Integer.MAX_VALUE, key, Integer.MAX_VALUE); return Integer.MAX_VALUE; } } @@ -155,7 +179,7 @@ public static String[] findNegotiableSubProtocols(MapValue confi return configs.getArrayValue(WebSocketConstants.ANNOTATION_ATTR_SUB_PROTOCOLS).getStringArray(); } - public static String getErrorMessage(Throwable err) { + static String getErrorMessage(Throwable err) { if (err.getMessage() == null) { return "Unexpected error occurred"; } @@ -165,49 +189,49 @@ public static String getErrorMessage(Throwable err) { /** * Creates the appropriate ballerina errors using for the given throwable. * - * @param throwable the throwable to be represented in Ballerina. + * @param throwable - the throwable to be represented in Ballerina. * @return the relevant WebSocketException with proper error code. */ public static WebSocketException createErrorByType(Throwable throwable) { - ErrorCode errorCode = ErrorCode.WsGenericError; + WebSocketConstants.ErrorCode errorCode = WebSocketConstants.ErrorCode.WsGenericError; ErrorValue cause = null; String message = getErrorMessage(throwable); if (throwable instanceof CorruptedWebSocketFrameException) { WebSocketCloseStatus status = ((CorruptedWebSocketFrameException) throwable).closeStatus(); if (status == WebSocketCloseStatus.MESSAGE_TOO_BIG) { - errorCode = ErrorCode.WsPayloadTooBigError; + errorCode = WebSocketConstants.ErrorCode.WsPayloadTooBigError; } else { - errorCode = ErrorCode.WsProtocolError; + errorCode = WebSocketConstants.ErrorCode.WsProtocolError; } } else if (throwable instanceof SSLException) { cause = createErrorCause(throwable.getMessage(), HttpErrorType.SSL_ERROR.getReason(), - HttpConstants.PROTOCOL_HTTP_PKG_ID); + WebSocketConstants.PROTOCOL_HTTP_PKG_ID); message = "SSL/TLS Error"; } else if (throwable instanceof IllegalStateException) { if (throwable.getMessage().contains("frame continuation")) { - errorCode = ErrorCode.WsInvalidContinuationFrameError; + errorCode = WebSocketConstants.ErrorCode.WsInvalidContinuationFrameError; } else if (throwable.getMessage().toLowerCase(Locale.ENGLISH).contains("close frame")) { - errorCode = ErrorCode.WsConnectionClosureError; + errorCode = WebSocketConstants.ErrorCode.WsConnectionClosureError; } } else if (throwable instanceof IllegalAccessException && throwable.getMessage().equals(WebSocketConstants.THE_WEBSOCKET_CONNECTION_HAS_NOT_BEEN_MADE)) { - errorCode = ErrorCode.WsConnectionError; + errorCode = WebSocketConstants.ErrorCode.WsConnectionError; } else if (throwable instanceof TooLongFrameException) { - errorCode = ErrorCode.WsPayloadTooBigError; + errorCode = WebSocketConstants.ErrorCode.WsPayloadTooBigError; } else if (throwable instanceof CodecException) { - errorCode = ErrorCode.WsProtocolError; + errorCode = WebSocketConstants.ErrorCode.WsProtocolError; } else if (throwable instanceof WebSocketHandshakeException) { - errorCode = ErrorCode.WsInvalidHandshakeError; + errorCode = WebSocketConstants.ErrorCode.WsInvalidHandshakeError; } else if (throwable instanceof IOException) { - errorCode = ErrorCode.WsConnectionError; + errorCode = WebSocketConstants.ErrorCode.WsConnectionError; cause = createErrorCause(throwable.getMessage(), IOConstants.ErrorCode.GenericError.errorCode(), - IO_PACKAGE_ID); + IOConstants.IO_PACKAGE_ID); message = "IO Error"; } return new WebSocketException(errorCode, message, cause); } - public static ErrorValue createErrorCause(String message, String reason, BPackage packageName) { + private static ErrorValue createErrorCause(String message, String reason, BPackage packageName) { MapValue detailRecordType = BallerinaValues.createRecordValue( packageName, WebSocketConstants.WEBSOCKET_ERROR_DETAILS); @@ -215,17 +239,365 @@ public static ErrorValue createErrorCause(String message, String reason, BPackag return BallerinaErrors.createError(reason, detailRecord); } - public static MapValue createDetailRecord(String errMsg) { - return createDetailRecord(errMsg, null); + /** + * Reconnect when the WebSocket connection is lost. + * + * @param connectionInfo - information about the connection. + * @return If attempts reconnection, then return true. + */ + public static boolean reconnect(WebSocketConnectionInfo connectionInfo) { + ObjectValue webSocketClient = connectionInfo.getWebSocketEndpoint(); + RetryContext retryConnectorConfig = (RetryContext) webSocketClient.getNativeData(WebSocketConstants. + RETRY_CONFIG); + int interval = retryConnectorConfig.getInterval(); + int maxInterval = retryConnectorConfig.getMaxInterval(); + int maxAttempts = retryConnectorConfig.getMaxAttempts(); + int noOfReconnectAttempts = retryConnectorConfig.getReconnectAttempts(); + double backOfFactor = retryConnectorConfig.getBackOfFactor(); + WebSocketService wsService = connectionInfo.getService(); + Date date = new Date(); + SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); + if (noOfReconnectAttempts < maxAttempts || maxAttempts == 0) { + retryConnectorConfig.setReconnectAttempts(noOfReconnectAttempts + 1); + String time = formatter.format(date.getTime()); + logger.debug(WebSocketConstants.LOG_MESSAGE, time, "reconnecting..."); + createDelay(calculateWaitingTime(interval, maxInterval, backOfFactor, noOfReconnectAttempts)); + establishWebSocketConnection(webSocketClient, wsService); + return true; + } + logger.debug(WebSocketConstants.LOG_MESSAGE, "Maximum retry attempts but couldn't connect to the server: ", + webSocketClient.getStringValue(WebSocketConstants.CLIENT_URL_CONFIG)); + return false; } - public static MapValue createDetailRecord(String errMsg, ErrorValue cause) { - MapValue detail = BallerinaValues.createRecordValue(HttpConstants.PROTOCOL_HTTP_PKG_ID, - WebSocketConstants.WEBSOCKET_ERROR_DETAILS); - return BallerinaValues.createRecord(detail, errMsg, cause); + /** + * Failover when webSocket connection lost. + * + * @param connectionInfo information about the connection + * @return if attempts failover, return true + */ + public static boolean failover(WebSocketConnectionInfo connectionInfo) { + ObjectValue webSocketClient = connectionInfo.getWebSocketEndpoint(); + FailoverContext failoverConfig = (FailoverContext) + webSocketClient.getNativeData(WebSocketConstants.FAILOVER_CONFIG); + int currentIndex = failoverConfig.getCurrentIndex(); + List targets = failoverConfig.getTargetUrls(); + int failoverInterval = failoverConfig.getFailoverInterval(); + WebSocketService wsService = connectionInfo.getService(); + // Set next url index + currentIndex++; + // Check current url index equals to target size or not. if equal, set the currentIndex = 0 + if (currentIndex == targets.size()) { + currentIndex = 0; + } + // Check the current url index equals with previous connected url index or not. + // If it isn't equal, call the initialiseWebSocketConnection() + // if it equals, return false + if (currentIndex != failoverConfig.getInitialIndex()) { + failoverConfig.setCurrentIndex(currentIndex); + createDelay(failoverInterval); + establishFailoverConnection(createWebSocketClientConnector(targets.get(currentIndex).toString(), + webSocketClient), webSocketClient, wsService); + return true; + } + logger.debug(WebSocketConstants.LOG_MESSAGE, "Couldn't connect to one of the server in the targets: ", + targets); + return false; } - private WebSocketUtil() { + /** + * Establish connection with the endpoint. + * + * @param webSocketClient - the WebSocket client. + * @param wsService - the WebSocket service. + */ + public static void establishWebSocketConnection(ObjectValue webSocketClient, WebSocketService wsService) { + WebSocketClientConnector clientConnector = (WebSocketClientConnector) webSocketClient. + getNativeData(WebSocketConstants.CLIENT_CONNECTOR); + boolean readyOnConnect = webSocketClient.getMapValue(CLIENT_ENDPOINT_CONFIG).getBooleanValue( + WebSocketConstants.CLIENT_READY_ON_CONNECT); + ClientHandshakeFuture handshakeFuture = clientConnector.connect(); + CountDownLatch countDownLatch = new CountDownLatch(1); + if (WebSocketUtil.hasRetryConfig(webSocketClient)) { + WebSocketClientConnectorListenerForRetry clientConnectorListener = + (WebSocketClientConnectorListenerForRetry) webSocketClient.getNativeData( + WebSocketConstants.CLIENT_LISTENER); + handshakeFuture.setWebSocketConnectorListener(clientConnectorListener); + handshakeFuture.setClientHandshakeListener(new WebSocketClientHandshakeListenerForRetry(webSocketClient, + wsService, clientConnectorListener, readyOnConnect, countDownLatch, + (RetryContext) webSocketClient.getNativeData(WebSocketConstants.RETRY_CONFIG))); + } else { + WebSocketClientConnectorListener clientConnectorListener = + (WebSocketClientConnectorListener) webSocketClient.getNativeData( + WebSocketConstants.CLIENT_LISTENER); + handshakeFuture.setWebSocketConnectorListener(clientConnectorListener); + handshakeFuture.setClientHandshakeListener(new WebSocketClientHandshakeListener(webSocketClient, wsService, + clientConnectorListener, readyOnConnect, countDownLatch)); + } + // Set the countDown latch for every handshake + waitForHandshake(webSocketClient, countDownLatch); + } + + /** + * Establish the connection with the endpoint. + * + * @param clientConnector - a client connector + * @param webSocketClient - a webSocket client + * @param wsService - a webSocket service + */ + public static void establishFailoverConnection(WebSocketClientConnector clientConnector, + ObjectValue webSocketClient, WebSocketService wsService) { + WebSocketFailoverClientListener clientConnectorListener = new WebSocketFailoverClientListener(); + boolean readyOnConnect = webSocketClient.getMapValue( + HttpConstants.CLIENT_ENDPOINT_CONFIG).getBooleanValue(WebSocketConstants.CLIENT_READY_ON_CONNECT); + ClientHandshakeFuture handshakeFuture = clientConnector.connect(); + handshakeFuture.setWebSocketConnectorListener(clientConnectorListener); + CountDownLatch countDownLatch = new CountDownLatch(1); + if (webSocketClient.getNativeData(WebSocketConstants.FAILOVER_CONFIG) != null) { + handshakeFuture.setClientHandshakeListener(new WebSocketFailoverClientHandshakeListener(webSocketClient, + wsService, clientConnectorListener, readyOnConnect, countDownLatch, + (FailoverContext) webSocketClient.getNativeData(WebSocketConstants.FAILOVER_CONFIG))); + // Set the countDown latch for every handshake + waitForHandshake(webSocketClient, countDownLatch); + } + } + + /** + * Check whether the client's config has the retryConfig property. + * + * @param webSocketClient - the WebSocket client. + * @return If the client's config has the retry config, then return true. + */ + public static boolean hasRetryConfig(ObjectValue webSocketClient) { + return webSocketClient.getMapValue(CLIENT_ENDPOINT_CONFIG). + getMapValue(WebSocketConstants.RETRY_CONFIG) != null; + } + + private static void waitForHandshake(ObjectValue webSocketClient, CountDownLatch countDownLatch) { + @SuppressWarnings(WebSocketConstants.UNCHECKED) + long timeout = WebSocketUtil.findTimeoutInSeconds((MapValue) webSocketClient.getMapValue( + CLIENT_ENDPOINT_CONFIG), "handShakeTimeoutInSeconds", 300); + try { + if (!countDownLatch.await(timeout, TimeUnit.SECONDS)) { + throw new WebSocketException(WebSocketConstants.ErrorCode.WsGenericError, + "Waiting for WebSocket handshake has not been successful", WebSocketUtil.createErrorCause( + "Connection timeout", IOConstants.ErrorCode.ConnectionTimedOut.errorCode(), + IOConstants.IO_PACKAGE_ID)); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new WebSocketException(WebSocketConstants.ERROR_MESSAGE + e.getMessage()); + } + } + + /** + * Set the time to wait before attempting to reconnect. + * + * @param interval - interval to wait before trying to reconnect. + */ + private static void createDelay(int interval) { + CountDownLatch countDownLatch = new CountDownLatch(1); + try { + if (!countDownLatch.await(interval, TimeUnit.MILLISECONDS)) { + countDownLatch.countDown(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new WebSocketException(WebSocketConstants.ERROR_MESSAGE + e.getMessage()); + } + } + + /** + * Calculate the waiting time. + * + * @param interval- interval to wait before trying to reconnect. + * @param maxInterval - maximum interval to wait before trying to reconnect. + * @param backOfFactor - the rate of increase of the reconnect delay. + * @param reconnectAttempts - the number of reconnecting attempts. + * @return The time to wait before attempting to reconnect. + */ + private static int calculateWaitingTime(int interval, int maxInterval, double backOfFactor, + int reconnectAttempts) { + interval = (int) (interval * Math.pow(backOfFactor, reconnectAttempts)); + if (interval > maxInterval) { + interval = maxInterval; + } + return interval; + } + + public static WebSocketConnectionInfo getWebSocketOpenConnectionInfo(WebSocketConnection webSocketConnection, + ObjectValue webSocketConnector, + ObjectValue webSocketClient, + WebSocketService wsService) { + WebSocketConnectionInfo connectionInfo = new WebSocketConnectionInfo( + wsService, webSocketConnection, webSocketClient); + webSocketConnector.addNativeData(WebSocketConstants.NATIVE_DATA_WEBSOCKET_CONNECTION_INFO, connectionInfo); + webSocketClient.set(WebSocketConstants.CLIENT_CONNECTOR_FIELD, webSocketConnector); + return connectionInfo; + } + + public static int getIntValue(MapValue configs, String key, int defaultValue) { + int value = Math.toIntExact(configs.getIntValue(key)); + if (value < 0) { + logger.warn("The value set for `{}` needs to be great than than -1. The `{}` value is set to {}", key, key, + defaultValue); + value = defaultValue; + } + return value; } + public static void populateClientConnectorConfig(MapValue clientEndpointConfig, + WebSocketClientConnectorConfig clientConnectorConfig, + String scheme) { + clientConnectorConfig.setAutoRead(false); // Frames are read sequentially in ballerina. + clientConnectorConfig.setSubProtocols(WebSocketUtil.findNegotiableSubProtocols(clientEndpointConfig)); + @SuppressWarnings(WebSocketConstants.UNCHECKED) + MapValue headerValues = (MapValue) clientEndpointConfig.getMapValue( + WebSocketConstants.CLIENT_CUSTOM_HEADERS_CONFIG); + if (headerValues != null) { + clientConnectorConfig.addHeaders(getCustomHeaders(headerValues)); + } + + long idleTimeoutInSeconds = findTimeoutInSeconds(clientEndpointConfig, + WebSocketConstants.ANNOTATION_ATTR_IDLE_TIMEOUT, 0); + if (idleTimeoutInSeconds > 0) { + clientConnectorConfig.setIdleTimeoutInMillis((int) (idleTimeoutInSeconds * 1000)); + } + + clientConnectorConfig.setMaxFrameSize(findMaxFrameSize(clientEndpointConfig)); + + MapValue secureSocket = clientEndpointConfig.getMapValue(HttpConstants.ENDPOINT_CONFIG_SECURE_SOCKET); + if (secureSocket != null) { + HttpUtil.populateSSLConfiguration(clientConnectorConfig, secureSocket); + } else if (scheme.equals(WebSocketConstants.WSS_SCHEME)) { + clientConnectorConfig.useJavaDefaults(); + } + clientConnectorConfig.setWebSocketCompressionEnabled( + clientEndpointConfig.getBooleanValue(WebSocketConstants.COMPRESSION_ENABLED_CONFIG)); + } + + private static Map getCustomHeaders(MapValue headers) { + Map customHeaders = new HashMap<>(); + headers.entrySet().forEach( + entry -> customHeaders.put(entry.getKey(), headers.get(entry.getKey()).toString()) + ); + return customHeaders; + } + + /** + * Waits until call the countDown(). + * + * @param countDownLatch - a countdown latch + */ + public static void waitForHandshake(CountDownLatch countDownLatch) { + try { + // Wait to call countDown() + countDownLatch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new WebSocketException(WebSocketConstants.ERROR_MESSAGE + e.getMessage()); + } + } + + public static WebSocketClientConnector createWebSocketClientConnector(String remoteUrl, + ObjectValue webSocketClient) { + @SuppressWarnings(WebSocketConstants.UNCHECKED) + MapValue clientEndpointConfig = (MapValue) webSocketClient.getMapValue( + HttpConstants.CLIENT_ENDPOINT_CONFIG); + WebSocketClientConnectorConfig clientConnectorConfig = new WebSocketClientConnectorConfig(remoteUrl); + populateClientConnectorConfig(clientEndpointConfig, clientConnectorConfig, remoteUrl); + // Get the connector factory from the native data + HttpWsConnectorFactory connectorFactory = ((HttpWsConnectorFactory) webSocketClient. + getNativeData(WebSocketConstants.CONNECTOR_FACTORY)); + // Create the client connector + return connectorFactory.createWsClientConnector(clientConnectorConfig); + } + + /** + * Validate and create the webSocket service. + * + * @param clientEndpointConfig - a client endpoint config. + * @param strand - a strand. + * @return webSocketService + */ + public static WebSocketService validateAndCreateWebSocketService(Strand strand, + MapValue clientEndpointConfig) { + Object clientService = clientEndpointConfig.get(WebSocketConstants.CLIENT_SERVICE_CONFIG); + if (clientService != null) { + BType param = ((ObjectValue) clientService).getType().getAttachedFunctions()[0].getParameterType()[0]; + if (param == null || !(WebSocketConstants.WEBSOCKET_CLIENT_NAME.equals(param.toString()) || + WEBSOCKET_FAILOVER_CLIENT_NAME.equals(param.toString()))) { + throw new WebSocketException("The callback service should be a WebSocket Client Service"); + } + return new WebSocketService((ObjectValue) clientService, strand.scheduler); + } else { + return new WebSocketService(strand.scheduler); + } + } + + public static void dispatchOnClose(WebSocketConnectionInfo connectionInfo, + WebSocketCloseMessage webSocketCloseMessage) { + WebSocketResourceDispatcher.dispatchOnClose(connectionInfo, webSocketCloseMessage); + } + + public static ObjectValue createWebSocketConnector(boolean readyOnConnect) { + ObjectValue webSocketConnector = BallerinaValues.createObjectValue(HttpConstants.PROTOCOL_HTTP_PKG_ID, + WebSocketConstants.WEBSOCKET_CONNECTOR); + // Sets readyOnConnect's value to the created webSocketConnector's isReady field + // It uses to check whether readNextFrame function already called or not When call the ready() function + webSocketConnector.set(WebSocketConstants.CONNECTOR_IS_READY_FIELD, readyOnConnect); + return webSocketConnector; + } + + public static WebSocketConnectionInfo getConnectionInfoForOnError(HttpCarbonResponse response, + ObjectValue webSocketClient, + WebSocketService wsService, + CountDownLatch countDownLatch) { + if (response != null) { + webSocketClient.set(WebSocketConstants.CLIENT_RESPONSE_FIELD, HttpUtil.createResponseStruct(response)); + } + ObjectValue webSocketConnector = BallerinaValues.createObjectValue(WebSocketConstants.PROTOCOL_HTTP_PKG_ID, + WebSocketConstants.WEBSOCKET_CONNECTOR); + WebSocketConnectionInfo connectionInfo = WebSocketUtil.getWebSocketOpenConnectionInfo(null, + webSocketConnector, webSocketClient, wsService); + countDownLatch.countDown(); + return connectionInfo; + } + + /** + * Calls the `readNextFrame()` function. + * + * @param readyOnConnect - the ready on connect. + * @param webSocketClient - the WebSocket client. + * @param webSocketConnection - the WebSocket connection. + */ + public static void readNextFrame(boolean readyOnConnect, ObjectValue webSocketClient, + WebSocketConnection webSocketConnection) { + if (readyOnConnect || (webSocketClient.get(WebSocketConstants.CLIENT_CONNECTOR_FIELD) != null && + ((boolean) ((ObjectValue) webSocketClient.get(WebSocketConstants.CLIENT_CONNECTOR_FIELD)). + get(WebSocketConstants.CONNECTOR_IS_READY_FIELD)))) { + webSocketConnection.readNextFrame(); + } + } + + public static void dispatchOnError(WebSocketConnectionInfo connectionInfo, Throwable throwable) { + logger.error(WebSocketConstants.ERROR_MESSAGE, throwable); + countDownForHandshake(connectionInfo.getWebSocketEndpoint()); + WebSocketResourceDispatcher.dispatchOnError(connectionInfo, throwable); + } + + /** + * Counts the initialized `countDownLatch`. + * + * @param webSocketClient - the WebSocket client. + */ + public static void countDownForHandshake(ObjectValue webSocketClient) { + if (webSocketClient.getNativeData(WebSocketConstants.COUNT_DOWN_LATCH) != null) { + ((CountDownLatch) webSocketClient.getNativeData(WebSocketConstants.COUNT_DOWN_LATCH)).countDown(); + webSocketClient.addNativeData(WebSocketConstants.COUNT_DOWN_LATCH, null); + } + } + + private WebSocketUtil() { + } } diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/FailoverContext.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/FailoverContext.java new file mode 100644 index 000000000000..3c415588e675 --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/FailoverContext.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.net.http.websocket.client; + +import java.util.List; + +/** + * Represents a failover client connector config. + * + * @since 1.2.0 + */ +public class FailoverContext { + + private boolean finishedFailover = false; + private int currentIndex = 0; + private int failoverInterval = 0; + private boolean firstConnectionMadeSuccessfully = false; + private List targetUrls = null; + private int initialIndex = 0; + + /** + * Get the value of completed failover. + * + * @return finishedFailover + */ + public boolean isFailoverFinished() { + return finishedFailover; + } + + /** + * Assign the finishedFailover of the FailoverContext to the variable finishedFailover. + * + * @param finishedFailover - if it is true, do reconnect in the target URL. + */ + public void setFailoverFinished(boolean finishedFailover) { + this.finishedFailover = finishedFailover; + } + + /** + * Get the index. + * + * @return currentIndex + */ + public int getCurrentIndex() { + return currentIndex; + } + + /** + * Assigns the index of the FailoverContext to the variable index. + * + * @param currentIndex - a current index. + */ + public void setCurrentIndex(int currentIndex) { + this.currentIndex = currentIndex; + } + + /** + * Gets the target URLs. + * + * @return targetUrls + */ + public List getTargetUrls() { + return targetUrls; + } + + /** + * Assigns the target URLs of the `FailoverContext` to the `targetUrls` variable. + * + * @param targetUrls - a target urls. + */ + void setTargetUrls(List targetUrls) { + this.targetUrls = targetUrls; + } + + /** + * Assign the failover interval of the FailoverContext to + * the `failoverInterval` variable. + * + * @param failoverInterval - a failover interval. + */ + void setFailoverInterval(int failoverInterval) { + this.failoverInterval = failoverInterval; + } + + /** + * Assigns the failover interval of the `FailoverContext` to the `failoverInterval` variable. + * @return failoverInterval + */ + public int getFailoverInterval() { + return failoverInterval; + } + + /** + * Gets the `firstConnectionMadeSuccessfully`. + * + * @return firstConnectionMadeSuccessfully + */ + public boolean isFirstConnectionMadeSuccessfully() { + return firstConnectionMadeSuccessfully; + } + + /** + * Assigns the connection state of the FailoverContext to the `firstConnectionMadeSuccessfully` variable. + */ + void setFirstConnectionMadeSuccessfully() { + this.firstConnectionMadeSuccessfully = true; + } + + /** + * Gets the initial index. + * + * @return initialIndex + */ + public int getInitialIndex() { + return initialIndex; + } + + /** + * Assigns the `initialIndex` of the FailoverContext to the `initialIndex` variable. + * + * @param initialIndex - a initial index. + */ + void setInitialIndex(int initialIndex) { + this.initialIndex = initialIndex; + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/FailoverInitEndpoint.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/FailoverInitEndpoint.java new file mode 100644 index 000000000000..3cd13c3b1fed --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/FailoverInitEndpoint.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.net.http.websocket.client; + +import org.ballerinalang.jvm.scheduling.Scheduler; +import org.ballerinalang.jvm.scheduling.Strand; +import org.ballerinalang.jvm.values.ArrayValue; +import org.ballerinalang.jvm.values.MapValue; +import org.ballerinalang.jvm.values.ObjectValue; +import org.ballerinalang.net.http.HttpUtil; +import org.ballerinalang.net.http.websocket.WebSocketConstants; +import org.ballerinalang.net.http.websocket.WebSocketException; +import org.ballerinalang.net.http.websocket.WebSocketUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +/** + * Initializes the Failover WebSocket Client. + * + * @since 1.2.0 + */ +public class FailoverInitEndpoint { + + private static final Logger logger = LoggerFactory.getLogger(FailoverInitEndpoint.class); + private static final String FAILOVER_INTERVAL = "failoverIntervalInMillis"; + + public static void init(ObjectValue webSocketClient) { + @SuppressWarnings(WebSocketConstants.UNCHECKED) + MapValue clientEndpointConfig = (MapValue) webSocketClient.getMapValue( + WebSocketConstants.CLIENT_ENDPOINT_CONFIG); + Strand strand = Scheduler.getStrand(); + ArrayValue targets = clientEndpointConfig.getArrayValue(WebSocketConstants.TARGET_URLS); + List newTargetUrls = new ArrayList<>(); + int index = 0; + // Checks whether the URL has a valid format or not. + // If It isn't in the valid format, remove that from the URL set. + for (int i = 0; i < targets.size(); i++) { + String url = targets.get(i).toString(); + try { + URI uri = new URI(url); + String scheme = uri.getScheme(); + if (!"ws".equalsIgnoreCase(scheme) && !"wss".equalsIgnoreCase(scheme)) { + String name = targets.get(i).toString(); + logger.error("{} drop from the targets url" + + "because webSocket client supports only WS(S) scheme.", name); + } else { + newTargetUrls.add(index, url); + index++; + } + } catch (URISyntaxException e) { + throw new WebSocketException("Error occurred when constructing a hierarchical URI from the " + + "given url[" + url + "]."); + } + } + logger.debug("New targetUrls: {}", newTargetUrls); + if (newTargetUrls.isEmpty()) { + throw new WebSocketException("TargetUrls should have atleast one valid URL."); + } + // Creates the connector factory and sets it as the native data. + webSocketClient.addNativeData(WebSocketConstants.CONNECTOR_FACTORY, HttpUtil.createHttpWsConnectionFactory()); + // Sets the failover config values. + FailoverContext failoverConfig = new FailoverContext(); + populateFailoverConnectorConfig(clientEndpointConfig, failoverConfig, newTargetUrls); + webSocketClient.addNativeData(WebSocketConstants.FAILOVER_CONFIG, failoverConfig); + CountDownLatch countDownLatch = new CountDownLatch(1); + webSocketClient.addNativeData(WebSocketConstants.COUNT_DOWN_LATCH, countDownLatch); + // Calls the function with the first URL in the target URLs set. + WebSocketUtil.establishFailoverConnection(WebSocketUtil.createWebSocketClientConnector(newTargetUrls.get(0), + webSocketClient), webSocketClient, WebSocketUtil.validateAndCreateWebSocketService(strand, + clientEndpointConfig)); + // Set the count Down latch for initial connection + WebSocketUtil.waitForHandshake(countDownLatch); + } + + /** + * Populate the failover config. + * + * @param failoverConfig - a failover config. + * @param failoverClientConnectorConfig - a failover client connector config. + * @param targetUrls - target urls. + */ + private static void populateFailoverConnectorConfig(MapValue failoverConfig, + FailoverContext failoverClientConnectorConfig, + List targetUrls) { + failoverClientConnectorConfig.setFailoverInterval(WebSocketUtil.getIntValue(failoverConfig, FAILOVER_INTERVAL, + 1000)); + failoverClientConnectorConfig.setTargetUrls(targetUrls); + } + + private FailoverInitEndpoint() { + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/InitEndpoint.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/InitEndpoint.java index a494d71296d6..7a2f668dd1e8 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/InitEndpoint.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/InitEndpoint.java @@ -29,20 +29,14 @@ import org.ballerinalang.net.http.websocket.WebSocketException; import org.ballerinalang.net.http.websocket.WebSocketService; import org.ballerinalang.net.http.websocket.WebSocketUtil; -import org.ballerinalang.stdlib.io.utils.IOConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.wso2.transport.http.netty.contract.HttpWsConnectorFactory; -import org.wso2.transport.http.netty.contract.websocket.ClientHandshakeFuture; import org.wso2.transport.http.netty.contract.websocket.WebSocketClientConnector; import org.wso2.transport.http.netty.contract.websocket.WebSocketClientConnectorConfig; import java.net.URI; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import static org.ballerinalang.net.http.websocket.WebSocketConstants.WSS_SCHEME; -import static org.ballerinalang.stdlib.io.utils.IOConstants.IO_PACKAGE_ID; /** * Initialize the WebSocket Client. @@ -51,90 +45,94 @@ */ public class InitEndpoint { + private static final Logger logger = LoggerFactory.getLogger(InitEndpoint.class); + private static final String INTERVAL_IN_MILLIS = "intervalInMillis"; + private static final String MAX_WAIT_INTERVAL = "maxWaitIntervalInMillis"; + private static final String MAX_COUNT = "maxCount"; + private static final String BACK_OF_FACTOR = "backOffFactor"; + public static void initEndpoint(ObjectValue webSocketClient) { @SuppressWarnings(WebSocketConstants.UNCHECKED) MapValue clientEndpointConfig = (MapValue) webSocketClient.getMapValue( HttpConstants.CLIENT_ENDPOINT_CONFIG); Strand strand = Scheduler.getStrand(); - String remoteUrl = webSocketClient.getStringValue(WebSocketConstants.CLIENT_URL_CONFIG); + WebSocketService wsService = validateAndCreateWebSocketService(clientEndpointConfig, strand); + HttpWsConnectorFactory connectorFactory = HttpUtil.createHttpWsConnectionFactory(); + WebSocketClientConnectorConfig clientConnectorConfig = new WebSocketClientConnectorConfig(remoteUrl); String scheme = URI.create(remoteUrl).getScheme(); + WebSocketUtil.populateClientConnectorConfig(clientEndpointConfig, clientConnectorConfig, scheme); + // Create the client connector. + WebSocketClientConnector clientConnector = connectorFactory.createWsClientConnector(clientConnectorConfig); + // Add the client connector as a native data + // because when using one URL, there is no need to create the client connector again. + webSocketClient.addNativeData(WebSocketConstants.CLIENT_CONNECTOR, clientConnector); + if (WebSocketUtil.hasRetryConfig(webSocketClient)) { + @SuppressWarnings(WebSocketConstants.UNCHECKED) + MapValue retryConfig = (MapValue) clientEndpointConfig.getMapValue( + WebSocketConstants.RETRY_CONFIG); + RetryContext retryConnectorConfig = new RetryContext(); + populateRetryConnectorConfig(retryConfig, retryConnectorConfig); + webSocketClient.addNativeData(WebSocketConstants.RETRY_CONFIG, retryConnectorConfig); + WebSocketClientConnectorListenerForRetry clientConnectorListener = new + WebSocketClientConnectorListenerForRetry(); + webSocketClient.addNativeData(WebSocketConstants.CLIENT_LISTENER, clientConnectorListener); + CountDownLatch countDownLatch = new CountDownLatch(1); + webSocketClient.addNativeData(WebSocketConstants.COUNT_DOWN_LATCH, countDownLatch); + WebSocketUtil.establishWebSocketConnection(webSocketClient, wsService); + // Set the count Down latch for initial connection + WebSocketUtil.waitForHandshake(countDownLatch); + } else { + WebSocketClientConnectorListener clientConnectorListener = new WebSocketClientConnectorListener(); + webSocketClient.addNativeData(WebSocketConstants.CLIENT_LISTENER, clientConnectorListener); + WebSocketUtil.establishWebSocketConnection(webSocketClient, wsService); + } + + } + + /** + * Populate the retry config. + * + * @param retryConfig - the retry config. + * @param retryConnectorConfig - the retry connector config. + */ + private static void populateRetryConnectorConfig(MapValue retryConfig, + RetryContext retryConnectorConfig) { + retryConnectorConfig.setInterval(WebSocketUtil.getIntValue(retryConfig, INTERVAL_IN_MILLIS, 1000)); + retryConnectorConfig.setBackOfFactor(getDoubleValue(retryConfig)); + retryConnectorConfig.setMaxInterval(WebSocketUtil.getIntValue(retryConfig, MAX_WAIT_INTERVAL, 30000)); + retryConnectorConfig.setMaxAttempts(WebSocketUtil.getIntValue(retryConfig, MAX_COUNT, 0)); + } + + /** + * Validate and create the webSocket service. + * + * @param clientEndpointConfig - a client endpoint config. + * @param strand - which holds the observer context being started. + * @return webSocketService + */ + private static WebSocketService validateAndCreateWebSocketService(MapValue clientEndpointConfig, + Strand strand) { Object clientService = clientEndpointConfig.get(WebSocketConstants.CLIENT_SERVICE_CONFIG); - WebSocketService wsService; if (clientService != null) { BType param = ((ObjectValue) clientService).getType().getAttachedFunctions()[0].getParameterType()[0]; - if (param == null || !WebSocketConstants.WEBSOCKET_CLIENT_NAME.equals( - param.toString())) { + if (param == null || !WebSocketConstants.WEBSOCKET_CLIENT_NAME.equals(param.toString())) { throw new WebSocketException("The callback service should be a WebSocket Client Service"); } - wsService = new WebSocketService((ObjectValue) clientService, strand.scheduler); + return new WebSocketService((ObjectValue) clientService, strand.scheduler); } else { - wsService = new WebSocketService(strand.scheduler); - } - WebSocketClientConnectorConfig clientConnectorConfig = new WebSocketClientConnectorConfig(remoteUrl); - populateClientConnectorConfig(clientEndpointConfig, clientConnectorConfig, scheme); - - HttpWsConnectorFactory connectorFactory = HttpUtil.createHttpWsConnectionFactory(); - WebSocketClientConnector clientConnector = connectorFactory.createWsClientConnector( - clientConnectorConfig); - WebSocketClientConnectorListener clientConnectorListener = new WebSocketClientConnectorListener(); - boolean readyOnConnect = clientEndpointConfig.getBooleanValue(WebSocketConstants.CLIENT_READY_ON_CONNECT); - ClientHandshakeFuture handshakeFuture = clientConnector.connect(); - handshakeFuture.setWebSocketConnectorListener(clientConnectorListener); - CountDownLatch countDownLatch = new CountDownLatch(1); - handshakeFuture.setClientHandshakeListener( - new WebSocketClientHandshakeListener(webSocketClient, wsService, clientConnectorListener, - readyOnConnect, countDownLatch)); - try { - // Wait for 5 minutes before timeout - if (!countDownLatch.await(60 * 5L, TimeUnit.SECONDS)) { - throw new WebSocketException(WebSocketConstants.ErrorCode.WsGenericError, - "Waiting for WebSocket handshake has not been successful", - WebSocketUtil.createErrorCause( - "Connection timeout", - IOConstants.ErrorCode.ConnectionTimedOut.errorCode(), - IO_PACKAGE_ID)); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new WebSocketException("Error occurred: " + e.getMessage()); + return new WebSocketService(strand.scheduler); } } - private static void populateClientConnectorConfig(MapValue clientEndpointConfig, - WebSocketClientConnectorConfig clientConnectorConfig, String scheme) { - clientConnectorConfig.setAutoRead(false); // Frames are read sequentially in ballerina. - clientConnectorConfig.setSubProtocols(WebSocketUtil.findNegotiableSubProtocols(clientEndpointConfig)); - @SuppressWarnings(WebSocketConstants.UNCHECKED) - MapValue headerValues = (MapValue) clientEndpointConfig.getMapValue( - WebSocketConstants.CLIENT_CUSTOM_HEADERS_CONFIG); - if (headerValues != null) { - clientConnectorConfig.addHeaders(getCustomHeaders(headerValues)); - } - - long idleTimeoutInSeconds = WebSocketUtil.findIdleTimeoutInSeconds(clientEndpointConfig); - if (idleTimeoutInSeconds > 0) { - clientConnectorConfig.setIdleTimeoutInMillis((int) (idleTimeoutInSeconds * 1000)); - } - - clientConnectorConfig.setMaxFrameSize(WebSocketUtil.findMaxFrameSize(clientEndpointConfig)); - - MapValue secureSocket = clientEndpointConfig.getMapValue(HttpConstants.ENDPOINT_CONFIG_SECURE_SOCKET); - if (secureSocket != null) { - HttpUtil.populateSSLConfiguration(clientConnectorConfig, secureSocket); - } else if (scheme.equals(WSS_SCHEME)) { - clientConnectorConfig.useJavaDefaults(); + private static Double getDoubleValue(MapValue configs) { + double value = Math.toRadians(configs.getFloatValue(BACK_OF_FACTOR)); + if (value < 1) { + logger.warn("The value set for `backOffFactor` needs to be great than than 1. The `backOffFactor`" + + " value is set to {}", 1.0); + value = 1.0; } - clientConnectorConfig.setWebSocketCompressionEnabled( - clientEndpointConfig.getBooleanValue(WebSocketConstants.COMPRESSION_ENABLED_CONFIG)); - } - - private static Map getCustomHeaders(MapValue headers) { - Map customHeaders = new HashMap<>(); - headers.entrySet().forEach( - entry -> customHeaders.put(entry.getKey(), headers.get(entry.getKey()).toString()) - ); - return customHeaders; + return value; } private InitEndpoint() { diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/RetryContext.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/RetryContext.java new file mode 100644 index 000000000000..fdfc938113aa --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/RetryContext.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.net.http.websocket.client; + +/** + * Represents a retry config. + * + * @since 1.2.0 + */ +public class RetryContext { + + private int interval = 0; + private Double backOfFactor = 0.0; + private int maxInterval = 0; + private int maxAttempts = 0; + private int reconnectAttempts = 0; + private boolean firstConnectionMadeSuccessfully = false; + + /** + * Gets the `interval`. + * + * @return interval + */ + public int getInterval() { + return interval; + } + + /** + * Assigns the interval of the `RetryContext` to the `interval` variable. + * + * @param interval - the initial index. + */ + public final void setInterval(int interval) { + this.interval = interval; + } + + /** + * Gets the `backOfFactor`. + * + * @return backOfFactor + */ + public Double getBackOfFactor() { + return backOfFactor; + } + + /** + * Assigns the` backOfFactor` of the `RetryContext` to the `backOfFactor` variable. + * + * @param backOfFactor - the rate of increase of the reconnect delay. + */ + void setBackOfFactor(Double backOfFactor) { + this.backOfFactor = backOfFactor; + } + + /** + * Gets the `maxInterval`. + * + * @return maximum interval + */ + public int getMaxInterval() { + return maxInterval; + } + + /** + * Assigns the `maxInterval` of the `RetryContext` to the `maxInterval` variable. + * + * @param maxInterval - the maximum time of the retry interval. + */ + void setMaxInterval(int maxInterval) { + this.maxInterval = maxInterval; + } + + /** + * Gets the `maxAttempts`. + * + * @return no of maximum attempts + */ + public int getMaxAttempts() { + return maxAttempts; + } + + /** + * Assigns the `maxAttempts` of the `RetryContext` to the `maxAttempts` variable. + * + * @param maxAttempts - the maximum number of retry attempts. + */ + void setMaxAttempts(int maxAttempts) { + this.maxAttempts = maxAttempts; + } + + /** + * Gets the `reconnectAttempts`. + * + * @return no of reconnect attempts + */ + public int getReconnectAttempts() { + return reconnectAttempts; + } + + /** + * Assigns the `reconnectAttempts` of the `RetryContext` to the `reconnectAttempts` variable. + * + * @param reconnectAttempts - the no of reconnect attempts. + */ + public void setReconnectAttempts(int reconnectAttempts) { + this.reconnectAttempts = reconnectAttempts; + } + + /** + * Gets the `firstConnectionMadeSuccessfully`. + * + * @return firstConnectionMadeSuccessfully + */ + boolean isFirstConnectionMadeSuccessfully() { + return firstConnectionMadeSuccessfully; + } + + /** + * Assigns the connection state of the `RetryContext` to the `firstConnectionMadeSuccessfully` variable. + */ + void setFirstConnectionMadeSuccessfully() { + this.firstConnectionMadeSuccessfully = true; + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientConnectorListener.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientConnectorListener.java index 47492964c4e1..2389472a15f3 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientConnectorListener.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientConnectorListener.java @@ -36,7 +36,7 @@ * @since 0.93 */ public class WebSocketClientConnectorListener implements WebSocketConnectorListener { - private WebSocketConnectionInfo connectionInfo; + private WebSocketConnectionInfo connectionInfo = null; public void setConnectionInfo(WebSocketConnectionInfo connectionInfo) { this.connectionInfo = connectionInfo; diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientConnectorListenerForRetry.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientConnectorListenerForRetry.java new file mode 100644 index 000000000000..1498b0f8cfba --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientConnectorListenerForRetry.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.net.http.websocket.client; + +import org.ballerinalang.jvm.values.ObjectValue; +import org.ballerinalang.net.http.websocket.WebSocketConstants; +import org.ballerinalang.net.http.websocket.WebSocketResourceDispatcher; +import org.ballerinalang.net.http.websocket.WebSocketUtil; +import org.ballerinalang.net.http.websocket.server.WebSocketConnectionInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.wso2.transport.http.netty.contract.websocket.WebSocketCloseMessage; +import org.wso2.transport.http.netty.contract.websocket.WebSocketConnection; + +import java.io.IOException; + +/** + * Client listener of the WebSocket. + * + * @since 1.2.0 + */ +public class WebSocketClientConnectorListenerForRetry extends WebSocketClientConnectorListener { + + private WebSocketConnectionInfo connectionInfo = null; + private static final Logger logger = LoggerFactory.getLogger(WebSocketClientConnectorListenerForRetry.class); + + @Override + public void setConnectionInfo(WebSocketConnectionInfo connectionInfo) { + super.setConnectionInfo(connectionInfo); + this.connectionInfo = connectionInfo; + } + + @Override + public void onMessage(WebSocketCloseMessage webSocketCloseMessage) { + ObjectValue webSocketClient = connectionInfo.getWebSocketEndpoint(); + int statusCode = webSocketCloseMessage.getCloseCode(); + if (WebSocketUtil.hasRetryConfig(webSocketClient)) { + if (statusCode == WebSocketConstants.STATUS_CODE_ABNORMAL_CLOSURE && + WebSocketUtil.reconnect(connectionInfo)) { + return; + } else { + if (statusCode != WebSocketConstants.STATUS_CODE_ABNORMAL_CLOSURE) { + logger.debug(WebSocketConstants.LOG_MESSAGE, "Reconnect attempt not made because of " + + "close initiated by the server: ", webSocketClient.getStringValue(WebSocketConstants. + CLIENT_URL_CONFIG)); + } + } + } + WebSocketUtil.dispatchOnClose(connectionInfo, webSocketCloseMessage); + } + + @Override + public void onError(WebSocketConnection webSocketConnection, Throwable throwable) { + ObjectValue webSocketClient = connectionInfo.getWebSocketEndpoint(); + if (WebSocketUtil.hasRetryConfig(webSocketClient) && throwable instanceof IOException && + WebSocketUtil.reconnect(connectionInfo)) { + return; + } + WebSocketResourceDispatcher.dispatchOnError(connectionInfo, throwable); + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientHandshakeListener.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientHandshakeListener.java index e2f4c5bb31f4..094ddc7c647f 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientHandshakeListener.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientHandshakeListener.java @@ -33,8 +33,6 @@ import java.util.concurrent.CountDownLatch; -import static org.ballerinalang.net.http.HttpConstants.PROTOCOL_HTTP_PKG_ID; - /** * The handshake listener for the client. * @@ -64,14 +62,14 @@ public void onSuccess(WebSocketConnection webSocketConnection, HttpCarbonRespons //using only one service endpoint in the client as there can be only one connection. webSocketClient.set(WebSocketConstants.CLIENT_RESPONSE_FIELD, HttpUtil.createResponseStruct(carbonResponse)); - ObjectValue webSocketConnector = BallerinaValues.createObjectValue(PROTOCOL_HTTP_PKG_ID, + ObjectValue webSocketConnector = BallerinaValues.createObjectValue(WebSocketConstants.PROTOCOL_HTTP_PKG_ID, WebSocketConstants.WEBSOCKET_CONNECTOR); - WebSocketConnectionInfo connectionInfo = getWebSocketOpenConnectionInfo(webSocketConnection, - webSocketConnector); + WebSocketConnectionInfo connectionInfo = WebSocketUtil.getWebSocketOpenConnectionInfo(webSocketConnection, + webSocketConnector, webSocketClient, wsService); WebSocketUtil.populateWebSocketEndpoint(webSocketConnection, webSocketClient); clientConnectorListener.setConnectionInfo(connectionInfo); if (readyOnConnect) { - WebSocketUtil.readFirstFrame(webSocketConnection, webSocketClient); + WebSocketUtil.readFirstFrame(webSocketConnection, webSocketConnector); } countDownLatch.countDown(); WebSocketObservabilityUtil.observeConnection(connectionInfo); @@ -79,22 +77,8 @@ public void onSuccess(WebSocketConnection webSocketConnection, HttpCarbonRespons @Override public void onError(Throwable throwable, HttpCarbonResponse response) { - if (response != null) { - webSocketClient.set(WebSocketConstants.CLIENT_RESPONSE_FIELD, HttpUtil.createResponseStruct(response)); - } - ObjectValue webSocketConnector = BallerinaValues.createObjectValue(PROTOCOL_HTTP_PKG_ID, - WebSocketConstants.WEBSOCKET_CONNECTOR); - WebSocketConnectionInfo connectionInfo = getWebSocketOpenConnectionInfo(null, webSocketConnector); - countDownLatch.countDown(); + WebSocketConnectionInfo connectionInfo = WebSocketUtil.getConnectionInfoForOnError(response, webSocketClient, + wsService, countDownLatch); WebSocketResourceDispatcher.dispatchOnError(connectionInfo, throwable); } - - private WebSocketConnectionInfo getWebSocketOpenConnectionInfo(WebSocketConnection webSocketConnection, - ObjectValue webSocketConnector) { - WebSocketConnectionInfo connectionInfo = new WebSocketConnectionInfo( - wsService, webSocketConnection, webSocketClient); - webSocketConnector.addNativeData(WebSocketConstants.NATIVE_DATA_WEBSOCKET_CONNECTION_INFO, connectionInfo); - webSocketClient.set(WebSocketConstants.CLIENT_CONNECTOR_FIELD, webSocketConnector); - return connectionInfo; - } } diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientHandshakeListenerForRetry.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientHandshakeListenerForRetry.java new file mode 100644 index 000000000000..495ab2fa28b5 --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketClientHandshakeListenerForRetry.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.net.http.websocket.client; + +import org.ballerinalang.jvm.values.ObjectValue; +import org.ballerinalang.net.http.HttpUtil; +import org.ballerinalang.net.http.websocket.WebSocketConstants; +import org.ballerinalang.net.http.websocket.WebSocketResourceDispatcher; +import org.ballerinalang.net.http.websocket.WebSocketService; +import org.ballerinalang.net.http.websocket.WebSocketUtil; +import org.ballerinalang.net.http.websocket.observability.WebSocketObservabilityUtil; +import org.ballerinalang.net.http.websocket.server.WebSocketConnectionInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.wso2.transport.http.netty.contract.websocket.ClientHandshakeListener; +import org.wso2.transport.http.netty.contract.websocket.WebSocketConnection; +import org.wso2.transport.http.netty.message.HttpCarbonResponse; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +/** + * The retry handshake listener for the client. + * + * @since 1.2.0 + */ +public class WebSocketClientHandshakeListenerForRetry implements ClientHandshakeListener { + + private final WebSocketService wsService; + private final WebSocketClientConnectorListenerForRetry clientConnectorListener; + private final boolean readyOnConnect; + private final ObjectValue webSocketClient; + private CountDownLatch countDownLatch; + private RetryContext retryConfig; + private static final Logger logger = LoggerFactory.getLogger(WebSocketClientHandshakeListenerForRetry.class); + + public WebSocketClientHandshakeListenerForRetry(ObjectValue webSocketClient, + WebSocketService wsService, + WebSocketClientConnectorListenerForRetry clientConnectorListener, + boolean readyOnConnect, CountDownLatch countDownLatch, + RetryContext retryConfig) { + this.webSocketClient = webSocketClient; + this.wsService = wsService; + this.clientConnectorListener = clientConnectorListener; + this.readyOnConnect = readyOnConnect; + this.countDownLatch = countDownLatch; + this.retryConfig = retryConfig; + } + + @Override + public void onSuccess(WebSocketConnection webSocketConnection, HttpCarbonResponse carbonResponse) { + ObjectValue webSocketConnector; + if (!retryConfig.isFirstConnectionMadeSuccessfully()) { + webSocketConnector = WebSocketUtil.createWebSocketConnector(readyOnConnect); + } else { + webSocketConnector = (ObjectValue) webSocketClient.get(WebSocketConstants.CLIENT_CONNECTOR_FIELD); + + } + setWebSocketClient(webSocketClient, carbonResponse, webSocketConnection, retryConfig); + WebSocketConnectionInfo connectionInfo = WebSocketUtil.getWebSocketOpenConnectionInfo(webSocketConnection, + webSocketConnector, webSocketClient, wsService); + clientConnectorListener.setConnectionInfo(connectionInfo); + // Reads the next frame when `readyOnConnect` is true or `isReady` is true. + WebSocketUtil.readNextFrame(readyOnConnect, webSocketClient, webSocketConnection); + countDownLatch.countDown(); + // Calls the countDown() to initial connection's countDown latch + WebSocketUtil.countDownForHandshake(webSocketClient); + WebSocketObservabilityUtil.observeConnection(connectionInfo); + logger.debug(WebSocketConstants.LOG_MESSAGE, "Connected to ", webSocketClient.getStringValue( + WebSocketConstants.CLIENT_URL_CONFIG)); + // The following are created for future connections. + // Checks whether the config has a retry config or not. + // If it has a retry config, set these variables to the default variable. + adjustContextOnSuccess(retryConfig); + } + + @Override + public void onError(Throwable throwable, HttpCarbonResponse response) { + WebSocketConnectionInfo connectionInfo = WebSocketUtil.getConnectionInfoForOnError(response, webSocketClient, + wsService, countDownLatch); + if (throwable instanceof IOException && WebSocketUtil.reconnect(connectionInfo)) { + return; + } + dispatchOnError(connectionInfo, throwable); + } + + private void setWebSocketClient(ObjectValue webSocketClient, HttpCarbonResponse carbonResponse, + WebSocketConnection webSocketConnection, RetryContext retryConfig) { + //Using only one service endpoint in the client as there can be only one connection. + webSocketClient.set(WebSocketConstants.CLIENT_RESPONSE_FIELD, HttpUtil.createResponseStruct(carbonResponse)); + if (retryConfig.isFirstConnectionMadeSuccessfully()) { + webSocketClient.set(WebSocketConstants.LISTENER_ID_FIELD, webSocketConnection.getChannelId()); + } else { + WebSocketUtil.populateWebSocketEndpoint(webSocketConnection, webSocketClient); + } + } + + /** + * Sets the value into the `retryContext`. + * + * @param retryConfig - the retry context that represents a retry config + */ + private void adjustContextOnSuccess(RetryContext retryConfig) { + retryConfig.setFirstConnectionMadeSuccessfully(); + retryConfig.setReconnectAttempts(0); + } + + private void dispatchOnError(WebSocketConnectionInfo connectionInfo, Throwable throwable) { + WebSocketUtil.countDownForHandshake(webSocketClient); + WebSocketResourceDispatcher.dispatchOnError(connectionInfo, throwable); + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketFailoverClientHandshakeListener.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketFailoverClientHandshakeListener.java new file mode 100644 index 000000000000..8a7cd83df21b --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketFailoverClientHandshakeListener.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.net.http.websocket.client; + +import org.ballerinalang.jvm.values.ObjectValue; +import org.ballerinalang.net.http.HttpUtil; +import org.ballerinalang.net.http.websocket.WebSocketConstants; +import org.ballerinalang.net.http.websocket.WebSocketService; +import org.ballerinalang.net.http.websocket.WebSocketUtil; +import org.ballerinalang.net.http.websocket.observability.WebSocketObservabilityUtil; +import org.ballerinalang.net.http.websocket.server.WebSocketConnectionInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.wso2.transport.http.netty.contract.websocket.ClientHandshakeListener; +import org.wso2.transport.http.netty.contract.websocket.WebSocketConnection; +import org.wso2.transport.http.netty.message.HttpCarbonResponse; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +/** + * The handshake listener of the failover client. + * + * @since 1.2.0 + */ +public class WebSocketFailoverClientHandshakeListener implements ClientHandshakeListener { + + private final WebSocketService wsService; + private final WebSocketFailoverClientListener clientConnectorListener; + private final boolean readyOnConnect; + private final ObjectValue webSocketClient; + private final CountDownLatch countDownLatch; + private final FailoverContext failoverConfig; + + private static final Logger logger = LoggerFactory.getLogger(WebSocketFailoverClientHandshakeListener.class); + + public WebSocketFailoverClientHandshakeListener(ObjectValue webSocketClient, WebSocketService wsService, + WebSocketFailoverClientListener clientConnectorListener, + boolean readyOnConnect, CountDownLatch countDownLatch, + FailoverContext failoverConfig) { + this.webSocketClient = webSocketClient; + this.wsService = wsService; + this.clientConnectorListener = clientConnectorListener; + this.readyOnConnect = readyOnConnect; + this.countDownLatch = countDownLatch; + this.failoverConfig = failoverConfig; + } + + @Override + public void onSuccess(WebSocketConnection webSocketConnection, HttpCarbonResponse carbonResponse) { + ObjectValue webSocketConnector; + if (!failoverConfig.isFirstConnectionMadeSuccessfully()) { + webSocketConnector = WebSocketUtil.createWebSocketConnector(readyOnConnect); + } else { + webSocketConnector = (ObjectValue) webSocketClient.get(WebSocketConstants.CLIENT_CONNECTOR_FIELD); + + } + setFailoverWebSocketEndpoint(carbonResponse, webSocketClient, webSocketConnection, failoverConfig); + WebSocketConnectionInfo connectionInfo = WebSocketUtil.getWebSocketOpenConnectionInfo(webSocketConnection, + webSocketConnector, + webSocketClient, wsService); + clientConnectorListener.setConnectionInfo(connectionInfo); + // Read the next frame when readyOnConnect is true or isReady is true + WebSocketUtil.readNextFrame(readyOnConnect, webSocketClient, webSocketConnection); + countDownLatch.countDown(); + // Calls the countDown() to initial connection's countDown latch + WebSocketUtil.countDownForHandshake(webSocketClient); + WebSocketObservabilityUtil.observeConnection(connectionInfo); + // Following these are created for future connection + int currentIndex = failoverConfig.getCurrentIndex(); + logger.debug(WebSocketConstants.LOG_MESSAGE, WebSocketConstants.CONNECTED_TO, + failoverConfig.getTargetUrls().get(currentIndex)); + // Set failover context variable's value + failoverConfig.setInitialIndex(currentIndex); + if (!failoverConfig.isFirstConnectionMadeSuccessfully()) { + failoverConfig.setFirstConnectionMadeSuccessfully(); + } + } + + @Override + public void onError(Throwable throwable, HttpCarbonResponse response) { + WebSocketConnectionInfo connectionInfo = WebSocketUtil.getConnectionInfoForOnError(response, webSocketClient, + wsService, countDownLatch); + // When connection lost, do the failover to the remaining server urls. + if (!(throwable instanceof IOException && WebSocketUtil.failover(connectionInfo))) { + WebSocketUtil.dispatchOnError(connectionInfo, throwable); + } + } + + private void setFailoverWebSocketEndpoint(HttpCarbonResponse carbonResponse, ObjectValue webSocketClient, + WebSocketConnection webSocketConnection, + FailoverContext failoverConfig) { + webSocketClient.set(WebSocketConstants.CLIENT_RESPONSE_FIELD, HttpUtil.createResponseStruct(carbonResponse)); + if (failoverConfig.isFirstConnectionMadeSuccessfully()) { + webSocketClient.set(WebSocketConstants.LISTENER_ID_FIELD, webSocketConnection.getChannelId()); + } else { + WebSocketUtil.populateWebSocketEndpoint(webSocketConnection, webSocketClient); + } + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketFailoverClientListener.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketFailoverClientListener.java new file mode 100644 index 000000000000..aeeecf586670 --- /dev/null +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/client/WebSocketFailoverClientListener.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.net.http.websocket.client; + +import org.ballerinalang.net.http.websocket.WebSocketConstants; +import org.ballerinalang.net.http.websocket.WebSocketResourceDispatcher; +import org.ballerinalang.net.http.websocket.WebSocketUtil; +import org.ballerinalang.net.http.websocket.server.WebSocketConnectionInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.wso2.transport.http.netty.contract.websocket.WebSocketCloseMessage; +import org.wso2.transport.http.netty.contract.websocket.WebSocketConnection; + +import java.io.IOException; + +/** + * Failover client listener of the WebSocket. + * + * @since 1.2.0 + */ +public class WebSocketFailoverClientListener extends WebSocketClientConnectorListener { + + private WebSocketConnectionInfo connectionInfo = null; + private static final Logger logger = LoggerFactory.getLogger(WebSocketFailoverClientListener.class); + + @Override + public void setConnectionInfo(WebSocketConnectionInfo connectionInfo) { + super.setConnectionInfo(connectionInfo); + this.connectionInfo = connectionInfo; + } + + @Override + public void onMessage(WebSocketCloseMessage webSocketCloseMessage) { + int statusCode = webSocketCloseMessage.getCloseCode(); + if (!(statusCode == WebSocketConstants.STATUS_CODE_ABNORMAL_CLOSURE && + WebSocketUtil.failover(connectionInfo))) { + WebSocketUtil.dispatchOnClose(connectionInfo, webSocketCloseMessage); + } + } + + @Override + public void onError(WebSocketConnection webSocketConnection, Throwable throwable) { + // When connection lost, do the failover to the remaining server urls. + if (!(throwable instanceof IOException && WebSocketUtil.failover(connectionInfo))) { + logger.error(WebSocketConstants.ERROR_MESSAGE, throwable); + WebSocketResourceDispatcher.dispatchOnError(connectionInfo, throwable); + } + } +} diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/observability/WebSocketObservabilityUtil.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/observability/WebSocketObservabilityUtil.java index 4c94cc2ac5f5..c465a747f1a1 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/observability/WebSocketObservabilityUtil.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/observability/WebSocketObservabilityUtil.java @@ -22,6 +22,7 @@ import org.ballerinalang.jvm.values.ObjectValue; import org.ballerinalang.net.http.websocket.WebSocketConstants; import org.ballerinalang.net.http.websocket.WebSocketService; +import org.ballerinalang.net.http.websocket.client.FailoverContext; import org.ballerinalang.net.http.websocket.server.WebSocketConnectionInfo; import org.ballerinalang.net.http.websocket.server.WebSocketServerService; import org.slf4j.Logger; @@ -209,7 +210,14 @@ static String getServicePathOrClientUrl(WebSocketConnectionInfo connectionInfo) if (service instanceof WebSocketServerService) { return ((WebSocketServerService) service).getBasePath(); } else { - return connectionInfo.getWebSocketEndpoint().getStringValue("url"); + if (connectionInfo.getWebSocketEndpoint().getType().getName(). + equalsIgnoreCase(WebSocketConstants.FAILOVER_WEBSOCKET_CLIENT)) { + FailoverContext failoverConfig = (FailoverContext) connectionInfo.getWebSocketEndpoint(). + getNativeData(WebSocketConstants.FAILOVER_CONFIG); + return failoverConfig.getTargetUrls().get(failoverConfig.getCurrentIndex()); + } else { + return connectionInfo.getWebSocketEndpoint().getStringValue("url"); + } } } diff --git a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/server/WebSocketServerService.java b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/server/WebSocketServerService.java index f987e427c7f7..81e2345f258f 100644 --- a/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/server/WebSocketServerService.java +++ b/stdlib/http/src/main/java/org/ballerinalang/net/http/websocket/server/WebSocketServerService.java @@ -63,7 +63,8 @@ private void populateConfigs() { MapValue configAnnotation = getServiceConfigAnnotation(); if (configAnnotation != null) { negotiableSubProtocols = WebSocketUtil.findNegotiableSubProtocols(configAnnotation); - idleTimeoutInSeconds = WebSocketUtil.findIdleTimeoutInSeconds(configAnnotation); + idleTimeoutInSeconds = WebSocketUtil.findTimeoutInSeconds(configAnnotation, + WebSocketConstants.ANNOTATION_ATTR_IDLE_TIMEOUT, 0); maxFrameSize = WebSocketUtil.findMaxFrameSize(configAnnotation); } // This will be overridden if there is an upgrade path diff --git a/stdlib/http/src/main/resources/META-INF/services/org.ballerinalang.compiler.plugins.CompilerPlugin b/stdlib/http/src/main/resources/META-INF/services/org.ballerinalang.compiler.plugins.CompilerPlugin index 816f50f7a9e3..ce511f17a4d7 100644 --- a/stdlib/http/src/main/resources/META-INF/services/org.ballerinalang.compiler.plugins.CompilerPlugin +++ b/stdlib/http/src/main/resources/META-INF/services/org.ballerinalang.compiler.plugins.CompilerPlugin @@ -1,3 +1,4 @@ org.ballerinalang.net.http.compiler.HttpServiceCompilerPlugin org.ballerinalang.net.http.compiler.websocket.WebSocketServiceCompilerPlugin org.ballerinalang.net.http.compiler.websocket.WebSocketClientServiceCompilerPlugin +org.ballerinalang.net.http.compiler.websocket.WebSocketFailoverClientServiceCompilerPlugin diff --git a/stdlib/http/src/test/java/org/ballerinalang/stdlib/services/nativeimpl/cookie/CookieNativeFunctionNegativeTest.java b/stdlib/http/src/test/java/org/ballerinalang/stdlib/services/nativeimpl/cookie/CookieNativeFunctionNegativeTest.java index f88c892ab5cf..58f2835d903c 100644 --- a/stdlib/http/src/test/java/org/ballerinalang/stdlib/services/nativeimpl/cookie/CookieNativeFunctionNegativeTest.java +++ b/stdlib/http/src/test/java/org/ballerinalang/stdlib/services/nativeimpl/cookie/CookieNativeFunctionNegativeTest.java @@ -40,22 +40,22 @@ public void setup() { result = BCompileUtil.compile(basePath + "cookie-native-function-negative.bal"); } - @Test(description = "Test add a cookie with unmatched domain to cookie store") + @Test(description = "Test to add a cookie with unmatched domain to the cookie store") public void testAddCookieWithUnmatchedDomain() { BValue[] returnVals = BRunUtil.invoke(result, "testAddCookieWithUnmatchedDomain"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "add a cookie with unmatched path to cookie store") + @Test(description = "Test to add a cookie with unmatched path to the cookie store") public void testAddCookieWithUnmatchedPath() { BValue[] returnVals = BRunUtil.invoke(result, "testAddCookieWithUnmatchedPath"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test add a similar cookie as in the store coming from a non-http request url, but existing " + - "old cookie is http only") + @Test(description = "Test to add a similar cookie as in the cookie store coming from a non-http request url, but " + + "existing old cookie is http only") public void testAddSimilarCookie() { BValue[] returnVals = BRunUtil.invoke(result, "testAddSimilarCookie"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -66,56 +66,57 @@ public void testAddSimilarCookie() { Assert.assertEquals(bvalue.get("value").stringValue(), "239d4dmnmsddd34"); } - @Test(description = "Test add a http only cookie coming from a non-http url") + @Test(description = "Test to add a http only cookie coming from a non-http url") public void testAddHttpOnlyCookie() { BValue[] returnVals = BRunUtil.invoke(result, "testAddHttpOnlyCookie"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test get a secure only cookie to unsecured request url") + @Test(description = "Test to get a secure only cookie to unsecured request url") public void testGetSecureCookieFromCookieStore() { BValue[] returnVals = BRunUtil.invoke(result, "testGetSecureCookieFromCookieStore"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test get a http only cookie to non-http request url") + @Test(description = "Test to get a http only cookie to non-http request url") public void testGetHttpOnlyCookieFromCookieStore() { BValue[] returnVals = BRunUtil.invoke(result, "testGetHttpOnlyCookieFromCookieStore"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test get a host only cookie for a subdomain from cookie store ") + @Test(description = "Test to get a host only cookie to a sub-domain from the cookie store ") public void testGetCookieToUnmatchedDomain1() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookieToUnmatchedDomain1"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test get a cookie to unmatched request domain") + @Test(description = "Test to get a cookie to unmatched request domain") public void testGetCookieToUnmatchedDomain2() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookieToUnmatchedDomain2"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test get a cookie to unmatched request path") + @Test(description = "Test to get a cookie to unmatched request path") public void testGetCookieToUnmatchedPath1() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookieToUnmatchedPath1"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test get a cookie with unspecified path to unmatched request path") + @Test(description = "Test to get a cookie with unspecified path to unmatched request path") public void testGetCookieToUnmatchedPath2() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookieToUnmatchedPath2"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test remove a specific cookie which is not in the cookie store") + @Test(description = "Test to remove a specific cookie which is not in the cookie store when persistent cookie " + + "handler is not configured") public void testRemoveCookieFromCookieStore() { BValue[] returnVals = BRunUtil.invoke(result, "testRemoveCookieFromCookieStore"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -124,4 +125,61 @@ public void testRemoveCookieFromCookieStore() { BMap bvalue = (BMap) returnVals[0]; Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } + + @Test(description = "Test to add cookies more than the number in maxTotalCookieCount in cookie configuration") + public void testCheckMaxTotalCookieCount() { + BValue[] returnVals = BRunUtil.invoke(result, "testCheckMaxTotalCookieCount"); + Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "No cookie objects in the return values"); + Assert.assertTrue(returnVals.length == 2); + BMap bvalue1 = (BMap) returnVals[0]; + BMap bvalue2 = (BMap) returnVals[1]; + Assert.assertEquals(bvalue1.get("name").stringValue(), "SID001"); + Assert.assertEquals(bvalue2.get("name").stringValue(), "SID002"); + } + + @Test(description = "Test to add cookies more than the number in maxCookiesPerDomain in cookie configuration") + public void testCheckMaxCookiesPerDomain() { + BValue[] returnVals = BRunUtil.invoke(result, "testCheckMaxCookiesPerDomain"); + Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "No cookie objects in the return values"); + Assert.assertTrue(returnVals.length == 2); + BMap bvalue1 = (BMap) returnVals[0]; + BMap bvalue2 = (BMap) returnVals[1]; + Assert.assertEquals(bvalue1.get("name").stringValue(), "SID001"); + Assert.assertEquals(bvalue2.get("name").stringValue(), "SID002"); + } + + @Test(description = "Test to give invalid file extension when creating a CsvPersistentCookieHandler object") + public void testAddPersistentCookieWithoutPersistentStore() { + BValue[] returnVals = BRunUtil.invoke(result, "testAddPersistentCookieWithoutPersistentStore"); + Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "Cookie objects are in the Return Values"); + } + + @Test(description = "Test to remove a specific cookie which is not in the cookie store, when there is a " + + "persistent cookie store") + public void testRemovePersistentCookieFromCookieStore_1() { + BValue[] returnVals = BRunUtil.invoke(result, "testRemovePersistentCookieFromCookieStore_1"); + Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "No cookie objects in the Return Values"); + Assert.assertTrue(returnVals.length == 1); + BMap bvalue = (BMap) returnVals[0]; + Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); + } + + @Test(description = "Test to remove a specific cookie which is not in the cookie store, when there is no " + + "persistent cookie store") + public void testRemovePersistentCookieFromCookieStore_2() { + BValue[] returnVals = BRunUtil.invoke(result, "testRemovePersistentCookieFromCookieStore_2"); + Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "Cookie objects are in the Return Values"); + } + + @Test(description = "Test to remove all cookies when there is no persistent cookie store") + public void testRemoveAllCookiesFromCookieStore() { + BValue[] returnVals = BRunUtil.invoke(result, "testRemoveAllCookiesFromCookieStore"); + Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "Cookie objects are in the Return Values"); + } } diff --git a/stdlib/http/src/test/java/org/ballerinalang/stdlib/services/nativeimpl/cookie/CookieNativeFunctionSuccessTest.java b/stdlib/http/src/test/java/org/ballerinalang/stdlib/services/nativeimpl/cookie/CookieNativeFunctionSuccessTest.java index 4db8472fec57..44d35b079061 100644 --- a/stdlib/http/src/test/java/org/ballerinalang/stdlib/services/nativeimpl/cookie/CookieNativeFunctionSuccessTest.java +++ b/stdlib/http/src/test/java/org/ballerinalang/stdlib/services/nativeimpl/cookie/CookieNativeFunctionSuccessTest.java @@ -45,9 +45,8 @@ public void setup() { result = BCompileUtil.compile(sourceRoot.resolve("cookie-native-function.bal").toString()); } - @Test(description = "Test add cookie with same domain and path values as in the request url , into cookie store") + @Test(description = "Test to add cookie with same domain and path values as in the request url , into cookie store") public void testAddCookieToCookieStore1() { - BValue[] returnVals = BRunUtil.invoke(result, "testAddCookieToCookieStore1"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "No cookie objects in the return values"); @@ -56,9 +55,8 @@ public void testAddCookieToCookieStore1() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test add cookie coming from a sub domain of the cookie's domain value, into cookie store") + @Test(description = "Test to add cookie coming from a sub domain of the cookie's domain value, into cookie store") public void testAddCookieToCookieStore2() { - BValue[] returnVals = BRunUtil.invoke(result, "testAddCookieToCookieStore2"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "No cookie objects in the return values"); @@ -67,7 +65,7 @@ public void testAddCookieToCookieStore2() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test add a host only cookie into cookie store") + @Test(description = "Test to add a host only cookie into cookie store") public void testAddCookieToCookieStore3() { BValue[] returnVals = BRunUtil.invoke(result, "testAddCookieToCookieStore3"); @@ -78,9 +76,8 @@ public void testAddCookieToCookieStore3() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test add cookie with unspecified path value, into cookie store") + @Test(description = "Test to add cookie with unspecified path value, into cookie store") public void testAddCookieToCookieStore4() { - BValue[] returnVals = BRunUtil.invoke(result, "testAddCookieToCookieStore4"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "No cookie objects in the return values"); @@ -89,9 +86,8 @@ public void testAddCookieToCookieStore4() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test add cookie coming from a sub directory of the cookie's path value, into cookie store") + @Test(description = "Test to add cookie coming from a sub directory of the cookie's path value, into cookie store") public void testAddCookieToCookieStore5() { - BValue[] returnVals = BRunUtil.invoke(result, "testAddCookieToCookieStore5"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "No cookie objects in the return values"); @@ -100,9 +96,8 @@ public void testAddCookieToCookieStore5() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test add a third party cookie into cookie store") + @Test(description = "Test to add a third party cookie into cookie store") public void testAddThirdPartyCookieToCookieStore() { - BValue[] returnVals = BRunUtil.invoke(result, "testAddThirdPartyCookieToCookieStore"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "No cookie objects in the return values"); @@ -111,9 +106,8 @@ public void testAddThirdPartyCookieToCookieStore() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test add an array of cookies into cookie store") + @Test(description = "Test to add an array of cookies into cookie store") public void testAddCookiesToCookieStore() { - BValue[] returnVals = BRunUtil.invoke(result, "testAddCookiesToCookieStore"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "No cookie objects in the return values"); @@ -124,9 +118,8 @@ public void testAddCookiesToCookieStore() { Assert.assertEquals(bvalue2.get("name").stringValue(), "SID002"); } - @Test(description = "Test add a similar cookie as in the store") + @Test(description = "Test to add a similar cookie as in the store") public void testAddSimilarCookieToCookieStore() { - BValue[] returnVals = BRunUtil.invoke(result, "testAddSimilarCookieToCookieStore"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "No cookie objects in the return values"); @@ -136,7 +129,7 @@ public void testAddSimilarCookieToCookieStore() { Assert.assertEquals(bvalue.get("value").stringValue(), "6789mnmsddd34"); } - @Test(description = "Test add cookies concurrently into cookie store") + @Test(description = "Test to add cookies concurrently into cookie store") public void testAddCookiesConcurrentlyToCookieStore() { BValue[] returnVals = BRunUtil.invoke(result, "testAddCookiesConcurrentlyToCookieStore"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -147,7 +140,7 @@ public void testAddCookiesConcurrentlyToCookieStore() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test get the relevant cookie with same domain and path values as in the request url from " + + @Test(description = "Test to get the relevant cookie with same domain and path values as in the request url from " + "cookie store") public void testGetCookiesFromCookieStore1() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookiesFromCookieStore1"); @@ -158,7 +151,8 @@ public void testGetCookiesFromCookieStore1() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test get the relevant cookie to a sub domain of the cookie's domain value from cookie store") + @Test(description = "Test to get the relevant cookie to a sub domain of the cookie's domain value from cookie " + + "store") public void testGetCookiesFromCookieStore2() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookiesFromCookieStore2"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -168,7 +162,7 @@ public void testGetCookiesFromCookieStore2() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test get a host only cookie to the relevant domain from cookie store") + @Test(description = "Test to get a host only cookie to the relevant domain from cookie store") public void testGetCookiesFromCookieStore3() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookiesFromCookieStore3"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -178,7 +172,8 @@ public void testGetCookiesFromCookieStore3() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test get the relevant cookie to a sub directory of the cookie's path value from cookie store") + @Test(description = "Test to get the relevant cookie to a sub directory of the cookie's path value from cookie " + + "store") public void testGetCookiesFromCookieStore4() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookiesFromCookieStore4"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -188,7 +183,7 @@ public void testGetCookiesFromCookieStore4() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test get a cookie with unspecified path value to the relevant path from cookie store") + @Test(description = "Test to get a cookie with unspecified path value to the relevant path from cookie store") public void testGetCookiesFromCookieStore5() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookiesFromCookieStore5"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -198,7 +193,8 @@ public void testGetCookiesFromCookieStore5() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test get cookies when both matched and unmatched cookies are available in the cookie store.") + @Test(description = "Test to get cookies when both matched and unmatched cookies are available in the cookie " + + "store.") public void testGetCookiesFromCookieStore6() { BValue[] returnVals = BRunUtil.invoke(result, "testGetCookiesFromCookieStore6"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -208,7 +204,7 @@ public void testGetCookiesFromCookieStore6() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test get a secure cookie to a secure url from cookie store") + @Test(description = "Test to get a secure cookie to a secure url from cookie store") public void testGetSecureCookieFromCookieStore() { BValue[] returnVals = BRunUtil.invoke(result, "testGetSecureCookieFromCookieStore"); Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, @@ -218,16 +214,82 @@ public void testGetSecureCookieFromCookieStore() { Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); } - @Test(description = "Test remove a specific session cookie from cookie store") + @Test(description = "Test to remove a specific session cookie from the cookie store") public void testRemoveCookieFromCookieStore() { BValue[] returnVals = BRunUtil.invoke(result, "testRemoveCookieFromCookieStore"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } - @Test(description = "Test remove all session cookies from cookie store") - public void testClearCookieStore() { - BValue[] returnVals = BRunUtil.invoke(result, "testClearAllCookiesInCookieStore"); + @Test(description = "Test to remove all cookies from the cookie store") + public void testRemoveAllCookiesInCookieStore() { + BValue[] returnVals = BRunUtil.invoke(result, "testRemoveAllCookiesInCookieStore"); + Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "Cookie objects are in the Return Values"); + } + + @Test(description = "Test to add persistent cookie into cookie store") + public void testAddPersistentCookieToCookieStore() { + BValue[] returnVals = BRunUtil.invoke(result, "testAddPersistentCookieToCookieStore"); + Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "No cookie objects in the return values"); + Assert.assertTrue(returnVals.length == 1); + BMap bvalue = (BMap) returnVals[0]; + Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); + } + + @Test(description = "Test to add persistent cookie with a value below 69 for the year in expires attribute") + public void testAddPersistentCookieToCookieStore_2() { + BValue[] returnVals = BRunUtil.invoke(result, "testAddPersistentCookieToCookieStore_2"); + Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "No cookie objects in the return values"); + Assert.assertTrue(returnVals.length == 1); + BMap bvalue = (BMap) returnVals[0]; + Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); + } + + @Test(description = "Test to get the relevant persistent cookie from the cookie store") + public void testGetPersistentCookieFromCookieStore() { + BValue[] returnVals = BRunUtil.invoke(result, "testGetPersistentCookieFromCookieStore"); + Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "No cookie objects in the return values"); + Assert.assertTrue(returnVals.length == 1); + BMap bvalue = (BMap) returnVals[0]; + Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); + } + + @Test(description = "Test to remove a specific persistent cookie from the cookie store") + public void testRemovePersistentCookieFromCookieStore() { + BValue[] returnVals = BRunUtil.invoke(result, "testRemovePersistentCookieFromCookieStore"); + Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "Cookie objects are in the Return Values"); + } + + @Test(description = "Test to get all cookies from the cookie store, which match the given cookie name") + public void testGetCookiesByName() { + BValue[] returnVals = BRunUtil.invoke(result, "testGetCookiesByName"); + Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "No cookie objects in the return values"); + Assert.assertTrue(returnVals.length == 1); + BMap bvalue = (BMap) returnVals[0]; + Assert.assertEquals(bvalue.get("name").stringValue(), "SID002"); + } + + @Test(description = "Test to get all cookies from the cookie store, which match the given cookie domain") + public void testGetCookiesByDomain() { + BValue[] returnVals = BRunUtil.invoke(result, "testGetCookiesByDomain"); + Assert.assertFalse(returnVals == null || returnVals.length == 0 || returnVals[0] == null, + "No cookie objects in the return values"); + Assert.assertTrue(returnVals.length == 2); + BMap bvalue1 = (BMap) returnVals[0]; + BMap bvalue2 = (BMap) returnVals[1]; + Assert.assertEquals(bvalue1.get("name").stringValue(), "SID001"); + Assert.assertEquals(bvalue2.get("name").stringValue(), "SID002"); + } + + @Test(description = "Test to remove all cookies from the cookie store, which match the given cookie domain") + public void testRemoveCookiesByDomain() { + BValue[] returnVals = BRunUtil.invoke(result, "testRemoveCookiesByDomain"); Assert.assertTrue(returnVals == null || returnVals.length == 0 || returnVals[0] == null, "Cookie objects are in the Return Values"); } diff --git a/stdlib/http/src/test/java/org/ballerinalang/stdlib/websocket/WebSocketCompilationTest.java b/stdlib/http/src/test/java/org/ballerinalang/stdlib/websocket/WebSocketCompilationTest.java index 31041da49af8..dd74270ebe21 100644 --- a/stdlib/http/src/test/java/org/ballerinalang/stdlib/websocket/WebSocketCompilationTest.java +++ b/stdlib/http/src/test/java/org/ballerinalang/stdlib/websocket/WebSocketCompilationTest.java @@ -179,6 +179,22 @@ public void testServicePathParams() { BAssertUtil.validateError(compileResult, 0, "Path params are not supported in service path", 23, 11); } + @Test(description = "Successfully compiling WebSocketFailoverClientService") + public void testSuccessfailoverClient() { + CompileResult compileResult = BCompileUtil.compileOnly(TEST_PATH + "success_failover_client.bal"); + + Assert.assertEquals(compileResult.toString(), "Compilation Successful"); + } + + @Test(description = "Invalid resource onOpen in WebSocketFailoverClientService") + public void testFailOnOpenFailoverClient() { + CompileResult compileResult = BCompileUtil.compileOnly(TEST_PATH + + "fail_onBinary_failoverClient.bal"); + assertExpectedDiagnosticsLength(compileResult, 2); + Assert.assertTrue(compileResult.toString().contains("Invalid resource signature for onBinary resource " + + "in service : The first parameter should be a WebSocketFailoverClient")); + } + private void assertExpectedDiagnosticsLength(CompileResult compileResult, int expectedLength) { Assert.assertEquals(compileResult.getDiagnostics().length, expectedLength); } diff --git a/stdlib/http/src/test/resources/test-src/services/nativeimpl/cookie/cookie-native-function-negative.bal b/stdlib/http/src/test/resources/test-src/services/nativeimpl/cookie/cookie-native-function-negative.bal index 1c68564581ad..1faae68098a3 100644 --- a/stdlib/http/src/test/resources/test-src/services/nativeimpl/cookie/cookie-native-function-negative.bal +++ b/stdlib/http/src/test/resources/test-src/services/nativeimpl/cookie/cookie-native-function-negative.bal @@ -15,8 +15,11 @@ // under the License. import ballerina/http; +import ballerina/file; +import ballerina/io; + +string filePath = "src/test/resources/test-src/services/nativeimpl/cookie/cookie-test-data/"; -// Tests for session cookies. function testAddCookieWithUnmatchedDomain() returns @tainted http:Cookie[] { http:CookieStore cookieStore = new; http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); @@ -25,7 +28,10 @@ function testAddCookieWithUnmatchedDomain() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://bar.example.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://bar.example.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://bar.example.com", "/sample"); + if (result is error) { + io:println(result); + } } // Gets all the cookies. return cookieStore.getAllCookies(); @@ -39,7 +45,10 @@ function testAddCookieWithUnmatchedPath() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://example.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://example.com", "/mail"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://example.com", "/mail"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -56,8 +65,14 @@ function testAddSimilarCookie() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); - cookieStore.addCookie(cookie2, cookieConfigVal, "google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + if (result is error) { + io:println(result); + } + result = cookieStore.addCookie(cookie2, cookieConfigVal, "google.com", "/sample"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -71,7 +86,10 @@ function testAddHttpOnlyCookie() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "google.com", "/sample"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -85,7 +103,7 @@ function testGetSecureCookieFromCookieStore() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); } return cookieStore.getCookies("http://google.com", "/sample"); } @@ -99,7 +117,7 @@ function testGetHttpOnlyCookieFromCookieStore() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); } return cookieStore.getCookies("google.com", "/sample"); } @@ -111,7 +129,7 @@ function testGetCookieToUnmatchedDomain1() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); } return cookieStore.getCookies("http://mail.google.com", "/sample"); } @@ -124,7 +142,7 @@ function testGetCookieToUnmatchedDomain2() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://foo.google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://foo.google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://foo.google.com", "/sample"); } return cookieStore.getCookies("http://google.com", "/sample"); } @@ -137,7 +155,7 @@ function testGetCookieToUnmatchedPath1() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/mail/inbox"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/mail/inbox"); } return cookieStore.getCookies("http://google.com", "/mail"); } @@ -149,7 +167,7 @@ function testGetCookieToUnmatchedPath2() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/mail"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/mail"); } return cookieStore.getCookies("http://google.com", "/sample"); } @@ -162,8 +180,126 @@ function testRemoveCookieFromCookieStore() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample" ); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample" ); + } + var removeResult = cookieStore.removeCookie("SID003", "google.com", "/sample"); + if (removeResult is error) { + io:println(removeResult); + } + return cookieStore.getAllCookies(); +} + +function testCheckMaxTotalCookieCount() returns @tainted http:Cookie[] { + http:CookieStore cookieStore = new; + http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + http:Cookie cookie2 = new("SID002", "jka6mnmsddd34"); + cookie2.path = "/sample"; + cookie2.domain = "google.com"; + http:Cookie cookie3 = new("SID003", "kafh34dmnmsddd34"); + cookie3.path = "/sample"; + cookie3.domain = "google.com"; + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, maxTotalCookieCount:2 } } ); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + if (cookieConfigVal is http:CookieConfig) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie3, cookieConfigVal, "http://google.com", "/sample"); + } + return cookieStore.getAllCookies(); +} + +function testCheckMaxCookiesPerDomain() returns @tainted http:Cookie[] { + http:CookieStore cookieStore = new; + http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + http:Cookie cookie2 = new("SID002", "jka6mnmsddd34"); + cookie2.path = "/sample"; + cookie2.domain = "google.com"; + http:Cookie cookie3 = new("SID003", "kafh34dmnmsddd34"); + cookie3.path = "/sample"; + cookie3.domain = "google.com"; + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, maxCookiesPerDomain:2 } } ); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + if (cookieConfigVal is http:CookieConfig) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie3, cookieConfigVal, "http://google.com", "/sample"); } - boolean isRemoved = cookieStore.removeCookie("SID003", "google.com", "/sample"); return cookieStore.getAllCookies(); } + +function testAddPersistentCookieWithoutPersistentStore() returns @tainted http:Cookie[] { + http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + cookie1.expires = "2030-07-15 05:46:22"; + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + http:Cookie[] cookies = []; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore && cookie1.isValid() == true) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + if (result is error) { + io:println(result); + } + cookies = cookieStore.getAllCookies(); + } + return cookies; +} + +function testRemovePersistentCookieFromCookieStore_1() returns @tainted http:Cookie[] { + http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + cookie1.expires = "2030-07-15 05:46:22"; + http:CsvPersistentCookieHandler myPersistentStore = new(filePath + "client-6.csv"); + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + http:Cookie[] cookies = []; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore && cookie1.isValid() == true) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.removeCookie("SID003", "google.com", "/sample"); + if (result is error) { + io:println(result); + } + cookies = cookieStore.getAllCookies(); + } + error? removeResults = file:remove(filePath, true); + return cookies; +} + +function testRemovePersistentCookieFromCookieStore_2() returns @tainted http:Cookie[] { + http:CsvPersistentCookieHandler myPersistentStore = new(filePath + "client-7.csv"); + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + http:Cookie[] cookies = []; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore) { + var result = cookieStore.removeCookie("SID003", "google.com", "/sample"); + if (result is error) { + io:println(result); + } + cookies = cookieStore.getAllCookies(); + } + return cookies; +} + +function testRemoveAllCookiesFromCookieStore() returns @tainted http:Cookie[] { + http:CsvPersistentCookieHandler myPersistentStore = new(filePath + "client-8.csv"); + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + http:Cookie[] cookies = []; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore) { + var result = cookieStore.removeAllCookies(); + if (result is error) { + io:println(result); + } + cookies = cookieStore.getAllCookies(); + } + return cookies; +} diff --git a/stdlib/http/src/test/resources/test-src/services/nativeimpl/cookie/cookie-native-function.bal b/stdlib/http/src/test/resources/test-src/services/nativeimpl/cookie/cookie-native-function.bal index 139865db1120..b8bcfd5022ea 100644 --- a/stdlib/http/src/test/resources/test-src/services/nativeimpl/cookie/cookie-native-function.bal +++ b/stdlib/http/src/test/resources/test-src/services/nativeimpl/cookie/cookie-native-function.bal @@ -15,17 +15,23 @@ // under the License. import ballerina/http; +import ballerina/file; +import ballerina/io; + +string filePath = "src/test/resources/test-src/services/nativeimpl/cookie/cookie-test-data/"; -// Tests for session cookies. function testAddCookieToCookieStore1() returns @tainted http:Cookie[] { http:CookieStore cookieStore = new; http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); cookie1.path = "/sample"; cookie1.domain = "google.com"; - http:Client cookieclientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); - var cookieConfigVal = cookieclientEndpoint.config.cookieConfig; + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + if (result is error) { + io:println(result); + } } // Gets all the cookies. return cookieStore.getAllCookies(); @@ -39,7 +45,10 @@ function testAddCookieToCookieStore2() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://mail.google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://mail.google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://mail.google.com", "/sample"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -51,7 +60,10 @@ function testAddCookieToCookieStore3() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -63,7 +75,10 @@ function testAddCookieToCookieStore4() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://mail.google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -76,7 +91,10 @@ function testAddCookieToCookieStore5() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://mail.google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://mail.google.com", "/mail/inbox"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://mail.google.com", "/mail/inbox"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -89,7 +107,10 @@ function testAddThirdPartyCookieToCookieStore() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://mail.google.com", { cookieConfig: { enabled: true, blockThirdPartyCookies:false } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://mail.google.com", "/mail/inbox"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://mail.google.com", "/mail/inbox"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -123,8 +144,14 @@ function testAddSimilarCookieToCookieStore() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); - cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + if (result is error) { + io:println(result); + } + result = cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + if (result is error) { + io:println(result); + } } return cookieStore.getAllCookies(); } @@ -139,22 +166,22 @@ function testAddCookiesConcurrentlyToCookieStore() returns @tainted http:Cookie[ var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; worker w1 { if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore) { - cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); } } worker w2 { if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore) { - cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); } } worker w3 { if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore) { - cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); } } worker w4 { if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore) { - cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); } } _ = wait {w1, w2, w3, w4}; @@ -174,7 +201,7 @@ function testGetCookiesFromCookieStore1() returns @tainted http:Cookie[] { var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; // Adds cookie. if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); } // Gets the relevant cookie from the cookie store. return cookieStore.getCookies("http://google.com", "/sample"); @@ -188,7 +215,7 @@ function testGetCookiesFromCookieStore2() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); } return cookieStore.getCookies("http://mail.google.com", "/sample"); } @@ -200,7 +227,7 @@ function testGetCookiesFromCookieStore3() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); } return cookieStore.getCookies("http://google.com", "/sample"); } @@ -213,7 +240,7 @@ function testGetCookiesFromCookieStore4() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/mail"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/mail"); } return cookieStore.getCookies("http://google.com", "/mail/inbox"); } @@ -225,7 +252,7 @@ function testGetCookiesFromCookieStore5() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); } return cookieStore.getCookies("http://google.com", "/sample"); } @@ -242,8 +269,8 @@ function testGetCookiesFromCookieStore6() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); - cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); } return cookieStore.getCookies("http://google.com", "/sample"); } @@ -257,7 +284,7 @@ function testGetSecureCookieFromCookieStore() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); } return cookieStore.getCookies("https://google.com", "/sample"); } @@ -270,26 +297,168 @@ function testRemoveCookieFromCookieStore() returns @tainted http:Cookie[] { http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + } + var result = cookieStore.removeCookie("SID002", "google.com", "/sample"); + if (result is error) { + io:println(result); } - boolean isRemoved = cookieStore.removeCookie("SID002", "google.com", "/sample"); return cookieStore.getAllCookies(); } -function testClearAllCookiesInCookieStore() returns @tainted http:Cookie[] { - http:CookieStore cookieStore = new; +function testRemoveAllCookiesInCookieStore() returns @tainted http:Cookie[] { http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); cookie1.path = "/sample"; cookie1.domain = "google.com"; http:Cookie cookie2 = new("SID003", "239d4dmnmsddd34"); cookie2.path = "/sample"; cookie2.domain = "google.com"; - http:Cookie[] cookiesToadd =[cookie1, cookie2]; + cookie2.expires = "2030-07-15 05:46:22"; + http:Cookie[] cookies = []; + http:CsvPersistentCookieHandler myPersistentStore = new(filePath + "client-5.csv"); + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore && cookie1.isValid() == true && cookie2.isValid() == true) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.removeAllCookies(); + if (result is error) { + io:println(result); + } + cookies = cookieStore.getAllCookies(); + } + error? removeResults = file:remove(filePath, true); + return cookies; +} + +function testAddPersistentCookieToCookieStore() returns @tainted http:Cookie[] { + http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + cookie1.expires = "2030-07-15 05:46:22"; + http:CsvPersistentCookieHandler myPersistentStore = new(filePath + "client-1.csv"); + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + http:Cookie[] cookies = []; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore && cookie1.isValid() == true) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + cookies = cookieStore.getAllCookies(); + } + error? removeResults = file:remove(filePath, true); + return cookies; +} + +function testAddPersistentCookieToCookieStore_2() returns @tainted http:Cookie[] { + http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + cookie1.expires = "0050-07-15 05:46:22"; + http:CsvPersistentCookieHandler myPersistentStore = new(filePath + "client-2.csv"); + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + http:Cookie[] cookies = []; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore && cookie1.isValid() == true) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + cookies = cookieStore.getAllCookies(); + } + error? removeResults = file:remove(filePath, true); + return cookies; +} + +function testGetPersistentCookieFromCookieStore() returns @tainted http:Cookie[] { + http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + cookie1.expires = "2030-07-15 05:46:22"; + http:CsvPersistentCookieHandler myPersistentStore = new(filePath + "client-3.csv"); + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + http:Cookie[] cookies = []; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore && cookie1.isValid() == true) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + cookies = cookieStore.getCookies("http://google.com", "/sample"); + } + error? removeResults = file:remove(filePath, true); + return cookies; +} + +function testRemovePersistentCookieFromCookieStore() returns @tainted http:Cookie[] { + http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + cookie1.expires = "2030-07-15 05:46:22"; + http:CsvPersistentCookieHandler myPersistentStore = new(filePath + "client-4.csv"); + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } } ); + http:CookieStore? cookieStore = cookieClientEndpoint.getCookieStore(); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + http:Cookie[] cookies = []; + if (cookieConfigVal is http:CookieConfig && cookieStore is http:CookieStore && cookie1.isValid() == true) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.removeCookie("SID002", "google.com", "/sample"); + if (result is error) { + io:println(result); + } + cookies = cookieStore.getAllCookies(); + } + error? removeResults = file:remove(filePath, true); + return cookies; +} + +function testGetCookiesByName() returns @tainted http:Cookie[] { + http:CookieStore cookieStore = new; + http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + http:Cookie cookie2 = new("SID002", "gha74dmnmsddd34"); + cookie2.path = "/sample"; + cookie2.domain = "google.com"; http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; if (cookieConfigVal is http:CookieConfig) { - cookieStore.addCookies(cookiesToadd, cookieConfigVal, "http://google.com", "/sample"); + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + } + return cookieStore.getCookiesByName("SID002"); +} + +function testGetCookiesByDomain() returns @tainted http:Cookie[] { + http:CookieStore cookieStore = new; + http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + http:Cookie cookie2 = new("SID002", "gha74dmnmsddd34"); + cookie2.path = "/sample"; + cookie2.domain = "google.com"; + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + if (cookieConfigVal is http:CookieConfig) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + } + return cookieStore.getCookiesByDomain("google.com"); +} + +function testRemoveCookiesByDomain() returns @tainted http:Cookie[] { + http:CookieStore cookieStore = new; + http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34"); + cookie1.path = "/sample"; + cookie1.domain = "google.com"; + http:Cookie cookie2 = new("SID002", "gha74dmnmsddd34"); + cookie2.path = "/sample"; + cookie2.domain = "google.com"; + http:Client cookieClientEndpoint = new("http://google.com", { cookieConfig: { enabled: true } } ); + var cookieConfigVal = cookieClientEndpoint.config.cookieConfig; + if (cookieConfigVal is http:CookieConfig) { + var result = cookieStore.addCookie(cookie1, cookieConfigVal, "http://google.com", "/sample"); + result = cookieStore.addCookie(cookie2, cookieConfigVal, "http://google.com", "/sample"); + } + var removeResult = cookieStore.removeCookiesByDomain("google.com"); + if (removeResult is error) { + io:println(removeResult); } - cookieStore.clear(); return cookieStore.getAllCookies(); } diff --git a/stdlib/http/src/test/resources/test-src/websocket/fail_onBinary_failoverClient.bal b/stdlib/http/src/test/resources/test-src/websocket/fail_onBinary_failoverClient.bal new file mode 100644 index 000000000000..baa02ff69ca3 --- /dev/null +++ b/stdlib/http/src/test/resources/test-src/websocket/fail_onBinary_failoverClient.bal @@ -0,0 +1,29 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +service wsClientService = @http:WebSocketServiceConfig {} service { + + resource function onText(http:WebSocketFailoverClient caller, string text) { + } + + resource function onBinary(http:WebSocketClient caller, byte[] text, boolean isFinal) { + } +}; + +http:WebSocketFailoverClient wsClient = new({callbackService: wsClientService, +targetUrls: ["ws://echo.websocket.org"] }); diff --git a/stdlib/http/src/test/resources/test-src/websocket/success_failover_client.bal b/stdlib/http/src/test/resources/test-src/websocket/success_failover_client.bal new file mode 100644 index 000000000000..505eb736ebc8 --- /dev/null +++ b/stdlib/http/src/test/resources/test-src/websocket/success_failover_client.bal @@ -0,0 +1,41 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +service wsClientService = @http:WebSocketServiceConfig {} service { + + resource function onText(http:WebSocketFailoverClient caller, string text) { + } + + resource function onBinary(http:WebSocketFailoverClient caller, byte[] text, boolean isFinal) { + } + + resource function onClose(http:WebSocketFailoverClient caller, int val, string text) { + } + + resource function onIdleTimeout(http:WebSocketFailoverClient caller) { + } + + resource function onPing(http:WebSocketFailoverClient caller, byte[] data) { + } + + resource function onPong(http:WebSocketFailoverClient caller, byte[] data) { + } +}; + +http:WebSocketFailoverClient wsClient = new({callbackService: wsClientService, +targetUrls: ["ws://echo.websocket.org"] }); diff --git a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/http/sample/HTTPCookiesTestCase.java b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/http/sample/HTTPCookiesTestCase.java index b33e3205ab54..51430b4fe680 100644 --- a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/http/sample/HTTPCookiesTestCase.java +++ b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/http/sample/HTTPCookiesTestCase.java @@ -32,72 +32,141 @@ @Test(groups = "http-test") public class HTTPCookiesTestCase extends HttpBaseTest { - @Test(description = "Test send requests by cookie client for first, second and third times") + @Test(description = "Test to send requests by cookie client for first, second and third times") public void testSendRequestsByCookieClient() throws BallerinaTestException { - String balFilepath = (new File("src" + File.separator + "test" + File.separator + "resources" + + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + File.separator + "http" + File.separator + "src" + File.separator + "cookie")).getAbsolutePath(); BMainInstance bMainInstance = new BMainInstance(balServer); String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ - "cookieClient_01.bal"}, balFilepath); - Assert.assertTrue(output.contains("SID003=895gd4dmnmsddd34; SID002=178gd4dmnmsddd34; SID001=239d4dmnmsddd34")); + "cookieClient_01.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID001=239d4dmnmsddd34; SID003=895gd4dmnmsddd34; SID002=178gd4dmnmsddd34")); } - @Test(description = "Test remove session cookie by client") + @Test(description = "Test to remove a session cookie by client") public void testRemoveSessionCookieByClient() throws BallerinaTestException { - String balFilepath = (new File("src" + File.separator + "test" + File.separator + "resources" + + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + File.separator + "http" + File.separator + "src" + File.separator + "cookie")).getAbsolutePath(); BMainInstance bMainInstance = new BMainInstance(balServer); String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ - "cookieClient_02.bal"}, balFilepath); - Assert.assertTrue(output.contains("SID003=895gd4dmnmsddd34")); + "cookieClient_02.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID001=239d4dmnmsddd34")); } @Test(description = "Test sending similar session cookies in the response by server,old cookie is replaced by new" + " cookie in the cookie store") - public void testAddSimilarSessionCookie() throws BallerinaTestException { - String balFilepath = (new File("src" + File.separator + "test" + File.separator + "resources" + + public void testAddSimilarSessionCookies() throws BallerinaTestException { + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + File.separator + "http" + File.separator + "src" + File.separator + "cookie")).getAbsolutePath(); BMainInstance bMainInstance = new BMainInstance(balServer); String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ - "cookieClient_03.bal"}, balFilepath); + "cookieClient_03.bal"}, balFilePath); Assert.assertTrue(output.contains("SID002=178gd4dmnmsddd34")); } - @Test(description = "Test remove session cookie by server") + @Test(description = "Test to remove a session cookie by server") public void testRemoveSessionCookieByServer() throws BallerinaTestException { - String balFilepath = (new File("src" + File.separator + "test" + File.separator + "resources" + + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + File.separator + "http" + File.separator + "src" + File.separator + "cookie")).getAbsolutePath(); BMainInstance bMainInstance = new BMainInstance(balServer); String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ - "cookieClient_04.bal"}, balFilepath); + "cookieClient_04.bal"}, balFilePath); Assert.assertTrue(output.contains("SID002=178gd4dmnmsddd34")); } - @Test(description = "Test send concurrent requests by cookie client") + @Test(description = "Test to send concurrent requests by cookie client") public void testSendConcurrentRequests() throws BallerinaTestException { - String balFilepath = (new File("src" + File.separator + "test" + File.separator + "resources" + + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + File.separator + "http" + File.separator + "src" + File.separator + "cookie")).getAbsolutePath(); BMainInstance bMainInstance = new BMainInstance(balServer); String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ - "cookieClient_05.bal"}, balFilepath); + "cookieClient_05.bal"}, balFilePath); // Since same two cookies are sent for all concurrent requests, only two cookies are stored in the cookie store. Assert.assertTrue(output.contains("SID001") && output.contains("SID003") && output.contains("2")); } - @Test(description = "Test send requests by a client with Circuit Breaker, Retry and Cookie configurations are " + + @Test(description = "Test to send requests by a client with Circuit Breaker, Retry and Cookie configurations are " + "enabled") public void testSendRequestsByClient() throws BallerinaTestException { - String balFilepath = (new File("src" + File.separator + "test" + File.separator + "resources" + + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + File.separator + "http" + File.separator + "src" + File.separator + "cookie")).getAbsolutePath(); BMainInstance bMainInstance = new BMainInstance(balServer); String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ - "cookieClient_06.bal"}, balFilepath); - Assert.assertTrue(output.contains("SID003=895gd4dmnmsddd34; SID002=178gd4dmnmsddd34; SID001=239d4dmnmsddd34")); + "cookieClient_06.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID001=239d4dmnmsddd34; SID003=895gd4dmnmsddd34; SID002=178gd4dmnmsddd34")); + } + + @Test(description = "Test to remove a persistent cookie by the client") + public void testRemovePersistentCookieByClient() throws BallerinaTestException { + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + + File.separator + "http" + File.separator + "src" + File.separator + + "cookie")).getAbsolutePath(); + BMainInstance bMainInstance = new BMainInstance(balServer); + String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ + "cookieClient_07.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID003=895gd4dmnmsddd34")); + } + + @Test(description = "Test to send similar persistent cookies in the response by server. The old cookie is " + + "replaced by the new cookie in the cookie store") + public void testAddSimilarPersistentCookies() throws BallerinaTestException { + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + + File.separator + "http" + File.separator + "src" + File.separator + + "cookie")).getAbsolutePath(); + BMainInstance bMainInstance = new BMainInstance(balServer); + String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ + "cookieClient_08.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID001=895gd4dmnmsddd34")); + } + + @Test(description = "Test to send a session cookie and a similar persistent cookie in the response by server. The" + + " old session cookie is replaced by the new persistent cookie in the cookie store") + public void testSendSimilarPersistentAndSessionCookies_1() throws BallerinaTestException { + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + + File.separator + "http" + File.separator + "src" + File.separator + + "cookie")).getAbsolutePath(); + BMainInstance bMainInstance = new BMainInstance(balServer); + String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ + "cookieClient_09.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID003=aeaa895gd4dmnmsddd34")); + } + + @Test(description = "Test to send a persistent cookie and a similar session cookie in the response by the server." + + " The old persistent cookie is replaced by the new session cookie in the cookie store") + public void testSendSimilarPersistentAndSessionCookies_2() throws BallerinaTestException { + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + + File.separator + "http" + File.separator + "src" + File.separator + + "cookie")).getAbsolutePath(); + BMainInstance bMainInstance = new BMainInstance(balServer); + String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ + "cookieClient_10.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID003=895gd4dmnmsddd34")); + } + + @Test(description = "Test to remove a persistent cookie by the server") + public void testRemovePersistentCookieByServer() throws BallerinaTestException { + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + + File.separator + "http" + File.separator + "src" + File.separator + + "cookie")).getAbsolutePath(); + BMainInstance bMainInstance = new BMainInstance(balServer); + String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ + "cookieClient_11.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID002=178gd4dmnmsddd34")); + } + + @Test(description = "Test to send persistent cookies when the persistentCookieHandler is not configured") + public void testSendPersistentCookiesWithoutPersistentCookieHandler() throws BallerinaTestException { + String balFilePath = (new File("src" + File.separator + "test" + File.separator + "resources" + + File.separator + "http" + File.separator + "src" + File.separator + + "cookie")).getAbsolutePath(); + BMainInstance bMainInstance = new BMainInstance(balServer); + String output = bMainInstance.runMainAndReadStdOut("run", new String[]{ + "cookieClient_12.bal"}, balFilePath); + Assert.assertTrue(output.contains("SID003=895gd4dmnmsddd34")); } } diff --git a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/ClientErrorsTest.java b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/ClientErrorsTest.java index 1c861f844d74..b3859dadb3d8 100644 --- a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/ClientErrorsTest.java +++ b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/ClientErrorsTest.java @@ -91,6 +91,15 @@ public void testHandshakeError() throws InterruptedException { } + @Test(description = "Tests the ready function using the WebSocket client. When `readyOnConnect` is true," + + " calls the `ready()` function.") + public void testReadyOnConnect() throws InterruptedException { + sendTextAndAssertResponse( + "ready", + "error {ballerina/http}WsGenericError message=Already started reading frames"); + + } + private void sendTextAndAssertResponse(String msg, String expected) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(1); client.setCountDownLatch(countDownLatch); diff --git a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/FailoverClientTest.java b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/FailoverClientTest.java new file mode 100644 index 000000000000..87ec6e8cda11 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/FailoverClientTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.test.service.websocket; + +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import org.ballerinalang.test.context.BallerinaTestException; +import org.ballerinalang.test.util.websocket.client.WebSocketTestClient; +import org.ballerinalang.test.util.websocket.server.WebSocketRemoteServer; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * This Class tests failover support of the WebSocket client. + */ +@Test(groups = {"websocket-test"}) +public class FailoverClientTest extends WebSocketTestCommons { + + private WebSocketRemoteServer remoteServer15300; + private WebSocketRemoteServer remoteServer15200; + private String url = "ws://localhost:21032"; + private int port = 15300; + private String message = "hi all"; + private String text = "hi"; + + @Test(description = "Tests the failover webSocket client by starts the second server in the target URLs.") + public void testTextFrameWithSecondServer() throws URISyntaxException, InterruptedException, + BallerinaTestException { + remoteServer15200 = initiateServer(15200); + WebSocketTestClient client = initiateClient(url); + sendTextDataAndAssert(client, message); + closeConnection(client, remoteServer15200); + } + + @Test(description = "Tests the failover webSocket client by starts the first server in the target URLs.") + public void testBinaryFrameForFailover() throws URISyntaxException, InterruptedException, BallerinaTestException { + remoteServer15300 = initiateServer(port); + WebSocketTestClient client = initiateClient(url); + sendBinaryDataAndAssert(client); + closeConnection(client, remoteServer15300); + } + + @Test(description = "Tests the failover webSocket client by doesn't start the any server in the targets URLs") + public void testFailingFailover() throws URISyntaxException, InterruptedException { + CountDownLatch countDownLatch = new CountDownLatch(1); + WebSocketTestClient client = initiateClient(url); + client.setCountDownLatch(countDownLatch); + countDownLatch.await(TIMEOUT_IN_SECS, TimeUnit.SECONDS); + CloseWebSocketFrame closeWebSocketFrame = client.getReceivedCloseFrame(); + Assert.assertNotNull(closeWebSocketFrame); + Assert.assertEquals(closeWebSocketFrame.statusCode(), 1011); + Assert.assertTrue(closeWebSocketFrame.reasonText().contains("Unexpected condition")); + closeWebSocketFrame.release(); + } + + @Test(description = "Tests the failover webSocket client by starts the both server in the target URLs.") + public void testFailoverWithBothServer() throws URISyntaxException, InterruptedException, + BallerinaTestException { + remoteServer15200 = initiateServer(15200); + remoteServer15300 = initiateServer(port); + WebSocketTestClient client = initiateClient(url); + sendTextDataAndAssert(client, message); + remoteServer15300.stop(); + sendTextDataAndAssert(client, text); + sendBinaryDataAndAssert(client); + closeConnection(client, remoteServer15200); + } + + @Test(description = "Tests the failover webSocket client by starts the both server in the target URLs.") + public void testFailoverWithBothServerFirstStartSecondServer() throws URISyntaxException, InterruptedException, + BallerinaTestException { + remoteServer15200 = initiateServer(15200); + WebSocketTestClient client = initiateClient(url); + sendTextDataAndAssert(client, message); + remoteServer15300 = initiateServer(port); + remoteServer15200.stop(); + sendTextDataAndAssert(client, text); + closeConnection(client, remoteServer15300); + } + + @Test(description = "Tests handshake's waiting time exception") + public void testCountDownLatch() throws URISyntaxException, InterruptedException, BallerinaTestException { + WebSocketTestClient serverClient = initiateClient("ws://localhost:21033/basic/ws"); + remoteServer15300 = initiateServer(port); + WebSocketTestClient client = initiateClient("ws://localhost:21034"); + CountDownLatch countDownLatch1 = new CountDownLatch(1); + countDownLatch1.await(8, TimeUnit.SECONDS); + sendTextDataAndAssert(client, message); + remoteServer15300.stop(); + CountDownLatch countDownLatch = new CountDownLatch(1); + countDownLatch.await(8, TimeUnit.SECONDS); + Assert.assertEquals(client.getTextReceived(), "error {ballerina/http}WsGenericError " + + "message={ballerina/http}WsGenericError"); + client.shutDown(); + serverClient.shutDown(); + } + + private WebSocketRemoteServer initiateServer(int port) throws InterruptedException, BallerinaTestException { + WebSocketRemoteServer remoteServer = new WebSocketRemoteServer(port); + remoteServer.run(); + return remoteServer; + } + + private WebSocketTestClient initiateClient(String url) throws InterruptedException, URISyntaxException { + WebSocketTestClient client = new WebSocketTestClient(url); + client.handshake(); + return client; + } + + private void closeConnection(WebSocketTestClient client, WebSocketRemoteServer remoteServer) throws + InterruptedException { + client.shutDown(); + remoteServer.stop(); + } + + private void sendTextDataAndAssert(WebSocketTestClient client, String text) throws InterruptedException { + CountDownLatch countDownLatch = new CountDownLatch(1); + client.setCountDownLatch(countDownLatch); + client.sendText(text); + countDownLatch.await(TIMEOUT_IN_SECS, TimeUnit.SECONDS); + Assert.assertEquals(client.getTextReceived(), text); + } + + private void sendBinaryDataAndAssert(WebSocketTestClient client) throws InterruptedException { + ByteBuffer data = ByteBuffer.wrap(new byte[]{1, 2, 3, 4, 6}); + CountDownLatch countDownLatch = new CountDownLatch(1); + client.setCountDownLatch(countDownLatch); + client.sendBinary(data); + countDownLatch.await(TIMEOUT_IN_SECS, TimeUnit.SECONDS); + Assert.assertEquals(client.getBufferReceived(), data); + } +} diff --git a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/RetryClientTest.java b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/RetryClientTest.java new file mode 100644 index 000000000000..8eca7c32a508 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/RetryClientTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http:www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http:www.apache.orglicensesLICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specif ic language governing permissions and limitations + * under the License. + */ + +package org.ballerinalang.test.service.websocket; + +import org.ballerinalang.test.context.BallerinaTestException; +import org.ballerinalang.test.util.websocket.client.WebSocketTestClient; +import org.ballerinalang.test.util.websocket.server.WebSocketRemoteServer; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * This Class tests the retry support of the WebSocket client and server. + */ +@Test(groups = {"websocket-test"}) +public class RetryClientTest extends WebSocketTestCommons { + + private WebSocketRemoteServer remoteServer; + private WebSocketTestClient client; + private static final String url = "ws://localhost:21030"; + private static final int port = 15300; + + @Test(description = "Tests the retry function using the WebSocket client (Restart the server and send the data") + public void testRetry() throws URISyntaxException, InterruptedException, BallerinaTestException { + remoteServer = initiateServer(); + client = initiateClient(url); + sendTextDataAndAssert("Hi"); + restartServerAndGiveTimeClientConnectToServer(); + sendTextDataAndAssert("Hi madam"); + closeConnection(); + } + + @Test(description = "Tests the retry function with the maximum count using the WebSocket client (" + + "Restart the server twice and send the data for every restart)") + public void testMultipleRetryAttempts() throws URISyntaxException, InterruptedException, BallerinaTestException { + remoteServer = initiateServer(); + client = initiateClient(url); + sendTextDataAndAssert("Hi"); + restartServerAndGiveTimeClientConnectToServer(); + sendTextDataAndAssert("Hi madam"); + restartServerAndGiveTimeClientConnectToServer(); + sendBinaryDataAndAssert(); + closeConnection(); + } + + @Test(description = "Tests the retry function using the WebSocket client (Restart the server and " + + "check the maximum count") + public void testBinaryFrameForRetryWithMaxCount() throws URISyntaxException, InterruptedException, + BallerinaTestException { + remoteServer = initiateServer(); + client = initiateClient("ws://localhost:21031"); + sendBinaryDataAndAssert(); + restartServerAndGiveTimeClientConnectToServer(); + CountDownLatch latchForSendBinary = new CountDownLatch(1); + client.setCountDownLatch(latchForSendBinary); + client.sendBinary(ByteBuffer.wrap(new byte[]{1, 2, 3, 4, 6})); + latchForSendBinary.await(TIMEOUT_IN_SECS, TimeUnit.SECONDS); + Assert.assertNull(client.getBufferReceived()); + closeConnection(); + } + + @Test(description = "Tests the `countDownLatch` for the retry function using the WebSocket client (" + + "Restart the server and check the countDownLatch for handshake)") + public void testCountdownLatchForRetry() throws URISyntaxException, InterruptedException, BallerinaTestException { + remoteServer = initiateServer(); + client = initiateClient(url); + sendBinaryDataAndAssert(); + restartServerAndGiveTimeClientConnectToServer(); + sendBinaryDataAndAssert(); + closeConnection(); + } + + private WebSocketRemoteServer initiateServer() throws InterruptedException, BallerinaTestException { + remoteServer = new WebSocketRemoteServer(port); + remoteServer.run(); + return remoteServer; + } + + private WebSocketTestClient initiateClient(String url) throws InterruptedException, URISyntaxException { + client = new WebSocketTestClient(url); + client.handshake(); + return client; + } + + private void closeConnection() throws InterruptedException { + client.shutDown(); + remoteServer.stop(); + } + + private void restartServerAndGiveTimeClientConnectToServer() throws InterruptedException, BallerinaTestException { + remoteServer.stop(); + CountDownLatch latchForRestart = new CountDownLatch(1); + latchForRestart.await(7, TimeUnit.SECONDS); + remoteServer.run(); + latchForRestart.await(2, TimeUnit.SECONDS); + } + + private void sendTextDataAndAssert(String text) throws InterruptedException { + CountDownLatch countDownLatch = new CountDownLatch(1); + client.setCountDownLatch(countDownLatch); + client.sendText(text); + countDownLatch.await(TIMEOUT_IN_SECS, TimeUnit.SECONDS); + Assert.assertEquals(client.getTextReceived(), text); + } + + private void sendBinaryDataAndAssert() throws InterruptedException { + ByteBuffer data = ByteBuffer.wrap(new byte[]{1, 2, 3, 4, 6}); + CountDownLatch countDownLatch = new CountDownLatch(1); + client.setCountDownLatch(countDownLatch); + client.sendBinary(data); + countDownLatch.await(TIMEOUT_IN_SECS, TimeUnit.SECONDS); + Assert.assertEquals(client.getBufferReceived(), data); + } +} diff --git a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/SimpleProxyTestCommons.java b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/SimpleProxyTestCommons.java index ce3de0252ec7..85e707572f4a 100644 --- a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/SimpleProxyTestCommons.java +++ b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/SimpleProxyTestCommons.java @@ -83,7 +83,7 @@ public void testSendBinary() throws URISyntaxException, InterruptedException { } @AfterClass(description = "Stops Ballerina") - public void cleanup() { + public void cleanup() throws InterruptedException { remoteServer.stop(); } } diff --git a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/WebSocketTestCommons.java b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/WebSocketTestCommons.java index 6987a978215d..979da1995146 100644 --- a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/WebSocketTestCommons.java +++ b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/service/websocket/WebSocketTestCommons.java @@ -46,7 +46,7 @@ public void start() throws BallerinaTestException { int[] requiredPorts = new int[]{21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21009, 21010, 21011, 21022, 21021, 21012, 21013, 21014, 21015, 21016, 21017, 21018, 21019, 21020, 21023, 21024, 21025, 21026, - 21027, 21028, 21029}; + 21027, 21028, 21029, 21030, 21031, 21032, 21033, 21034}; String balFile = new File("src" + File.separator + "test" + File.separator + "resources" + File.separator + "websocket").getAbsolutePath(); String keyStore = StringEscapeUtils.escapeJava( diff --git a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/util/websocket/server/WebSocketRemoteServer.java b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/util/websocket/server/WebSocketRemoteServer.java index 497ad3703d3e..440860ff13d1 100644 --- a/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/util/websocket/server/WebSocketRemoteServer.java +++ b/tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/util/websocket/server/WebSocketRemoteServer.java @@ -63,10 +63,10 @@ public void run() throws InterruptedException, BallerinaTestException { bootstrap.bind(port).sync(); } - public void stop() { + public void stop() throws InterruptedException { log.info("Shutting down websocket remote server at '" + port + "'"); - bossGroup.shutdownGracefully(); - workerGroup.shutdownGracefully(); + bossGroup.shutdownGracefully().sync(); + workerGroup.shutdownGracefully().sync(); Utils.waitForPortsToClose(new int[]{port}, 30000); } } diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_01.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_01.bal index 4660aa3d4695..c3d860cf35fe 100644 --- a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_01.bal +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_01.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. // // WSO2 Inc. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except @@ -14,24 +14,27 @@ // specific language governing permissions and limitations // under the License. +import ballerina/file; import ballerina/http; import ballerina/io; public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-1.csv"); http:Client cookieClientEndpoint = new ("http://localhost:9253", { - cookieConfig: { enabled: true } + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } }); http:Request req = new; - // Server sends the session cookies in the response for the first request. - var response = cookieClientEndpoint->get("/cookie/cookieBackend", req); - // Second request is with cookie header and server sends more cookies in the response. - response = cookieClientEndpoint->get("/cookie/cookieBackend", req); - // Third request is with cookie header including all relevant session cookies. - response = cookieClientEndpoint->get("/cookie/cookieBackend", req); + // Server sends the cookies in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + // Second request is with a cookie header and server sends more cookies in the response. + response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + // Third request is with the cookie header including all relevant cookies. + response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); if (response is http:Response) { var payload = response.getTextPayload(); if (payload is string) { io:print(payload); } } + error? removeResults = file:remove("./cookie-test-data", true); // Removes persistent store file. } diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_02.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_02.bal index 9b2830ad6d82..fd26db2a1223 100644 --- a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_02.bal +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_02.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. // // WSO2 Inc. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except @@ -14,27 +14,33 @@ // specific language governing permissions and limitations // under the License. +import ballerina/file; import ballerina/http; import ballerina/io; public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-2.csv"); http:Client cookieClientEndpoint = new ("http://localhost:9253", { - cookieConfig: { enabled: true } + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } }); http:Request req = new; - // Server sends the session cookies in the response for the first request. - var response = cookieClientEndpoint->get("/cookie/cookieBackend", req); + // Server sends cookies in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); // Removes a session cookie. http:CookieStore? myCookieStore = cookieClientEndpoint.getCookieStore(); if (myCookieStore is http:CookieStore) { - boolean isRemoved = myCookieStore.removeCookie("SID001", "localhost:9253", "/cookie"); + var removeResult = myCookieStore.removeCookie("SID003", "localhost:9253", "/cookie/cookieBackend_1"); + if (removeResult is error) { + io:println(removeResult); + } } // Sends a request again after one session cookie is removed. - response = cookieClientEndpoint->get("/cookie/cookieBackend", req); + response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); if (response is http:Response) { var payload = response.getTextPayload(); if (payload is string) { io:print(payload); } } + error? removeResults = file:remove("./cookie-test-data", true); } diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_03.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_03.bal index 4de2b0e1c7df..83bf98b0508b 100644 --- a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_03.bal +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_03.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. // // WSO2 Inc. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except @@ -22,7 +22,7 @@ public function main() { cookieConfig: { enabled: true } }); http:Request req = new; - // Server sends similar session cookies in the response for the first request.. + // Server sends similar session cookies in the response for the first request. var response = cookieClientEndpoint->get("/cookie/cookieBackend_2", req); // Sends second request after replacing the old cookie with the new. response = cookieClientEndpoint->get("/cookie/cookieBackend_2", req); diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_04.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_04.bal index c692495b7506..f2946ed66eb4 100644 --- a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_04.bal +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_04.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. // // WSO2 Inc. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except @@ -18,13 +18,14 @@ import ballerina/http; import ballerina/io; public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookies-test-data/client-4.csv"); http:Client cookieClientEndpoint = new ("http://localhost:9253", { - cookieConfig: { enabled: true, enablePersistence: true } + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } }); http:Request req = new; // Server sends the session cookies in the response for the first request. var response = cookieClientEndpoint->get("/cookie/cookieBackend_3", req); - // Server sends an expired cookie in the response in order to remove the existing cookie in the cookie store. + // Server removes an existing session cookie in the cookie store by sending an expired cookie in the response. response = cookieClientEndpoint->get("/cookie/cookieBackend_3", req); // Third request after removing the cookie. response = cookieClientEndpoint->get("/cookie/cookieBackend_3", req); diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_05.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_05.bal index 9a2af54af956..a483a25505ce 100644 --- a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_05.bal +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_05.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. // // WSO2 Inc. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except @@ -14,28 +14,30 @@ // specific language governing permissions and limitations // under the License. +import ballerina/file; import ballerina/http; import ballerina/io; public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-5.csv"); http:Client cookieClientEndpoint = new ("http://localhost:9253", { - cookieConfig: { enabled: true } + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } }); worker w1 { http:Request req = new; - var response = cookieClientEndpoint->get("/cookie/cookieBackend", req); + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); } worker w2 { http:Request req = new; - var response = cookieClientEndpoint->get("/cookie/cookieBackend", req); + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); } worker w3 { http:Request req = new; - var response = cookieClientEndpoint->get("/cookie/cookieBackend", req); + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); } worker w4 { http:Request req = new; - var response = cookieClientEndpoint->get("/cookie/cookieBackend", req); + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); } _ = wait {w1, w2, w3, w4}; http:CookieStore? myCookieStore = cookieClientEndpoint.getCookieStore(); @@ -46,4 +48,5 @@ public function main() { io:println(item.name); } } + error? removeResults = file:remove("./cookie-test-data", true); } diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_06.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_06.bal index 13b3c4c2e483..0cf0851e15b6 100644 --- a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_06.bal +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_06.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. // // WSO2 Inc. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except @@ -14,10 +14,12 @@ // specific language governing permissions and limitations // under the License. +import ballerina/file; import ballerina/http; import ballerina/io; public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-6.csv"); http:Client cookieClientEndpoint = new ("http://localhost:9253", { retryConfig: { intervalInMillis: 3000, @@ -36,20 +38,22 @@ public function main() { statusCodes: [400, 404, 500] }, cookieConfig: { - enabled: true + enabled: true, + persistentCookieHandler: myPersistentStore } }); http:Request req = new; - // Server sends the session cookies in the response for the first request. - var response = cookieClientEndpoint->get("/cookie/cookieBackend", req); - // Second request is with cookie header and server sends more cookies in the response. - response = cookieClientEndpoint->get("/cookie/cookieBackend", req); - // Third request is with cookie header including all relevant session cookies. - response = cookieClientEndpoint->get("/cookie/cookieBackend", req); + // Server sends cookies in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + // Second request is with a cookie header and server sends more cookies in the response. + response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + // Third request is with the cookie header including all relevant cookies. + response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); if (response is http:Response) { var payload = response.getTextPayload(); if (payload is string) { io:print(payload); } } + error? removeResults = file:remove("./cookie-test-data", true); } diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_07.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_07.bal new file mode 100644 index 000000000000..74cd8bcb2446 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_07.bal @@ -0,0 +1,46 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/file; +import ballerina/http; +import ballerina/io; + +public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-7.csv"); + http:Client cookieClientEndpoint = new ("http://localhost:9253", { + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } + }); + http:Request req = new; + // Server sends the cookies in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + // Removes a persistent cookie. + http:CookieStore? myCookieStore = cookieClientEndpoint.getCookieStore(); + if (myCookieStore is http:CookieStore) { + var removeResult = myCookieStore.removeCookie("SID001", "localhost:9253", "/cookie/cookieBackend_1"); + if (removeResult is error) { + io:println(removeResult); + } + } + // Sends a request again after one persistent cookie is removed. + response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + if (response is http:Response) { + var payload = response.getTextPayload(); + if (payload is string) { + io:print(payload); + } + } + error? removeResults = file:remove("./cookie-test-data", true); +} diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_08.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_08.bal new file mode 100644 index 000000000000..076f651d5389 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_08.bal @@ -0,0 +1,38 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/file; +import ballerina/http; +import ballerina/io; + +public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-8.csv"); + http:Client cookieClientEndpoint = new ("http://localhost:9253", { + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } + }); + http:Request req = new; + // Server sends similar persistent cookies in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_4", req); + // Sends the second request after replacing the old cookie with the new. + response = cookieClientEndpoint->get("/cookie/cookieBackend_4", req); + if (response is http:Response) { + var payload = response.getTextPayload(); + if (payload is string) { + io:print(payload); + } + } + error? removeResults = file:remove("./cookie-test-data", true); +} diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_09.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_09.bal new file mode 100644 index 000000000000..9fda464c867d --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_09.bal @@ -0,0 +1,38 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/file; +import ballerina/http; +import ballerina/io; + +public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-9.csv"); + http:Client cookieClientEndpoint = new ("http://localhost:9253", { + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } + }); + http:Request req = new; + // Server sends a session cookie and a similar persistent cookie in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_5", req); + // Sends the second request after replacing the session cookie with the new persistent cookie. + response = cookieClientEndpoint->get("/cookie/cookieBackend_5", req); + if (response is http:Response) { + var payload = response.getTextPayload(); + if (payload is string) { + io:print(payload); + } + } + error? removeResults = file:remove("./cookie-test-data", true); +} diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_10.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_10.bal new file mode 100644 index 000000000000..43614c9122ec --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_10.bal @@ -0,0 +1,38 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/file; +import ballerina/http; +import ballerina/io; + +public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-10.csv"); + http:Client cookieClientEndpoint = new ("http://localhost:9253", { + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } + }); + http:Request req = new; + // Server sends a persistent cookie and a similar session cookie in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_6", req); + // Sends the second request after replacing the persistent cookie with the new session cookie. + response = cookieClientEndpoint->get("/cookie/cookieBackend_6", req); + if (response is http:Response) { + var payload = response.getTextPayload(); + if (payload is string) { + io:print(payload); + } + } + error? removeResults = file:remove("./cookie-test-data", true); +} diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_11.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_11.bal new file mode 100644 index 000000000000..27d48ece4ecd --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_11.bal @@ -0,0 +1,40 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/file; +import ballerina/http; +import ballerina/io; + +public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-11.csv"); + http:Client cookieClientEndpoint = new ("http://localhost:9253", { + cookieConfig: { enabled: true, persistentCookieHandler: myPersistentStore } + }); + http:Request req = new; + // Server sends cookies in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_7", req); + // Server removes an existing persistent cookie in the cookie store by sending an expired cookie in the response. + response = cookieClientEndpoint->get("/cookie/cookieBackend_7", req); + // Third request is sent after removing the cookie. + response = cookieClientEndpoint->get("/cookie/cookieBackend_7", req); + if (response is http:Response) { + var payload = response.getTextPayload(); + if (payload is string) { + io:print(payload); + } + } + error? removeResults = file:remove("./cookie-test-data", true); +} diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_12.bal b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_12.bal new file mode 100644 index 000000000000..c19c4a2f4907 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/http/src/cookie/cookieClient_12.bal @@ -0,0 +1,40 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/file; +import ballerina/http; +import ballerina/io; + +public function main() { + http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-12.csv"); + http:Client cookieClientEndpoint = new ("http://localhost:9253", { + cookieConfig: { enabled: true } + }); + http:Request req = new; + // Server sends the cookies in the response for the first request. + var response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + // Second request is with a cookie header and server sends more cookies in the response. + response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + // Third request is sent with the cookie header including all relevant cookies. + response = cookieClientEndpoint->get("/cookie/cookieBackend_1", req); + if (response is http:Response) { + var payload = response.getTextPayload(); + if (payload is string) { + io:print(payload); + } + } + error? removeResults = file:remove("./cookie-test-data", true); // Removes persistent store file. +} diff --git a/tests/jballerina-integration-test/src/test/resources/http/src/httpservices/43_http_cookies.bal b/tests/jballerina-integration-test/src/test/resources/http/src/httpservices/43_http_cookies.bal index d4832c984982..be5f16040306 100644 --- a/tests/jballerina-integration-test/src/test/resources/http/src/httpservices/43_http_cookies.bal +++ b/tests/jballerina-integration-test/src/test/resources/http/src/httpservices/43_http_cookies.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2019 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. // // WSO2 Inc. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except @@ -23,24 +23,25 @@ service cookie on new http:Listener(9253) { @http:ResourceConfig { methods: ["GET"], - path: "/cookieBackend" + path: "/cookieBackend_1" } - resource function addSessionCookies(http:Caller caller, http:Request req) { - // Creates the cookies. + resource function addPersistentAndSessionCookies(http:Caller caller, http:Request req) { http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34"); - cookie1.path = "/cookie"; + cookie1.path = "/cookie/cookieBackend_1"; cookie1.domain = "localhost:9253"; cookie1.httpOnly = true; cookie1.secure = false; + cookie1.expires = "2030-06-26 05:46:22"; http:Cookie cookie2 = new("SID002", "178gd4dmnmsddd34"); - cookie2.path = "/cookie/cookieBackend"; + cookie2.path = "/cookie/cookieBackend_1"; cookie2.domain = "localhost:9253"; cookie2.httpOnly = true; cookie2.secure = false; + cookie2.expires = "2030-07-15 05:46:22"; http:Cookie cookie3 = new("SID003", "895gd4dmnmsddd34"); - cookie3.path = "/cookie/cookieBackend"; + cookie3.path = "/cookie/cookieBackend_1"; cookie3.domain = "localhost:9253"; cookie3.httpOnly = true; cookie3.secure = false; @@ -109,6 +110,138 @@ service cookie on new http:Listener(9253) { cookie2.httpOnly = true; cookie2.secure = false; + http:Response res = new; + http:Cookie[] reqstCookies=req.getCookies(); + // Adds cookies if there are no cookies in the inbound request. + if (reqstCookies.length() == 0) { + res.addCookie(cookie1); + res.addCookie(cookie2); + var result = caller->respond(res); + } else if (reqstCookies.length() == 2) { + res.removeCookiesFromRemoteStore(cookie1); + var result = caller->respond(res); + } else { + string cookieHeader = req.getHeader("Cookie"); + res.setPayload(<@untainted> cookieHeader); + var result = caller->respond(res); + } + } + + @http:ResourceConfig { + methods: ["GET"], + path: "/cookieBackend_4" + } + resource function sendSimilarPersistentCookies(http:Caller caller, http:Request req) { + http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34"); + cookie1.path = "/cookie/cookieBackend_4"; + cookie1.domain = "localhost:9253"; + cookie1.httpOnly = false; + cookie1.secure = false; + cookie1.expires = "2030-06-26 05:46:22"; + + http:Cookie cookie3 = new("SID001", "895gd4dmnmsddd34"); + cookie3.path = "/cookie/cookieBackend_4"; + cookie3.domain = "localhost:9253"; + cookie3.httpOnly = true; + cookie3.secure = false; + cookie3.expires = "2030-06-26 05:46:22"; + http:Response res = new; + + http:Cookie[] reqstCookies=req.getCookies(); + // Adds cookies if there are no cookies in the inbound request. + if (reqstCookies.length() == 0) { + res.addCookie(cookie1); + res.addCookie(cookie3); + var result = caller->respond(res); + } else { + string cookieHeader = req.getHeader("Cookie"); + res.setPayload(<@untainted> cookieHeader); + var result = caller->respond(res); + } + } + + @http:ResourceConfig { + methods: ["GET"], + path: "/cookieBackend_5" + } + resource function sendSimilarPersistentAndSessionCookies_1(http:Caller caller, http:Request req) { + http:Cookie cookie2 = new("SID003", "895gd4dmnmsddd34"); + cookie2.path = "/cookie/cookieBackend_5"; + cookie2.domain = "localhost:9253"; + cookie2.httpOnly = true; + cookie2.secure = false; + + http:Cookie cookie3 = new("SID003", "aeaa895gd4dmnmsddd34"); + cookie3.path = "/cookie/cookieBackend_5"; + cookie3.domain = "localhost:9253"; + cookie3.httpOnly = false; + cookie3.secure = false; + cookie3.expires = "2030-07-15 05:46:22"; + + http:Response res = new; + http:Cookie[] reqstCookies=req.getCookies(); + // Adds cookies if there are no cookies in the inbound request. + if (reqstCookies.length() == 0) { + res.addCookie(cookie2); // Adds a session cookie. + res.addCookie(cookie3); // Adds a similar persistent cookie. + var result = caller->respond(res); + } else { + string cookieHeader = req.getHeader("Cookie"); + res.setPayload(<@untainted> cookieHeader); + var result = caller->respond(res); + } + } + + @http:ResourceConfig { + methods: ["GET"], + path: "/cookieBackend_6" + } + resource function sendSimilarPersistentAndSessionCookies_2(http:Caller caller, http:Request req) { + http:Cookie cookie2 = new("SID003", "aeaa895gd4dmnmsddd34"); + cookie2.path = "/cookie/cookieBackend_6"; + cookie2.domain = "localhost:9253"; + cookie2.httpOnly = false; + cookie2.secure = false; + cookie2.expires = "2030-07-15 05:46:22"; + + http:Cookie cookie3 = new("SID003", "895gd4dmnmsddd34"); + cookie3.path = "/cookie/cookieBackend_6"; + cookie3.domain = "localhost:9253"; + cookie3.httpOnly = true; + cookie3.secure = false; + + http:Response res = new; + http:Cookie[] reqstCookies=req.getCookies(); + // Adds cookies if there are no cookies in the inbound request. + if (reqstCookies.length() == 0) { + res.addCookie(cookie2); // Adds a persistent cookie. + res.addCookie(cookie3); // Adds a similar session cookie. + var result = caller->respond(res); + } else { + string cookieHeader = req.getHeader("Cookie"); + res.setPayload(<@untainted> cookieHeader); + var result = caller->respond(res); + } + } + + @http:ResourceConfig { + methods: ["GET"], + path: "/cookieBackend_7" + } + resource function removePersistentCookieByServer(http:Caller caller, http:Request req) { + // Creates the cookies. + http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34"); + cookie1.path = "/cookie/cookieBackend_7"; + cookie1.domain = "localhost:9253"; + cookie1.httpOnly = true; + cookie1.expires = "2030-07-15 05:46:22"; + + http:Cookie cookie2 = new("SID002", "178gd4dmnmsddd34"); + cookie2.path = "/cookie/cookieBackend_7"; + cookie2.domain = "localhost:9253"; + cookie2.httpOnly = true; + cookie2.secure = false; + http:Response res = new; http:Cookie[] reqstCookies=req.getCookies(); // Adds cookies if there are no cookies in the inbound request. diff --git a/tests/jballerina-integration-test/src/test/resources/testng.xml b/tests/jballerina-integration-test/src/test/resources/testng.xml index cf5a27231224..7ffbe9e75a82 100644 --- a/tests/jballerina-integration-test/src/test/resources/testng.xml +++ b/tests/jballerina-integration-test/src/test/resources/testng.xml @@ -185,6 +185,8 @@ + + diff --git a/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/27_client_exceptions.bal b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/27_client_exceptions.bal index 026c3120d931..0f261271e32e 100644 --- a/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/27_client_exceptions.bal +++ b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/27_client_exceptions.bal @@ -49,7 +49,14 @@ service clientError on new http:Listener(21027) { checkpanic wsEp->pushText(err.toString()); } } else if (text == "handshake") { - http:WebSocketClient wsClientEp = new (REMOTE_BACKEND_URL, {callbackService: errorResourceService, subProtocols: ["abc"]}); + http:WebSocketClient wsClientEp = new (REMOTE_BACKEND_URL, {callbackService: errorResourceService, + subProtocols: ["abc"]}); + } else if (text == "ready") { + http:WebSocketClient wsClientEp = new (REMOTE_BACKEND_URL, {callbackService: errorResourceService}); + var returnVal = wsClientEp->ready(); + if (returnVal is error) { + checkpanic wsEp->pushText(returnVal.toString()); + } } else { checkpanic wsEp->pushText(text); } diff --git a/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/30_retry_client.bal b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/30_retry_client.bal new file mode 100644 index 000000000000..d859486733b2 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/30_retry_client.bal @@ -0,0 +1,62 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +@http:WebSocketServiceConfig { +} +service on new http:Listener(21030) { + + resource function onOpen(http:WebSocketCaller wsEp) { + http:WebSocketClient wsClientEp = new("ws://localhost:15300/websocket", { callbackService: + retryClientCallbackService, readyOnConnect: false, retryConfig: {}, handShakeTimeoutInSeconds: 5}); + wsEp.setAttribute(ASSOCIATED_CONNECTION, wsClientEp); + wsClientEp.setAttribute(ASSOCIATED_CONNECTION, wsEp); + checkpanic wsClientEp->ready(); + } + + resource function onText(http:WebSocketCaller wsEp, string text) { + http:WebSocketClient clientEp = getAssociatedClientEndpoint(wsEp); + checkpanic clientEp->pushText(text); + } + + resource function onBinary(http:WebSocketCaller wsEp, byte[] data) { + http:WebSocketClient clientEp = getAssociatedClientEndpoint(wsEp); + checkpanic clientEp->pushBinary(data); + } + + resource function onClose(http:WebSocketCaller wsEp, int statusCode, string reason) { + http:WebSocketClient clientEp = getAssociatedClientEndpoint(wsEp); + checkpanic clientEp->close(statusCode, reason); + } +} + +service retryClientCallbackService = @http:WebSocketServiceConfig {} service { + resource function onText(http:WebSocketClient wsEp, string text) { + http:WebSocketCaller serviceEp = getAssociatedListener(wsEp); + checkpanic serviceEp->pushText(text); + } + + resource function onBinary(http:WebSocketClient wsEp, byte[] data) { + http:WebSocketCaller serviceEp = getAssociatedListener(wsEp); + checkpanic serviceEp->pushBinary(data); + } + + resource function onClose(http:WebSocketClient wsEp, int statusCode, string reason) { + http:WebSocketCaller serviceEp = getAssociatedListener(wsEp); + checkpanic serviceEp->close(statusCode = statusCode, reason = reason); + } +}; diff --git a/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/31_retry_client_with_configurations.bal b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/31_retry_client_with_configurations.bal new file mode 100644 index 000000000000..1d4393b99396 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/31_retry_client_with_configurations.bal @@ -0,0 +1,53 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +@http:WebSocketServiceConfig { +} +service on new http:Listener(21031) { + + resource function onOpen(http:WebSocketCaller wsEp) { + http:WebSocketClient wsClientEp = new("ws://localhost:15300/websocket", { callbackService: + retryCallbackService, readyOnConnect: false, retryConfig: {maxCount: 10, intervalInMillis: 500, + backOffFactor: 0.5}}); + wsEp.setAttribute(ASSOCIATED_CONNECTION, wsClientEp); + wsClientEp.setAttribute(ASSOCIATED_CONNECTION, wsEp); + checkpanic wsClientEp->ready(); + } + + resource function onText(http:WebSocketCaller wsEp, string text) { + http:WebSocketClient clientEp = getAssociatedClientEndpoint(wsEp); + checkpanic clientEp->pushText(text); + } + + resource function onBinary(http:WebSocketCaller wsEp, byte[] data) { + http:WebSocketClient clientEp = getAssociatedClientEndpoint(wsEp); + checkpanic clientEp->pushBinary(data); + } +} + +service retryCallbackService = @http:WebSocketServiceConfig {} service { + resource function onText(http:WebSocketClient wsEp, string text) { + http:WebSocketCaller serviceEp = getAssociatedListener(wsEp); + checkpanic serviceEp->pushText(text); + } + + resource function onBinary(http:WebSocketClient wsEp, byte[] data) { + http:WebSocketCaller serviceEp = getAssociatedListener(wsEp); + checkpanic serviceEp->pushBinary(data); + } +}; diff --git a/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/32_failover_client.bal b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/32_failover_client.bal new file mode 100644 index 000000000000..9b18a891d10a --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/32_failover_client.bal @@ -0,0 +1,97 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +@http:WebSocketServiceConfig { +} +service on new http:Listener(21032) { + + resource function onOpen(http:WebSocketCaller wsEp) { + http:WebSocketFailoverClient wsClientEp = new({ callbackService:failoverClientCallbackService, + readyOnConnect: false, targetUrls:["ws://localhost:15300/websocket", "ws://localhost:15200/websocket"], + failoverIntervalInMillis: 900 }); + + wsEp.setAttribute(ASSOCIATED_CONNECTION, wsClientEp); + wsClientEp.setAttribute(ASSOCIATED_CONNECTION, wsEp); + var returnVal = wsClientEp->ready(); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } + + resource function onText(http:WebSocketCaller wsEp, string text) { + http:WebSocketFailoverClient clientEp = getAssociatedFailoverClientEndpoint(wsEp); + var returnVal = clientEp->pushText(text); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } + + resource function onBinary(http:WebSocketCaller wsEp, byte[] data) { + http:WebSocketFailoverClient clientEp = getAssociatedFailoverClientEndpoint(wsEp); + var returnVal = clientEp->pushBinary(data); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } + + resource function onClose(http:WebSocketCaller wsEp, int statusCode, string reason) { + http:WebSocketFailoverClient clientEp = getAssociatedFailoverClientEndpoint(wsEp); + var returnVal = clientEp->close(statusCode = statusCode, reason = reason); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } +} + +service failoverClientCallbackService = @http:WebSocketServiceConfig {} service { + + resource function onText(http:WebSocketFailoverClient wsEp, string text) { + http:WebSocketCaller serviceEp = getAssociatedFailoverListener(wsEp); + var returnVal = serviceEp->pushText(text); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } + + resource function onBinary(http:WebSocketFailoverClient wsEp, byte[] data) { + http:WebSocketCaller serviceEp = getAssociatedFailoverListener(wsEp); + var returnVal = serviceEp->pushBinary(data); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } + + resource function onClose(http:WebSocketFailoverClient wsEp, int statusCode, string reason) { + http:WebSocketCaller serviceEp = getAssociatedFailoverListener(wsEp); + var returnVal = serviceEp->close(statusCode = statusCode, reason = reason); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } + }; + +public function getAssociatedFailoverClientEndpoint(http:WebSocketCaller wsServiceEp) +returns (http:WebSocketFailoverClient) { + var returnVal = wsServiceEp.getAttribute(ASSOCIATED_CONNECTION); + return returnVal; +} + +public function getAssociatedFailoverListener(http:WebSocketFailoverClient wsClientEp) returns (http:WebSocketCaller) { + var returnVal = wsClientEp.getAttribute(ASSOCIATED_CONNECTION); + return returnVal; +} diff --git a/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/33_server.bal b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/33_server.bal new file mode 100644 index 000000000000..18a1a6c48793 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/33_server.bal @@ -0,0 +1,63 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; +import ballerina/io; +import ballerina/runtime; + +int counter = 1; +@http:ServiceConfig { + basePath: "/basic" +} +service httpService on new http:Listener(21033) { + @http:ResourceConfig { + path: "/world", + methods: ["POST"] + } + resource function httpResource(http:Caller caller, http:Request req) { + http:Response resp = new; + var payload = req.getTextPayload(); + if (payload is error) { + resp.setPayload("Error in payload"); + resp.statusCode = 500; + } else { + resp.setPayload(string `HTTP POST received: {payload}`); + } + + var err = caller->respond(resp); + if (err is error) { + panic err; + } + } + @http:ResourceConfig { + webSocketUpgrade: { + upgradePath: "/ws", + upgradeService: wsService + } + } + resource function upgrader(http:Caller caller, http:Request req) { + if (counter > 1) { + runtime:sleep(500000); + } + counter = counter + 1; + } +} +service wsService = @http:WebSocketServiceConfig {subProtocols: ["xml, json"]} service { + + resource function onOpen(http:WebSocketCaller caller) { + io:println("New WebSocket connection: " + caller.getConnectionId()); + } +}; diff --git a/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/34_counDown_latch.bal b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/34_counDown_latch.bal new file mode 100644 index 000000000000..9a3d033f6e33 --- /dev/null +++ b/tests/jballerina-integration-test/src/test/resources/websocket/src/wsservices/34_counDown_latch.bal @@ -0,0 +1,63 @@ +// Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/http; + +@http:WebSocketServiceConfig { +} +service on new http:Listener(21034) { + + resource function onOpen(http:WebSocketCaller wsEp) { + http:WebSocketFailoverClient wsClientEp = new({ callbackService:countDownService, + readyOnConnect: false, targetUrls:["ws://localhost:15300/websocket", + "ws://localhost:21033/basic/ws"], handShakeTimeoutInSeconds:7 }); + + wsEp.setAttribute(ASSOCIATED_CONNECTION, wsClientEp); + wsClientEp.setAttribute(ASSOCIATED_CONNECTION, wsEp); + var returnVal = wsClientEp->ready(); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } + + resource function onText(http:WebSocketCaller wsEp, string text) { + http:WebSocketFailoverClient clientEp = getAssociatedFailoverClientEndpoint(wsEp); + var returnVal = clientEp->pushText(text); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } +} + +service countDownService = @http:WebSocketServiceConfig {} service { + + resource function onText(http:WebSocketFailoverClient wsEp, string text) { + http:WebSocketCaller serviceEp = getAssociatedFailoverListener(wsEp); + var returnVal = serviceEp->pushText(text); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } + + //This resource gets invoked when an error occurs in the connection. + resource function onError(http:WebSocketFailoverClient wsEp, error err) { + http:WebSocketCaller serviceEp = getAssociatedFailoverListener(wsEp); + var returnVal = serviceEp->pushText(err.toString()); + if (returnVal is http:WebSocketError) { + panic returnVal; + } + } +}; diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/string/StringValueBasicsTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/string/StringValueBasicsTest.java index a675bf8d3084..c63234247c64 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/string/StringValueBasicsTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/types/string/StringValueBasicsTest.java @@ -56,6 +56,12 @@ public void testNonBMPStringLength() { Assert.assertEquals(((BInteger) returns[0]).intValue(), 5); } + @Test + public void testRecordStringValuePut() { + BValue[] returns = BRunUtil.invoke(result, "recordStringValuePut"); + //TODO assert return value has BString + } + @Test public void testError() { BValue[] returns = BRunUtil.invoke(result, "testError"); diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/types/string/string-value-test.bal b/tests/jballerina-unit-test/src/test/resources/test-src/types/string/string-value-test.bal index 77a70077fa86..7b5945e22fc0 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/types/string/string-value-test.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/types/string/string-value-test.bal @@ -9,6 +9,12 @@ function nonBMPLength() returns (int) { return smiley.length(); } +function recordStringValuePut() returns () { + string smiley = "h😀llo"; + record {| string myField; |} r = {myField: smiley}; + //TODO: return r +} + function testError() returns int { string smiley = "h🤷llo"; error err = error(smiley);