Skip to Content
Author's profile photo Jocelyn Dart

Using ABAP OO methods in Workflow Tasks

In the previous blogs of this series, I talked about why we want to use ABAP OO with workflow and how to make an ABAP Class workflow-ready. This blog deals with using a workflow-ready ABAP Class directly in the simplest type of workflow – a single-step task.

How do I know if I’m ready for this?

If you haven’t read the first two blogs yet, do that now.
Why use ABAP OO with Workflow?
Getting started with ABAP OO for Workflow … using the IF_WORKFLOW interface

If you want to try the exercise in this blog in your own system, you will need an ABAP Class with the IF_WORKFLOW interface, and a system/client (SAPNetWeaver 6.20 minimum) with the workflow environment activated. If you aren’t sure if your workflow environment is activated, check transaction SWU3 in your system to quickly view and activate the workflow environment in your system. Make sure both the definition and runtime environments are activated, so you can create a task and then test it.

As mentioned in the last blog, this blog won’t teach you ABAP OO. It won’t teach you workflow either, but it should give you enough to get going even if you’ve never touched workflow before.

Note: I’ve based the examples on an ABAP Class representing a Plant as this is a well known business entity in most R/3 and ECC systems. However if you are not in a suitable system or just don’t want to use a Plant example for whatever reason, you can use your own business entity. All you will need for this exercise is an entity with a key (preferably less than 32 characters in length) and some code to call a display user interface (transaction, function, whatever) for your entity.

How do I use an ABAP OO method in a Task?

The simplest type of workflow is a single-step task, i.e. a piece of work that does one thing only. In ABAP OO terms, a single-step task calls one method only to perform this piece of work. In future blogs we’ll deal with multi-step workflows, but as multi-step workflows essentially organise single-step tasks, single-step tasks are a good place to start when building workflows.

In the last blog I mentioned that you cannot call any method inherited from the IF_WORKFLOW interface directly. So to start we need an additional method in the ABAP Class example we have been creating.

The simplest type of method for this purpose is a Public, Instance method with no parameters. A classic example of this is a DISPLAY method. Now of course the code in the method will vary depending on what you are displaying. Here is the code needed to display a Plant in a typical R/3 or ECC system.

method DISPLAY . data: ls_vt001w type v_t001w. CLEAR ls_vT001W. ls_VT001W-MANDT = SY-MANDT. ls_VT001W-WERKS = me->PLANT. CALL FUNCTION 'VIEW_MAINTENANCE_SINGLE_ENTRY' EXPORTING ACTION = 'SHOW' VIEW_NAME = 'V_T001W' CHANGING ENTRY = ls_vT001W. endmethod.

Have you noticed that I have used an attribute of the class called PLANT? This is the key (Public, Instance) attribute of my class (data type is WERKS). Make sure you add this attribute to the ABAP Class before you activate your new method.

How do you set up the value of Plant? Well of course to create an instance of an ABAP Class in the first place we need a CONSTRUCTOR method, and it’s in this method that we fill the attribute plant.

Note: Make sure you use the Create Constructor button to add the constructor method to your class.

As our ABAP Class represents a business entity, rather than a technical entity, an instance is meaningless without having this key attribute provided. So add an import parameter PLANT (data type WERKS) to the CONSTRUCTOR class so that the plant id can be provided during instantiation.

Here is some very simple code for the CONSTRUCTOR method.

METHOD constructor . me->plant = plant. ENDMETHOD.

Tip! Don’t forget to activate and test your class in transaction SE24 before contuining.

Now that we can instantiate the ABAP Class and have a method, DISPLAY, that we can call from workflow, we are ready to include the method in a single-step task.

To create a single-step task, go to transaction PFTC_INS. Choose the task type “TS” (Standard Task, i.e. a single-step task) and press the Create button. image

On the second screen the real work begins. On the Basic Data tab, give your task an abbreviation, name, and work item text – these are all free text fields so enter whatever you like. Then choose Object Category “ABAP Class”, enter your ABAP Class as the Object Type, and your DISPLAY method as Method. image

Note: If you are in a 6.20 system and can’t see the Object Category choice “ABAP Class”, then you first need to execute report SWF_CATID to enable “ABAP Classes” as an available object category. It’s already done for you in releases 6.40 and higher.

Move across to the Container tab. This is the workflow data storage area – think of it as the equivalent of a data declaration area in a program. You’ll notice that workflow has automatically added a container element (equivalent of a data variable in a program) to hold an instance of your class. It’s even marked it as available for import/export from the task to other workflow objects such as multi-step tasks and events. You can drill down on the container element if you want to see more.

image

Save your task, and then there’s two things we still need to do before you can test it.

  1. You need to clarify how the system will know when this task is complete. For a display task this is easy… running the method is all we have to do, nothing has to be changed on a database or synchronised with another system. So all that’s needed is to check the flag Synchronous object method below the Method field on the Basic Data tab, and save the task again.
  2. You need to specify who is allowed to execute this task. For simplicity’s sake, you can let anyone execute the task by making the task a General Task. Follow the menu path Additional Data – Agent Assignment – Maintain. Place your cursor on the task name, and press the Attributes… button. Select the General Task radio button, press enter and Save your task again.

image

Finally make a note of your task number and go to transaction SWUS to test your task. Type in your task id (“TS” followed by the task number) and press Enter. You’ll see the import container elements listed below. You’ll need to fill in which plant we want to display. Select the container element _WI_Object_Id and the local persistent object reference to your class is displayed below. Type a valid plant id into the field INSTID, and press Enter. image

Now simply press the Execute button in the top left hand corner of the screen and you should see the plant details displayed. That’s it! image

How do I explicitly instantiate an instance in a Task?

Last time I mentioned that you can’t call the special method CONSTRUCTOR directly from a task. Usually that’s not a problem for workflow as we would use an event to implicitly create the instance and pass that in as we started the workflow.

I’ll talk about events in the next blog, but there are occasions when you do want to explicitly create an instance in a workflow step. For example it can be more convenient to instantiate an object based on a flat value attribute of another object, rather than risk potentially recursive code by making the attribute an object instance itself. Or you might simply want to take one of the standard workflow tracked fields, such as the user id that executed a previous workflow step, and get more details, such as the user’s name.

This is also a good chance to look at:

  • Using method parameters with workflow
  • Using background methods with workflow

Start by creating a static, public method in your class – call it CREATEINSTANCE. The purpose of this method is to import a plant id and export an instance of the plant class. Make sure you create a suitable signature (import/export parameters) for your method. image

Inside the class all you need to do is to call the create object command to create the instance. Don’t worry about error handling at this stage … we’ll cover that in a later blog.

METHOD createinstance. TRY. CREATE OBJECT eo_plantinst EXPORTING plant = iv_plant . CATCH cx_bo_error . ENDTRY. ENDMETHOD.

Note: Don’t forget to syntax check, activate, and test your method works before using it in workflow.

Create a task with your CREATEINSTANCE method just as you did with the DISPLAY method. You’ll be asked if you want to “Transfer missing elements from the object method?” – Answer “yes” and you’ll notice that the import and export parameters of your method are automatically added to the task container.

This sort of task is a technical step that is called in background by the workflow system, rather than being executed by a user, so instead of making the task a General Task, mark task as a Background processing in the Execution section of the task (below the method on the Basic Data tab). Don’t forget to check the flag Synchronous object method and save again as we did for the DISPLAY task.

Test your new task using SWUS. Fill the import parameter IV_PLANT with a plant id, e.g. 1000, then press the Execute function. Because the task is executed in background we need to look at the workflow log to see if it worked. Use the Workflow log button display the work item. Then use menu path Extras > Container to see the end result. You should see the container element EO_PLANTINST has an valid reference to the plant class. image

What about functional methods?

Functional methods (i.e. a method with a RETURNING parameter) can be used as above, or you can also use them in workflow bindings (think “parameter passing” between different parts of a multi-step workflow). However at this stage, you only have a single-step task to work with so I’m going to leave how to use functional methods in a binding until later in this blog series by which time I’ll have expanded our workflow example a little further.

How do I call the task from an application?

Although it’s possible to call a task directly, e.g. using standard workflow API functions such as SAP_WAPI_START_WORKFLOW, that’s not usually the best way to tackle this very common scenario. In general, we call a task by raising an event which then use to trigger the task. So the next blog will be on using ABAP OO events as workflow events.

Assigned Tags

      33 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member
      I can't wait for the next one about OO events. 
      Thanks for the ground work Jocelyn
      Author's profile photo Jocelyn Dart
      Jocelyn Dart
      Blog Post Author
      Thanks for the encouragement Nathan! Glad you are enjoying the series. 
      Author's profile photo Luis Lu
      Luis Lu
      Thanks very much for the anylysis of workflow, such information from SAP experts are quite helpful and clarifying.
      Author's profile photo Jocelyn Dart
      Jocelyn Dart
      Blog Post Author
      Thanks Luis ... glad you are finding it helpful.
      Author's profile photo Former Member
      Former Member
      Hi Jocelyn

      In the traditional we could use EXIT_CANCELLED statement if we want to keep the workitem with the user although they have executed it - how can we achieve this with a class method without using the Confirm End Processing Checkbox

      Is there any macro we can use for the class methods to have the same behavior?

      Hoping you can help

      Your blogs are very inspiring

      Thanks & regards
      Sen

      Author's profile photo Jocelyn Dart
      Jocelyn Dart
      Blog Post Author
      Hi Sen,
      Thanks for the kind comments.
      Yes there certainly are equivalents to the EXIT_CANCELLED macro of BOR days.
      In ABAP OO, exceptions are raised using exception classes.
      The exception class to raise instead of EXIT_CANCELLED is CX_BO_ACTION_CANCELLED.
      I'm hoping to include a blog on exception classes when I find a moment.
      Regards,
      Jocelyn
      Author's profile photo Former Member
      Former Member
      Hi Jocelyn,
      We are on 6.20 SP39.  When I try to run the report SWF_CATID I get a "not found" message.  I also tried to run it as a transaction, just for grins.  No luck.

      Are we on the wrong SP level?

      Thanks,
      Ed

      Author's profile photo Former Member
      Former Member
      Ed the report is RSWF_CATID
      Author's profile photo Former Member
      Former Member
      Same issues as Ed... Cannot find SWF_CATID. My SAP system is 4.7 6.2 sp60.
      Author's profile photo Former Member
      Former Member
      Hi Jocelyn,

      This is an excellent blog. I've read all the entries and have found it very useful. Thanks for taking the time to enlighten us.

      Can I ask a question though?

      I've created an instance public method that I call from a task in a workflow, as a synchronous background task. I raise exceptions in the method and fill an exporting table (of type BAPIRET2_T) with messages that I want to include in my next step in the error handling. The exception is raised, but the table isn't filled.

      How can I raise an exception in the method, and pass some texty info about exactly what the error(s) was?

      I know I can not raise an exception, and query the messages table in the workflow. But this doesn't seem so neat.

      Thanks again,
      Para

      PS I have checked that I fill the messages table before I raise the exception.

      Author's profile photo Jocelyn Dart
      Jocelyn Dart
      Blog Post Author
      Hi Para,
      Thanks for the kind comments.  Glad you are finding the blogs useful.  Re your question:
      The nature of exceptions is that they preclude any exporting parameters being passed back.  So you can never pass back the exception AND the error messages.

      You have a couple of choices. 

      One is to pass your messages as an attribute of the exception class itself.  I haven't experimented much with this approach yet so whether you would actually be able to use the messages in a subsequent step I am not sure. 

      Another approach is as you have suggested - pass back a return code plus messages instead of an exception - and you're right this is not as neat as you then have to add a condition step just ot query the return code. 

      A third approach would be to raise a workflow event passing your messages as an event parameter.  This would definitely work in terms of passing the messages to a subsequent step and is a reasonably neat solution as the effect on the workflow template is similar to raising an exception.  You can use events to terminate synchronous steps as well as asynchronous steps.  

      Hope that helps.
      Regards,
      Jocelyn

      Author's profile photo Former Member
      Former Member
      Hi Jocelyn,

      Wow, thanks for the quick & useful response.

      I decided to go with the return code option.

      When I tried the workflow event option, the work item completed before the event was received by it. I considered changing it to an asynchronous task and trigerring an event to complete the work item when there are no exceptions, but though that it was less appropriate (for a background read some stuff work item).

      If you do get to experimenting with using exception classes, I'd love to see a blog entry on that 🙂

      Thanks,
      Para

      Author's profile photo Former Member
      Former Member
      Hi jocelyn

      Your blogs on ABAP OO and workflow are superb, but I do have one question.

      Is it possible to fill an attribute in a task and use the new value from the attribute in a later task.
      The way I read your blogs and trying it on my own system, it seems the object-constructor is called everytime a reference to the object is made and therefor the attributes are recalculated and the value written to the attribute in a earlier task is gone.
      Is this right?

      Rgds
      Flemming

      Author's profile photo Former Member
      Former Member
      Hi jocelyn

      Your blogs on ABAP OO and workflow are superb, but I do have one question.

      Is it possible to fill an attribute in a task and use the new value from the attribute in a later task.
      The way I read your blogs and trying it on my own system, it seems the object-constructor is called everytime a reference to the object is made and therefor the attributes are recalculated and the value written to the attribute in a earlier task is gone.
      Is this right?

      Rgds
      Flemming

      Author's profile photo Jocelyn Dart
      Jocelyn Dart
      Blog Post Author
      Hi Flemming,
      Thanks for the vote of confidence.

      Re your question: It's important not to confuse the role of the object and the role of the workflow.  Because there could be days/weeks/months potentially between steps of course workflow must reconstruct the object with a new step - as the value of the attribute could potentially change over time.

      However if you want to pass an object attribute from one step to another you can always do this using a container operation step or during the binding from the task to workflow of a suitable (i.e. uses your object) activity or user decision step.

      I.e. Pass the attribute value into the workflow container, and then in your subsequent step, access the value from the workflow container.

      Hope that helps.
      Regards,
      Jocelyn

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      I appreciate you taking time to help the community use ABAP classes in Workflow. These blogs are indeed useful especially when there is no book available yet.

      while trying an example of CREATEINSTANCE method, the issue i am facing is that even after successful execution of the method (i checked in the debug mode, instance is created), the container element in the task (Workflow log) remains initial. (Binding definition is correct, and parameter properties have properly been set as well). Do you see any reason why?

      Thanks,
      Saurabh

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      I appreciate you taking time to help the community, this was needed especially when there is no book available yet.

      got a question, i am unable to see the instance of Plant class created using CREATEINSTANCE method in the Workflow Log. The method is working fine (tested independently), Binding is properly set, Import/Export paramters for container elements are set, and i even checked in the debug mode (temporarily made the task Foreground) that the method creates an instance of the class. Do you know why i fail to receive the instance in the task container element?

      Thanks,
      Saurabh

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      I appreciate you taking time to help the community, this was needed especially when there is no book available yet.

      got a question, i am unable to see the instance of Plant class created using CREATEINSTANCE method in the Workflow Log. The method is working fine (tested independently), Binding is properly set, Import/Export paramters for container elements are set, and i even checked in the debug mode (temporarily made the task Foreground) that the method creates an instance of the class. Do you know why i fail to receive the instance in the task container element?

      Thanks,
      Saurabh

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      I appreciate you taking time to help the community, this was needed especially when there is no book available yet.

      got a question, i am unable to see the instance of Plant class created using CREATEINSTANCE method in the Workflow Log. The method is working fine (tested independently), Binding is properly set, Import/Export paramters for container elements are set, and i even checked in the debug mode (temporarily made the task Foreground) that the method creates an instance of the class. Do you know why i fail to receive the instance in the task container element?

      Thanks,
      Saurabh

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      I appreciate you taking time to help the community, this was needed especially when there is no book available yet.

      got a question, i am unable to see the instance of Plant class created using CREATEINSTANCE method in the Workflow Log. The method is working fine (tested independently), Binding is properly set, Import/Export paramters for container elements are set, and i even checked in the debug mode (temporarily made the task Foreground) that the method creates an instance of the class. Do you know why i fail to receive the instance in the task container element?

      Thanks,
      Saurabh

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      I appreciate you taking time to help the community, this was needed especially when there is no book available yet.

      got a question, i am unable to see the instance of Plant class created using CREATEINSTANCE method in the Workflow Log. The method is working fine (tested independently), Binding is properly set, Import/Export paramters for container elements are set, and i even checked in the debug mode (temporarily made the task Foreground) that the method creates an instance of the class. Do you know why i fail to receive the instance in the task container element?

      Thanks,
      Saurabh

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      I appreciate you taking time to help the community, this was needed especially when there is no book available yet.

      got a question, i am unable to see the instance of Plant class created using CREATEINSTANCE method in the Workflow Log. The method is working fine (tested independently), Binding is properly set, Import/Export paramters for container elements are set, and i even checked in the debug mode (temporarily made the task Foreground) that the method creates an instance of the class. Do you know why i fail to receive the instance in the task container element?

      Thanks,
      Saurabh

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      I appreciate you taking time to help the community, this was needed especially when there is no book available yet.

      got a question, i am unable to see the instance of Plant class created using CREATEINSTANCE method in the Workflow Log. The method is working fine (tested independently), Binding is properly set, Import/Export paramters for container elements are set, and i even checked in the debug mode (temporarily made the task Foreground) that the method creates an instance of the class. Do you know why i fail to receive the instance in the task container element?

      Thanks,
      Saurabh

      Author's profile photo Jocelyn Dart
      Jocelyn Dart
      Blog Post Author
      Thanks Saurabh!
      Most likely cause of your problem is binding issues between the method and the task. I've noticed that in some release/support pack combinations the task/method binding automatically generates a binding of the standard work item object id container element (_WI_OBJECT_ID) to the created instance.   However this doesn't work all that well as _WI_OBJECT_ID isn't filled by the CREATEINSTANCE method.  Use the binding button on the task to explicitly bind your returning/export paramter e.g. EO_PLANT to the matching export container element of your task, e.g. EO_PLANT and that should resolve the problem.
      Regards,
      Jocelyn
      Author's profile photo Amlan Bardhan
      Amlan Bardhan
      Hi Jocelyn,

      First of all thanks for great blog series.

      I did exactly like the way you mentioned in your reply. I see the instance of the class in the container element, however the key attributes do not have a value.

      Basically, I have a CREATEINSTANCE method with two import parameters...COMPANY_CODE and CONTRACT_NUMBER..This method calls the constructor during the CREATE OBJECT call, which has the same import parameters.
      Now the constructor sets the value of the public key attributes.

      When I run the class through SE24, everything is fine. However when instantiated through the workflow, the container element has the instance, but once expanded the key attributes dont. This is the first issue.

      The second issue is, when I bind this container element in a subsequent step to call a method of the same class, step never completes when viewed in the workflow log. The status is always "In Process"

      Here are the code snippets

      1) CREATE INSTANCE
      TRY.
            CREATE OBJECT eo_contract_inst
              EXPORTING
                i_company_code    = i_company_code
                i_contract_number = i_contract_number.
          CATCH cx_bo_error .
        ENDTRY.

      2) CONSTRUCTOR
      me->por-catid = 'CL'.
        me->por-typeid = 'ZCL_REFX_APR'.

      CONCATENATE i_company_code i_contract_number INTO me->por-instid.

      me->company_code = i_company_code.
      me->contract_number = i_contract_number.

      Any advice would be greatly appreciated.

      Thanks a lot in advance

      Author's profile photo Former Member
      Former Member
      Jocelyn,

      thanks for the great blog. What I am missing is the equivalent for the "result type" that is specified in BO-methods.

      How do you define the "outcomes" of a background task when an oo method is called?

      Thanks,
      Nils

      Author's profile photo Former Member
      Former Member
      hi.
      I'm new 2 workflow
      this blog is helpful to know the concept of classes in workflow.

      thank u and keep blogging

      Author's profile photo Former Member
      Former Member
      Hi Jocelyn,

      How are you doing ? Well, I am quiet impressed with your blogs(which acts as BASICS in OBJECT ORIENTED WORKFLOW PROGRAMMING even today for me).

      I am kind of stuck with one issue...
      I am striving to reduce the workflow container elements in the worklow, by creating the respective elements as workflow attributes. So, I wrote a method which extracts the data(with predefined logic) into these attributes, and when I call that method from workflow just by passing the instance alone as IMPORT parameter, it never updates the instance attributes back at container level(which got updated at the class level). Do you know what could been missing.

      To present my issue precisely, I defined a class which implements the interface - IF_WORKFLOW, have two attributes - PERNR and START_DATE. PERNR is a part LPOR key, so I did the following code in the BI_PERSISTENT~FIND_BY_LPOR...
      method BI_PERSISTENT~FIND_BY_LPOR.
        DATA : lv_pernr type pernr_d,
               lo_exception type ref to cx_bo_error.
        move lpor-instid(8) to lv_pernr.
        try.
          create object result
            type
              ztestingwf1
            exporting
              pernr = lv_pernr.
        endtry.
      endmethod.

      And the respective constructor definition is...
      method CONSTRUCTOR.
        data : lv_instance_result type string.
        me->lpo-catid = 'CL'.
        me->lpo-typeid = 'ZTESTINGWF1'.
        move pernr to lv_instance_result.
        me->lpo-instid = lv_instance_result.
        me->pernr = pernr.
        me->start_date = start_date.
      endmethod.

      And finally, the SET_PERNR method which is called from workflow has the following definition...
        ME->PERNR = '10007809'.
        me->start_date = sy-datum.

      At the workflow container level, I can only see the PERNR attribute being set as 10007809, but not the START_DATE attribute.

      Is there any way, that I can set these attributes by calling the standard task(method) ?

      Any clue ?

      Author's profile photo César Augusto Scheck
      César Augusto Scheck

      Hi Jocelyn,
      Congratulations for this so well-explained article! It 's helped me a lot!
      Yes it's been written a long time ago but it keeps extremelly helpful.
      I'm a newbie in workflow and your article provided me a precious guidance.
      Thanks for sharing!

      Author's profile photo César Augusto Scheck
      César Augusto Scheck

      In this article Jocelyn is totally able to help you in using abap classes and workflow in a very simple manner. There are some relevant tips she includes here to improve your knowledge and call your attention. Also, the screenshots are very clear and consistent with the text.

      Author's profile photo Modak Gupta
      Modak Gupta

      I totally agree with you Cesar!

      Author's profile photo Julius Ernesto Ku Lam
      Julius Ernesto Ku Lam

      I loved this! I have been learning a lot from you examples! Thank you!
      I only wonder, why when I try to test the instance my workflow status is ready and I cannot see the instance in the container.

      Thanks

      Author's profile photo Jocelyn Dart
      Jocelyn Dart
      Blog Post Author

      Hi Julius, If you are still stuck suggest you post your question on answers.sap.com using the tag SAP Business Workflow and include some screenshots.

      Usually it's a simple matter of correcting the local object persistence reference. Double check your code and be careful not to skip steps.

      Cheers

      Jocelyn