Some tips and tricks for adapter modules lifecycle management

From my SCN blog : http://scn.sap.com/community/pi-and-soa-middleware/blog/2015/01/25/some-tips-and-tricks-for-adapter-modules-lifecycle-management

Recently I was involved in migrating lot of adapter modules from a PI 7.0 system to a PI 7.4 environment. Creating a custom adapter module is not too complicated but like anything else, we need to be clear of all the components involved and their implications. There is a very good SDN document about the steps to create one. However, in my experience keeping the following points i makes the development process much smoother.

1. Understanding the descriptor files:

Most of the issues with adapter modules occur as one of the descriptors is wrong. Let’s go through them.

a) ejb-j2ee-engine.xml: This file will be in the EJB project. This links the EJB name with the JNDI name. Hence, if you are getting a module not found error, most likely you need to check your jndi-name.

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”no”?>

<ejb-j2ee-engine

  xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance

  xsi:noNamespaceSchemaLocation=”ejb-j2ee-engine.xsd”>

  <enterprise-beans>

  <enterprise-bean>

  <ejb-name>ToUpperCase</ejb-name>

  <jndi-name>ToUpperCase</jndi-name>

  </enterprise-bean>

  </enterprise-beans>

</ejb-j2ee-engine>

b) ejb-jar.xml : This is in the EJB project as well . This has the actual class name, EJB interface names, bean type etc. The key thing here is to check the ejb-name and the class name. The home,local, remote and local-home names always stay the same.( to standard SAP values ). This causes a lot of errors as normally people just accept the default provided names for these interfaces and it causes errors.

<?xml version=1.0 encoding=UTF-8?>
<ejb-jar xmlns=http://java.sun.com/xml/ns/j2eexmlns:xsi=http://www.w3.org/2001/XMLSchema-instance id=ejb-jar_ID version=2.1xsi:schemaLocation=http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd>
  <enterprise-beans>
  <session>
  <icon/>
  <ejb-name>ToUpperCase</ejb-name>
  <home>com.sap.aii.af.lib.mp.module.ModuleHome</home>
  <remote>com.sap.aii.af.lib.mp.module.ModuleRemote</remote>
  <local-home>com.sap.aii.af.lib.mp.module.ModuleLocalHome</local-home>
  <local>com.sap.aii.af.lib.mp.module.ModuleLocal</local>
  <ejb-class>com.demo.ToUpperCasebean</ejb-class>
  <session-type>Stateless</session-type>
  <transaction-type>Container</transaction-type>
  </session>
  </enterprise-beans>
</ejb-jar>

c) application-j2ee-engine.xml : This file is in the EAR project and stays the same, unless the project needs additional libraries.

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”no”?>

<application-j2ee-engine

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance

xsi:noNamespaceSchemaLocation=”application-j2ee-engine.xsd”>

<reference

reference-type=”hard”>

<reference-target

provider-name=”sap.com”

target-type=”service”>engine.security.facade</reference-target>

</reference>

<reference

reference-type=”hard”>

<reference-target

provider-name=”sap.com”

target-type=”library”>engine.j2ee14.facade</reference-target>

</reference>

<reference

reference-type=”hard”>

<reference-target

provider-name=”sap.com”

target-type=”service”>com.sap.aii.af.svc.facade</reference-target>

</reference>

<reference

reference-type=”hard”>

<reference-target

provider-name=”sap.com”

target-type=”interface”>com.sap.aii.af.ifc.facade</reference-target>

</reference>

<reference

reference-type=”hard”>

<reference-target

provider-name=”sap.com”

target-type=”library”>com.sap.aii.af.lib.facade</reference-target>

</reference>

<reference

reference-type=”hard”>

<reference-target

provider-name=”sap.com”

target-type=”library”>com.sap.base.technology.facade</reference-target>

</reference>

<provider-name>sap.com</provider-name>

<fail-over-enable

mode=”disable”

xsi:type=”fail-over-enableType_disable”/>

</application-j2ee-engine>

This file has references of libraries etc. when the application is running. A good way to check that the references are correct is by going to Java Class Loader on the application server and give the component name.

In the below screen-shot we’re able to fins component type “service” with name “engine.security.facade” as updated in application-j2ee-engine.xml .

AM1_app_engine.png

Addiing additional references:  If we’re using additional libraries, we need to update the reference in the below way.

– Add the client libraries to allow compilation. Many of the libraries are already available in NWDS plugins ( e.g. JCO 2/3 libraries ). However, in some cases they will need to be obtained from SAP PI application server.

– Refer Javadoc to understand the DC that contains the class. Taking interface ApplicationPropertiesAccess as an example. Javadoc at

http://help.sap.com/javadocs/NW73/SPS05/CE/en/com.sap.en/com/sap/engine/services/configuration/appconfiguration/ApplicationPropertiesAccess.html

gives the DC as:

[sap.com] tc/je/appconfiguration/api

AM_2.png

Hence, the deployment descriptor will need to be updated as:

<reference reference-type=”hard”>

    <reference-target provider-name=”sap.com”

target-type=”service“>

      tc~je~appconfiguration~api

    </reference-target>

</reference>

2. Renaming adapter module name: We need to update a module name many a times. Some of the reasons could be:

– While testing, we gave a “test” name and want to change the module name without rewriting the whole project.

– Create a new version and test it out in some scenarios before changing configuration everywhere.

The adapter module name that we configure in adapter modules is actually the JNDI name in ejb-j2ee-engine.xml. So initially the ejb and jndi names were the same.

AM_4.png

In the below screenshot, I changed the JNDI name to Convert2Up

AM_3.png

After making only the JNDI name, I sent a test message after updating the adapter module config parameters and it works fine.

AM_5.png

3. Adding software component information: The adapter module can be deployed directly from NWDS by running the EAR project on the application server. However, it is better to organise custom software components like SAP delivered software components in its own namespace so that it’s easier to track the inventory and get all the benefits of application lifecycle management.

Without the software component information, we can verify the bean is successfully deployed by checking JNDI browser.

AM_12.png

However, if there are multiple beans, we need to know their names.  It’s better to organise in their own namespace. We need to go through the below process : EAR –> SDA –> SCA

The steps required are :

– Convert EAR to SDA file ( which is EAR file along with SAP specific manifest info in SAP_MANIFEST.MF file )

– Add SDA file to a SCA file along with the software component information

The easiest approach is to use nwpacktool . Update the batch file with JAVA_HOME and NWPACKTOOLLIB.

AM_6.png

Then lanuch the batch ( or .sh ) file. As an example, to create a SDA file from the EAR.

AM_7.png

Now, add component information and create a SCA file.

AM_8.png

Now, deploy the SCA file .  We can display all custom modules created under the same component.In the below screen-shot, two beans are deployed under SC “AdaptModules” with the first bean having version 3.

AM_9.png,

It’s easier to deploy to any system as well since there is only one SCA file to be updated .

Advertisement

Storing password in SAP PI modules

From my SCN blog : http://scn.sap.com/community/pi-and-soa-middleware/blog/2015/01/21/storing-password-in-sap-pi-modules

Storing password in SAP PI modules.

Setting user and password inside a module is slightly different from normal adapter module parameters as the text can’t be kept in clear-text in module parameters.

Three strategies we can use:

1) Use hard-coded user id and password in the module. Not a great approach but sometimes this can be the only feasible option. The advantage of course is that there is no risk of locking the user.

2) Setting in comm channel as a secure parameter ( displayed as asterisk ).

Here, user can be set as a normal string parameter. For passwords, we don’t want the password to show up in clear text. Hence, password can be the following:

  • – If password parameter  starts with pwd, it’s displayed as asterisks when entered and displayed. However, the database folder is unencrypted.
  • – If password parameter starts with cryptedpassword, the database folder is encrypted. This is more secure as the database folder is encrypted.

The advantage is that the values can be configured for each system and the drawback being if the password is not correctly entered it can get locked and trying to find the comm channel which is locking the user can be time consuming.

3) Setting values in Application Properties. This  combines the best of both worlds – we’re able to configure values in each environment and as we’re configuring it in only one location, the chances of accidentally locking the user due to incorrect values is reduced.

The values can be modified from NWA. The path is:

NWA_1.png

Configuration Management->Infrastructure->Java System Properties

Steps required to add configuration capacity.

a)  Add sap.com~tc~je~configuration~impl.jar to the module EJB project.

Path to get the client library: /usr/sap/<SID>/<instance>/j2ee/cluster/bin/services/configuration/lib/private/sap.com~tc~je~configuration~impl.jar

b) Create sap.application.global.properties file under META-INF. It’s essentially a  .properties file.

EAR_1.png

Sample content to make User modifiable and appear as clear text

## Comment for user

#? secure = false; onlinemodifiable = true

#% type = STRING;

User =

Sample content to make User modifiable and appear as asterisk when entering in NWA.

## Comment for password

#? secure = true; onlinemodifiable = true

#% type = STRING;

Password =

c) Update module code to read the property

Sample code will look something like this ( to be added in the module code )

// Obtain the JNDI context

InitialContext ctx = new InitialContext();


// access the Application-Configuration-Façade service

ApplicationPropertiesAccess appCfgProps = (ApplicationPropertiesAccess) ctx.lookup(“ApplicationConfiguration”);

java.util.Properties appProps = appCfgProps.

if (appProps == null) {

// perform error handling

}

else

{

userID = appProps.getProperty(“

password = appProps.getProperty(“Password”);

                                                                }

d) Update application deployment descriptor to indicate the library being used. Add this to application-j2ee-engine.xml .

<reference reference-type=”hard”>

    <reference-target provider-name=”sap.com”

target-type=”service”>

      tc~je~appconfiguration~api

    </reference-target>

</reference>


Understanding SLD API for mass creation of business systems / other SLD objects

From my blog on SCN:

http://scn.sap.com/community/pi-and-soa-middleware/blog/2014/10/30/understanding-sld-api-for-mass-creation-of-sld-objects

I had to recently work with SLD API to mass create business systems. There were over thousands of business systems to be created and we needed a solution to automate the process as going to SLD for each business system creation will be very time consuming process as the tasks require business system creation, linking with other business systems etc.

Overview of the steps involved.

1. Navigate to SLD and look at the Development area . Click on CIM Classes ( bottom right in the below image ).

  1. Find the CIM class you’re interested in – in our case we’re interested in “Business System”.

  1. Click on the Class Diagram. This is important as this will understand objects that need to be created. This is important to understand as when we create a business system, system creates various objects – the class diagram helps to understand the relationships. Some objects are directly linked and others have an indirect relationship.

  1. Again in SLD Development area, click on CIM Classes and chose the class name as “Business System”.

Chose a business system to display. All associations need to be created for successful creation of business system.


  1. Look at examples in package SLD_API. You can do a good test by copying program SLDAPI_READ_EXAMPLE to do a read test and SLDAPI_WRITE_EXAMPLE for writing to SLD.

With information from these three sources, we’re good to start ABAP development.

Steps to get a handle of a SLD object

  • SLD operations require the “handle” of the object to be retrieved before it can be used for operations. It involves the following steps
  1. Create a filter using class CL_SLD_FILTER.
  2. Add pattern to the filtter for property “Name” and the value. It will be the object value . Look in SLD CIM Instance to get the string to be created. As an example, technical system name is <TS_NAME>.Systemhome.<Hostname>
  3. Get the list of instances by supplying cname as the name for the object and filter object created.
  4. Loop at instances and get the ‘CreationClassName’ . If the value matches the classname we’re looking for, store the object.
  5. Call get_objectname to get the system handle.

E.g sample code for creating technical system
concatenate p_tec_sys_name ‘.SystemHome.’ p_hostname into lv_tech_sys_full_name.
create object lo_filter.  lo_filter->add_pattern( pname = ‘Name’                          value = lv_tech_sys_full_name ).
lt_instances = o_accessor->enumerate_instances( cname = gc_sap_appl_sys  filter = lo_filter ). “’SAP_ApplicationSystem
loop at lt_instances into lo_instance.    lv_classname = lo_instance->get_property( pname = ‘CreationClassName’ ).    i_sld =  lo_instance->get_properties( ).
if  lv_classname = gc_sap_standal_sys . “’SAP_StandaloneJavaSystem’      c_tec_sys = lo_instance.      c_tec_sys_handle = lo_instance->get_objectname( ).      exit.    endif.
endloop.
Process of creating SLD objects:

  1. Create an object of type CL_SLD_CIM_INSTANCE passing the classname from SLD CIMInstance and accessor ( an object of type reference to class CL_SLD_ACCESSOR ).
  2. Set property ‘CreationClassName’ as the name of the class from SLD CIMInstance.
  3. Set property name

      d)  Set any other attribute ( like caption , description etc )

  1. Finally write to SLD by using CREATE_INSTANCE method of accessor ( reference to class CL_SLD_ACCESSOR )

Sample code:
create object lo_bus_sys “type CL_SLD_CIM_INSTANCE            exporting              classname = gc_sap_bus_sys   “’SAP_BusinessSystem’              accessor  = o_accessor.    “type CL_SLD_ACCESSOR
lo_bus_sys->set_property( pname = ‘CreationClassName’                    value = gc_sap_bus_sys ). “SAP_BusinessSystem
lo_bus_sys->set_property( pname = ‘Name’                    value = p_bus_system ).
…….Set other attributes…..c_handle = o_accessor->create_instance( iref = lo_bus_sys ). “c_hanlde is a string

Steps we took to create business systems:

  1. Get handle of PI Integration Server Business system
  2. Get handle for the group of business systems we’ll be creating
  3. Get handle of technical system
  4. Create business system
  5. Create business system GUID
  6. Attach GUID to the business system
  7. Create entry for SAP_BusinessSystemViewedStandaloneJavaSystem ( using BS and TS handle – it links the BS and TS )
  8. Create entry for SAP_BusinessSystemExchangeServer ( using BS and IS ( Integration Server ) handle – it assigns the IS for the BS )
  9. Create entry for SAP_LogicalALESystem
  10. Create entry for SAP_ALESystemViewedBusinessSystem
  11. Add the business system to collection using the group handle from b)
  12. Create relationship with other business systems ( dev -> pre-prod, prod etc).

oData AND SAP NW Gateway OVERVIEW

Link to presentation on “oDATA  AND SAPGateway”I did earlier this year.

http://slides.com/sakiv/odatagatewayintro#/


SAPUI5 with Gateway

Link to presentation I did earlier for training my colleagues.

http://slides.com/sakiv/sapui5withgateway#/


Understanding CSV files and their handling in ABAP

From my blog on SCN

http://scn.sap.com/community/abap/blog/2014/09/09/understanding-csv-files-and-their-handling-in-abap

In many ABAP developments, we use CSV files and sometimes there is confusion regarding CSV itself. Is it just a text file with values separated by commas ?

Let’s look at semantics of the various components involved so we have a vocabulary to work with.

Separator: Demarcates between two fields – so it will be a comma ‘,’ for CSVs.

Delimiter: It signifies limits of things, where it begins and ends. e.g. “Test String” has two delimiters, both double quote characters. Many CSVs can have double quotes as delimiters when comma values are to be placed as text.

Terminator : Indicates end of sequence. For CSV, we can think of newline as the terminator.

So if we have confusion about whether commas or double quotes are allowed inside data, looking at the CSV specification:

The de facto standard for CSV is here in case you want to read the full standard.

http://tools.ietf.org/html/rfc4180

Definition of the CSV Format

1.  Each record is located on a separate line, delimited by a line break.

2. The last record in the file may or may not have an ending line break.

3.  There maybe an optional header line appearing as the first line of the file with the same format as normal record lines.

4.  Within the header and each record, there may be one or more fields, separated by commas.  Each line should contain the same

number of fields throughout the file.  Spaces are considered part of a field and should not be ignored.  The last field in the

record must not be followed by a comma.

5.  Each field may or may not be enclosed in double quotes (however some programs, such as Microsoft Excel, do not use double quotes

at all).  If fields are not enclosed with double quotes, then double quotes may not appear inside the fields.

6.  Fields containing line breaks (CRLF), double quotes, and commas should be enclosed in double-quotes.

7. If double-quotes are used to enclose fields, then a double-quote appearing inside a field must be escaped by preceding it with

another double quote.

In my experience, point 7 is where we get tripped the most. CSV stands as comma separated values leading to the impression that commas are the separator and given that excel doesn’t put commas, it can start to get confusing.

So looking at some examples

Basic Example:

10, Vikas , Sydney

Data with separator / delimiter inside them.

“11”, “Vikas”, “Sydney, AU”      <– Data containing comma

“12”, “Vikas”, “Sydney, “NSW” AU”   <– Data containing comma and quotes in data

Handling in ABAP:

I’m focusing on reading the files as that’s where we face issues. The file can be uploaded from user’s desktop or read from the application server.

1)  Write your own code:

This can be easiest to start with but can start to get complicated with time.

Get data as a string, split at comma.

   split lv_data at ‘,’ into lw_struct-test1 lw_struct-test2 lw_struct-test3.

Drawbacks:

a) This won’t work if we have data with separator, terminator or delimiter ( so no commas, double-quotes or newline within data ).

b)  The code will need to be updated if the file format changes – say we need to add another field test4. The code then changes to :

   split lv_data at ‘,’ into lw_struct-test1 lw_struct-test2 lw_struct-test3 lw_struct-test4.

2) Read the file using KCD_CSV_FILE_TO_INTERN_CONVERT

CALL FUNCTION ‘KCD_CSV_FILE_TO_INTERN_CONVERT’

  EXPORTING

    i_filename      = ‘C:\Temp\Upload.csv’

    i_separator     = ‘,’

  TABLES

    e_intern        = gt_intern

  EXCEPTIONS

    upload_csv      = 1

    upload_filetype = 2.

Drawbacks

a) The file can be read only from presentation server/ desktop.

b) If a CSV file exists with double quotes, the last field is left with double quotes.

c) In case the file is to be read from application server, we need to read the code inside this FM and write some custom logic.

3) Use RTTI and dynamic programming along with FM RSDS_CONVERT_CSV .

It works but has lots of code . You can have a look at the code in this GIST.

CSV_Upload_long_process

In summary the steps are :

– Get structre of destination table using RTTI

– Create field catalog

– Create a dynamic table for field catalog values

– Create dynamic table lines

– Process Raw CSV data

– Store CSV files into dynamic table

Drawback:

a) Relatively long code leading to results especially if you have to program it from scratch.

Advantage:

a) Code is free from the target table format. If a new field is to be added, just update the structure for table typez_data_tty

4) Use class CL_RSDA_CSV_CONVERTER .

So the call becomes very straight forward – Instantiate the class with the separator and delimiter values. For a normal CSV, leave them as default .

* Instantiate the CSV object

  call method cl_rsda_csv_converter=>create

*  EXPORTING

*    i_delimiter = C_DEFAULT_DELIMITER

*    i_separator = C_DEFAULT_SEPARATOR

    receiving

      r_r_conv    = lo_csv

* Process records

  loop at lt_upload_data into lv_data.

 

    CALL METHOD lo_csv->csv_to_structure

      EXPORTING

        i_data   = lv_data

      IMPORTING

        e_s_data = lw_struct.

 

That’s It !

Advantages:

a) The code is very small – less chances of us making an error compared to the one in 3) above.

b) The code is decoupled with file structure – we get to keep the benefit from the above point .

c) It can be used for both application server / presentation server files – of course file reading will need to be done before the call.

d) The developer has documented the examples exhaustively in method CSV_TO_STRUCTURE . Big thank to him/her !

e) It’s part of package RSDA which is present in ABAP trial environments as well such as NSP .

If you feel lazy to type the full program, here is the whole source code:

CSV_Reading_option_4

 


Mac – add ADB to path ( Android )

cd

create file .bash_profile

touch .bash_profile

open file with TextEdit

open -e .bash_profile

insert line into TextEdit

export PATH=$PATH:/Users/username/custompath/sdk/platform-tools/

save file and reload file

source ~/.bash_profile

check if adb was set into path

adb version


Installation and version management of mobile applications without any MDM solution

From my SCN blog post:

http://scn.sap.com/community/mobile/blog/2014/08/24/installation-and-version-management-of-mobile-applications-without-any-mdm-solution

While testing applications, we used the below strategies and it took us some time to work these out. So I sum these up as reference – I trust people will find it useful. These are based on my experience in dealing with iOS apps.

Problem 1: I was working on an enterprise mobile application project but we couldn’t use the organisation’s pre-existing mobile device management ( MDM ) solution. This can happen due to any number of factors – in our case, the app was simply too big to be supported by the current version of MDM solution (it’s not a SAP MDM solution ).

Solution :

We used the below alternatives and they can be employed to work.

1. DropBox. A simple html page can be created in DropBox which points to the app’s plist file ( property list file ) and the plist file in turn will point to the relative location of the .app file. I kept the app in the Public folder of dropbox.

Let me draw a picture to make it clearer.

Screen Shot 2014-08-23 at 11.07.08 pm.png

2. TestFlight: I wasn’t aware of this site when we were first working on testing release I but found it extremely useful for subsequent releases. You can set up a project team, assign users to test and check the devices registered.

See the sample screenshot below.

Screen Shot 2014-08-23 at 6.png

3. Through a public site. You’ll need infrastructure team to create a publicly accessible domain ( if you want them to access via normal internet ).

Add the below MIME types to your web server ( for IIS ).

Mime type for plist -> application/xml

Mimet type for ipa -> application/octet-stream

4. The most obvious one : If the users can come to your desk, of course just use Xcode to install by making the device a developer device.

Hints on creating the HTML page:

a) Create the HTML page – this page will point to the plist file.

e.g.

<a href=”itms-services://?action=download-manifest&url=http://dl.dropbox.com/u/xxxxxxxxx/app_live.plist“>Download App</a>

This will create a quick and dirty page for users to install the app.

Screen Shot 2014-08-23 at 5.58.09 pm.png

Of course, you can make it better by adding icons etc.

b) The plist file will in turn point to the .ipa file. You’ll need to edit it manually from the one generated by Xcode.

<?xml version=”1.0″ encoding=”UTF-8″?>

<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd“>

<plist version=”1.0″>

<dict>

<key>items</key>

<array>

<dict>

  <key>assets</key>

  <array>

   <dict>

    <key>kind</key>

    <string>software-package</string>

    <key>url</key>

    <string>http://www.domain.com/app/Application.ipa</string>

   </dict>

  </array>

  <key>metadata</key>

  <dict>

   <key>bundle-identifier</key>

   <string>com.domain.ApplicationBundle</string>

   <key>bundle-version</key>

   <string>1.0.0</string>

   <key>kind</key>

   <string>software</string>

   <key>title</key>

   <string>Name Of Application</string>

  </dict>

</dict>

</array>

</dict>

</plist>

Problem 2: While testing we realised that sometimes the user’s app version was outdated and they’ll report issues or have inconsistencies due to a lower version. This can cause a lot of confusion.

Solution :

 

– Store the supported version of the app on a text file in an external URL .

– Get the version of the app and compare the version from an external URL.

– If the version in the app is lower than the supported version , display a message asking the user to upgrade and quit.

The supported version may not be the current version of the app – for minor UI tweaks, we may not change the supported version but if there are changes to the underlying object structure, the supported version will need to be changed.

Sample Objective-C code:  We can put it in the Main View Controller.

Main view controller :

    [self checkifObsoleteAppVersion];

….

– (void) checkifObsoleteAppVersion{

 

//Get version from external site

    NSString *versionURLString = @”http://URL/version.txt;  //<<– Version information stored in a simple text file

    NSURL *versionURL = [NSURL URLWithString:[versionURLStringstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

    NSString *versionOnExternalSite = [[NSString stringWithContentsOfURL:versionURLencoding:NSUTF8StringEncoding error:nilsubstringToIndex:6];

 

//Get version from App

    NSString *versionFromApp = [self.syncManager.appVersion substringToIndex:6];

 

//Format the versions to numbers

    NSNumberFormatter *versionFromAppNo = [[[NSNumberFormatter alloc]init]autorelease];

    NSNumber *appNo = [ versionFromAppNo numberFromString:versionFromApp];

 

    NSNumberFormatter *versionFromAppNoExt = [[[NSNumberFormatter alloc]init]autorelease];

    NSNumber *appNoExt = [ versionFromAppNoExt numberFromString:versionOnExternalSite];

       

//App version shouldn’t be lower than the one maintained in version file

       

    if ([appNo floatValue] < [appNoExt floatValue] )

    {

 

// Show a message

        UIAlertView *appObsoleteView = [[[UIAlertView alloc]initWithTitle:@”App version obsolete”message:@”A new version of App has been released and this version is obsolete.Please upgrade App to the new version.” delegate:self cancelButtonTitle:@”Exit” otherButtonTitles:nil, nil]autorelease];

        appObsoleteView.tag = 666;

        [appObsoleteView show];

 

    }

 

}

 

@end

 

Problem 3: Just putting as a reference to consolidate the information in a single place. Users were required to be manually registered and there were issues caused sometimes due to wrong information being set up due to manual process.

 

Solution:

I created a solution using SUP’s Java APIs and shared the experience in an earlier blog.

 

http://scn.sap.com/community/mobile/blog/2013/05/30/automating-user-registration-in-sybase-control-center

 


Retain selection screen values on program restart for transactions with chosen selections

From my blog on SCN

http://scn.sap.com/community/abap/blog/2014/08/20/retain-selection-screen-values-on-program-restart-for-transactions-with-chosen-selections

I had an interesting last week and what looked easy at the outset did my head in for quite a while. I tried various methods and the below approach was able to give me a satisfactory solution.

Let’s have a look at the high level requirement.

– Copy a standard SAP transaction and customise it . Below picture describes the requirement

Screen Shot 2014-08-16 at 7.28.17 pm.png

The transaction is started with only few fields of the complete selection screen as the selection screen has too many fields and may confuse the users.

2.PNG

The users need to navigate back and forth between different modes of output screen. At the first display of output screen ( let’s call them as levels – so the output screen is at level 0 when initially displayed and if called again goes to level 1 and so on . Similarly when the user comes back from a higher level of screen, the level will decrease : from 1 to 0 ). And of course when the program navigates back from level 0 of selection screen, it should display the selection screen.

I prototyped using a simple program using flight model.

– Selection Screen : Contains all fields.

All fields.PNG

However, the transaction is always run with a variant which hides the last field.

Selection Screen.PNG

– Let’s test with some data.

Selection Test.PNG

We get the level 0 output screen.

Level 0.PNG

Now click on filter ( search icon on top right )

Filter.PNG

and we get level 1 screen.

Level 1.PNG

Looks good so far. Now, let’s try going back – going back to level 0 gives the screen as anticipated. However, when we go back and see that the selection screen parameters have gone back. The selection screen has gone blank !

Selection Screen.PNG

Let’s see what’s going on.

As we need to keep track of different levels of screen, if the level of screen is greater than 0.

…….

ELSEIF syucomm = ‘EXIT’.

    IF gv_list_level > 0.

      gv_list_level = gv_list_level 1.

      gt_flight[] = gt_master_flight[].

      CALL SCREEN 100.

    ENDIF.

When we want to go back to selection screen from screen at level 0, we use below:

SUBMIT zsubmit_flight

            WITH report EQ ‘ZTESTFLIGHT’

            WITH variant = ‘ZFLIGHT_VAR’

            WITH SELECTION-TABLE gt_seltab .

zsubmit_flight is a standard SAP report used by the report and can’t be changed by us.

SUBMIT (REPORT) WITH VARIANT  = VARIANT

                    USING SELECTIONSET VARIANT

                    VIA SELECTION-SCREEN

Workaround:

1) Store selected values by call of RS_REFRESH_FROM_SELECTOPTIONS 

2) Export the selection table before doing a program restart.

EXPORT gt_seltab TO MEMORY ID gc_sel_mem.

3)  Retrieve the selection table AT SELECTION-SCREEN OUTPUT.

RS_VARIANT_CONTENTS gives the parameters and select-options actually visible in the variant.

IMPORT gt_seltab FROM MEMORY ID gc_sel_mem.

  IF NOT gt_seltab[] IS INITIAL.

    CALL FUNCTION ‘RS_VARIANT_CONTENTS’

      EXPORTING

        report              = ‘ZTESTFLIGHT’

        variant              = ‘ZFLIGHT_VAR’

      TABLES

        l_params            = lt_params

        l_selop              = lt_selops

        valutab              = lt_value

      EXCEPTIONS

        variant_non_existent = 1

        variant_obsolete    = 2

        OTHERS              = 3.

    IF sysubrc <> 0.

clear: lt_value,

          lt_selops,

          lt_value.

    ENDIF.

* Update parameters values

    LOOP AT lt_params INTO lw_param.

      READ TABLE gt_seltab REFERENCE INTO lo_values WITH KEY selname = lw_paramname.

      IF sysubrc = 0.

        lv_attr = lo_values->selname.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_val>.

        <fs_attr_val> = lo_values->low.

      ENDIF.

    ENDLOOP.

* Update select-option values

    LOOP AT lt_selops INTO lw_param.

      READ TABLE gt_seltab REFERENCE INTO lo_values WITH KEY selname = lw_paramname.

      IF sysubrc = 0.

        CONCATENATE lo_values->selname ‘SIGN’ INTO lv_attr SEPARATED BY ‘-‘.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_sign>.

        <fs_attr_sign> = lo_values->sign.

        CONCATENATE lo_values->selname ‘OPTION’ INTO lv_attr SEPARATED BY ‘-‘.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_option>.

        <fs_attr_option> = lo_values->option.

        CONCATENATE lo_values->selname ‘LOW’ INTO lv_attr SEPARATED BY ‘-‘.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_low>.

        <fs_attr_low> = lo_values->low.

        CONCATENATE lo_values->selname ‘HIGH’ INTO lv_attr SEPARATED BY ‘-‘.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_high>.

        <fs_attr_high> = lo_values->high.

        lv_attr = lo_values->selname.

        TRANSLATE lv_attr TO UPPER CASE.

        ASSIGN (lv_attr) TO <fs_attr_main>.

        CONCATENATE lv_attr ‘[]’ INTO lv_attr_tab.

        ASSIGN (lv_attr_tab) TO <fs_attr_tab>.

        IF lo_values->low IS NOT INITIAL OR lo_values->high IS NOT INITIAL.

          REFRESH <fs_attr_tab>.

          APPEND <fs_attr_main> TO <fs_attr_tab>.

        ENDIF.

      ENDIF.

    ENDLOOP.

  ENDIF.

– Create a transaction ‘ZFLIGHT’ with program ZTESTFLIGHT , variant ZFLIGHT_VAR.

The code can be referred here:

The code can be referred here:

ZSUBMIT_FLIGHT

https://github.com/viksingh/ABAP_Demo/blob/master/ZSUBMIT_FLIGHT

Program ZTESTFLIGHT with issues:

https://github.com/viksingh/ABAP_Demo/blob/master/ZTESTFLIGHT_1

Program  ZTESTFLIGHT with corrections:

ABAP_Demo/ZTESTFLIGHT_2 at master · viksingh/ABAP_Demo · GitHub

The key here is function module RS_VARIANT_CONTENTS and the dynamic update of selection screen after restart of a transaction.

ZSUBMIT_FLIGHT

https://github.com/viksingh/ABAP_Demo/blob/master/ZSUBMIT_FLIGHT

Program ZTESTFLIGHT with issues:

https://github.com/viksingh/ABAP_Demo/blob/master/ZTESTFLIGHT_1

Program  ZTESTFLIGHT with corrections:

ABAP_Demo/ZTESTFLIGHT_2 at master · viksingh/ABAP_Demo · GitHub

The key here is function module RS_VARIANT_CONTENTS and the dynamic update of selection screen after restart of a transaction.


ABAP dynamic internal table sort saves the day

Requirement to refresh the ALV to display only display unique fields. Thankfully the sort fields of an itab can be specified dynamically now.

TRY.

SORT gt_output BY (lt_sorttab).
DELETE ADJACENT DUPLICATES FROM gt_output COMPARING ALL FIELDS.
CATCH cx_sy_dyn_table_ill_comp_val.
gt_output[] = lt_output[].
ENDTRY.