Using functional methods in workflows and tasks
How do I know I’m ready for this?
This is number 6 in a series of blogs on ABAP OO for workflow, so you it would be a really good idea to make sure you have worked through the first 5 blogs. The examples we’ll use here continue on from those we used in the earlier blogs.
Here’s the list of the earlier blogs:
- Why use ABAP OO with Workflow?
- Getting started with ABAP OO for Workflow … using the IF_WORKFLOW interface
- Using ABAP OO methods in Workflow Tasks
- Raising ABAP OO events for workflow
- Using ABAP OO attributes in workflows and tasks
What are functional methods?
A functional method is a method that returns a single result, i.e. a method that has a Returning parameter. Typically a functional method calculates a value, e.g. you might use a functional method to return the number of entries in a table, or the formatted name of an employee or whatever. The method can have importing parameters, but does not have any other exporting parameters.
Here’s a simple example using the same ABAP Class we used for the exercises in the previous blogs. This is a static method that retrieves a list of plants relevant for a nominated country. Here are the parameters:
And the method code – as you can see it’s a very simple example.
METHOD plants_of_country. SELECT werks FROM t001w INTO TABLE et_plants WHERE land1 = iv_country. ENDMETHOD.
What’s the equivalent of functional methods in BOR?
For those who are used to coding business objects (BOR) then functional methods replace virtual attributes (a calculation derived from the object instance). Virtual attributes, and their replacement functional methods, are particularly useful where you have a value that can be derived from the current object instance, but there is enough of a performance cost with deriving the value that you don’t want to derive the value every time you construct the instance.
One advantage of functional methods over virtual attributes is that you can pass importing parameters. You can derive your calculation from the class instance (assuming you are using an instance method of course) and the importing parameters. However its a fairly simple mechanism so its easy to use this for simple parameters that can be hardcoded into the workflow, but you may still need to call the functional method as the main method of a normal task if you want to dynamically set the parameters.
How can I use functional methods in workflows?
You can use a functional method in much the same way as an object attribute. For example: in a container operation, or as the source of a binding.
Here’s an example where a functional method is used in container operation:
When selecting your functional method from the drop down look for the “methods” or “functional methods” section within the object. For example this is what the drop down on the Expression field of the Container Operation above looks like:
This is the format for passing importing parameters.
&ZCL_PLANT.PLANTS_OF_COUNTRY(IV_COUNTRY='DE')&
If you have multiple parameters, just separate them with an ampersand (&).
Note: You can’t use functional methods with importing parameters directly in logical expressions as yet (you can select them but an error is returned) – as the condition editor does not provide a way to enter the parameter values. So in this case, use your functional method in a container operation first, then use the derived container element in your logical expression.
How can I use functional methods in tasks?
You can use a functional method in much the same way as an object attribute in a task, for example in the subject text of a task or in the binding to a method, with one exception:
You can’t call a functional method directly from the long text of a task.
This is a SAPScript restriction not a workflow restriction – i.e. SAPScript doesn’t know how to call a functional method to build the text. However this is not a major problem as you can always create an import container element to hold the result of the functional method in your task, and then in the binding source the container element from your functional method. The example below gives an idea of what such a binding would look like.
Can I use a functional method in a task like other methods?
Yes of course you can use a functional method as the main method of a task, and then it behaves exactly like any other method called from a task. This could be helpful if you need to handle exceptions for that particular workflow, or if it’s simply easier to build that way as for this particular workflow you need to pass many/complex importing parameters.
How do I decide whether to use a functional method or create a task?
The decision is much the same as for virtual attributes in the BOR repository, i.e.
- Do you need to return more than one value? – If so use a task (of course this task will call a normal method – i.e. one with multiple exporting parameters)
- Do you need to handle exceptions? – If so use a task
- Do you only need to return a single value and exceptions are unlikley or irrelevant (will be ignored, or will be checked in a subsequent step)? – If so use a functional method
Can I use functional methods for BOR objects?
You may notice that functional methods (i.e. methods with the special “result” parameter) can also be selected. However I have personally found them a little unreliable in practice (they tend to throw errors or fail to pass data). A safer approach would be to link the BOR object to an equivalent ABAP Class, and handle the call to the BOR method inside an ABAP Class method. Linking BOR objects to ABAP Classes is the topic of our next blog.
This step-by-step explanation is fantastic.
I guess we should think about collating these blogs and adding them to the workflow Wiki.
All the best,
Alan
Is this stuff dealt with in the later two workflow courses after 600/601 ?
BTW, I just purchased the book.
As for the courses - I'm not sure to what extent ABAP OO for workflow is covered in the course content as yet, but if its in any of the courses the most likely would be BIT610 - the workflow programming course.
You might want to talk to your local SAP education office about the content in detail.
Regards,
Jocelyn
I wanted to try it, but seems to me that there are still some gaps.
Seems to me that it is quite difficult to pass parameters from WF to OO method. Is that correct that it is only possible to pass static parameters (As 'DE' in your example: &ZCL_PLANT.PLANTS_OF_COUNTRY(IV_COUNTRY='DE')&
)?
In fact I thought about re-coding selfitem.sendtaskdescription (in order to enable HTM format, CC/BCC fields etc.). But it seems to be impossible to pass the WI ID to OO method, not mentioning a task ID that is behind it.
Regards,
Michal
I'd agree that it's difficult to pass parameters when using the functional method directly in a binding or a work item subject text - usually the lack of space itself is a problem. I've not yet successfully passed a dynamic parameter using this format as usually just trying to describe the value is problematic due to the length issues.
I do find them very useful for attributes that do not require parameters - similar to the BOR virtual attributes. And also where I want a simple function with simple static parameters.
I still find it easier to call the method as a separate background task if the parameters are complex - and this is also helpful for troubleshooting when trying to understand if the problem is caused by the parameter value or the method itself.
Selfitem.sendtaskdescription is quite a complicated method - that's why the send mail step was created - and it's also a true background action with a lot of possiblities for problems to be resolved - e.g. mail server down, email address missing, etc. So it's worth keeping that as a full step.
A better use of functional methods is not for actions but for calculations - think of them as similar to a mathematical function where you want to do a calculation and return a single result - and where there's really very little that can go wrong underneath the calculation. Although there are certainly cases where it's useful to pass dynamic parameters to a calculation as well.
I would be careful of trying to convert action methods to functional methods. I usually make the decision based on whether I think I may need to troubleshoot that step - if I do I want it as a separate step so I can get the maximum possible detail about what happened in the workflow log to resolve the problem.
Regards,
Jocelyn
Thanks very much for this one. I am very much enjoying using your blog content on site here.
I hope you have a great Christmas and New Year.
Regards
Gareth Ellem
Regards,
Jocelyn
I have gone ahead and used this way of obtaining data to fill my workflow container but it has been really unreliable, the container operation works on some but not every time.
I have a static method with a returning parameter that behaves erratically a similar method returns the values because of which I am unable to identify the source of the instability.
We are on ECC5.0
Well check for starters that you are not assuming that methods are being executed in a particular order. Try just filling your static method with a constant value for the returning parameter to start with - this should help you diagnose if you have a binding problem or if the problem is in your method code.
Also carefully check your static method code - if you are calling a function module or method within it, whatever you are calling may have dependencies of its own.
Regards,
Jocelyn
Thanks for the reply.
I am basically reading the PCR Notification characteristics and their values into a predefined structure.
The functional method expects the Notification.Number as input to return the relevant data. I think I was a bit hasty in shooting off my mail as I read elsewhere that functional methods don't work with input parameters.
Regards
Ravi
I've used fairly static input parameters ok as shown in the blog, but dynamic input parameters - which is what you would need to pass your notification at runtime - are difficult and often not possible. Better to call your method via a workflow step + task if this is your requirement.
Regards,
Jocelyn
In the workflow container, under objects ZCL_PLANT, I do not see the the "Methods" section,
therefore, I could not pick any of the method (ex. Plants_of_country) under expression in the Container Operation. Did I missing something ?
Janet
Well firstly check you have defined the method correctly with a returning parameter - without that it cannot be used as a functional method and will not appear.
Secondly check your release - remember full functionality for functional methods is only available from SAPNetWeaver 6.40 and above.
Thirdly - just to double check the obvious - make sure you have expanded the object in the workflow binding. Remember you won't be able to expand it directly in the workflow container itself - only when you are using the object properties in a binding.
Hope that helps.
REgards,
Jocelyn
We are in 6.20. I guess that is why the Method does not show.
Thank you for the info.
Janet
Hello Jocelyn,Roman
Very interesting blog. i needed some help I am testing a workflow which is upgraded from 4.70 version to 6.0 . When I execute it, it gives me an error
Error '9' when calling service 'SO_OBJECT_SEND'
Could you please suggest what exactly the problem could be.
Thanks in advance.
First, the blog was a gr8 job. Helped a lot with the basics.
But I have a doubt regarding sending the values to the functional method dynamically where you have given it as
&ZCL_PLANT.PLANTS_OF_COUNTRY(IV_COUNTRY='DE')&
In my requirement, I had to give it as,
&_WI_OBJECT_ID.PLANT(W_PLANT='1000')&
But instead of giving the plant number as 1000, I am passing the plant value from user-exit to workflow, workflow to task, task to method and from method back to workflow where I have a mail step.
So while passing the plant details from the method to workflow, could you please give an idea as of how to pass it dynamically.
Thanks and regards
Indu.
Suggest you read through the other comments on this blog for the details as this question has already been asked and answered. In short - if you want to use dynamic parameters then stick to calling your method as a background task.
Hope that helps.
Regards,
Jocelyn
Hi everyone,
dynamic parameters in container operations or bindings are just working fine, but only for instance-dependent methods. At least until 6.40 SP1, calling a static class method didn't work.
Florin