Gary Guo

Learning never ends


  • Home

  • About

  • Tags

  • Categories

  • Archives

  • Sitemap

  • Search

Lessons Learnt during creating SCP CF Node.js application

Posted on 2018-06-19 | In SAP

How to install SAP modules

Run the below command before running npm install
npm config set @sap:registry https://npm.sap.com


How to create a SCP CF node.js application

Check the below link for detail:
https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/772b45ce6c46492b908d4c985add932a.html


How to install Cloud Foundry client tools

Download the Cloud Foundry client tool from the below link and install it
https://github.com/cloudfoundry/cli#downloads

Reference:

https://www.sap.com/developer/tutorials/hcp-cf-getting-started.html
https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/75125ef1e60e490e91eb58fe48c0f9e7.html#loio4ef907afb1254e8286882a2bdef0edf4


How to connect to CF region

cf api https://api.cf.us10.hana.ondemand.com
cf login
cf target -o ORG -s SPACE


How to deploy an application to SCP CF environment

cf push is executed in the same directory to deploy an application where the manifest.yml is located.
cf app myapp is used to check the status of application myapp.
cf apps is used to check the status of all deployed applications.


How to access a deployed application

Access the application via link <app_host>.cfapps.us10.hana.ondemand.com

Lessons Learned When Consuming On-Premise Service in SCP Cloud Foundry Application

Posted on 2018-06-19 | In SAP

I am trying to follow the below links to build a SCP (SAP Cloud Platform) Cloud Foundry application which is using XSUAA (User account and authentication) service, SCP Connectivity service and SCC (SAP Cloud Connector) to consume On-Premise OData service. The below lessons are learned during the prototype.

https://blogs.sap.com/2017/07/09/how-to-use-the-sap-cloud-platform-connectivity-and-the-cloud-connector-in-the-cloud-foundry-environment-part-1/
https://blogs.sap.com/2017/07/13/part-2-how-to-use-the-sap-cloud-platform-connectivity-and-the-cloud-connector-in-the-cloud-foundry-environment/

Maven installation

  1. Install JDK and set environment variable JAVA_HOME
  2. Download Apache Maven and unzip the file
  3. Add environment variable M2_HOME and MAVEN_HOME
  4. Update environment variable PATH for Maven bin folder
  5. Run command mvn -version to verify the installation

Reference:

https://www.mkyong.com/maven/how-to-install-maven-in-windows/
http://maven.apache.org/download.cgi


Maven eclipse plugin installation

Please check the below reference links for details. Update site to install Maven plugin in Eclipse:
http://download.eclipse.org/technology/m2e/releases/

Reference:

https://stackoverflow.com/questions/8620127/maven-in-eclipse-step-by-step-installation
http://toolsqa.com/java/maven/how-to-install-maven-eclipse-ide/


Error:

Failed to read artifact descriptor for org.apache.maven.plugins:maven-resources-plugin:jar:2.6
Could not transfer artifact org.springframework.boot:spring-boot-starter-parent:pom:1.5.7.RELEASE from/to Central (http://repo1.maven.org/maven2): Connection refused: connect and ‘parent.relativePath’ points at wrong local POM

Resolution:

  1. Run the below command in Linux:
    find ~/.m2 -name "*.lastUpdated" -exec grep -q "Could not transfer" {} \; -print -exec rm {} \;
    Run the below commands in Windows
    cd %userprofile%\.m2\repository
    for /r %i in (*.lastUpdated) do del %i
    Then right click on your project in eclipse and choose Maven->Update Project ..., make sure “Update Dependencies” is checked in the resulting dialog and click OK.
  2. You can always try mvn -U clean install
    -U Forces a check for updated releases and snapshots on remote repositories
  3. There may be different versions of Maven running between command prompt and Eclipse. Check the Maven installations and Maven user settings in Eclipse -> Windows -> Preferences

Reference:

https://stackoverflow.com/questions/5074063/maven-error-failure-to-transfer


Error:

No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

Resolution:

  1. Install JDK instead of JRE
  2. Set environment variables JAVA_HOME, classpath, PATH to link them to JDK, instead of JRE
  3. Check the settings Windows -> Preferences -> Java ->Installed JREs in Eclipse. Make sure there is at least one JDK there. Link the Run configuration of Maven build to the JDK

Reference:

https://stackoverflow.com/questions/19655184/no-compiler-is-provided-in-this-environment-perhaps-you-are-running-on-a-jre-ra


Error:

The following artifacts could not be resolved: com.sap.xs2.security:java-container-security-api:jar:0.26.4, com.sap.xs2.security:java-container-security:jar:0.26.4: Failure to find com.sap.xs2.security:java-container-security-api:jar:0.26.4 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced

Resolution:

Install XS Security libs to your local Maven repository:

  1. The first step is to get some additional Java libs from Service Marketplace.
    Download additional XS security libs from service marketplace:https://launchpad.support.sap.com/#/softwarecenter/search/XS_JAVA
  2. Unzip the file
  3. Install XS Security Libs to your local maven repo using:
    cd <destLocation>
    mvn clean install

Reference:

https://blogs.sap.com/2017/07/18/step-7-with-sap-s4hana-cloud-sdk-secure-your-application-on-sap-cloud-platform-cloudfoundry/


Error:

The import org.json cannot be resolved
The import org.apache.commons.io cannot be resolved

Resolution:

  1. Download the ZIP file from the below URL and extract it to get the Jar.

  2. Add the Jar to your build path. To Add this Jar to your build path Right click the Project > Build Path > Configure build path > Select Libraries tab > Click Add External Libraries > Select the Jar file downloaded

http://www.java2s.com/Code/JarDownload/java/java-json.jar.zip
http://commons.apache.org/proper/commons-io/download_io.cgi

Reference

https://stackoverflow.com/questions/8997598/importing-json-into-an-eclipse-project


Error

package json.java does not exist
package org.apache.commons.io does not exist

Resolution

  1. Run the below Maven command to install the Maven repository
    mvn install:install-file -Dfile=java-json.jar -DgroupId=json.java -DartifactId=java-json -Dversion=1.0 -Dpackaging=jar
    mvn install:install-file -Dfile=commons-io-2.6.jar -DgroupId=commons-io -DartifactId=commons-io -Dversion=2.6 -Dpackaging=jar
  2. Add the below dependencies to the pom.xml file
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <dependency>
    <groupId>json.java</groupId>
    <artifactId>java-json</artifactId>
    <version>1.0</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
    <scope>compile</scope>
    </dependency>

Reference

https://stackoverflow.com/questions/41779195/maven-compilation-error-even-if-dependency-path-is-correct


Error

Cannot instantiate the type XSTokenRequest

Resolution

  1. Run the below command to install the Jar file to local Maven repository
    mvn install:install-file -Dfile=java-container-security-api-0.26.4.jar -DgroupId=com.sap.xs2.security -DartifactId=java-container-security-api -Dversion=0.26.4 -Dpackaging=jar
    mvn install:install-file -Dfile=java-container-security-0.26.4.jar -DgroupId=com.sap.xs2.security -DartifactId=java-container-security -Dversion=0.26.4 -Dpackaging=jar
  2. Change the pom.xml with the below:
    <dependency>
          <groupId>com.sap.xs2.security</groupId>
          <artifactId>java-container-security-api</artifactId>
          <version>0.26.4</version>
    </dependency>
    <dependency>
        <groupId>com.sap.xs2.security</groupId>
        <artifactId>java-container-security</artifactId>
         <version>0.26.4</version> 
    </dependency>
    
  3. Run Maven update for the project
  4. Check the build path for the Java file to see if multiple libraries are used

Error

The import javax.servlet can’t be resolved [duplicate]

Resolution

You need to add the Servlet API to your classpath. In Tomcat 6.0, this is in a JAR called servlet-api.jar in Tomcat’s lib folder. You can either add a reference to that JAR to the project’s classpath, or put a copy of the JAR in your Eclipse project and add it to the classpath from there.

Reference

https://stackoverflow.com/questions/4119448/the-import-javax-servlet-cant-be-resolved


Error:

Unable to extract request URI: URI must contain a host
http://<virtual_host>:80/sap/opu/odata/sap/<odata_service>//$metadata

Resolution:

Update the SCC (SAP Cloud Connector) and SCP destination to make sure underscore is not used in the hostname


How to change the font size in Eclipse editor

Windows -> Preferences -> General -> Appearance -> Color and Fonts -> Basic -> Text Font -> Edit -> Apply


How to search for a string in a project in Eclipse

Ctrl + H


How to upload a project over 20M to SCP CF environment

Use Eclipse Cloud Foundry plugin

Encoding in SAP

Posted on 2018-04-12 | In SAP

Since different applications are using different encodings to process data, there may be encoding issue when the source application and destination application are using different encodings.

ECC Encoding

  • SAP ECC is saving data in database with Unicode encoding. You can check if your SAP application server is using Little Indian (4103) or Big Indian (4102) via t-code I18N -> I18N Customizing -> I18N System Configuration -> Display Current NLS config -> "Code Page of Application Server".
  • When SAP ECC is sending a XML file to PI, UTF-8 encoding (4110) will be used.
  • When SAP ECC is writing a flat file to application server folder, the encoding will depend on the ABAP statement OPEN DATASET ... ENCODING .... If ENCODING DEFAULT or ENCODING UTF-8 is used, UTF-8 will be used.
  • When SAP ECC is using file port to write an IDOC flat file, the encoding will be UTF-8 if the Unicode format checkbox is selected in port (t-code WE21).
  • When SAP ECC is using file port to write an IDOC flat file, the encoding will be using the relevant code page if Unicode format is not selected and Char. Set is specified in port (t-code WE21).
  • When SAP ECC is using file port to write an IDOC flat file, if Unicode format and Char. Set are not specified, the encoding will be using the same encoding as ABAP statement ENCODING NON-UNICODE. In an Unicode SAP system, the encoding in the table TCP0C by platform, language and country will be used. In the case of Linux, English, and US, the encoding will be ISO-8859-1 (1100). You can use ABAP statements SET COUNTRY and SET LOCALE LANGUAGE to change the language and country in a ABAP session.

PI Encoding

  • PI sender file channel will use the specified file encoding to read the file, if file type is set to Text instead of Binary.
  • You can convert a flat file to XML file via adapter module AF_Modules/MessageTransformBean, and specify the encoding of the XML file by setting the parameter Transform.ContentType to text/plain;charset=utf-8.
  • You can convert the encoding of an output file from UTF-8 to ISO-8859-1 via adapter module AF_Modules/TextCodepageConversionBean with parameter Conversion.charset equal to iso-8859-1.

Utilities

You can check the hex code and UTF-8 bytes for one character in this site. Please note:

  • The hex code is using Unicode big indian, such as 0421 for CYRILLIC CAPITAL LETTER ES - C.
  • The UTF-8 bytes should contain space if there are multiple bytes for one character, such as D0 A1.
  • In some cases, UTF-8 bytes as Latin-1 characters bytes will be showing the same invalid characters as destination application, if source application is using UTF-8 encoding, and the destination application is using encoding like ISO-8859-1 to process data.
    You can use Notepad++ to open a file with different encodings, and you can also convert it to use another encoding.
    You can use some application like WinHex or Hex_edit to see the hex code for one text file.

Common Encoding/Code Pages

  • 1100 for ISO-8859-1, which is similar to WINDOWS-1252/ANSI
  • 4110 for UTF-8, the optional BOM (Byte Order Mask) will be EFBBBF for UTF-8
  • 4102 for UTF-16be
  • 4103 for UTF-16le
  • 8400 for GB2312

One encoding issue in my work

  • Issue: Below is one encoding issue I came accross with in my work. In SAP ECC system, the character is showing as C, but in destination application, the character is showing as Ð ¡, and can not be recoginzed.
  • Analysis: The special character CYRILLIC CAPITAL LETTER ES which is showing exactly the same as LATIN LETTER C is used in SAP ECC. In debugging mode, we will see that the hex code is 2104 since SAP ECC system is using Unicode little indian. In the site, we checked with the hex code 0421 which is Unicode big indian, and we can find that the UTF-8 bytes for this character is D0 A1, and UTF-8 bytes as Latin-1 characters bytes is showing as Ð ¡.

References

Check hex code and UTF-8 bytes for one character
SAP note 552464 - What is Big Endian / Little Endian? What Endian do I have?

ABAP development for Status Management in SAP

Posted on 2018-03-28 | In SAP

Below you will find some objects which is useful when you are performing ABAP development for status management in SAP.

Function Modules

  1. STATUS_READ: With this function, you can get the system status and user status internal codes, such as I0001, E0001.
  2. STATUS_TEXT_EDIT: With this function, you can get the external status code REL APPR for one object. In an update transaction, if you set the input parameter BYPASS_BUFFER to X, it will get the old status code from database. If you set the input parameter BYPASS_BUFFER to blank, it will get the new status code after the change.
  3. STATUS_CHANGE_INTERN: With this function, you can update the system status.
  4. STATUS_CHANGE_EXTERN: With this function, you can update the user status.
  5. STATUS_CHANGES_GET: With this function, you can get the status changes in the current update transaction.

Tables

  1. JSTO: Status object information. It contains the status profile and object category for one object.
  2. JEST: Individual Object Status. It contains the object status information. Field INACT indicates whether the status is active or not.
  3. TJ02T: System status texts. It contains the external status code and description for one system status, which is INNNN.
  4. TJ30T: Texts for User Status. It contains the external status code and description for one user status, which is ENNNN.
  5. JCDS: Change Documents for system/user status. It contains the change documents for status management.

T-codes

  1. BS23: Display system status
  2. BS03: Display status profile (user status)

Tips

  • You can use Authorization key to control the authorization to update user status. If the auth key is assigned to one user status in status profile, the authorization with auth object B_USERSTAT and auth key should be assigned to the user, so that one is able to update the user status.

Async and Await Keywords in JavaScript

Posted on 2018-03-27 | In JavaScript

Async/Await

To better understand the behavior of async and await keywords in JavaScript, I have written the below code and check the result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const fs = require('fs');
const util = require('util');
// Convert fs.readFile into Promise version of same
const readFile = util.promisify(fs.readFile);

async function asyncReadfile1() {
console.log("The await async function to read file 1 is called");
const text = await readFile("C:/Download/129.xps");
console.log('The file 1 contains: ' + text.length + ' bytes');
}

async function asyncReadfile2() {
console.log("The await async function to read file 2 is called");
const text =await readFile("C:/Download/141.xps");
console.log('The file 2 contains: ' + text.length + ' bytes');
}

async function asyncMain() {
await asyncReadfile1();
console.log("Processing between reading 2 files");
await asyncReadfile2();
return "successful";
}

console.log("Start processing...");
asyncMain().then((result) => {
console.log("The async main function is called " + result);
});
console.log("Go to the next statement after the async main function");

Result:

1
2
3
4
5
6
7
8
9
$ node app.js
Start processing...
The await async function to read file 1 is called
Go to the next statement after the async main function
The file 1 contains: 251610 bytes
Processing between reading 2 files
The await async function to read file 2 is called
The file 2 contains: 549337 bytes
The async main function is called successful

Here are the processing steps for the above example.

  1. The runtime engine will call main function asyncMain, which will in turn call the first await async function asyncReadfile1 , which will output console log The await async function to read file 1 is called
  2. When the function asyncReadfile1 runs to the statement const text = await readFile("C:/Download/129.xps");, the Promise object returned from readFile is not resolved yet, so the execution stack will go back to upper function asyncMain. In the main function, the Promise object returned from asyncReadfile1 is not resolved yet, so the executation stack will go back to upper level. Therefore, the next console log is Go to the next statement after the async main function.
  3. When the sync processing logic in the upmost level is completed, the call stack goes back to deepest unresolved Promise function asyncReadfile1. In the async function asyncReadfile1, the statement const text = await readFile("C:/Download/129.xps"); is completed and the Promise object is resolved, so it will continue with the next statement, and the next console log is The file 1 contains: 251610 bytes. After the console log, the Promise object of async function asyncReadfile1 is resolved.
  4. Since the promise object of async function asyncReadfile1 is resolved, the main function will continue with next statement, which will output console log Processing between reading 2 files.
  5. In the next statement of main function, async function asyncReadfile2 wil be called, and the console log will be The await async function to read file 2 is called and The file 2 contains: 549337 bytes
  6. After the return statement of main function, the Promise object of the main function is resolved, so the callback function in Promise.prototype.then method will be executed to output console log The async main function is called successful

Understanding for async/await:

  1. When the Promise object returned from await child function is not resolved yet, the execution stack will go back to parent function.
  2. When the Promise object returned from await child function is resolved, the execution stack will continue with next statement in the current function.
  3. When the sync processing logic in the upmost level is completed, the call stack goes back to deepest unresolved Promise function.

Promise

To achieve the same functionality with Promise object, we would need to more complex code with nested Promise.prototype.then method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const fs = require('fs');
const util = require('util');
// Convert fs.readFile into Promise version of same
const readFile = util.promisify(fs.readFile);

function asyncReadfile1() {
console.log("The await async function to read file 1 is called");
return new Promise(function (resolve, reject) {
readFile("C:/Download/129.xps").then( (text) => {
console.log('The file 1 contains: ' + text.length + ' bytes');
resolve();
} );
} );
}

function asyncReadfile2() {
console.log("The await async function to read file 2 is called");
return new Promise(function (resolve, reject) {
readFile("C:/Download/141.xps").then( (text) => {
console.log('The file 2 contains: ' + text.length + ' bytes');
resolve();
} );
} );
}

function asyncMain() {
return new Promise(function (resolve, reject) {
asyncReadfile1().then( () => {
console.log("Processing between reading 2 files");
asyncReadfile2().then( () => {
resolve("successful");
});
});
});
}

console.log("Start processing...");
asyncMain().then((result) => {
console.log("The async main function is called " + result);
});
console.log("Go to the next statement after the async main function");

Understanding for Promise

  1. The resolved immediately Promise object will be effective in next Event loop, instead of current Event loop.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    setTimeout(function () {
    console.log('three');
    }, 0);

    Promise.resolve().then(function () {
    console.log('two');
    });

    console.log('one');

    // one
    // two
    // three
  2. The Promise.prototype.then method will return another Promise object, which is not the original Promise object.

  3. The new Promise object will be executed immediately after creation.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var promise = new Promise(function(resolve, reject){
    console.log("New Promise object");
    resolve();
    }).then( () => {
    console.log("Callback method");
    });

    console.log("After creating new Promise object");

    // New Promise object
    // After creating new Promise object
    // Callback method

Reference

Promise object
async function

12…5

Gary Guo

23 posts
9 categories
19 tags
Links
  • Markdown Cheatsheet
  • JSFiddle
  • JavaScript - Liao XueFeng
  • Git - Liao XueFeng
  • Blog - Ruan YiFeng
© 2018 Gary Guo
Powered by Hexo
|
Theme — NexT.Gemini v6.0.5