Quantcast
Channel: Jive Syndication Feed
Viewing all 18 articles
Browse latest View live

Web Dynpro Forms using HCM Processes and Forms

$
0
0

Like the idea of HCM Processes and Forms but not so keen on Adobe Interactive Forms?

 

There are other options! It is possible to enhance the HCM P&F Framework to cater for Web Dynpro based forms. The enhancement to the HCM P&F framework creates an alternative route and loads a custom Web Dynpro based form while still entirely utilising the HCM framework and all of the functionality that it offers, such as user events, validations and much more. This can be done using the SAP Standard Enhancement Framework available to Web Dynpro ABAP. All enhancements are recorded in the Enhancement implementation. Absolutely no modifications to SAP standard objects are necessary. Enhancements implementations can be easily activated or de-activated if necessary using the Switch Framework.

 

The only real change is around the UI layer and how the information is presented to the user. The framework and backend logic remains the same. The configuration around the HCM Processes & Forms Design Time remains the same and the Web Dynpro based forms will continue to use the settings in the config in the same manner as the Adobe Interactive forms are using them. In fact, you can even convert existing Adobe Interactive forms into Web Dynpro forms using the same config as the Adobe Interactive Form. This does not have to be a replacement for Adobe Interactive forms, but can be used in conjunction with Adobe Interactive forms.

 

Any Web Dynpro ABAP UI elements can be used within these forms, such as tabstrips, roadmaps, Collapsible Trays, Groups and even flash islands if that was required.  Tab strips, roadmaps or collapsible trays can make it easier for the user to navigate within extremely large forms. Standard features in the Web Dynpro ABAP Framework can be used, such as F4 search helps, field validations and OTR (Online Text Repository). UI control can be handled easily via UI element property bindings and the use of action handlers. The WD form can also fire user events to be handled by the backend just as you would in an Adobe Interactive Form.

 

 

The SAP Standard Adobe Interactive Forms route

Start the standard Process Execute application HRASR00_PROCESS_EXECUTE

image

 

Search for an employee using the standard employee search screen

image

 

Select the Bonus Payment process in the standard process selection step

image

 

The Process Execute application then loads up the Bonus Payment Adobe Interactive form.

image

 

The Web Dynpro Forms route

Now going back to the Process selection, this time select the Voluntary Terminations process which has been setup in configuration to be a Web Dynpro based form.


image


Now still within the Process Execute application the Adobe Interactive form is now replaced by a Web Dynpro ABAP Form.

image

 

Due to the size of this form it has been done using Tab Strips to avoid the need for scrolling. Note that as part of the enhancement a print button has also been added that loads an Adobe print form in a popup window.

image

 

In the print form popup the form can now be printed or saved if necessary

image

 

The user can then hit the "Check and Send" button and submit the process for approval, utilising the framework and workflows exactly the same as an Adobe Interactive form would.

 

This process works perfectly end to end and performance on the Web Dynpro Forms is quite impressive.


Mobile SAP Applications using DHTMLX Touch

$
0
0

Thanks to all the brilliant blogs that have been posted and most notably John Moy's series of 5 blogs around JQuery Mobile and SAP. I was inspired to do some more research around the different HTML5 Javascript Frameworks out there, and to my surprise I discovered there are actually very many of them. However, many of them are immature and not overly impressive, and were mostly catering for smartphones, and not as much for tablet devices such as iPads.

There were however 2 alternatives to JQuery Mobile that caught my attention;
Those were DHTMLX Touch and Sencha Touch. More so DHTMLX Touch, hence the reason I decided to start playing around with it and subsequently why I'm writing this blog.

I found DHTMLX Touch contains an extensive library of powerful UI components, components which I found were somewhat lacking in some of the other frameworks. UI Components which are particularly useful for designing complex user interfaces, especially for tablet devices where real estate is not as scarce as on a smartphone.

These UI components are:

  • Layout Component - allows you to design complex multi pane screens. 

  • Accordion Component - similar to the layout component but the views can be collapsed or expanded, both horizontally and vertically. Similar to the Tray UI element in Web Dynpro.

  • Grid Component - this is a table with rows and column, the grid has built in sorting capability by each column.

  • Data View Component - allows you to display a collection of objects in a multi pane view where you can specify the number of columns it is displayed in, as well as the ability to define a custom HTML template for the cells.

  • Chart Component - pie charts, bar charts and a few other types of charts can be displayed using this component

Those are the main components that make it notably different to other  frameworks but it also includes components such as Google Maps, windows, popups, lists, forms( including all HTML5 form components), carrousel, iFrame, calendar,  group list, page list, multi view ( tabbed view), scroll view, template view,  video view and toolbars.

For some good sample screenshots of the components and UI look and feel check out this link: http://www.dhtmlx.com/blog/?p=668

The framework also includes features such as navigation, pages transitions, touch event, table/list sorting & filtering etc.

An extremely power feature of DHTMLX touch is that many of the UI Components can be directly bound to a data source of any of these 4 formats: XML, JSON, JSArray or CSV. This data source can either be from a file, or from a RESTFul web service call. With minimal effort by just specifying the data source and field names per column, you can easily display the contents of a data source in table format using the grid component.

As a very quick and basic proof of concept, I wrote a few lines of code to populate an internal table from the MARAV view.  I tried using DHTMLX via a BSP, just converting the contents of an internal table into a JSON string, and binding that string to the data grid component and that worked perfectly with no problems at all.

Second task was to try an offline capable version that used a RESTFul web service call into the SAP system, again just populating some data into an internal table from view MARAV view, then converting the contents of the internal table into a JSON string and returning it in the http response. At this point i stumbled upon the issue of a CORS (Cross-Origin Resource Sharing) exception, where the browser restricts an http get/post request from communicating across multiple domains. I managed to overcome this by returning an extra header field in the http response as: Access-Control-Allow-Origin=*

Screenshot of the simple table read app I wrote as a proof of concept:

image

 

DHTMLX Touch fully supports iPhone, iPad and Android devices, and may be compatible with some others as well. It is also compatible with Phone Gap, so by using this your apps can be converted into native apps.

Another really cool feature is the online UI Design application that allows you to build your UI through a graphical designer. Very similar to the layout designer offered in Web Dynpro ABAP. You can design your UI with no code at all, and once complete you can then download the application source.
Check it out here: http://www.dhtmlx.com/touch/designer/

This is a framework I really see a lot of potential in, so I thought I would just put it out there to let people know it exists.

 

How to recreate this on your own system

Step 1 

Create HTTP Handler Class implementing IF_HTTP_EXTENSION image

 

Step 2

image

Paste the following code into the IF_HTTP_REQUEST~HANDLE_REQUEST method

 

Step 3

In transaction SICF Create a new service called zget_marav

image

 

Setting the handler to ZCL_GET_MARAV_HANDLER image

 

Lastly, activate the service.

image

 

 

Step 4

Download the following file http://dev.abap.me/get_marav.html by either right clicking on the link, and saving target, or by going to the link and viewing the source of the page. You will not be able to see anything as the file only has a place holder server url and user and password. Replace the server URL on line 14 with your own server, and on line 36 replace the user, password and client.

I am unable to paste the code here as some of the characters get changed.

 

Step 5

Either download the entire DHTMLX Framework (17MB) from here http://www.dhtmlx.com/x/download/dhtmlxTouch/dhtmlxTouch_10rc_110527.zip

Or you can download just the codebase directory zipped (174KB) that is needed from here dev.abap.me/codebase.zip

Place the codebase directory which contains the DHTMLX JavaScript library into the directory where you have created the get_marav.html file.

 

Online Demo

To view the above app on a mobile device or via a compatible web browser (Chrome, Safari or Firefox) go to: http://dev.abap.me

 

Additional Reading

I recommend reading the below blogs by John Moy on JQuery Mobile and SAP, as he goes into alot more detail on creating BSP applications, using PhoneGap and more.

Build your first Mobile web app using jQuery Mobile and ABAP - Part 1

Build your first Mobile web app using jQuery Mobile and ABAP - Part 2

Build your first Mobile web app using jQuery Mobile and ABAP - Part 3

Extend your SAP jQuery Mobile web app with HTML5 concepts and Native device features - Part 1

Extend your SAP jQuery Mobile web app with HTML5 concepts and Native device features - Part 2

 


Building offline native apps with Gateway and LBO’s

$
0
0

I’m not sure if this approach has been done before, but when searching SCN for LBO it only returned 11 results for my search, and none of them covering the use of LBO’s in this scenario. So I thought I would share this approach that I have been using in native app development to enable offline functionality.

 

Over the past few months I have been using the Gateway productivity tools for Android native development as a means to get started with consuming Netweaver Gateway OData services. The tool is a great way to accelerate the development of native apps, however given that OData does not currently support offline capability (although apparently this will be possible soon, according to SAP) it is only really useful for online apps at this point in time. Which can be expensive on bandwidth if the same data needs to constantly be downloaded every time the user accesses the app. Although the OData SDK does currently have persistence capabilities, it seems rather basic and not suitable for more complex requirements. 

 

Initially I went down the path of creating MBO’s which consumed the Gateway REST services, which worked however performance didn’t seem great. Also it felt as if by doing this, I lost all the benefits of using the OData SDK.

 

I initially considered the idea of creating my own sql lite database in the app, but due to the manual effort required to do that on each mobile platform, I started exploring the idea of using Local Business Objects (LBO’s).

 

Local Business Objects are also created in the SAP Mobile SDK eclipse development environment, in a similar way to creating MBO’s except they are not bound to a backend datasource. This means that all attributes need to be created manually. Once created they do not need to be deployed to the SAP Mobile Platform as you would do with MBO's. The Object API code can be generated for the chosen platform: Android, iOS, Blackberry, etc. The code can then be copied into your IDE, whether it be eclipse or xcode and you can start using almost all of the features of the Object API,  excluding synchronization as they LBO’s are not deployed on the SAP Mobile Platform server and are purely used for persisting the data for offline capability.

 

I thought I would list what I thought are the advantages and disadvantages of using this approach:

 

Advantages

  • Relational Database designed centrally and can be deployed to multiple mobile platforms such as Android, iOS etc.
  • Easy to use Graphical Database design tool (SAP/Sybase Mobile SDK)
  • Benefits of using the Object API excluding synchronization
  • No need to deal directly with SQL statements in native code as Object API generates all the entity classes and query methods
  • Easy generation of CRUD (Create, Read, Update and Delete) methods and any custom queries can also be easily defined in LBO in SAP Mobile SDK
  • Benefits of encrypted UltraLite Database
  • Can be used with or without SAP Mobile Platform

 

Disadvantages

 

  • Requires manual coding to map from ODP Entities to Object API Entities
  • Requires manual handling of delta query. This can be handled on the server side, by passing through a filter such as a last updated datetime stamp. Or alternatively using the OData Delta Query Support (Which I have not tried myself yet)
  • May not strictly stick to REST principals
  • Requires slightly manual means of dealing with links
  • Requires manual method of dealing with pending operations

 

I am by no means saying that this is the ideal or even best way to deal with offline scenarios, but I am just putting it out there as an idea of a possible approach to it. In fact once SAP do introduce offline capability into the OData SDK this approach will most likely become redundant.

 

I would be interested to hear how others have dealt with offline scenarios in native apps while using Netweaver Gateway, as well as any criticism, recommendations or alternative approaches.

Mobile Workflow using SAP Netweaver Gateway–Part 1

$
0
0

During April SAP ran the SAP Netweaver Gateway Partner-built Solution Drive to try increase the adoption of SAP Netweaver Gateway, by offering training and free certification of your app or UI, Netweaver Gateway Interface, or both.

 

I thought this was a great opportunity and decided to take on the challenge. Having already been experimenting with Netweaver Gateway and the Netweaver Gateway productivity accelerator, I decided to take on one of the most common business requirements there is, SAP Business Workflow.

 

Thanks to the excellent SAP standard Netweaver Gateway Workflow Services (WFSERVICE & WFHUBSERVICE) and the Gateway productivity accelerator tools for eclipse, I had an excellent starting point and foundation already built for my app.

 

 

Intro to Workflow Services

There are 2 services available as part of the SAP Netweaver Gateway Workflow Services framework, they are:

  • WFSERVICE – for use when running the service on the backend system (Embedded deployment)
  • WFHUBSERVICE – for use when running SAP Netweaver Gateway system as a Hub installation connecting to remote systems running the SAP Netweaver Gateway BEP Add-on. (Central Hub Deployment)

 

To better understand the deployment options, check out the SAP Help on Deployment Options. In my case I had setup Gateway directly on the backend system. So I ended up using the WFSERVICE option, so what I am referring to here in this blog is focusing on the Embedded deployment option using WFSERVICE. I believe they both function similarly, however I have not tried the WFHUBSERVICE option yet. The services are actually extremely well documented in the SAP Netweaver Gateway help, so it’s definitely worth a read.

 

The SAP Netweaver Gateway Workflow Services exposes all the core functionality around SAP Business Workflow including actioning decisions for tasks, forwarding tasks, attachments, substitution, notifications and much more. In addition to this, it is also highly customisable via the config tables and 3 Badis which are made available for adding in custom code.

 

Configuring Workflow Services in 10 easy steps

 

1. In transaction SPRO, go to SAP Netweaver->Gateway Service Enablement->Content->Workflow Settings

config1.PNG

 

2. Go into “Maintain Task Names and Decision Options”

config2.PNG

 

3. For each workflow type above that you would like to appear in the Workflow service, enter the Workflow ID, the step ID (which you can find in the workflow definition) and the path to an image in the mime repository which you have uploaded for use for that workflow type, as well as a step description (Workflow type description)

 

4. Select the specific workflow type and enter the Decision key, Icon Mime repository path (Icon to be used for the decision) and the Decision text

config3.PNG

 

5. Return to the menu path in SPRO and select “Enable Task Filter” and Activate the filter

config4.PNG

 

6. Go to transaction /IWFND/MAINT_SERVICE

config5.PNG

 

7. Click  Add Service button

config6.PNG

 

8. Search for WFSERVICE and click on the /IWWRK/WFSERVICE to add.

config7.PNG

 

9. Fill in the package and press the green tick

config8.PNG

 

10. You are now complete, you should see the service in the Service Catalog and can call on it by clicking on the Call browser button, where you will be able to see the path to the service and the response.

config9.PNG

 

 

Customizing Workflow Services

It can customized via the config tables mentioned above, or if there are more complex requirements which require custom coding, this can be done via 3 Badis which are made available in the framework. One of which I have utilized in my app in order to return more details for work item details.


These Badis are:

  • /IWWRK/ES_WF_MODIFY_ITEMS_IB - To change the task subject on inbox and outbox queries and when reading specific items.
  • /IWWRK/ES_WF_CUST_EXT_IB - To add extensible elements and change of task subject and description when reading a specific item.
  • /IWWRK/ES_WF_WI_BEFORE_UPD_IB - To make new functionality applicable before a decision has been applied on a 'User Decision' item.

 

 

SAP Netweaver Gateway Productivity Accelerator Tools

The Productivity accelerator tool actually has a workflow template starter app. See these blogs on how to generate your own:

 

The tool is great for proof of concepts, or to fast-track development, but still a lot of work is required to refine the apps, which is expected since the Gateway productivity accelerator is only a “Wizard” type starting point for an application, and is not intended for creating production ready apps.

 

Thanks to this great tool, it allowed me to spend more time on refining the UI/UX and additional functionality such as offline capability and other native features. It reduces much of the need to write all the low level service handling code, as the Service Proxy is automatically generated and all the parsing of data is taken care of by the OData SDK which is called on by generated proxy methods. There obviously is still a need to understand how to call OData requests and how to handle the responses, but much of it is handled by the OData SDK library and generated code.

 


The app

 

Thanks to the free certification offered by the SAP Netweaver Gateway Partner-built Solution drive, I have decided to release this version of the app for free.

You can download it through google play by searching for “pokit action” or by clicking the link below:


  Android app on Google Play

 

Some screenshots below:

 

small_web_2013-10-10-15.39.42.pngsmall_web_2013-10-10-15.41.121.png
small_web_2013-10-10-05.33.08.pngsmall_web_2013-10-10-05.34.31.png
small_web_2013-10-10-05.33.28.pngsmall_web_2013-10-10-06.10.20.png

                                        

                              

The app includes a demo mode to get a feel for it, but can also be connected to a live Netweaver Gateway system which has the Workflow Services configured. All feedback is welcome.


 

In conclusion

 

SAP Netweaver Gateway is a really great product and I’m looking forward to seeing increased customer adoption especially now that as of SAP Netweaver 7.4 it is a standard component and no longer an add-on.


Part 2 of this blog covers my experience and lessons learned in building a native Android Mobile Workflow app for SAP Netweaver Gateway: Mobile Workflow using SAP Netweaver Gateway - Part 2 – Native Android Experience

 

The iOS version is currently in development and will be available in the next few months.

Mobile Workflow using SAP Netweaver Gateway - Part 2 – Native Android Experience

$
0
0

As a follow up to my previous blog: Mobile Workflow using SAP Netweaver Gateway-Part 1, I will be going into more detail about my experience and lessons learned while building a native Android version of this app. Most of this blog is around the data consumption part of the app, and not necessarily specific to Android.

 

 

The starting point

As mentioned in my previous blog, I used the SAP Netweaver Gateway Productivity Accelerator tools and the Workflow template starter app as a starting point. The truth is, it’s a great starting point, but to achieve my goals and get the app to the quality and functionality I was aiming for, it did require an entire refactor/rewrite of most of the UI Generated code. It was definitely a great reference to assist in understanding how the OData SDK functions, and is probably advisable to use either as a reference or starting point for your first Gateway consuming app. For the next Android app I write, I will probably just use the proxy generation tool and manually write the code for the UI, as it ends up being a lot of rework to change things to how you want it.

 

 

Building offline capabilities


As OData is predominantly designed for online scenarios. This meant that the app generated would connect each time to the gateway server, and re-download the same data every time the app was loaded. As this is highly inefficient, I needed to figure out a way to persist the data so that it is saved between sessions, and then only delta updates are performed. I also wanted to include offline capabilities so the user can view and action work items while offline, and sync them when back online.


I tried experimenting with the use of MBO’s which consumed the OData services, but this approach did not work very well. I felt as if all the benefits and great features you get from the OData SDK were lost.

 

I then started considering building a SQL lite database. This process would have worked, but would have been quite time consuming, especially considering my intent to build an iOS version as well, it would require me to rebuild the data model for each platform.

 

I started using a different approach, which I wrote a blog about a few months ago, see Building offline native apps with Gateway and LBO’s

 

The approach of using LBO's has really worked great, you still get all the benefits of the Object API generated code that you would get from MBO's, excluding the synchronization to the backend, as that is done using the OData SDK. It did require manual mapping of the gateway service proxy objects to the LBO's, however this really wasn't too much effort . I also had to handle the delta updates manually.

 

I think the greatest benefit comes in now that I am building an iOS version of the app. I can just generate the Object API code for iOS or other supported platform without needing to redesign the data model.


However, with the talk of OData potentially offering offline capabilities in future, this use of LBO’s may become redundant, at which time I will revisit this approach.

 


 

Dealing with delta updates

 

OData Delta Query Support is a feature in SAP Netweaver Gateway. But due to the fact that delta support requires handling of the delta token on the server side, which I don’t believe the Workflow Services is using, in addition to the current constraint that is mentioned in the SAP Help: “Deleted records are not supported at present”, I opted to build custom logic for the handling of delta updates.

 

As a workflow inbox has the possibility of new items as well as items being removed from a person’s inbox, I opted for a checklist approach. After the initial inbox load, which retrieves the entire inbox, the subsequent calls use the $select query parameter to only return a checklist of keys of work items for the user. The checklist is then compared against the local database. Removing any keys for work items that no longer exist and creating a list of new work items that don’t yet exist on the device. If there are no new items, it will not do anything further, If there are new items, it will do subsequent query with a $filter for the work items it needs to retrieve, so only the required data is downloaded.

 

Although I do not necessarily believe this approach is ideal, it definitely does work well for this scenario. Going forward I intend to use push notifications for better delta support.

 

In other scenarios, it would probably be advisable to try and use the OData Delta Query Support for delta updates.

 

 

Performance Considerations

 

By using the $select query parameter, I am only retrieving the properties that are required by the client, thereby reducing the response size.


For data that is needed upfront, $expand is being used to retrieve data from navigational properties in one single call, instead of retrieving it individually. For all other details such as work item details, they are retrieved only when the user clicks on the item, but are then persisted so they are read from the local database subsequent times, only checking for new updates of comments and attachments from then on.


JSON support is not yet available in OData SDK 2.3. I have heard that it will probably be available later this year, and when it is I intend to convert the $format from Atom XML to JSON.

 

I have recently been running some tests to see the difference between the response size for the exact same query of a really large result set in XML vs JSON. The XML response was 6.82MB and the same response in JSON was 3.64MB, which is around 54% of the size of the Atom XML. So it’s very apparent that JSON is undoubtedly the best choice.

 

Then by adding in content-encoding gzip compression, you would be able to get the response down to around 240KB for XML and 130KB for JSON for the above scenario.

 


Compression is king

After initially not doing anything about compressing the response data, I decided to do some investigation and noticed how incredibly important compression of the data really is. By default, the code generated by the Gateway Productivity accelerator and the SDMConnectivityHelper class it generates, does not add in “Content-Encoding”.

 

When running a test on a read request without compression, the response size was 278KB. After compressing the response by adding in “ContentEncoding=gzip, deflate” to the header of the request, the response size was decreased to a mere 10KB. That’s 3.5% of the original response size, making this absolutely essential to reduce network traffic and increase performance.


The amount that the response is compressed by will be determined by the content type. Plain text will compress at a higher ratio than an already compressed image.

 

I ran 3 tests comparing the size of the XML response body, for a small, medium and large scenario:


No compression

With GZIP Compression

Compression ratio

Test 1 – Small response

24.8KB

1.25KB

95%

Test 2 – Medium response

278KB

10KB

96.4%

Test 3 – Large response

1290KB

31.88KB

97.5%

 

 

Complexities encountered

 

One of the biggest complexities I had was around how to display detailed information for the work item, considering each work item type would require different information. The description returned contains the work item text as setup in the workflow definition, however it is returned unformatted text and isn’t really very useful.

 

After investigating, I decided to make use of the Workflow Services Extensible Elements Customer Properties (XPROPS) to store the items details and use a metadata driven dynamic content population approach in the app. The Workflow Services framework offers a Badi which can be used to populate the Extensible Elements XPROPS as name value pairs. By populating this with the data as well as special tags, the app is able to read the data and format it properly using dynamically created native UI elements. 

 

See screenshot of dynamically generated work item details.

small_web2013-10-10-05.35.49.png

 

 

Native Android UI/UX Design

 

With UI/UX being something I am absolutely passionate about, I believe that one of the greatest benefits of native is in the superior UI/UX. I also believe it is of utmost importance to abide by the specific platforms design patterns and best practices.

 

Android users do not like to use native apps which look and behave like an iOS app.


With Android having such a massive developer ecosystem, one of the greatest things is the abundance of resources, open source libraries and tools to use in assisting with your development.

 

I thought I would mention some that I found most useful:

Redefining a Gateway Service to enable Delta Query Support

$
0
0

After finally upgrading Gateway to SP07, I decided to look into the new Delta Query Support functionality. I found a really great document written by Andre Fischer, How to Implement Basic Delta Query Support in SAP Netweaver Gateway, which gave me all the direction I needed. I recommend reading it to get a better understanding of Delta Query Support and the different techniques.

 

As I am currently working on incorporating offline OData support using the new OData SDK’s included in the SMP 3.0 SDK, I needed to add in Delta Query Support to my Gateway Service. However, in my case the service I am consuming is a standard service, namely WFSERVICE (Workflow Service).

 

The technique and code I applied to get this working with WFSERVICE can be applied to any service.

 

Follow the following steps to redefine and add Delta Query Support:

 

 

Step 1

 

Create a new Gateway Project in transaction SEGW

1.PNG

2.PNG

 

 

Step 2

 

Right click on the Data Model under your new project and go to Redefine->OData Service GW

3.PNG



Step 3


Select the service you would like to redefine and click Next

4.PNG



Step 4

 

Select the entities and associations you would like to redefine. Although in this case I am only going to add the Delta Query Support to the WorkflowTaskCollection entity set which uses the WorkflowTask entity, it seems to error when I don't include all the associated entities.

5.PNG

6.PNG

 

 

Step 5

 

Generate Runtime by right clicking on the project and selecting Generate Runtime.

7.PNG

 

Give the Technical Service a new name

8.PNG

 

 

 

Step 6

 

Now we need to redefine the GET_ENTITYSET and GET_ENTITYSET_DELTA methods for the Entity Collection.

 

Start by right clicking the GetEntitySet of the Service Implementation for WorkflowTaskCollection and click on Go to ABAP Workbench

9.PNG

 

 

In the ABAP Workbench, we need to redefine both GET_ENTITYSET and GET_ENTITYSET_DELTA methods.

10.PNG

 

Once both methods have been redefined, go into their Redefinitions and paste the following code:

 

 


METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset.
DATA: lo_dp_facade   TYPE REF TO /iwbep/if_mgw_dp_facade.

DATA: lv_delta_token TYPE        string.

FIELD-SYMBOLS:
      <fs_entityset>
TYPE ANY TABLE.

TRY.
     
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~get_entityset
          
EXPORTING
                iv_entity_name          
= iv_entity_name
                iv_entity_set_name      
= iv_entity_set_name
                iv_source_name          
= iv_source_name
                it_filter_select_options
= it_filter_select_options
                it_order                
= it_order
                is_paging               
= is_paging
                it_navigation_path      
= it_navigation_path
                it_key_tab              
= it_key_tab
                iv_filter_string        
= iv_filter_string
                iv_search_string        
= iv_search_string
                io_tech_request_context 
= io_tech_request_context
          
IMPORTING
                er_entityset            
= er_entityset
                es_response_context     
= es_response_context.


* get the data provider facade
     
TRY.
           lo_dp_facade
= /iwbep/if_mgw_conv_srv_runtime~get_dp_facade( ).
     
CATCH /iwbep/cx_mgw_tech_exception.
          
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception.
     
ENDTRY.


ASSIGN er_entityset->* TO <fs_entityset>.

* call the delta token functionality
     
TRY.
          
CALL METHOD /iwbep/cl_query_result_log=>create_update_log_entry_hash
               
EXPORTING
                     io_tech_request_context 
= io_tech_request_context
                     io_dp_facade            
= lo_dp_facade
                     ir_service_document_name
= mr_service_document_name
                     ir_service_version      
= mr_service_version
                     it_entityset            
= <fs_entityset>
               
CHANGING
                     ev_delta_token          
= lv_delta_token.

           es_response_context
-deltatoken = lv_delta_token.

     
CATCH /iwbep/cx_qrl_locked.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_locked.
     
CATCH /iwbep/cx_qrl_delta_unavailabl.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_delta_unavailabl.
     
ENDTRY.

     
CATCH /iwbep/cx_mgw_busi_exception .
     
CATCH /iwbep/cx_mgw_tech_exception .
ENDTRY.


ENDMETHOD.




and....

 

 

 

METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset_delta.
DATA: lo_dp_facade           TYPE REF TO /iwbep/if_mgw_dp_facade.

DATA: lv_delta_token         TYPE        string.

FIELD-SYMBOLS:
      <fs_entityset>         TYPE ANY TABLE,
      <fs_deleted_entityset>
TYPE ANY TABLE.

TRY.
     
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~get_entityset_delta
          
EXPORTING
                io_tech_request_context
= io_tech_request_context
          
IMPORTING
                er_entityset           
= er_entityset
                er_deleted_entityset   
= er_deleted_entityset
                es_response_context    
= es_response_context.

     
ASSIGN er_entityset->* TO <fs_entityset>.

     
IF er_deleted_entityset IS NOT BOUND.
          
CREATE DATA er_deleted_entityset LIKE <fs_entityset>.
     
ENDIF.

     
ASSIGN er_deleted_entityset->* TO <fs_deleted_entityset>.


* get the data provider facade
     
TRY.
           lo_dp_facade
= /iwbep/if_mgw_conv_srv_runtime~get_dp_facade( ).
     
CATCH /iwbep/cx_mgw_tech_exception.
          
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception.
     
ENDTRY.

*  call the delta token functionality
     
TRY.
          
CALL METHOD /iwbep/cl_query_result_log=>create_update_log_entry_hash
               
EXPORTING
                     io_tech_request_context 
= io_tech_request_context
                     io_dp_facade            
= lo_dp_facade
                     ir_service_document_name
= mr_service_document_name
                     ir_service_version      
= mr_service_version
                     it_entityset            
= <fs_entityset>
               
IMPORTING
                     et_deleted_entityset    
= <fs_deleted_entityset>
                     et_entityset            
= <fs_entityset>
               
CHANGING
                     ev_delta_token          
= lv_delta_token.


           es_response_context
-deltatoken = lv_delta_token.

     
CATCH /iwbep/cx_qrl_locked.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_locked.
            CATCH /iwbep/cx_qrl_delta_unavailabl.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_delta_unavailabl.
     
ENDTRY.

CATCH /iwbep/cx_mgw_busi_exception .
CATCH /iwbep/cx_mgw_tech_exception .
ENDTRY.

ENDMETHOD
.



 

 

Step 7

 

Add the new service in transaction /IWFND/MAINT_SERVICE

 

11.PNG

12.PNG

 

Click on ZWFSERVICE to add it

13.PNG

 

 

Step 8

 

Run the service in a browser via its URL: http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection

 

The difference you will notice is that there is the following additional tag at the second last line of the response:

 

<linkrel="delta"href="WorkflowTaskCollection?!deltatoken='22000AB22B051EE397AFF3B8EE42B356_20131205073405'"/>

 

Now on subsequent calls you will use the new delta token retrieved from the latest response to make sure that only new/updated and deleted entries are returned like follows: http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection?!deltatoken='22000AB22B051EE397AFF3B8EE42B356_20131205073405'

 

In the case where an entry has been deleted since the last service call and in the case of Workflow, when a work item has been approved and is no longer in the approvers worklist, the following will appear in the response:

 

<at:deleted-entryref="http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection('000001224760')"when="2013-12-05T07:33:41Z"/>



 

And that is all you need to do from the backend side, the rest would be handled on the client side.

Mobile Workflow using SAP Netweaver Gateway–Part 1

$
0
0

During April SAP ran the SAP Netweaver Gateway Partner-built Solution Drive to try increase the adoption of SAP Netweaver Gateway, by offering training and free certification of your app or UI, Netweaver Gateway Interface, or both.

 

I thought this was a great opportunity and decided to take on the challenge. Having already been experimenting with Netweaver Gateway and the Netweaver Gateway productivity accelerator, I decided to take on one of the most common business requirements there is, SAP Business Workflow.

 

Thanks to the excellent SAP standard Netweaver Gateway Workflow Services (WFSERVICE & WFHUBSERVICE) and the Gateway productivity accelerator tools for eclipse, I had an excellent starting point and foundation already built for my app.

 

 

Intro to Workflow Services

There are 2 services available as part of the SAP Netweaver Gateway Workflow Services framework, they are:

  • WFSERVICE – for use when running the service on the backend system (Embedded deployment)
  • WFHUBSERVICE – for use when running SAP Netweaver Gateway system as a Hub installation connecting to remote systems running the SAP Netweaver Gateway BEP Add-on. (Central Hub Deployment)

 

To better understand the deployment options, check out the SAP Help on Deployment Options. In my case I had setup Gateway directly on the backend system. So I ended up using the WFSERVICE option, so what I am referring to here in this blog is focusing on the Embedded deployment option using WFSERVICE. I believe they both function similarly, however I have not tried the WFHUBSERVICE option yet. The services are actually extremely well documented in the SAP Netweaver Gateway help, so it’s definitely worth a read.

 

The SAP Netweaver Gateway Workflow Services exposes all the core functionality around SAP Business Workflow including actioning decisions for tasks, forwarding tasks, attachments, substitution, notifications and much more. In addition to this, it is also highly customisable via the config tables and 3 Badis which are made available for adding in custom code.

 

Configuring Workflow Services in 10 easy steps

 

1. In transaction SPRO, go to SAP Netweaver->Gateway Service Enablement->Content->Workflow Settings

config1.PNG

 

2. Go into “Maintain Task Names and Decision Options”

config2.PNG

 

3. For each workflow type above that you would like to appear in the Workflow service, enter the Workflow ID, the step ID (which you can find in the workflow definition) and the path to an image in the mime repository which you have uploaded for use for that workflow type, as well as a step description (Workflow type description)

 

4. Select the specific workflow type and enter the Decision key, Icon Mime repository path (Icon to be used for the decision) and the Decision text

config3.PNG

 

5. Return to the menu path in SPRO and select “Enable Task Filter” and Activate the filter

config4.PNG

 

6. Go to transaction /IWFND/MAINT_SERVICE

config5.PNG

 

7. Click  Add Service button

config6.PNG

 

8. Search for WFSERVICE and click on the /IWWRK/WFSERVICE to add.

config7.PNG

 

9. Fill in the package and press the green tick

config8.PNG

 

10. You are now complete, you should see the service in the Service Catalog and can call on it by clicking on the Call browser button, where you will be able to see the path to the service and the response.

config9.PNG

 

 

Customizing Workflow Services

It can customized via the config tables mentioned above, or if there are more complex requirements which require custom coding, this can be done via 3 Badis which are made available in the framework. One of which I have utilized in my app in order to return more details for work item details.


These Badis are:

  • /IWWRK/ES_WF_MODIFY_ITEMS_IB - To change the task subject on inbox and outbox queries and when reading specific items.
  • /IWWRK/ES_WF_CUST_EXT_IB - To add extensible elements and change of task subject and description when reading a specific item.
  • /IWWRK/ES_WF_WI_BEFORE_UPD_IB - To make new functionality applicable before a decision has been applied on a 'User Decision' item.

 

 

SAP Netweaver Gateway Productivity Accelerator Tools

The Productivity accelerator tool actually has a workflow template starter app. See these blogs on how to generate your own:

 

The tool is great for proof of concepts, or to fast-track development, but still a lot of work is required to refine the apps, which is expected since the Gateway productivity accelerator is only a “Wizard” type starting point for an application, and is not intended for creating production ready apps.

 

Thanks to this great tool, it allowed me to spend more time on refining the UI/UX and additional functionality such as offline capability and other native features. It reduces much of the need to write all the low level service handling code, as the Service Proxy is automatically generated and all the parsing of data is taken care of by the OData SDK which is called on by generated proxy methods. There obviously is still a need to understand how to call OData requests and how to handle the responses, but much of it is handled by the OData SDK library and generated code.

 


The app

 

Thanks to the free certification offered by the SAP Netweaver Gateway Partner-built Solution drive, I have decided to release this version of the app for free.

You can download it through google play by searching for “pokit action” or by clicking the link below:


  Android app on Google Play

 

Some screenshots below:

 

small_web_2013-10-10-15.39.42.pngsmall_web_2013-10-10-15.41.121.png
small_web_2013-10-10-05.33.08.pngsmall_web_2013-10-10-05.34.31.png
small_web_2013-10-10-05.33.28.pngsmall_web_2013-10-10-06.10.20.png

                                        

                              

The app includes a demo mode to get a feel for it, but can also be connected to a live Netweaver Gateway system which has the Workflow Services configured. All feedback is welcome.


 

In conclusion

 

SAP Netweaver Gateway is a really great product and I’m looking forward to seeing increased customer adoption especially now that as of SAP Netweaver 7.4 it is a standard component and no longer an add-on.


Part 2 of this blog covers my experience and lessons learned in building a native Android Mobile Workflow app for SAP Netweaver Gateway: Mobile Workflow using SAP Netweaver Gateway - Part 2 – Native Android Experience

 

The iOS version is currently in development and will be available in the next few months.

Mobile Workflow using SAP Netweaver Gateway - Part 2 – Native Android Experience

$
0
0

As a follow up to my previous blog: Mobile Workflow using SAP Netweaver Gateway-Part 1, I will be going into more detail about my experience and lessons learned while building a native Android version of this app. Most of this blog is around the data consumption part of the app, and not necessarily specific to Android.

 

 

The starting point

As mentioned in my previous blog, I used the SAP Netweaver Gateway Productivity Accelerator tools and the Workflow template starter app as a starting point. The truth is, it’s a great starting point, but to achieve my goals and get the app to the quality and functionality I was aiming for, it did require an entire refactor/rewrite of most of the UI Generated code. It was definitely a great reference to assist in understanding how the OData SDK functions, and is probably advisable to use either as a reference or starting point for your first Gateway consuming app. For the next Android app I write, I will probably just use the proxy generation tool and manually write the code for the UI, as it ends up being a lot of rework to change things to how you want it.

 

 

Building offline capabilities


As OData is predominantly designed for online scenarios. This meant that the app generated would connect each time to the gateway server, and re-download the same data every time the app was loaded. As this is highly inefficient, I needed to figure out a way to persist the data so that it is saved between sessions, and then only delta updates are performed. I also wanted to include offline capabilities so the user can view and action work items while offline, and sync them when back online.


I tried experimenting with the use of MBO’s which consumed the OData services, but this approach did not work very well. I felt as if all the benefits and great features you get from the OData SDK were lost.

 

I then started considering building a SQL lite database. This process would have worked, but would have been quite time consuming, especially considering my intent to build an iOS version as well, it would require me to rebuild the data model for each platform.

 

I started using a different approach, which I wrote a blog about a few months ago, see Building offline native apps with Gateway and LBO’s

 

 

The approach of using LBO's has really worked great, you still get all the benefits of the Object API generated code that you would get from MBO's, excluding the synchronization to the backend, as that is done using the OData SDK. It did require manual mapping of the gateway service proxy objects to the LBO's, however this really wasn't too much effort . I also had to handle the delta updates manually.

 

 

I think the greatest benefit comes in now that I am building an iOS version of the app. I can just generate the Object API code for iOS or other supported platform without needing to redesign the data model.


However, with the talk of OData potentially offering offline capabilities in future, this use of LBO’s may become redundant, at which time I will revisit this approach.

 


 

Dealing with delta updates

 

OData Delta Query Support is a feature in SAP Netweaver Gateway. But due to the fact that delta support requires handling of the delta token on the server side, which I don’t believe the Workflow Services is using, in addition to the current constraint that is mentioned in the SAP Help: “Deleted records are not supported at present”, I opted to build custom logic for the handling of delta updates.

 

As a workflow inbox has the possibility of new items as well as items being removed from a person’s inbox, I opted for a checklist approach. After the initial inbox load, which retrieves the entire inbox, the subsequent calls use the $select query parameter to only return a checklist of keys of work items for the user. The checklist is then compared against the local database. Removing any keys for work items that no longer exist and creating a list of new work items that don’t yet exist on the device. If there are no new items, it will not do anything further, If there are new items, it will do subsequent query with a $filter for the work items it needs to retrieve, so only the required data is downloaded.

 

Although I do not necessarily believe this approach is ideal, it definitely does work well for this scenario. Going forward I intend to use push notifications for better delta support.

 

In other scenarios, it would probably be advisable to try and use the OData Delta Query Support for delta updates.

 

 

Performance Considerations

 

By using the $select query parameter, I am only retrieving the properties that are required by the client, thereby reducing the response size.


For data that is needed upfront, $expand is being used to retrieve data from navigational properties in one single call, instead of retrieving it individually. For all other details such as work item details, they are retrieved only when the user clicks on the item, but are then persisted so they are read from the local database subsequent times, only checking for new updates of comments and attachments from then on.


JSON support is not yet available in OData SDK 2.3. I have heard that it will probably be available later this year, and when it is I intend to convert the $format from Atom XML to JSON.

 

I have recently been running some tests to see the difference between the response size for the exact same query of a really large result set in XML vs JSON. The XML response was 6.82MB and the same response in JSON was 3.64MB, which is around 54% of the size of the Atom XML. So it’s very apparent that JSON is undoubtedly the best choice.

 

Then by adding in content-encoding gzip compression, you would be able to get the response down to around 240KB for XML and 130KB for JSON for the above scenario.

 

 


Compression is king

After initially not doing anything about compressing the response data, I decided to do some investigation and noticed how incredibly important compression of the data really is. By default, the code generated by the Gateway Productivity accelerator and the SDMConnectivityHelper class it generates, does not add in “Content-Encoding”.

 

When running a test on a read request without compression, the response size was 278KB. After compressing the response by adding in “ContentEncoding=gzip, deflate” to the header of the request, the response size was decreased to a mere 10KB. That’s 3.5% of the original response size, making this absolutely essential to reduce network traffic and increase performance.


The amount that the response is compressed by will be determined by the content type. Plain text will compress at a higher ratio than an already compressed image.

 

I ran 3 tests comparing the size of the XML response body, for a small, medium and large scenario:


 

No compression

With GZIP Compression

Compression ratio

Test 1 – Small response

24.8KB

1.25KB

95%

Test 2 – Medium response

278KB

10KB

96.4%

Test 3 – Large response

1290KB

31.88KB

97.5%

 

 

Complexities encountered

 

One of the biggest complexities I had was around how to display detailed information for the work item, considering each work item type would require different information. The description returned contains the work item text as setup in the workflow definition, however it is returned unformatted text and isn’t really very useful.

 

After investigating, I decided to make use of the Workflow Services Extensible Elements Customer Properties (XPROPS) to store the items details and use a metadata driven dynamic content population approach in the app. The Workflow Services framework offers a Badi which can be used to populate the Extensible Elements XPROPS as name value pairs. By populating this with the data as well as special tags, the app is able to read the data and format it properly using dynamically created native UI elements. 

 

See screenshot of dynamically generated work item details.

small_web2013-10-10-05.35.49.png

 

 

Native Android UI/UX Design

 

With UI/UX being something I am absolutely passionate about, I believe that one of the greatest benefits of native is in the superior UI/UX. I also believe it is of utmost importance to abide by the specific platforms design patterns and best practices.

 

Android users do not like to use native apps which look and behave like an iOS app.


With Android having such a massive developer ecosystem, one of the greatest things is the abundance of resources, open source libraries and tools to use in assisting with your development.

 

I thought I would mention some that I found most useful:


Redefining a Gateway Service to enable Delta Query Support

$
0
0

After finally upgrading Gateway to SP07, I decided to look into the new Delta Query Support functionality. I found a really great document written by Andre Fischer, How to Implement Basic Delta Query Support in SAP Netweaver Gateway, which gave me all the direction I needed. I recommend reading it to get a better understanding of Delta Query Support and the different techniques.

 

As I am currently working on incorporating offline OData support using the new OData SDK’s included in the SMP 3.0 SDK, I needed to add in Delta Query Support to my Gateway Service. However, in my case the service I am consuming is a standard service, namely WFSERVICE (Workflow Service).

 

The technique and code I applied to get this working with WFSERVICE can be applied to any service.

 

Follow the following steps to redefine and add Delta Query Support:

 

 

Step 1

 

Create a new Gateway Project in transaction SEGW

1.PNG

2.PNG

 

 

Step 2

 

Right click on the Data Model under your new project and go to Redefine->OData Service GW

3.PNG



Step 3


Select the service you would like to redefine and click Next

4.PNG



Step 4

 

Select the entities and associations you would like to redefine. Although in this case I am only going to add the Delta Query Support to the WorkflowTaskCollection entity set which uses the WorkflowTask entity, it seems to error when I don't include all the associated entities.

5.PNG

6.PNG

 

 

Step 5

 

Generate Runtime by right clicking on the project and selecting Generate Runtime.

7.PNG

 

Give the Technical Service a new name

8.PNG

 

 

 

Step 6

 

Now we need to redefine the GET_ENTITYSET and GET_ENTITYSET_DELTA methods for the Entity Collection.

 

Start by right clicking the GetEntitySet of the Service Implementation for WorkflowTaskCollection and click on Go to ABAP Workbench

9.PNG

 

 

In the ABAP Workbench, we need to redefine both GET_ENTITYSET and GET_ENTITYSET_DELTA methods.

10.PNG

 

Once both methods have been redefined, go into their Redefinitions and paste the following code:

 

 


METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset.
DATA: lo_dp_facade   TYPE REF TO /iwbep/if_mgw_dp_facade.

DATA: lv_delta_token TYPE        string.

FIELD-SYMBOLS:
      <fs_entityset>
TYPE ANY TABLE.

TRY.
     
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~get_entityset
          
EXPORTING
                iv_entity_name          
= iv_entity_name
                iv_entity_set_name      
= iv_entity_set_name
                iv_source_name          
= iv_source_name
                it_filter_select_options
= it_filter_select_options
                it_order                
= it_order
                is_paging               
= is_paging
                it_navigation_path      
= it_navigation_path
                it_key_tab              
= it_key_tab
                iv_filter_string        
= iv_filter_string
                iv_search_string        
= iv_search_string
                io_tech_request_context 
= io_tech_request_context
          
IMPORTING
                er_entityset            
= er_entityset
                es_response_context     
= es_response_context.


* get the data provider facade
     
TRY.
           lo_dp_facade
= /iwbep/if_mgw_conv_srv_runtime~get_dp_facade( ).
     
CATCH /iwbep/cx_mgw_tech_exception.
          
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception.
     
ENDTRY.


ASSIGN er_entityset->* TO <fs_entityset>.

* call the delta token functionality
     
TRY.
          
CALL METHOD /iwbep/cl_query_result_log=>create_update_log_entry_hash
               
EXPORTING
                     io_tech_request_context 
= io_tech_request_context
                     io_dp_facade            
= lo_dp_facade
                     ir_service_document_name
= mr_service_document_name
                     ir_service_version      
= mr_service_version
                     it_entityset            
= <fs_entityset>
               
CHANGING
                     ev_delta_token          
= lv_delta_token.

           es_response_context
-deltatoken = lv_delta_token.

     
CATCH /iwbep/cx_qrl_locked.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_locked.
     
CATCH /iwbep/cx_qrl_delta_unavailabl.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_delta_unavailabl.
     
ENDTRY.

     
CATCH /iwbep/cx_mgw_busi_exception .
     
CATCH /iwbep/cx_mgw_tech_exception .
ENDTRY.


ENDMETHOD.




and....

 

 

 

METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset_delta.
DATA: lo_dp_facade           TYPE REF TO /iwbep/if_mgw_dp_facade.

DATA: lv_delta_token         TYPE        string.

FIELD-SYMBOLS:
      <fs_entityset>         TYPE ANY TABLE,
      <fs_deleted_entityset>
TYPE ANY TABLE.

TRY.
     
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~get_entityset_delta
          
EXPORTING
                io_tech_request_context
= io_tech_request_context
          
IMPORTING
                er_entityset           
= er_entityset
                er_deleted_entityset   
= er_deleted_entityset
                es_response_context    
= es_response_context.

     
ASSIGN er_entityset->* TO <fs_entityset>.

     
IF er_deleted_entityset IS NOT BOUND.
          
CREATE DATA er_deleted_entityset LIKE <fs_entityset>.
     
ENDIF.

     
ASSIGN er_deleted_entityset->* TO <fs_deleted_entityset>.


* get the data provider facade
     
TRY.
           lo_dp_facade
= /iwbep/if_mgw_conv_srv_runtime~get_dp_facade( ).
     
CATCH /iwbep/cx_mgw_tech_exception.
          
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception.
     
ENDTRY.

*  call the delta token functionality
     
TRY.
          
CALL METHOD /iwbep/cl_query_result_log=>create_update_log_entry_hash
               
EXPORTING
                     io_tech_request_context 
= io_tech_request_context
                     io_dp_facade            
= lo_dp_facade
                     ir_service_document_name
= mr_service_document_name
                     ir_service_version      
= mr_service_version
                     it_entityset            
= <fs_entityset>
               
IMPORTING
                     et_deleted_entityset    
= <fs_deleted_entityset>
                     et_entityset            
= <fs_entityset>
               
CHANGING
                     ev_delta_token          
= lv_delta_token.


           es_response_context
-deltatoken = lv_delta_token.

     
CATCH /iwbep/cx_qrl_locked.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_locked.
            CATCH /iwbep/cx_qrl_delta_unavailabl.
          
RAISE EXCEPTION TYPE /iwbep/cx_qrl_delta_unavailabl.
     
ENDTRY.

CATCH /iwbep/cx_mgw_busi_exception .
CATCH /iwbep/cx_mgw_tech_exception .
ENDTRY.

ENDMETHOD
.



 

 

Step 7

 

Add the new service in transaction /IWFND/MAINT_SERVICE

 

11.PNG

12.PNG

 

Click on ZWFSERVICE to add it

13.PNG

 

 

Step 8

 

Run the service in a browser via its URL: http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection

 

The difference you will notice is that there is the following additional tag at the second last line of the response:

 

<linkrel="delta"href="WorkflowTaskCollection?!deltatoken='22000AB22B051EE397AFF3B8EE42B356_20131205073405'"/>

 

Now on subsequent calls you will use the new delta token retrieved from the latest response to make sure that only new/updated and deleted entries are returned like follows: http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection?!deltatoken='22000AB22B051EE397AFF3B8EE42B356_20131205073405'

 

In the case where an entry has been deleted since the last service call and in the case of Workflow, when a work item has been approved and is no longer in the approvers worklist, the following will appear in the response:

 

<at:deleted-entryref="http://my.domain.com:8200/sap/opu/odata/sap/ZWFSERVICE/WorkflowTaskCollection('000001224760')"when="2013-12-05T07:33:41Z"/>



 

And that is all you need to do from the backend side, the rest would be handled on the client side.

Real-time notifications and workflow using ABAP Push Channels (websockets) Part 2: Broadcasting the message via Workitem exits

$
0
0

This is Part 2 of the below series of blogs:

 

 

 

There are many ways to approach the broadcasting of the message. You could either do this via user-exits, BADI’s, implicit enhancement points, using Event Type Linkages such as in transaction SWETYPV as used by SAP Business workflow and using a Receiver Function Module instead of a workflow or any other way you can think of.

 

However, in my case, as I want to notify a user when a work item has been created, it seemed appropriate to use a work item Program Exit class handler. Each use case should be assessed on a case by case basis and use the appropriate method. You may choose to do it differently if you find a more efficient way of doing it.

 

So in my example, I’m going to use a Parked Journal Approval workflow and in the dialog activity step I’m going to go to the Program Exits tab. There you will see you can enter any number of classes to be used as Program exits. If you go to the F1 help of the class field, it shows that the class must implement the IF_SWF_IFS_WORKITEM_EXIT interface and the code executed must be in the method EVENT_RAISED.

 

011.PNG

 

 

We now need to create an Exit handler class which implements this interface.

012.PNG

013.PNG

 

And implement the following code in the IF_SWF_IFS_WORKITEM_EXIT~EVENT_RAISED method.



METHOD if_swf_ifs_workitem_exit~event_raised.


     DATA: lo_producer_text TYPE REF TO if_amc_message_producer_text.
     DATA: lx_amc_error     TYPE REF TO cx_amc_error.


     DATA: lv_channel_ext TYPE amc_channel_extension_id.


* Check the work item event, it could be any of the following:

* BEF_CREAT  - before creation

* CREATED    - after creation

* BEF_EXEC   - before execution

* AFT_EXEC   - after execution

* AFT_ASYINV  - after async invoke

* BEF_REMOVE - before remove

* STATE_CHG  - state changed

* AFT_REXEC  - after rule exec

* BEF_ACTION - before action

* AFT_ACTION - after_action

* BEF_DECI   - before decision

*

* In our case we are going to broadcast a message for CREATED event


    CASE im_event_name.

      WHEN if_swf_ifs_workitem_exit=>c_evttyp_after_create.


         DATA(ls_header) = im_workitem_context->get_header( ).


         DATA(lo_wi) = cl_swf_run_wim_factory=>find_by_wiid( im_wiid = ls_header-wi_id ).


* Get the workitem agents to broadcast the message to

         DATA(lt_agents) = lo_wi->get_agents( ).


* Create the notification message, which will just be 'You have a new work item:' + work item text

         DATA(lv_message) = 'You have a new work item:'&& cl_abap_char_utilities=>horizontal_tab&& ls_header-wi_text.


         LOOP lt_agents AT ASSIGNING FIELD-SYMBOL(<ls_agent>) WHERE otype = 'US'.

              lv_channel_ext = sy-mandt && <ls_agent>-objid.

             
              TRY.

                    lo_producer_text ?= cl_amc_channel_manager=>create_message_producer( i_application_id = 'ZAMC_WF_NOTIFY'

                                             i_channel_id      = '/workflow_notify'

                                             i_channel_extension_id = lv_channel_ext ).


* Send message to the AMC channel

                    lo_producer_text->send( i_message = lv_message ).


              CATCH cx_amc_error INTO lx_amc_error.

                    MESSAGE lx_amc_error->get_text( ) TYPE 'E'.
              ENDT
RY.

         ENDLOOP.

     ENDCASE.
ENDMETHOD.

 

 

 

After saving and activating this class, add it as a Program Exit in the Workitem Activity step and reactivate the Workflow template.

014.PNG

 

 

 

Lastly, we want to add this Program exit class to our AMC (ABAP Messaging Channel) under the list of Authorised Programs. Do this by going back to the AMC in transaction SAMC. Entering the following:

 

 

Authorised Program: ZCL_WORKITEM_EXIT_WF_NOTIFY
Prog. Type: CLASS
Activity: Send

 

015.PNG

 

Next we need to create a client which will connect to the APC(websocket) and listen for messages that are broadcast from the workitem exit.

 

If you are interested in doing this via a UI5 application see: Real-time notifications and workflow using ABAP Push Channels (websockets)  Part 3: Creating a UI5 Application for receiving notifications

 

Or if you are more interested in doing this in Web Dynpro ABAP you can go straight to: Real-time notifications and workflow using ABAP Push Channels (websockets)  Part 4: Creating a Web Dynpro ABAP Application for receiving notifications

Real-time notifications and workflow using ABAP Push Channels (websockets) Part 1: Creating the APC and AMC

$
0
0

After hearing all about websocket technology at Tech-ed last year, I’ve been extremely eager to try it out. I found there were a few great blogs already written about ABAP Push Channels and how to create your own. I recommend reading the following useful blogs and documents to get a good understanding of ABAP Push Channels:

 


and the following series of blogs by Masoud Aghadavoodi Jolfaei

 

 

So in this blog I'm not going to go into detail about what ABAP Push Channels are all about, I'd recommend reading the blogs and documents above for that.
I’m rather going to demonstrate a real-life possible use case for ABAP Push Channels (websockets).  As entertaining as it is seeing it being used for ping pong games, thats unlikely to be very useful in an enterprise environment.

 

After writing this, I realised that it would be way too large to post as 1 blog. So I have divided it into several parts and each part will be posted in the appropriate space on SCN. See links below:

 


Please Note that this was all done on an ABAP 740 SP06 backend. Much of this is really new and may not be available or the same in prior versions.

 

The idea is to build a small UI5 or Web Dynpro ABAP Application to display the users Workflow Inbox. This application can either be run standalone or could even be used as a Side Panel Application in the NWBC client, which would possibly be the most appropriate use since it will always be open and be in the users sight while they are busy with other transactions.

 

Although I am using workflow as the use case to demo this, truthfully, this can be applied to any application in a very similar manner. These notifications are not only being used to display a message in the application, but also to inform the application that there has been a change and a refresh is necessary, therefore the application can reload the data. A push to pull type scenario. This prevents the need for periodic refreshes or for the user to constantly be pressing the refresh button to see if there have been changes.

 

Step 1 – Create the ABAP Push Channel


Got transaction SAPC (ABAP Push Channels). Right click on “ABAP Push Channels” and click Create.

001.PNG

 

 

Enter the name, in this case ZAPC_WF_NOTIFY. Then save to transport or as local object.

002.PNG

 

 

Enter a description then press the Generate Class and Service button.

003.PNG

 

 

Once generation is complete you will see the following message:

004.PNG

 

 

Navigate into the new generated class ZCL_APC_WS_EXT_ZAPC_WF_NOTIFY. Select IF_APC_WS_EXTENSION~ON_START and press the Redefine button . Then do the same for IF_APC_WS_EXTENSION~ON_MESSAGE.

005.PNG

 

 

 

For now leave the implementations of these methods blank, as we will return to enter the code in here after creating the AMC (ABAP Messaging Channel). Activate the class. Then Save and Activate the ABAP Push Channel.

006.PNG

 

 

 

Step 2 – Create the ABAP Messaging Channel


Goto transaction SAMC and right click on “ABAP Messaging Channels” and press Create.

007.PNG

 

 

Enter the name ZAMC_WF_NOTIFY. Then save to transport or as local object.

008.PNG

 

 

Enter a Description. Put /workflow_notify in Channels and set Message Type ID to TEXT and Activity Scope to System (User will not allow messages to be sent from one user to another). In order to make the messages user specific, we use the channel extension in bind_message_amc_consumer method call and the create_message_producer calls.

 

Then add the following entry to list of Authorised Programs:

Authorised Program: ZCL_APC_WS_EXT_ZAPC_WF_NOTIFY (class was created in the previous  step)
Prog. Type: CLAS
Activity: Receive via APC WebSocket

 

In subsequent steps we will add in an additional entry in Authorised programs to allow the program broadcasting the message to use the ABAP Messaging Channel.

009.PNG

Save and Activate the AMC (ABAP Messaging Channel)

010.PNG

 

 

 

Step 3 - Implement the code for the Messaging Channel in the APC

 

Go back to the APC class we created in step 1 and now implement the following code in the IF_APC_WS_EXTENSION~ON_START method. We are going to leave the IF_APC_WS_EXTENSION~ON_MESSAGE method blank as in this use case the client won't be sending any messages back to the ABAP backend. However, if it were to do so, we would need to add code into this method to handle it.

 

METHOD if_apc_ws_extension~on_start .
     
DATA: lv_channel_ext TYPE amc_channel_extension_id.

     
TRY.
* Set the Channel extension to the user who is connecting,

* this is to ensure the user in a specific client only receives their own messages   

      lv_channel_ext = sy-mandt && sy-uname.

 

* Bind the APC (Websocket) we created in step 1 to the AMC ABAP Messagin Channel we created in step 2   

      DATA(lo_binding)= i_context->get_binding_manager( ).
      lo_binding->bind_amc_message_consumer( i_application_id  = 'ZAMC_WF_NOTIFY'

                                             i_channel_id      = '/workflow_notify'

                                             i_channel_extension_id = lv_channel_ext ).
     

     CATCH cx_apc_error INTO DATA(lx_apc_error).
          DATA(lv_message) = lx_apc_error->get_text( ).

          MESSAGE lx_apc_error->get_text( ) TYPE 'E'.
     ENDT
RY.

ENDMETHOD.

 

In the next part we will create the work item exits which will broadcast the message via the ABAP Messaging Channel.

 

See Real-time notifications and workflow using ABAP Push Channels (websockets) Part 2: Broadcasting the message via Workitem exits

Real-time notifications and workflow using ABAP Push Channels (websockets) Part 3: Creating a UI5 Application for receiving notifications

$
0
0

This is Part 3 of the below series of blogs:

 

 

 

Here we are going to create a simple UI5 Application which consumes the standard Gateway TASKPROCESSING service. This requires component IWPGW to be installed on the system and is the same service as is used by the Unified Inbox and Fiori Approve Requests. The application will display the users workflow inbox and will automatically notify them of new messages and refresh the list when a new work item is created via the workitem exit created in Part 2.

 

In Eclipse Using the UI5 Toolkit Create a new application.

 

Goto File->New->Other…

016.PNG

 

 

Select UI5 Application and press Next

017.PNG

 

 

Give the Project a name: ZWF_WF_INBOX_MINI

018.PNG

 

 

Give the view a name: Main and leave the Development Paradigm as Javascript and press Finish.

019.PNG

 

Expand the application created and paste the following code into Main.controller.js and Main.view.js

020.PNG


Main.view.js code:




sap.ui.jsview("zwf_inbox_mini.Main", {

 

      /**SpecifiestheControllerbelongingtothisView.

      *Inthecasethatitisnotimplemented,orthat"null"isreturned,thisViewdoesnothaveaController.

      *@memberOfzwf_inbox_mini.Main

      */

      getControllerName : function() {

            return"zwf_inbox_mini.Main";

      },

 

      /**IsinitiallycalledonceaftertheControllerhasbeeninstantiated.ItistheplacewheretheUIisconstructed.

      *SincetheControllerisgiventothismethod,itseventhandlerscanbeattachedrightaway.

      *@memberOfzwf_inbox_mini.Main

      */

      createContent : function(oController) {

            //Create List

            varoList = new sap.m.List();

  

            //Create ListItem Template

            varoListItem =

  

            //Bind list to collection

            oList.bindItems("/TaskCollection",

                                    new sap.m.StandardListItem({title : "{CreatedByName}", description : "{TaskTitle}"}),

                                    new sap.ui.model.Sorter ("CreatedOn", true));

  

            returnnew sap.m.Page("idPage1",{

                  title: "Worklist",

                  content: [ oList

                  ]

            });

      }

});

 

 

Main.controller.js code:



sap.ui.controller("zwf_inbox_mini.Main", {

 

/**

*CalledwhenacontrollerisinstantiatedanditsViewcontrols(ifavailable)arealreadycreated.

*CanbeusedtomodifytheViewbeforeitisdisplayed,tobindeventhandlersanddootherone-timeinitialization.

*@memberOfzwf_inbox_mini.Main

*/

      onInit: function() {

            //Initialise the websocket connection

            this.initWorkflowNotifyWebsocket();

  

            //Initialise OData Model using SAP standard TASK PROCESSING service from component IWPGW

            oModel = new sap.ui.model.odata.ODataModel("/sap/opu/odata/IWPGW/TASKPROCESSING;v=2");

            sap.ui.getCore().setModel(oModel);

  

            //Get Work item count

            this.setWorkitemsCount();

      },

 

      // this function returns the count of work items

      setWorkitemsCount: function(){

            // Get Tasks count

          $.get( sap.ui.getCore().getModel().sServiceUrl +"/TaskCollection/$count" , function(data) {      

            sap.ui.getCore().byId("idPage1").setTitle("Worklist (" + data + ")");

              }, "text")  ; 

      },

 

      //this function initialises the websocket connection

      initWorkflowNotifyWebsocket : function() {

            var hostLocation = window.location, socket, socketHostURI, webSocketURI;

            if (hostLocation.protocol === "https:") {

                  socketHostURI = "wss:";

            } else {

                  socketHostURI = "ws:";

            }

            socketHostURI += "//" + hostLocation.host;

            webSocketURI = socketHostURI + '/sap/bc/apc/sap/zapc_wf_notify';

             

            try {

                  socket = new WebSocket(webSocketURI);

                  socket.onopen = function() { };

                  varthat = this;

        

                  //Create function for handling websocket messages

                  socket.onmessage = function(wfNotify) {

                        //When a message is received refresh the OData model

                        sap.ui.getCore().getModel().refresh(false, null, null);

              

                        //Re-calculate the workitem count

                        that.setWorkitemsCount();

              

                        //Create a popup toast message to notify the user

                        sap.m.MessageToast.show(wfNotify.data);  

                  };

                  socket.onclose = function() {

                  };

            } catch (exception) {

            }

      },

 

/**

*SimilartoonAfterRendering,butthishookisinvokedbeforethecontroller'sViewisre-rendered

*(NOTbeforethefirstrendering!onInit()isusedforthatone!).

*@memberOfzwf_inbox_mini.Main

*/

//    onBeforeRendering: function() {

//

//    },

 

/**

*CalledwhentheViewhasbeenrendered(soitsHTMLispartofthedocument).Post-renderingmanipulationsoftheHTMLcouldbedonehere.

*ThishookisthesameonethatSAPUI5controlsgetafterbeingrendered.

*@memberOfzwf_inbox_mini.Main

*/

//    onAfterRendering: function() {

//

//    },

 

/**

*CalledwhentheControllerisdestroyed.Usethisonetofreeresourcesandfinalizeactivities.

*@memberOfzwf_inbox_mini.Main

*/

//    onExit: function() {

//

//    }

 

});

 

 

 

Deploy the application on your ABAP server or wherever you choose to and run it.

021.PNG

 

 

Now open the window next to the SAP GUI and create a new parked journal, which will go to my inbox for approval. On saving the Parked Journal document, the notification is immediately displayed in my browser window and the list is automatically refreshed with the worklist count in the header increasing from 260 to 261.

 

Before save:

022.PNG

 

After save - Inbox updated with new document automatically and popup notification displayed:

023.PNG

 

If you would like to try create a similar application in Web Dynpro ABAP see: Real-time notifications and workflow using ABAP Push Channels (websockets)  Part 4: Creating a Web Dynpro ABAP Application for receiving notifications

Real-time notifications and workflow using ABAP Push Channels (websockets) Part 4: Creating a Web Dynpro ABAP Application for receiving notifications

$
0
0

This is Part 4 of the below series of blogs:

 

 

Now we are going to create a similar application to what we did in Part 3, however this time we are going to use APC (websockets) in a Web Dynpro ABAP application. We do this using a fairly new feature called HTML Islands.

 

 

Create a new Web Dynpro ABAP component called ZWDC_WF_INBOX_MINI

024.PNG

 

 

In the Component Controller create a new Node

025.PNG

 

 

Enter the following:
Node Name: WORKITEMS
Dictionary structure: SWR_WIHDR
Cardinality: 0..n
Init. Lead Selection: No

 

 

Then press the Add Attributes from Structure button

026.PNG

 

Select the WI_TEXT, WI_CD and WI_CT attributes and press the green tick

027.PNG

 

 

 

Create a new method GET_USER_WORKITEMS is the Component Controller and put the following code in it:

028.PNG

 

 

METHOD get_user_workitems .
     
DATA: lo_nd_workitems TYPE REF TO if_wd_context_node.

     
DATA: lt_workitems TYPE wd_this->elements_workitems.

      lo_nd_workitems
= wd_context->get_child_node( name = wd_this->wdctx_workitems ).

     
CALL FUNCTION 'SAP_WAPI_CREATE_WORKLIST'
          
TABLES
                worklist
= lt_workitems.

     
SORT lt_workitems BY wi_id DESCENDING.

      lo_nd_workitems
->bind_table( new_items = lt_workitems set_initial_elements = abap_true ).

ENDMETHOD.

 

 

Then add the following code to the WDDOINIT Method:

METHOD wddoinit .
      wd_this
->get_user_workitems( ).
ENDMETHOD.

 

 

In the V_MAIN View, go to Context and map WORKITEMS to CONTEXT by dragging and dropping it from the right side to the left side.

030.PNG

 

 

Go into Layout tab and start by changing the ROOTUIELEMENTCONTAINER Layout to a RowLayout:

031.PNG

 

 

Right click on ROOTUIELEMENTCONTAINER and click Insert Element.

032.PNG

 

 

 

Enter the following:
ID: WS_HTML_ISLAND
Typ: HtmlIsland

033.PNG

 

 

 

Select WS_HTML_ISLAND and change the height and width to 0px as we do not want this HTML Island to be visible.

034b.PNG

 

 

Now right click on WS_HTML_ISLAND and click on Insert Event.

035.PNG

 

 

Give the Event a name ON_MESSAGE and the press the Create button next to onAction to Create an event handler.

036.PNG

 

 

Enter the Action name as ON_MESSAGE and make sure to tick Transfer UI Event Parameters, then press the green tick.

037.PNG

 

 

Double click on the ON_MESSAGE action created to forward navigate into the method. Then paste in the code below

038.PNG

 

METHOD onactionon_mesage .
     
DATA: lo_api_controller     TYPE REF TO if_wd_controller.

      lo_api_controller ?= wd_this
->wd_get_api( ).

*   report message
      lo_api_controller
->get_message_manager( )->report_message( message_text = data
                                                                message_type
= if_wd_message_manager=>co_type_info
                                                                is_permanent
= abap_false  ).
* refresh work items
      wd_comp_controller
->get_user_workitems( ).
ENDMETHOD.

 

 

 

Go back into the Layout tab and right click on WS_HTML_ISLAND again and add a script this time.

039.PNG

 

 

Enter in websocket_wf_notify.js in the source field. We wil create and upload this javascript file afterwards.

040.PNG

 

 

Save the following source to a file name websocket_wf_notify.js and upload it as a MIME object for the webdynpro.

 

Source code:

 

var MySocket = { 

 

      init: function(callback){

            //Save the call back object to this object

            this.callback = callback;

            var that = this;

            var hostLocation = window.location, socket, socketHostURI, webSocketURI;

 

            if (hostLocation.protocol === "https:") {

                  socketHostURI = "wss:";

            } else {

                  socketHostURI = "ws:";

            }

            socketHostURI += "//" + hostLocation.host;

            webSocketURI = socketHostURI + '/sap/bc/apc/sap/zapc_wf_notify';

       

            try {

                  socket = new WebSocket(webSocketURI);

                  socket.onopen = function() { };

                  var that = this;

  

                  //Create function for handling websocket messages

                  socket.onmessage = function(wfNotify) {

                        // When a message is received fire an event to call the web dynpro code to post the message and

                        // refresh the worklist

                        that.callback.fireEvent('ON_MESSAGE', wfNotify.data);

                  };

  

                  socket.onclose = function() {

                  };

            } catch (exception) {

  

            }

      }

};

 

 

 

Right click on the web dynpro component and go to Create->Mime Object->Import.

041.PNG

 

 

Select the file you created in the previous step websocket_wf_notify.js and click open.

042.PNG

 

 

Then press save.

043.PNG

 

 

Right click on ROOTUIELEMENTCONTAINER again and Insert Element.

044.PNG

 

 

And enter MESSAGE_AREA and select MessageArea as the Type.

045.PNG

 

 

Make sure ROOTUIELEMENTCONTAINER is selected and then press the Wizard button

046.PNG

 

 

Select Table and press Continue.

047.PNG

 

 

Press Context to select the WORKITEMS context:

048.PNG

 

 

Select WORKITEMS and press the green tick.

049.PNG

 

 

No Need to change anything on the next screen, just press the green tick.

 

 

 

In the table properties change design to Alternating and set visibleRowCount to 25.

051.PNG

 

 

Now go into the Methods tab and select the WDDOMODIFYVIEW method.

 

 

And enter the following code to initialise the web socket when the view first loads:

 

METHOD wddomodifyview .
     
DATA: lo_html_island TYPE REF TO cl_wd_html_island.

     
IF first_time EQ abap_true.

           lo_html_island ?= view
->get_element( `WS_HTML_ISLAND` ).

           lo_html_island
->add_script_call( cl_wd_html_script_call=>new_call( )->variable( `MySocket` )->function( `init` )->add_callback_api( )  ).
     
ENDIF.
ENDMETHOD.

 

 

 

Right click on ZWDC_WF_INBOX_MINI and go to Create->Web Dynpro Application.

 

Enter an application name and Description and press the green tick.

 

054.PNG

 

Save and activate everything then right click the Web Dynpro application to run.

 

 

 

Now open the window next to the SAP GUI and create a new parked journal, which will go to my inbox for approval. On saving the Parked Journal document, the notification is immediately displayed in my browser window and the list is automatically refreshed.

 

Before saving:

056.PNG

 

After Saving - Inbox updated with new document automatically and notification displayed:

057.PNG

Real-time notifications and workflow using ABAP Push Channels (websockets) Part 5: Using the UI5 or Web Dynpro applications in Side Panels

$
0
0

This is Part 5 of the below series of blogs:

 

 

 

In this part we will add the applications as Side Panels to be used in NWBC Client. Please note that this will require Internet Explorer to be at least version 10. Thanks to Simon Kemp  for answering the questions I had regarding setting up the Side Panels.

 

 

Go to transaction PFCG and edit the role you want to add it to.

058.PNG

 

 

Select a folder created for side panels:

059.PNG

 

 

Add a BSP Application.

060.PNG

 

 

 

 

Enter BSP Application details.

061.PNG

 

 

Click Other Node Details and make the Node Option Side Panel.

062.PNG

 

 

Now add the Web Dynpro Application.

063.PNG

 

 

Enter the Web Dynpro details.

064.PNG

 

 

Click Other Node Details and select Node Option as Side Panel.

065.PNG

 

 

Make sure in the root folder Side Panels you have a list of transactions you want the side panel to appear in.

066.PNG

 

 

Save the role and restart NWBC.

 

 

Go to the transaction to Park a Journal and open the Side Panel. You will notice the 2 Side Panels added for the UI5 and WDA applications:

071.PNG

 

 

Now create and save a parked journal which will be assigned to myself as the approver.

 

Before Save:

067.PNG

 

 

After Save - there will be a popup notification and the inbox will be refreshed automatically:

068.PNG

 

 

 

Now switch to the Web Dynpro version and do the same:

 

Before Save:

069.PNG

 

 

After Save – notification message displayed and inbox refreshed:

070.PNG

UI5 Workflow Log Side Panel in NWBC

$
0
0

In this blog I am going to show the code required to communicate between a SAP UI5 application and the NWBC DataContext and automatically updating the UI5 application when the Data Context changes. Thanks to Simon Kemp for pointing me in the right direction with this and the idea of turning this into a blog and John Moy for your blog on Context sensitive help in NWBC using side panels, it was really helpful.

 

In this specific use case the UI5 application displays any workflow logs linked to the Business Object Type and Object Key. The Business Object Type is available as a standard tag, however the Object Key was not, and was not available anywhere on the screen, therefore the GUI Property customising could not be used, and the LSAPI was required to write the Object Key to a custom ZOBJKEY tag.

 

 

 

Step 1 - Making the Data available in the DataContext API

 

NWBC uses the DataContext API in order to make data from the current NWBC session available to the Side Panel. See the SAP Help on the DataContext API for more details: Implementation of a Side Panel Application with HTML and JavaScript - SAP NetWeaver Business Client - SAP Library

 

SAP makes certain tags available for use without you needing to do anything, however if you require additional values to be available in the DataContext API you can do 1 of the following:

 

 

 

To see the data available in the DataContext hold down the control key and go to Help--->Tools--->Side Panel--->Data Context AppData Viewer as shown below:

001.PNG

 

This will show you all standard tags and values available in the CANVAS_appData context. Note that ZOBJKEY is not standard and has been added using the LSAPI via a BAdI.

002.PNG

 

Due to the fact that in this use case, the workflow log was applicable for any transaction which had GOS (Generic Object Services). Which meant that the BAdI GOS_SRV_SELECT was an appropriate place to put the code to write the Object Key to the DataContext, as in this BAdI the Object Key was available there.

 

The following code writes the Object Key to the DataContext in the NWBC Client:

003.PNG

 

METHOD if_ex_gos_srv_select~select_services.

   DATA: lo_lsapi TYPE REF TO if_lsapi.

 

   DATA: lv_tag_value TYPE string.

 

* Get an instance of LSAPI

   lo_lsapi = cl_lsapi_manager=>get_instance( ).

 

* Copy the Object Key into the Tag value

   lv_tag_value = is_lpor-instid.

 

* Check that the DataContext is supported via this client. As it only works for NWBC Client and not SAP GUI or NWBC for HTML

   IF lo_lsapi->is_supported( 0 ) EQ abap_true AND cl_nwbc=>context_get( )-nwbc_shell = cl_nwbc=>for_desktop.

 

* Set the tag ZOBJKEY in the DataContext with the Object Key   

     lo_lsapi->if_lsapi_data_context~set_tag_value( name  = 'ZOBJKEY'

                                                    value = lv_tag_value  ).

 

   ENDIF.

ENDMETHOD.

 

 

 

 

 

Step 2 - Accessing the DataContext from the UI5 application

 

You want to automatically update the UI5 application the first time the Side Panel is loaded and everytime there is a change to the DataContext.

 

In order to do this you need to create a custom event handler function which can be called onChangedwithXML and then you will need to subscribe to the DataContext changedWithXML event setting the custom event handler.

 

See the event handler code below:

 

//event handler for event forwarding - done by NWBC

OnChangedWithXML: function(evtObject){

              //Get the Object Type and Object Key from the DataContext API

              var sObjType = window.external.DataContext.read("/BSSP/:BORTYPE", "CANVAS_appData", null);

              var sObjKey = window.external.DataContext.read("ZOBJKEY", "CANVAS_appData", null);

       

              // Load the workflow logs for Object Type and Key

              this.oWorkflowLogComp.loadObjTypeKey(sObjType, sObjKey);

}

 

Then you will use the epcm object which will be available from the NWBC Client to subscribe to the changedWithXML event setting the custom handler.

 

// Check that the Data Context API is available, and if it is register it to listen for "changedWithXML" event, which is triggered

// Initially when the Side Panel is loaded and everytime the Data Context is changed

if (window.external.DataContext != undefined){

    window.external.epcm.subscribeEventReliable("com.sap.lsapi.dataContext", "changedWithXML", this, "OnChangedWithXML");

}

 

 

 

 

 

Step 3 - Add the UI5 Application as a Side Panel

 

I'm not going to go into that here, as many other blogs cover that including one of my previous blogs: Real-time notifications and workflow using ABAP Push Channels (websockets) Part 5: Using the UI5 or Web Dynpro applications in Side Panels

 

 

 

 

 

Step 4 - Load the transaction with the Side Panel and expand it

004.PNG

 

Wider view:

005.PNG

 

 

006.PNG

 

007.PNG


Journey into the Unified Inbox

$
0
0

Over the past 6 months I have been delving deep into the Unified inbox and its inner workings.

 

After doing an indepth analysis and comparison as shown here Workflow Inbox Feature Comparison Matrix of all the SAP standard options to use as a Workflow Inbox. It became apparent that the Unified Inbox would be the best option to go with. After asking the question on SCN Anyone using the Unified Inbox in a Production Environment yet? and not receiving an answer to that, it also became pretty clear that it is not widely adopted yet.

 

There is a really good blog Unified Inbox in Gateway SP09 written by Shyam Sunder Suthar showing what the latest version of the Unified Inbox is capable of, with screenshots demonstrating its functionality. However it doesn't discuss much technical detail about how everything works behind the scenes and how to set it up, which I intend to cover in this blog.

 

 

 

Key strengths of the Unified Inbox

 

  • Its much more than just another Workflow Inbox. Its a Task Inbox which allows you to view tasks not only from SAP Business Workflow, but also BPM and practically any other source you can think of or code, using the custom task provider concept. You are only limited by your imagination and external API's available.
  • It has excellent multi system support with the ability to do parallel calls to retrieve your tasks from multiple systems.
  • It's highly extensible given that it is a UI5 component which can be embedded in your own application and enhanced from there. Which I will talk about in more detail in my next blog. The gateway service can also be redefined and you have the ability to redefine task providers or completely create one from scratch.
  • The power is in the API / Gateway service and you can use any number of custom or standard User Interfaces to utilise it. This is evident in the way that both the unified inbox and Fiori Approve Requests use this Gateway service and much of the same config.
  • It has a modern HTML5 look and feel.
  • It is not dependant on SAP Portal and can be run stand alone, in NWBC Client and NWBC for HTML as well as in Fiori Launchpad.
  • Although not designed for mobile use, it is tablet friendly, meaning it can be used via a tablet although it is not optimised for that purpose.
  • Works with Task Visualisation transaction SWFVISU similar to the UWL.
  • Easy to brand using UI5 Theme Designer.

 

 

 

 

Unified Inbox  System Software requirements.

 

Although the Unified Inbox is available in older versions, I recommend being on the following minimum component versions as the older Support Packs are not as complete in functionality,

 

IW_PGW SP06  - Process Gateway Component– This component contains the main Gateway service /IWPGW/TASKPROCESSING and the UI5 Component and BSP application /IWPGW/TGW_UNIF_INBOX which is the UI layer of the Unified Inbox. This component is not installed by default so will need to be installed manually.

 

SAP_UI SP09 – SAP UI Component– This contains the UI5 library with UI5 version 1.22.2 (Current latest version at writing of this blog is 1.24.4 - It won't hurt to have the latest as there are Inbox Control bug fixes which are mentioned in the release notes).

 

Netweaver Gateway SP09 on pre Netweaver 740 and Netweaver Gateway (SAP_GWFND) SP08 if you are on Netweaver 740 – these are the minimum required versions for IW_PGW SP06.

 

Internet Explorer 9– Although it does work on Internet Explorer 8, it just looks and feels better on IE9 and up. Or Chrome and Firefox work great too.

 

009.PNG

 

 

 

 

Setup steps to start using the Unified Inbox

 

If you are planning to use SAP Business Workflow, make sure that it is configured already in you system in transaction SWU3.

If you are using BPM, you will need to go through other steps to setup the webservice to a BPM system. I won't be covering these details in this blog.

 

You also need to have setup the destination RFC connections in SM59 for each of the systems you intend to use.

 

 

 

Step 1 - Setting up the System Aliases

 

Go to SAP Netweaver->Gateway->OData Channel->Configuration->Connection Settings->SAP Netweaver Gateway to SAP System->Manage System Aliases

010.PNG

 

 

In here, if you are already using Gateway and connecting to the systems, you will notice there will be entries in the table already, with the Software version field as DEFAULT. It does not work if you try and use these connections, you will get an error in the Gateway service. You will need to create additional entries for each system you intend to use and specify the correct software version. For SAP Business workflow that will be /IWPGW/BWF as shown below. For BPM it will be /IWPGW/BPM.

 

If you are using a Gateway Hub, you will put the destination systems as the external systems you want to access, for e.g. ECC or SRM. For an embedded deployment you will specify a local alias with RFC destination as NONE.

011.PNG

 

 

Step 2 - Adding the TASKPROCESSING Service in Service Maintenance

 

Go to transaction /IWFND/MAINT_SERVICE and click on the Add Service button.

012.PNG

 

Enter the filter criteria. Note that the Unified Inbox uses Version 2 of the service.

013.PNG

 

Click on the entry to add the service.

014.PNG

All you need to do is enter the package and press the green tick, the rest of the details are filled in for you.

015.PNG

 

You should see this successfully created message.

016.PNG

 

In the main screen of transaction /IWFND/MAINT_SERVICE you should now see the following entry:

017.PNG

 

 

 

Step 3 - Setting up Multiple System Aliases

 

In the bottom right in the System aliases section, click on Add System Alias button.

018.PNG

 

Since this is on a Gateway Hub system and the 2 systems I would like to connect to are ECC and SRM, I will remove the LOCAL_BWF and add 2 entries, one for ECC and the other for SRM, marking ECC as the default system. What this does is when the service is called without ;mo (Multi Origin) added to the service URL, only the default system will be called.

 

019.PNG

 

If you use the Call Browser button in the main screen of transaction /IWFND/MAINT_SERVICE it will open the service in a browser loading the meta data. By default there will not be the ;mo option in the service URL. If you add in TaskCollection as the Entity Set to query, notice the difference between the service call with and without the multi origin option.

020.PNG

Notice that an additional property is added automatically: <d:SAP__Origin>SAP_ECC_BWF</d:SAP__Origin>

 

This SAP__Origin property is used to determine which system the entity is in.

 

By default the Gateway system should be setup so that parallelization is used when more than 1 backend System Alias is called. This can be setup or changed in the config as below:

021.PNG

 

Another useful thing to setup when using multiple System Aliases is setting the TASKPROCESSING service as error tolerant. This means that if the call to 1 system fails, then the whole call does not fail, that system is just excluded from the results.

 

022.PNG

 

 

 

Step 4 - Activate and run the Unified Inbox

 

If it is not already activated, go into SICF and active the following service /sap/bc/bsp/iwpgw/tgw_unif_inbox and run it.

 

023.PNG

 

 

Or run it via the BSP Application in SE80.

024.PNG

 

And then you should see the following. Note there is nothing you need to setup to allow certain tasks to be viewed. You should see any items in your SAP Business Workplace (SBWP) in the Unified Inbox. If you are not seeing this, then you most likely need to look at transaction /IWFND/ERROR_LOG to see why. Authorisations is a likely cause.

025.PNG

 

 

 

 

 

Understanding the architecture behind the Unified Inbox

 

 

The Unified Inbox is actually made up of several layers and components. I thought the following diagram would best describe it.

001.PNG

 

 

 

The Gateway Service of the Unified Inbox

 

The core of Unified Inbox is actually the Gateway service (API): /IWPGW/TASKPROCESSING which provides an extremely powerful API for accessing Task Processing functionality including the following:

 

  • Tasks Query
  • Reading of Task Details - as plain text or as HTML
  • Task Forwarding
  • Reading Task Actions/Decisions
  • Task Actioning / Actioning Decisions
  • Comments handling
  • Attachments handling
  • Possible Agents
  • Substitution handling
  • and much more

 

And any other custom functionality can be added by redefining the /IWPGW/TASKPROCESSING service and/or redefining a task provider.

 

This service has 2 versions. Version 1 is the version being used by Fiori Approve Requests and Version 2 is being used by the Unified Inbox. Version 2 has much of the same functionality as Version 1 and more.

 

 

 

The Task Provider Layer

 

There are 2 standard Task Providers available:

  1. BPM  - Business Process Management
  2. BWF - Business Workflow

 

If you require additional functionality in one of the above, you can redefine the Task Facade Implementation Class and use your redefined class by changing it in the config. Alternatively you can create a completely custom Task Provider, I'd recommend reading How to create a custom data provider for Task Gateway to learn how to do that.

 

See below where to change or specify new Task Providers:

002.PNG

 

003.PNG

 

 

The UI Layer of Unified Inbox

 

The core of the Unified Inbox is actually made up of a really powerful complex control: the Inbox Control as you can see in the SAPUI5 SDK here: Inbox Control Demo or you can view the more advanced functionality available if you look at the Inbox API Reference here: Inbox API Reference.

This control is one of the few controls which is not available in OpenUI5 and only in the SAPUI5 SDK.


The next layer is the Unified Inbox UI5 Component which is inside the BSP application /IWPGW/TGW_UNIF_INBOX as illustrated in the top right of the architecture diagram above. This component instantiates the Inbox control and has the Unified Inbox View and Controller and binds the Gateway service /IWPGW/TASKPROCESSING to the Inbox, then sets up the Inbox control and configures it. Very little actually happens here besides instantiating the control and basic configuration of the control.

 

The next layer is still within the /IWPGW/TGW_UNIF_INBOX BSP Application and is the UI5 Application which instantiates the Unififed Inbox Component, places it in a Component Container and on the web page. This layer also adds the application header and handles the login and logoff aspects of the Unified Inbox. It also sets up user configurable settings, which are set up in a config table via SPRO. This allows the user to configure a few things such as:

  • UI5 theme - default is sap_goldreflection, but personally I prefer sap_bluecrystal.
  • Opening a task in an overlay frame or in a new tab. Default is for it to open in a new tab.
  • Is the header visible or not. Default is for it to be visible.
  • Is the user list enabled. Default is true.

 

See: Configuring the Unified Inbox - SAP NetWeaver Gateway - SAP Library

 

See below where to setup the Unified Inbox config parameters:

004.PNG

 

005.PNG

Please note that it is not mandatory to fill in this table. If you leave the table blank the application will just use the defaults as mentioned above.

 

See below by setting the theme in the table above to sap_bluecrystal it now shows the Unified Inbox using this theme.

026.PNG

 

 

 

The Configuration Layer of the /IWPGW/TASKPROCESSING Service

 

There is not much to configure on the UI layer more than mentioned above, such as theme and a few other options. However there are more configuration options which you can use for the backend TASKPROCESSING service. Things such as:

  • Configuring custom actions / decisions. In the case of a workflow user decision these decisions are automatically determined and do not require any configuration, however if you would like to add manual actions on a normal activity task, you will need to configure the actions / decisions here and deal with the action handling using the BAdI /IWWRK/BADI_WF_BEFORE_UPD_IB which is mentioned in the next section.
  • Maintain Task Names which is used by the filter in the Unified Inbox.

 

See below how to configure this:

006.PNG

 

007.PNG

 

 

008.PNG

 

 

 

The Enhancement Layer of the Unified Inbox / TASKPROCESSING service.

 

There are a number of BAdI's available for:

  • Handling custom actions or adding additional functionality to actions.
  • Changing the task title.
  • Changing the task description or setting HTML content for the description.
  • Custom attributes.

 

These are the available BAdI's:

 

  • /IWWRK/BADI_WF_BEFORE_UPD_IB
    • BEFORE_UPDATE - Before Work Item handler update - This is used for custom actions behind the Decision Keys configured in the table above.

 

  • /IWWRK/BADI_TGW_CUSTOM_ATTR
    • PROVIDE_ATTRIBUTE_DEFINITION - Read custom attributes definition - Define custom attributes metadata here.
    • PROVIDE_ATTRIBUTE_DATA - Read custom attributes value - Populate custom attribute data in here

 

  • /IWPGW/BADI_TGW_TASK_DATA
    • MODIFY_TASK_TITLE - Modify Task Title - If you need to modify the task title from the work item task.
    • MODIFY_TASK_DESCRIPTION - Modify Task Description - Allows you to modify the plain text description or HTML description which is populated by default from the task description. One reason for using this could be to create an HTML table of items.

 

  • /IWPGW/BADI_TGW_TASK_QUERY
    • MODIFY_ITEMS - Modify subject in task query - Mass modification of the task titles for a number of work items.

 

  • /IWPGW/BADI_TGW_USER_DETAIL
    • READ_USER_DETAILS_BY_CONTEXT - Provide User Details
    • GET_USER_PICTURE_STREAM - Provide a user picture - Defines where the user picture comes from. This BAdI is necessary if you want pictures as there is no standard implementation for providing user pictures.

 

 

In future blogs I would like to demonstrate these enhancement options and also showcase what's possible when enhancing the Unified Inbox. Stay tuned.

Enhancing the Unified Inbox

$
0
0

Following the recent webinar on the soon to be released My Inbox which is intended to be a replacement for the Unified Inbox and Fiori Approve Requests, I thought it would be an opportune time to demonstrate the lost potential of what the Unified Inbox could have become if it were developed further or at least what is possible by enhancing it yourself.

 

The truth is we have all been longing for the long overdue “perfect inbox” and the reality is that as much as we would like to have a one size fits all inbox, it just doesn't work that way, all users have different needs and all customers have different requirements. That's not to say we expect 10 different versions of an inbox, but 1 just won’t cater for every one. 

 

Imagine a sock manufacturer made 1 size of socks for all their Customers. It may fit some perfectly and others a bit, but not quite comfortably. Then some customers it would simply not fit at all. But just like some sock manufacturers may make 2 sizes, 5-8 and 9-12. So should we  have 2 versions of the inbox. One which is “mobile first” and the other which is “desktop first”. Sure you can probably run the desktop one on a tablet and the tablet one on a desktop. But neither will feel optimised in the others' environment.

 

That brings on my debate, is the “mobile first” approach sufficient for all users and scenarios as the only option?

 

I have recently been spending  a significant amount of time analysing the SAP Standard inbox options as per my document here: Workflow Inbox Feature Comparison Matrix. Followed by the decision to go with SAP’s new and widely unadopted Unified Inbox, as explained in my blog here: Journey into the Unified Inbox.

 

One of the biggest attractions of the Unified Inbox was it’s extensibility due to the way it has been designed as a UI5 component and the extensibility of the Process Gateway Task Processing service by redefining the Netweaver Gateway service. This was all made possible by new functionality as of SAP Netweaver Gateway SP08 which allows you to redefine a SAP standard service and overwrite the base service, as shown in this blog: Extending a service using the Gateway Service Builder. What this does is it allows you to redefine the service and access the redefined service via the original SAP standard URL. This is particularly useful in Enhancing the Unified Inbox as the standard Unified Inbox Component refers to the SAP standard TASKPROCESSING service.

 

The reality was that no inbox met 100% of our needs on the project. However the Unified Inbox was most certainly the closest and given the way in which it can be extended without ugly Z copies of the SAP standard application and Gateway service, this was a big advantage. It means we inherit all SAP bug fixes and improvements automatically. Although improvements no longer seem likely with the recent news that the Unified Inbox won’t be developed further. Sad news I believe as I really thought SAP were going in the right direction with the Unified Inbox.

 

Here is a summary the enhancements we made to make it fit our needs:

  • Preview pane – a feature which is available in the UWL, POWL Inbox and SBWP, seemed to have just been missed out in the Unified Inbox. I believe the explanation for this is that the stream view is supposed to replace the need for this, as well as the ability to open the Task details either in a new tab or in a pop-up view which covers the inbox.
  • Attachments in the main view, not through Stream View
  • Comments in the main view, not through the Stream View
  • Linked Objects - with the ability to launch the transaction linked to the linked object via OBN (Object Based Navigation)
  • Workflow Log / Processing Log
  • Custom Forwarding - restricted forwarding list of agents
  • Outbox - My Forwarded Tasks list and My Requests / Workflows Started by me.

 

 

 

 

The Standard Unified Inbox Component embedded in a custom UI5 Application

001.PNG

 

 

 

 

Custom Task Details UI5 Component (Preview pane) embedded in custom UI5 Application

 

By using the attachTaskSelectionChange function in the Inbox Control API you can register an event handler to know which task to load in the work item preview pane below.

002.PNG

 

 

 

Created By Agent Details

 

003.PNG

 

 

 

 

Attachments Upload and Display

 

Uses standard functionality in the TASKPROCESSING Gateway service.

004.PNG

 

 

 

 

Comments Create and Display

 

Uses standard functionality in the TASKPROCESSING Gateway service.

005.PNG

 

 

 

Linked Objects

 

Displays the linked objects for the task and allows the user to navigate to the linked Object using OBN (Object Based Navigation). In NWBC client this will open up the SAP GUI and in NWBC for HTML this will open up the webgui.

 

This required a new custom Entity set in the redefined version of the TASKPROCESSING Gateway service.

006.PNG

 

 

 

Workflow Log / Processing Log

 

This required new custom Entity sets in the redefined version of the TASKPROCESSING Gateway service.

007.PNG

 

 

 

 

Forward Task

 

Custom forwarding which returns a restricted list of agents to forward to:

 

009.PNG

 

 

 

 

Outbox - Tasks Forwarded by Me and Started by me (My Requests)

 

This adds in outbox functionality and allows the user to view tasks they have forwarded and their current status and Workflows they created (My Requests)

008.PNG

 

 

 

 

This is not meant to be a tutorial on how to enhance the Unified Inbox, but rather a demonstration to show that it is possible, and that you are only limited by your imagination and ability to code

JavaScript Debugging in NWBC

$
0
0

While working on a project where we are using NWBC Client with UI5 Applications, some custom and some standard, we were unable to debug the JavaScript and see the JavaScript console for the UI5 Applications when they were running in the NWBC client as the F12 Developer tools are deactivated when Internet Explorer is used as an embedded control.

 

Thanks to Simon Kemp for finding the solution to this problem in this discussion: Use browser debugging tools in the NWBC side panel? and in this external link: Debugging JavaScript in a WebBrowser Control from VS2010 | Mark Leighton Fisher [blogs.perl.org]

 

So I thought I would document the following steps to help others facing this issue.

 

 

 

1. Download Visual Studio 2013 free Community edition here: Visual Studio 2013 Free Community Edition

Screenshot 2014-12-17 17.37.12.png

 

 

 

2. Hold the control key and go to Help->Tools->IE Settings Dialog in the NWBC Client.

 

001.png

 

 

 

 

3. Make sure the "Disable script debugging" checkboxes for both Internet Explorer and Other are not checked and that "Display a notification about every script error" is enabled as shown in the highlighted options below.

 

002.png

 

 

 

 

4. Make sure that NWBC is open and open Visual Studio 2013. In Visual Studio go to DEBUG->Attach to Process...


003.png

 

 

 

 

 

5. Select NWBC.exe and press Attach.

 

004.png

 

 

 

 

6. Here you will see the open Internet Explorer sessions within NWBC.

 

005.png

 

 

 

 

7. If we open a new tab with a custom UI5 Application you will notice another Internet Explorer session appears and you can see the code and console messages in the output section below when the "JavaScript Language Service" dropdown option is selected.

 

006.png

 

 

 

 

8. Changing the "JavaScript Language Service" dropdown option to "Debug" you can see all the JavaScript errors.

 

007.png

 

 

 

 

9. For some reason which I am not sure of, you are unable to debug and step through by setting break points in the code above. In order to debug your code you will need to add in a debugger; statement into your code as shown below. This unfortunately is not an option if its a SAP standard UI5 Application.

 

 

008.png

 

 

 

 

 

 

10. Now when this UI5 Application is opened via NWBC it will stop in the Visual Studio Debugger as shown below.

 

009.png

 

 

 

 

11. You can now use the Visual Studio Debug controls shown below to debug your JavaScript code.

 

010.png

 

 

If anyone manages to find out a way to debug SAP Standard UI5 Javascript code without needing to put in the debugger; statement I would love to know.

Viewing all 18 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>