S4Hana(ERP) backend does not return localized error message due to additional ‘sap-language’ header is being added by the Cloud SDK - sap-cloud-sdk

Note: Application is built in CAP Java Stack along with DWC framework. Technical user is configurated in destination service for making an API call.
Flow :
API call gets initiated from UI.
The application layer receives the
request and respond with 204
Then starts the async process
explicitly via spring events and adds custom header as ‘sap-language’
based on user's locale before making the call to S4 backend.
httpHeaders.put(DefaultErpHttpDestination.LOCALE_HEADER_NAME, dwcHeaderContainer.getHeader(HttpHeaders.ACCEPT_LANGUAGE));
ModificationResponse<PurchaseRequisition> s4ReqResponse =
s4opRequistionService.createPurchaseRequisition(s4opRequistion).withHeaders(httpHeaders).executeRequest(destinationProvider.getDestination());
However, Observed the underlying cloud SDK layer which 1st makes the call to destination service and retrieves the provided headers and then gets system current locale based on some constraint and adds a header again for ‘sap-language’ with the default system locale as 'en' which leads to problem in our case.
Calling stack trace :
Thread [SimpleAsyncTaskExecutor-60] (Suspended)
CdsRequestHeaderFacade.tryGetRequestHeaders() line: 28
RequestHeaderAccessor.tryGetHeaderContainer() line: 89
DefaultLocaleFacade.getLocalesByHeaders() line: 48
DefaultLocaleFacade.getCurrentLocales() line: 36
DefaultLocaleFacade(LocaleFacade).getCurrentLocale() line: 27
LocaleAccessor.getCurrentLocale() line: 53
371621826.get() line: not available
Option$None<T>(Option<T>).getOrElse(Supplier<? extends T>) line: 336
DefaultErpHttpDestination(ErpHttpDestinationProperties).getLocale() line: 51
DefaultErpHttpDestination.getHeadersToAdd() line: 188
DefaultErpHttpDestination.getHeaders(URI) line: 169
HttpClientWrapper.wrapRequest(HttpUriRequest) line: 98
HttpClientWrapper.execute(HttpUriRequest) line: 116
HttpClientWrapper.execute(HttpUriRequest) line: 35
DefaultCsrfTokenRetriever.retrieveCsrfTokenResponseHeader(HttpClient, String, Map<String,String>) line: 91
DefaultCsrfTokenRetriever.retrieveCsrfToken(HttpClient, String, Map<String,String>) line: 54
ODataRequestCreate(ODataRequestGeneric).lambda$tryGetCsrfToken$5ab307ff$1(CsrfTokenRetriever, HttpClient) line: 266
659039215.apply() line: not available
Try<T>.of(CheckedFunction0<? extends T>) line: 75
ODataRequestCreate(ODataRequestGeneric).tryGetCsrfToken(HttpClient, CsrfTokenRetriever) line: 266
ODataRequestCreate(ODataRequestGeneric).tryExecuteWithCsrfToken(HttpClient, Supplier<HttpResponse>) line: 239
ODataRequestCreate.execute(HttpClient) line: 93
PurchaseRequisitionCreateFluentHelper(FluentHelperCreate<FluentHelperT,EntityT>).executeRequest(HttpDestinationProperties) line: 246
xxxxxx.copyPR(Map<String,Object>) line: 176
xxxxxx.s4AdapterResponseToxxxxxx(xxxxxx) line: 69
xxxxxx.onApplicationEvent(xxxxxx) line: 58
xxxxxxSpringListener.onApplicationEvent(ApplicationEvent) line: 1
SimpleApplicationEventMulticaster.doInvokeListener(ApplicationListener, ApplicationEvent)
SimpleApplicationEventMulticaster.invokeListener(ApplicationListener<?>, ApplicationEvent)
SimpleApplicationEventMulticaster.lambda$multicastEvent$0(ApplicationListener, ApplicationEvent)
1824178544.run() line: not available
DwcContextTaskDecorator.lambda$decorate$0(Map, Runnable) line: 33
1126784716.run() line: not available
Thread.run() line: 829
Sample Http Out Going request and response looks like :
http-outgoing-13 >> "POST /sap/opu/odata/sap/API_PURCHASEREQ_PROCESS_SRV/A_PurchaseRequisitionHeader HTTP/1.1[\r][\n]"
http-outgoing-13 >> "sap-language: de[\r][\n]"
http-outgoing-13 >> "Accept: application/json[\r][\n]"
http-outgoing-13 >> "RequestID: xxxxx[\r][\n]"
http-outgoing-13 >> "RepeatabilityCreation: 2022-09-19T08:50:00.889315900Z[\r][\n]"
http-outgoing-13 >> "X-CorrelationID: [\r][\n]"
http-outgoing-13 >> "x-csrf-token: xxxxx==[\r][\n]"
http-outgoing-13 >> "Content-Type: application/json[\r][\n]"
http-outgoing-13 >> "Authorization: Basic XXXX[\r][\n]"
http-outgoing-13 >> "sap-language: en[\r][\n]"
http-outgoing-13 >> "Content-Length: 1383[\r][\n]"
http-outgoing-13 >> "Host: XXXX[\r][\n]"
http-outgoing-13 >> "Connection: Keep-Alive[\r][\n]"
http-outgoing-13 >> "User-Agent: Apache-HttpClient/4.5.13 (Java/11.0.16)[\r][\n]"
http-outgoing-13 >> "Cookie: XXX%3d; sap-usercontext=sap-language=en&sap-client=xxx[\r][\n]"
http-outgoing-13 >> "Accept-Encoding: gzip,deflate[\r][\n]"
http-outgoing-13 >> "[\r][\n]"
http-outgoing-13 >> "body_xxx"
http-outgoing-13 << "HTTP/1.1 400 Bad Request[\r][\n]"
http-outgoing-13 << {"error":{"code":"06/101","message":{"lang":"en","value":"No master record exists for supplier EPRINT"}"}
If you notice, there are two 'sap-language' header goes to backend as mentioned above and S4 backend layer considers the last header attribute and returns the error message always in English. Our expectation is error messages should come based on user’s locale…
Following queries :
Is there any way by which application layer can instruct to Cloud SDK like Not to append again 'sap-language' header and give preference to what is being passed by the custom header as ‘sap-language’ As ‘de’ in our case?
Is it the bug from Cloud SDK?
Any recommendation or inputs to address this issue..

Answers
Is it the bug from Cloud SDK?
Not really, to me this looks like an incorrect API usage:
Your Destination is of type DefaultErpHttpDestination. It is significantly different from regular destination types, because it automatically adds headers sap-client and sap-language. It seems like the class cannot resolve the request headers at runtime, therefore falls back to system default en.
You are adding headers via OData API, while technically possible it's unreasonable for your actual call. As it results in duplicate header entry.
Is there any way for Cloud SDK not to append again 'sap-language' header?
Yes, do not cast to ErpHttpDestination explicitly.
Recommendation
Instead of fiddling with the destination or odata request, I would suggest to use the following code:
ModificationResponse<PurchaseRequisition> s4ReqResponse =
RequestHeaderAccessor.executeWithHeaderContainer(
dwcHeaderContainer.getHeaders(),
() -> s4opRequistionService
.createPurchaseRequisition(s4opRequistion)
.executeRequest(destinationProvider.getDestination()));
Reason:
Keep benefits of ErpHttpDestination
Enable correct locale resolution by leveraging the request headers and establishing a ThreadContext.

#Alexander, Tried with the following code, however did not work as expected.
Could you plz check once and suggest if i am missing something or anything w.r.t version which needs to be upgraded in order to adopt the recommendation
ModificationResponse<PurchaseRequisition> s4ReqResponse =
RequestHeaderAccessor.executeWithHeaderContainer(dwcHeaderContainer.getHeaders(), () -> {
ModificationResponse<PurchaseRequisition> s4Response = null;¬
try {
s4Response = s4opRequistionService.createPurchaseRequisition(s4opRequistion)
.executeRequest(destinationProvider.getDestination());
return s4Response;
} catch (ODataException e) {
logger.error(EXCEPTION_FROM_COPYPR);
logAndSendErrorMessageToCore(e, requisition);
}
return s4Response;
}
);
Also ensured dwcHeaderContainer consists the values as such {accept-language=de} along with few other attributes.
Still stack trace looks similar and could not found a place underneath where it picks the header value from the supplied header values via RequestHeaderAccessor. executeWithHeaderContainer()
StackTrace:
Thread [SimpleAsyncTaskExecutor-41] (Suspended)
CdsRequestHeaderFacade.tryGetRequestHeaders() line: 28
RequestHeaderAccessor.tryGetHeaderContainer() line: 89
DefaultLocaleFacade.getLocalesByHeaders() line: 48
DefaultLocaleFacade.getCurrentLocales() line: 36
DefaultLocaleFacade(LocaleFacade).getCurrentLocale() line: 27
LocaleAccessor.getCurrentLocale() line: 53
2065479632.get() line: not available
Option$None<T>(Option<T>).getOrElse(Supplier<? extends T>) line: 336
DefaultErpHttpDestination(ErpHttpDestinationProperties).getLocale() line: 51
DefaultErpHttpDestination.getHeadersToAdd() line: 188
DefaultErpHttpDestination.getHeaders(URI) line: 169
HttpClientWrapper.wrapRequest(HttpUriRequest) line: 98
HttpClientWrapper.execute(HttpUriRequest) line: 116
HttpClientWrapper.execute(HttpUriRequest) line: 35
DefaultCsrfTokenRetriever.retrieveCsrfTokenResponseHeader(HttpClient, String, Map<String,String>) line: 91
DefaultCsrfTokenRetriever.retrieveCsrfToken(HttpClient, String, Map<String,String>) line: 54
ODataRequestCreate(ODataRequestGeneric).lambda$tryGetCsrfToken$5ab307ff$1(CsrfTokenRetriever, HttpClient) line: 266
1607932978.apply() line: not available
Try<T>.of(CheckedFunction0<? extends T>) line: 75
ODataRequestCreate(ODataRequestGeneric).tryGetCsrfToken(HttpClient, CsrfTokenRetriever) line: 266
ODataRequestCreate(ODataRequestGeneric).tryExecuteWithCsrfToken(HttpClient, Supplier<HttpResponse>) line: 239
ODataRequestCreate.execute(HttpClient) line: 93
PurchaseRequisitionCreateFluentHelper(FluentHelperCreate<FluentHelperT,EntityT>).executeRequest(HttpDestinationProperties) line: 246
S4Adapter.lambda$0(PurchaseRequisition, Map) line: 177
64962500.call() line: not available
ThreadContextCallable<T>.call() line: 229
ThreadContextExecutor(AbstractThreadContextExecutor<ExecutorT>).execute(Callable<T>) line: 320
RequestHeaderAccessor.executeWithHeaderContainer(RequestHeaderContainer, Callable<T>) line: 185
RequestHeaderAccessor.executeWithHeaderContainer(Map<String,String>, Callable<T>) line: 160
S4Adapter.copyPR(Map<String,Object>) line: 173

Related

Create an AzureBlobDatastore() with SDK-V2

I am trying to create an AzureBlobDatastore() via the azure-sdk-v2. Previously, I successfully managed to perform the same operation via azure-sdk-v1 (from tutorial link in the next paragraph).
I am following this tutorial : https://learn.microsoft.com/en-us/azure/machine-learning/migrate-to-v2-resource-datastore#create-a-datastore-from-an-azure-blob-container-via-account_key in order to set up/create my AzureBlobDatastore().
This is the code that I am using (like in the tutorial, only updating the parameters in MLClient.from_config() (if I don't use the credential parameter I get an error stating that the parameter is empty):
ml_client = MLClient.from_config(credential=DefaultAzureCredential(),
path="./workspace_config_sdk2.json")
store = AzureBlobDatastore(
name="azureml_sdk2_blob",
description="Datastore created with sdkv2",
account_name=storage_account_name,
container_name=container_name,
protocol="wasbs",
credentials={
"account_key": "..my_account_key.."
},
)
ml_client.create_or_update(store)
I get the following error:
AttributeError: 'dict' object has no attribute
'_to_datastore_rest_object'
Note that the workspace_config_sdk2.json config has the following scheme:
{
"subscription_id": "...",
"resource_group": "...",
"workspace_name": "..."
}
How can I solve this error?
EDIT: On investigating the issue, it seems that it falls back to some code in "azure\ai\ml\entities\_datastore\azure_storage.py"
175 def _to_rest_object(self) -> DatastoreData:
176 blob_ds = RestAzureBlobDatastore(
177 account_name=self.account_name,
178 container_name=self.container_name,
--> 179 credentials=self.credentials._to_datastore_rest_object(),
180 endpoint=self.endpoint,
181 protocol=self.protocol,
182 tags=self.tags,
183 description=self.description,
184 )
185 return DatastoreData(properties=blob_ds)
AttributeError: 'dict' object has no attribute '_to_datastore_rest_object'

Databricks DataLakeFileClient Returns Error

I have a databricks notebook running every 5 mins, part of the functionality is to connect to a file in Azure Data Lake Storage Gen2 (ADLS Gen2).
I get the following error in the code, but it seems to have "come out of nowhere" as the process was previously working fine. the "file = " part is written by me, all the parameters are as expected and matching the correct file names/containers and do exist in the data lake.
---> 92 file = DataLakeFileClient.from_connection_string("DefaultEndpointsProtocol=https;AccountName="+storage_account_name+";AccountKey=" + storage_account_access_key,
93 file_system_name=azure_container, file_path=location_to_write)
94
/databricks/python/lib/python3.8/site-packages/azure/storage/filedatalake/_data_lake_file_client.py in from_connection_string(cls, conn_str, file_system_name, file_path, credential, **kwargs)
116 :rtype ~azure.storage.filedatalake.DataLakeFileClient
117 """
--> 118 account_url, _, credential = parse_connection_str(conn_str, credential, 'dfs')
119 return cls(
120 account_url, file_system_name=file_system_name, file_path=file_path,
/databricks/python/lib/python3.8/site-packages/azure/storage/filedatalake/_shared/base_client.py in parse_connection_str(conn_str, credential, service)
402 if service == "dfs":
403 primary = primary.replace(".blob.", ".dfs.")
--> 404 secondary = secondary.replace(".blob.", ".dfs.")
405 return primary, secondary, credential
Any thoughts/help? The actual error is in the base_client.py code, but I don't even know what "secondary" is supposed to be and why there would be an error there.
For some reason, after restarting the cluster, something changed and the following "endpoint suffix" was required for this to continue working, couldn't find any docs on why it would work without this, but until a few days ago, it had always worked:
"DefaultEndpointsProtocol=https;AccountName="+storage_account_name+";AccountKey="+storage_account_access_key+";EndpointSuffix=core.windows.net"

Kohana app database not connecting

ErrorException [ Fatal Error ]: Class 'Database_Mysqli' not found
MODPATH/database/classes/kohana/database.php [ 78 ]
73
74 // Set the driver class name
75 $driver = 'Database_'.ucfirst($config['type']);
76
77 // Create the database connection instance
78 new $driver($name, $config);
79 }
80
81 return Database::$instances[$name];
82 }
83
{PHP internal call} » Kohana_Core::shutdown_handler()
Environment
i tried everything doesnt work, can anyone help, i cant configure it, i can give remote access to see whats wrong
As mentioned in comment download enter link description here
In config -> database.php use type => 'MySQLi'
Note: It looks like you typed it as Mysqli as In kohana 3.3 onward class name are case sensitive.

Zurb Foundation for Apps - CLI Fails2

At the risk of posting a duplicate, I am new here and don't have a rating yet so it wouldn't let me comment on the only relevant similar question I did find here:
Zurb Foundation for Apps - CLI Fails.
Zurb Foundation for Apps - CLI Fails
However I tried the answer there and I still get the same fail.
My message is :
(I don't have a reputation so I can't post images "!##"):
but it is essentially the same as the other post except mine mentions line 118 of foundationCLI.js where theirs notes line 139. Also the answer said to fix line 97 but in mine that code is on line 99.
92 // NEW
93 // Clones the Foundation for Apps template and installs dependencies
94 module.exports.new = function(args, options) {
95 var projectName = args[0];
96 var gitClone = ['git', 'clone', 'https://github.com/zurb/foundation-apps-template.git', args[0]];
97 var npmInstall = [npm, 'install'];
98 var bowerInstall = [bower, 'install'];
99 var bundleInstall = [bundle.bat];
100 if (isRoot()) bowerInstall.push('--allow-root');
101
102 // Show help screen if the user didn't enter a project name
103 if (typeof projectName === 'undefined') {
104 this.help('new');
105 process.exit();
106 }
107
108 yeti([
109 'Thanks for using Foundation for Apps!',
110 '-------------------------------------',
111 'Let\'s set up a new project.',
112 'It shouldn\'t take more than a minute.'
113 ]);
114
115 // Clone the template repo
116 process.stdout.write("\nDownloading the Foundation for Apps template...".cyan);
117 exec(gitClone, function(err, out, code) {
118 if (err instanceof Error) throw err;
119
120 process.stdout.write([
121 "\nDone downloading!".green,
122 "\n\nInstalling dependencies...".cyan,
123 "\n"
124 ].join(''));
I also posted an error log here
https://github.com/npm/npm/issues/7024
yesterday, as directed in the following error message: (which I am unable to post the image of "!##").
But I have yet to receive a response there.
Any idea how I can get past this so I can start an app?
Thanks, A
You may need to also install the git command-line client. On line 117, the foundation-cli.js is trying to run git clone and this is failing.
Could you please run
git --version
and paste the text (not image) of the output you see?
If you have installed git already (e.g., because you have Github for Windows < https://windows.github.com/ > ) then you may need to use the Git Shell shortcut or close/re-open your command prompt window in order to use git on the command line.
Once you've installed git and closed/reopened your shell, try the command
foundation-apps new myApp again.

Components.interfaces.nsIProcess2 in Firefox 3.6 -- where did it go?

I am beta testing an application that includes a Firefox extension as one component. It was originally deployed when FF3.5.5 was the latest version, and survived 3.5.6 and 3.5.7. However on FF3.6 I'm getting the following in my error console:
Warning: reference to undefined property Components.interfaces.nsIProcess2
Source file: chrome://overthewall/content/otwhelper.js
Line: 55
Error: Component returned failure code: 0x80570018 (NS_ERROR_XPC_BAD_IID)
[nsIJSCID.createInstance]
Source file: chrome://overthewall/content/otwhelper.js
Line: 55
The function throwing the error is:
48 function otwRunHelper(cmd, aCallback) {
49 var file =
50 Components.classes["#mozilla.org/file/local;1"].
51 createInstance(Components.interfaces.nsILocalFile);
52 file.initWithPath(otwRegInstallDir+'otwhelper.exe');
53
54 otwProcess = Components.classes["#mozilla.org/process/util;1"]
55 .createInstance(Components.interfaces.nsIProcess2);
56
57 otwProcess.init(file);
58 var params = new Array();
59 params = cmd.split(' ');
60
61 otwNextCallback = aCallback;
62 otwObserver = new otwHelperProcess();
63 otwProcess.runAsync(params, params.length, otwObserver, false);
64 }
As you can see, all this function does is run an external EXE helper file (located by a registry key) with some command line parameters and sets up an Observer to asynchronously wait for a response and process the Exit code.
The offending line implies that Components.interfaces.nsIProcess2 is no longer defined in FF3.6. Where did it go? I can't find anything in the Mozilla documentation indicating that it has been changed in the latest release.
The method on nsIProcess2 was moved to nsIProcess. For your code to work in both versions, change this line:
otwProcess = Components.classes["#mozilla.org/process/util;1"]
.createInstance(Components.interfaces.nsIProcess2);
to this:
otwProcess = Components.classes["#mozilla.org/process/util;1"]
.createInstance(Components.interfaces.nsIProcess2 || Components.interfaces.nsIProcess);
You will still get the warning, but the error will go away, and your code will work just fine in both versions. You could also store the interface iid in a variable and use the variable:
let iid = ("nsIProcess2" in Components.interfaces) ?
Components.interfaces.nsIProcess2 :
Components.interfaces.nsIProcess;
otwProcess = Components.classes["#mozilla.org/process/util;1"]
.createInstance(iid);

Resources