From d29f574d487ac9c214edd1665cf4c681416e2616 Mon Sep 17 00:00:00 2001 From: luca364 Date: Wed, 25 Feb 2026 11:14:16 +0100 Subject: [PATCH 1/5] feat: add test for creating records with special characters in POST request --- test/request-types/TestPOST.bbjt | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/request-types/TestPOST.bbjt b/test/request-types/TestPOST.bbjt index c5d5e91..60e1bb1 100644 --- a/test/request-types/TestPOST.bbjt +++ b/test/request-types/TestPOST.bbjt @@ -101,6 +101,67 @@ class public TestPOST rem comparing the JSON Strings Assert.Equals(actualRow!.toJson(0), #insertRow!.toJson(0)) methodend + + rem @Test + method public void testCreateRecordWithSpecialCharactersInBody() + declare ResultSet resultSet! + resultSet! = #chileCustomerBC!.retrieve() + initialSize = resultSet!.size() + + special_first$ = "ÄÖÜß" + special_last$ = "ÉÁäöüßéá" + + rem Prepare a row that uses the special characters + rowWithSpecial! = #insertRow!.clone() + rowWithSpecial!.setFieldValue("FIRST_NAME", special_first$) + rowWithSpecial!.setFieldValue("LAST_NAME", special_last$) + + #uriBuilder!.setPath(#configurator!.getRestBridgeMapping() + "ChileCustomer") + + declare HttpPost request! + request! = #configurator!.getRequestPOST(#uriBuilder!) + request!.setHeader("Accept", "application/json") + request!.setHeader("Content-Type", "application/json; charset=UTF-8") + + entity! = EntityBuilder.create().setText(rowWithSpecial!.toJson()).setContentType(ContentType.create("application/json", "UTF-8")).build() + request!.setEntity(entity!) + + declare HttpResponse response! + response! = #client!.execute(request!) + + rem verify that the request was executed successfully + Assert.Equals(response!.getStatusLine().getStatusCode(), 201) + + rem checking that the record was actually created + resultSet! = #chileCustomerBC!.retrieve() + Assert.Equals(initialsize +1, resultSet!.size()) + + rem Read back the record via the BC to validate what was written + declare DataRow filter! + filter! = new DataRow() + filter!.setFieldValue("CUST_NUM", rowWithSpecial!.getFieldAsString("CUST_NUM")) + #chileCustomerBC!.setFilter(filter!) + resultSet! = #chileCustomerBC!.retrieve() + Assert.Equals(resultSet!.size(), 1) + + declare DataRow storedRow! + storedRow! = resultSet!.get(0) + Assert.Equals(storedRow!.getFieldAsString("FIRST_NAME"), special_first$) + Assert.Equals(storedRow!.getFieldAsString("LAST_NAME"), special_last$) + + rem Also validate the echoed response body from RestBridge + declare ResultSet responseRS! + responseRS! = ResultSet.fromJson(#configurator!.getResultAsString(response!)) + + rem the result set shouldn't be null + Assert.IsNotNull(responseRS!) + Assert.Equals(responseRS!.size(), 1) + + declare DataRow responseRow! + responseRow! = responseRS!.get(0) + Assert.Equals(responseRow!.getFieldAsString("FIRST_NAME"), special$) + Assert.Equals(responseRow!.getFieldAsString("LAST_NAME"), special$) + methodend rem @Test method public void testUpdateRecordDataRowBody() From 72d812d084e3eeaf948fe927fddff0649b64a071 Mon Sep 17 00:00:00 2001 From: luca364 Date: Wed, 25 Feb 2026 11:26:37 +0100 Subject: [PATCH 2/5] refactor: rename REST_TIMEOUT to REST_SERVLET_TIMEOUT across multiple files for consistency --- README.md | 2 +- RestBCAdapter.bbj | 4 ++-- RestBridge.bbj | 3 +-- cfg/RestBridgeConfigurationWindow.bbj | 8 ++++---- test/CreateTestRestBridge.bbj | 2 +- test/RestBridgeTestConfigurator.bbj | 2 +- test/TestRestBridge.bbjt | 2 +- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 19a76d4..44ba971 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ in the Context Configuration: | REST_WD | The working directory to be set for every request | | REST_ADAPTERPGM | The adapter, typically RestBCAdapter.bbj | | REST_ADAPTERTERM | The terminal to set, e.g. IO or Tx | -| REST_TIMEOUT | The timeout after which idle background workers terminate. Default: 60 seconds. | +| REST_SERVLET_TIMEOUT | The timeout after which idle background workers terminate. Default: 60 seconds. | | REST_TRACE | The path of a directory to write a SETTRACE of the servlet and the BC Adapter. The directory must exist and be writable. Else the parameter will be ignored | | REST_SERVLET_TIMEOUT | Timeout after which a timeout is sent as response if the worker did not return in this moment. | | REST_KILL_WORKER_AT_TIMEOUT | If set to 1 the worker will be killed when the servlet observes a timeout. If not set or 0, the worker will continue to run, potentially for a long time if the request was bad and leads to long code execution. | diff --git a/RestBCAdapter.bbj b/RestBCAdapter.bbj index 0c3a9da..e97ede7 100644 --- a/RestBCAdapter.bbj +++ b/RestBCAdapter.bbj @@ -94,8 +94,8 @@ done_login: REST_TIMEOUT=60 -if servletParams!.containsKey("REST_TIMEOUT") then - REST_TIMEOUT=num(servletParams!.get("REST_TIMEOUT").toString(),err=*next) +if servletParams!.containsKey("REST_SERVLET_TIMEOUT") then + REST_TIMEOUT=num(servletParams!.get("REST_SERVLET_TIMEOUT").toString(),err=*next) endif diff --git a/RestBridge.bbj b/RestBridge.bbj index 8044857..93de5e4 100644 --- a/RestBridge.bbj +++ b/RestBridge.bbj @@ -1193,7 +1193,7 @@ class public RestBridge rem *
  • REST_WD
  • rem *
  • REST_ADAPTERPGM
  • rem *
  • REST_ADAPTERTERM
  • - rem *
  • REST_TIMEOUT
  • + rem *
  • REST_SERVLET_TIMEOUT
  • rem *
  • REST_AUTHPGM
  • rem *
  • REST_REQUESTLOG
  • rem *
  • USE_GET_ALLOWED_FILTER
  • @@ -1223,7 +1223,6 @@ class public RestBridge parameterNames!.add("REST_WD") parameterNames!.add("REST_ADAPTERPGM") parameterNames!.add("REST_ADAPTERTERM") - parameterNames!.add("REST_TIMEOUT") parameterNames!.add("REST_SERVLET_TIMEOUT") parameterNames!.add("REST_KILL_WORKER_AT_TIMEOUT") parameterNames!.add("REST_MAX_WORKER_RECYCLECOUNT") diff --git a/cfg/RestBridgeConfigurationWindow.bbj b/cfg/RestBridgeConfigurationWindow.bbj index 2196790..aea9ff7 100644 --- a/cfg/RestBridgeConfigurationWindow.bbj +++ b/cfg/RestBridgeConfigurationWindow.bbj @@ -336,7 +336,7 @@ class public RestBridgeConfigurationWindow servlet! = #reciveBridgeInformation() if (servlet! <> null()) then - error = 1; #setTimeout(num(servlet!.getParameter("REST_TIMEOUT")),err=*next); error = 0 + error = 1; #setTimeout(num(servlet!.getParameter("REST_SERVLET_TIMEOUT")),err=*next); error = 0 if error = 1 then #setTimeout(0) #setMapping(servlet!.getMapping()) @@ -402,7 +402,7 @@ class public RestBridgeConfigurationWindow endif params! = new HashMap() - params!.put("REST_TIMEOUT", str(#getTimeout())) + params!.put("REST_SERVLET_TIMEOUT", str(#getTimeout())) params!.put("REST_WD", #getWorkingDirectoryPath()) params!.put("REST_AUTHPGM", #getAuthProgramPath()) params!.put("REST_PGM_PREFIX", #getProgramPrefix()) @@ -507,7 +507,7 @@ class public RestBridgeConfigurationWindow auth! = bbjHome!.getAbsolutePath().replaceAll("\\|\/", java.io.File.separator,err=*next) params! = new HashMap() - params!.put("REST_TIMEOUT","1000") + params!.put("REST_SERVLET_TIMEOUT","1000") params!.put("REST_WD", "") params!.put("REST_AUTHPGM",auth!) params!.put("REST_PGM_PREFIX","") @@ -737,7 +737,7 @@ class public RestBridgeConfigurationWindow builder!.append("REM Here you can add Parameter to your Birdge."+$0A$) builder!.append("bridgeConf!.addParameter(""REST_ADAPTERPGM"", adapterProgram!.getAbsolutePath())"+$0A$) builder!.append("bridgeConf!.addParameter(""REST_ADAPTERTERM"", ""IO"")"+$0A$) - builder!.append("bridgeConf!.addParameter(""REST_TIMEOUT"",timeOut!)"+$0A$) + builder!.append("bridgeConf!.addParameter(""REST_SERVLET_TIMEOUT"",timeOut!)"+$0A$) builder!.append("bridgeConf!.addParameter(""REST_WD"",workingDirectory!)"+$0A$) builder!.append("bridgeConf!.addParameter(""REST_AUTHPGM"",authpgm!)"+$0A$) builder!.append("bridgeConf!.addParameter(""REST_PGM_PREFIX"",preffix!)"+$0A$) diff --git a/test/CreateTestRestBridge.bbj b/test/CreateTestRestBridge.bbj index da0d35f..8808a05 100644 --- a/test/CreateTestRestBridge.bbj +++ b/test/CreateTestRestBridge.bbj @@ -12,7 +12,7 @@ directory! = new File(path!).getParent() bcDir! = new File(directory!, "test/example-bcs/") config! = context!.addBBxServlet("/rest_test/*", path!, "RestBridge", "service") -config!.addParameter("REST_TIMEOUT", "100") +config!.addParameter("REST_SERVLET_TIMEOUT", "100") config!.addParameter("REST_AUTHPGM", new File(directory!, "authenticate.bbj").getAbsolutePath()) config!.addParameter("REST_WD", bcDir!.getAbsolutePath()) config!.addParameter("REST_PGM_SUFFIX", ".bbj") diff --git a/test/RestBridgeTestConfigurator.bbj b/test/RestBridgeTestConfigurator.bbj index 742c597..a7422b3 100644 --- a/test/RestBridgeTestConfigurator.bbj +++ b/test/RestBridgeTestConfigurator.bbj @@ -49,7 +49,7 @@ class public RestBridgeTestConfigurator #mapping! = "/rest" + str(System.currentTimeMillis()) + "/" config! = context!.addBBxServlet(#mapping! + "*", path!, "RestBridge", "service") - config!.addParameter("REST_TIMEOUT", "100") + config!.addParameter("REST_SERVLET_TIMEOUT", "100") config!.addParameter("REST_AUTHPGM", new File(directory!, "authenticate.bbj").getAbsolutePath()) config!.addParameter("REST_WD", bcDir!.getAbsolutePath()) config!.addParameter("REST_PGM_SUFFIX", ".bbj") diff --git a/test/TestRestBridge.bbjt b/test/TestRestBridge.bbjt index 3f0c5d7..96720c6 100644 --- a/test/TestRestBridge.bbjt +++ b/test/TestRestBridge.bbjt @@ -62,7 +62,7 @@ class public RestBridgeTest #mapping! = "/rest" + str(System.currentTimeMillis()) + "/" config! = context!.addBBxServlet(#mapping! + "*", path!, "RestBridge", "service") - config!.addParameter("REST_TIMEOUT", "100") + config!.addParameter("REST_SERVLET_TIMEOUT", "100") config!.addParameter("REST_AUTHPGM", new File(directory!, "authenticate.bbj").getAbsolutePath()) config!.addParameter("REST_WD", bcDir!.getAbsolutePath()) config!.addParameter("REST_PGM_SUFFIX", ".bbj") From 3b0cf98708478050b7bf54d971289818f9406df6 Mon Sep 17 00:00:00 2001 From: luca364 Date: Wed, 25 Feb 2026 11:30:04 +0100 Subject: [PATCH 3/5] fix: add missing import ContentType --- test/request-types/TestPOST.bbjt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/request-types/TestPOST.bbjt b/test/request-types/TestPOST.bbjt index 60e1bb1..4e4c9b9 100644 --- a/test/request-types/TestPOST.bbjt +++ b/test/request-types/TestPOST.bbjt @@ -13,6 +13,7 @@ use org.apache.http.client.methods.HttpPost use org.apache.http.client.entity.EntityBuilder use org.apache.http.HttpEntity +use org.apache.http.entity.ContentType class public TestPOST From 0b6a2b34b3e933affab1c0d265fa5fdffe82e8d9 Mon Sep 17 00:00:00 2001 From: Sebastian Adams Date: Wed, 25 Feb 2026 11:28:02 +0100 Subject: [PATCH 4/5] feat: Adjusted the encoding conversion fixing an issue with special characters --- RestBridge.bbj | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/RestBridge.bbj b/RestBridge.bbj index 93de5e4..5189be6 100644 --- a/RestBridge.bbj +++ b/RestBridge.bbj @@ -258,7 +258,7 @@ class public RestBridge System.out.println("REST: "+str(running_list!.size())+" running.") fi - if running_list!.size() <= REST_MAX_WORKER_COUNT then + if running_list!.size() >= REST_MAX_WORKER_COUNT then rem first try to see if they're really all busy ks! = running_list!.clone().iterator() @@ -364,8 +364,20 @@ class public RestBridge if bodyBytes! <> null() then rem converting the request body into the server's character encoding - body! = new String(bodyBytes!, info(1,2)) + if requestCharSet$ = "" then + body! = new String(bodyBytes!, defaultCharset!).getBytes("ISO-8859-1") + body! = new String(body!, defaultCharset!).getBytes(info(1,2)) + if (debug) then + System.out.println("Used default charset: " + defaultCharset!) + endif + else + body! = new String(bodyBytes!, requestCharSet$).getBytes(info(1,2)) + + if (debug) then + System.out.println("Used request charset: " + requestCharSet$) + endif + endif if (debug) then System.out.println("Server Encoding: " + info(1,2)) System.out.println("Encoded Body: " + body!) @@ -373,7 +385,8 @@ class public RestBridge req!.put("body", body!) endif - + req!.put("defaultCharset", defaultCharset!) + req!.put("requestCharSet", requestCharSet$) req!.put("preferredlocales", request!.getLocales()) if str(uri!)="/admin/requestlog" then From 2f091707495ae66a0cfa5d51a1c7c0039fee43e7 Mon Sep 17 00:00:00 2001 From: luca364 Date: Wed, 25 Feb 2026 12:10:18 +0100 Subject: [PATCH 5/5] fix: use globalnamespace instead of db --- test/request-types/TestPOST.bbjt | 62 +++++++++++--------------------- 1 file changed, 20 insertions(+), 42 deletions(-) diff --git a/test/request-types/TestPOST.bbjt b/test/request-types/TestPOST.bbjt index 4e4c9b9..40df212 100644 --- a/test/request-types/TestPOST.bbjt +++ b/test/request-types/TestPOST.bbjt @@ -105,63 +105,41 @@ class public TestPOST rem @Test method public void testCreateRecordWithSpecialCharactersInBody() - declare ResultSet resultSet! - resultSet! = #chileCustomerBC!.retrieve() - initialSize = resultSet!.size() - - special_first$ = "ÄÖÜß" - special_last$ = "ÉÁäöüßéá" + special_param$ = "ÄÖÜßÉÁäöüßéá" - rem Prepare a row that uses the special characters - rowWithSpecial! = #insertRow!.clone() - rowWithSpecial!.setFieldValue("FIRST_NAME", special_first$) - rowWithSpecial!.setFieldValue("LAST_NAME", special_last$) - #uriBuilder!.setPath(#configurator!.getRestBridgeMapping() + "ChileCustomer") declare HttpPost request! request! = #configurator!.getRequestPOST(#uriBuilder!) request!.setHeader("Accept", "application/json") request!.setHeader("Content-Type", "application/json; charset=UTF-8") + request!.setHeader("ExecuteBCMethod", "customMethodWithParameter") - entity! = EntityBuilder.create().setText(rowWithSpecial!.toJson()).setContentType(ContentType.create("application/json", "UTF-8")).build() + rs! = new ResultSet() + row! = new DataRow() + row!.setFieldValue("param", special_param$) + rs!.add(row!) + + entity! = EntityBuilder.create().setText(rs!.toJson()).setContentType(ContentType.create("application/json", "UTF-8")).build() request!.setEntity(entity!) declare HttpResponse response! response! = #client!.execute(request!) - rem verify that the request was executed successfully - Assert.Equals(response!.getStatusLine().getStatusCode(), 201) - rem checking that the record was actually created - resultSet! = #chileCustomerBC!.retrieve() - Assert.Equals(initialsize +1, resultSet!.size()) + wasExecuted = BBjAPI().getGlobalNamespace().getKeys().contains("customMethodWithParameter", err=*next) + param! = BBjAPI().getGlobalNamespace().getValue("customMethodWithParameter", err=*next) + BBjAPI().getGlobalNamespace().removeValue("customMethodWithParameter", err=*next) - rem Read back the record via the BC to validate what was written - declare DataRow filter! - filter! = new DataRow() - filter!.setFieldValue("CUST_NUM", rowWithSpecial!.getFieldAsString("CUST_NUM")) - #chileCustomerBC!.setFilter(filter!) - resultSet! = #chileCustomerBC!.retrieve() - Assert.Equals(resultSet!.size(), 1) - - declare DataRow storedRow! - storedRow! = resultSet!.get(0) - Assert.Equals(storedRow!.getFieldAsString("FIRST_NAME"), special_first$) - Assert.Equals(storedRow!.getFieldAsString("LAST_NAME"), special_last$) - - rem Also validate the echoed response body from RestBridge - declare ResultSet responseRS! - responseRS! = ResultSet.fromJson(#configurator!.getResultAsString(response!)) - - rem the result set shouldn't be null - Assert.IsNotNull(responseRS!) - Assert.Equals(responseRS!.size(), 1) - - declare DataRow responseRow! - responseRow! = responseRS!.get(0) - Assert.Equals(responseRow!.getFieldAsString("FIRST_NAME"), special$) - Assert.Equals(responseRow!.getFieldAsString("LAST_NAME"), special$) + if !wasExecuted then + Assert.Fail("The customMethodWithParameter was not executed") + endif + + if param! <> special_param$ then + Assert.Fail("The custom method was executed but the parameter was not processed correctly") + endif + + Assert.Equals(param!, special_param$) methodend rem @Test