Handling OData Exceptions with Batch mode - error-handling

I'm implementing SAPUI5 (Fiori like) application, that calls multiple CREATE operations in one batch. At now I've just redefined methods /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN / END and proper method is called multiple times. It is working fine when there is no errors.
How should I throw business exception in CREATE_ENTITY method to get message at ForntEnd layer? In console I can see only:
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code>005056A509B11ED1B9BF9F46AA8E82ED</code>
<message xml:lang="en">In the context of Data Services an unknown internal server error occured</message>
</error>
How to handle that?

I solved by myself.
Redefine /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN and not
implement any code. That will allow to call multiple operations (eg.
_CREATE_ENTITY) in one batch.
Implement _CREATE_ENTITY accordingly, make necessary checks and prepare data to be processed (create/ update), do not use COMMIT in that methods.
Redefine /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END and call all needed BAPI's or SQL INSERT / UPDATE statements. In case of any error throw /IWBEP/CX_MGW_BUSI_EXCEPTION - it will be handled properly on Front End. COMMIT will be called automatically.

Related

Camunda : Set Assignee to all UserTasks of the process instance

I have a requirement where I need to set assignee's to all the "user-tasks" in a process instance as soon as the instance is created, which is based on the candidate group set to the user-task.
i tries getting the user-tasks using this :
Collection<UserTask> userTasks = execution.getBpmnModelInstance().getModelElementsByType(UserTask.class);
which is correct in someway but i am not able to set the assignee's , Also, looks like this would apply to the process itself and not the process instance.
secondly , I tried getting it from the taskQuery which gives me only the next task and not all the user-tasks inside a process.
Please help !!
It does not work that way. A process flow can be simplified to "a token moves through the bpmn diagram" ... only the current position of the token is relevant. So naturally, the tasklist only gives you the current task. Not what could happen after ... which you cannot know, because if you had a gateway that continues differently based on the task outcome? So drop playing with the BPMN meta model. Focus on the runtime.
You have two choices to dynamically assign user tasks:
1.) in the modeler, instead of hard-assigning the task to "a-user", use an expression like ${taskAssignment.assignTask(task)} where "taskAssignment" is a bean that provides a String method that returns the user.
2.) add a taskListener on "create" to the task and set the assignee in the listener.
for option 2 you can use the camunda spring boot events (or the (outdated) camunda-bpm-reactor extension) to register one central component rather than adding a listener to every task.

runtimeservice.getVariables does not work because it can't find process instance id

I'm new to flowable and I'm trying to start a process instance with variables. params here is the Map of <String,Object> that I'm using to start the process. It all goes well, but if I try to get my variables back it tells me
"execution 22f42f67-5f88-11e9-9df0-d46d6dbfea92 doesn't exist"
But if I search for it in my process instances list, is there. This is what I do:
pi = runtimeService.startProcessInstanceById(processDefinitionId, params);
runtimeService.getVariables(pi.getId());
I'm stuck with this problem and I do not understand why it keeps doing this. What am I missing?
Flowable has the concept of RuntimeService and HistoryService. The first one contains only the runtime data (what is currently active) and the second one has all the data. The runtime data is a subset of the history data.
The reason why you can’t find the variables via the RuntimeService is due to the fact that the process is completed.
If you use the HistoryService then it would work as expected.

Get stacktrace of errors from PyRFC call?

Up to now I get only an error message if something inside my SAP RFC function is wrong
pyrfc._exception.ABAPRuntimeError: RFC_ABAP_MESSAGE (rc=4): key=No authorization,
message=No authorization [MSG: class=00, type=E, number=001, v1-4:=No authorization;;;]
It would increase the development speed a lot if I could get a stacktrace of ABAP function. Is there a way to get a stacktrace like for example in Python?
Related: https://softwarerecs.stackexchange.com/questions/52350/sentry-event-from-exception-to-html
Sentry uses a particular JSON to represent a stacktrace and the content of the local variables. Above link contains an example.
Stack trace inside ABAP can be called
with the class cl_abap_get_call_stack.
Local variables are not included in the stack trace returned by the class cl_abap_get_call_stack.
But you could use a log-point to monitor local variables and the stack trace. Log-points can be created, changed and viewed in transaction saab.
A example code snippet:
DATA(formatted_stack) =
cl_abap_get_call_stack=>format_call_stack_with_struct(
cl_abap_get_call_stack=>get_call_stack( ) ).
LOG-POINT ID my_log_point FIELDS formatted_stack
local_variable1 local_variable2.
For the authorization-error, please check transaction su53.
When you see the red authorization-object S_RFC, it means you are not allowed to call the function module in any way!
With ABAP 753 release there was introduced such structure as EPP - Extended Passport.
It seems to be doing something that you want, i.e. showing trace of the called system. I put "seems to be" because I have no 753+ system by my hands so I cannot check in practice.
From the description it should do what you want:
An Extended Passport (EPP) is a data structure that can be sent from a client to a server and is used to analyze call stacks
Extended Passport can be used by frameworks and analysis tools to track external call stacks in communication between clients and servers beyond system boundaries. The values of the EPP components can be saved to log files and used for monitoring. One example of this are short dumps, which all display the most important EPP components.
The DEMO_EPP gives the following usage pattern of EPP:
cl_demo_epp=>init( ).
"this program
cl_demo_epp=>append( ).
"Calling RFC to remote instance
CALL FUNCTION 'DEMO_RFM_EPP_1' DESTINATION instance.
"New SAP LUW
CALL FUNCTION 'DEMO_UPDATE_DELETE' IN UPDATE TASK
EXPORTING
values = VALUE demo_update_tab( ).
COMMIT WORK.
cl_demo_epp=>append( ).
cl_demo_output=>new(
)->begin_section( `Extended Passport (EPP)`
)->display( name = 'EPP Trace'
data = cl_demo_epp=>get( ) ).

Where the function ap_run_pre_connection in Apache httpd source code?

I'm reading the source code of the Apache2.2 and I found that when I use the prefork module,it call the ap_process_connection to deal with a connection and in this method it calls the ap_run_pre_connection.
When it comes to here,I can find neither ap_run_pre_connection nor pre_connection (I find a macro named AP_DECLARE_HOOK, it linked the ap and _hook_ before the name pre_connection).
Where can I find the next step?
You can find the modules that participate in this hook by looking for ap_hook_pre_connection.
AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c, void *csd),(c, csd),OK,DECLINED)
AP_IMPLEMENT_HOOK_RUN_ALL means multiple modules that called ap_hook_pre_connection() will be run until an error is returned
/**
* Implement an Apache core hook that runs until one of the functions
* returns something other than ok or decline. That return value is
* then returned from the hook runner. If the hooks run to completion,
* then ok is returned. Note that if no hook runs it would probably be
* more correct to return decline, but this currently does not do
* so. The implementation is called ap_run_<i>name</i>.
The actual impl of ap_run_pre_connection is just a macro that loops through a linked list of registered functions. See apr_hooks.h

Grails transactions (not GORM based but using Groovy Sql)

My Grails application is not using GORM but instead uses my own SQL and DML code to read and write the database (The database is a huge normalized legacy one and this was the only viable option).
So, I use the Groovy Sql Class to do the job. The database calls are done in Services that are called in my Controllers.
Furthermore, my datasource is declared via DBCP in Tomcat - so it is not declared in Datasource.groovy.
My problem is that I need to write some transaction code, that means to open a transaction and commit after a series of successful DML calls or rollback the whole thing back in case of an error.
I thought that it would be enough to use groovy.sql.Sql#commit() and groovy.sql.Sql#rollback() respectively.
But in these methods Javadocs, the Groovy Sql documentation clearly states
If this SQL object was created from a DataSource then this method does nothing.
So, I wonder: What is the suggested way to perform transactions in my context?
Even disabling autocommit in Datasource declaration seems to be irrelevant since those two methods "...do nothing"
The Groovy Sql class has withTransaction
http://docs.groovy-lang.org/latest/html/api/groovy/sql/Sql.html#withTransaction(groovy.lang.Closure)
public void withTransaction(Closure closure)
throws java.sql.SQLException
Performs the closure within a transaction using a cached connection. If the closure takes a single argument, it will be called with the connection, otherwise it will be called with no arguments.
Give it a try.
Thanks James. I also found the following solution, reading http://grails.org/doc/latest/guide/services.html:
I declared my service as transactional
static transactional = true
This way, if an Error occurs, the previously performed DMLs will be rolled back.
For each DML statement I throw an Error describing the message. For example:
try{
sql.executeInsert("""
insert into mytable1 (col1, col2) values (${val1}, ${val2})
""")
catch(e){
throw new Error("you cant enter empty val1 or val2")
}
try{
sql.executeInsert("""
insert into mytable2 (col1, col2) values (${val1}, ${val2})
""")
catch(e){
throw new Error("you cant enter empty val1 or val2. The previous insert is rolledback!")
}
Final gotcha! The service when called from the controller, must be in a try catch, as follows:
try{
myService.myMethod(params)
}catch(e){
//http://jts-blog.com/?p=9491
Throwable t = e instanceof UndeclaredThrowableException ? e.undeclaredThrowable : e
// use t.toString() to send info to user (use in view)
// redirect / forward / render etc
}