cancel
Showing results for 
Search instead for 
Did you mean: 

SAP Cloud SDK for JAVA: Acces On-Premise System via localhost

christoffer_fuss
Participant

Hello,

I followed this blog post to access an OData service with the Cloud Platform SDK. I Used a custom OData Service instead of the standard Businesspartner OData service and a R3 ERP on-Premise backend system instead of S/4 HANA.

If I deploy the app to my Cloud Foundry subaccount it is working fine and my OData service is executed via Cloud Connector and destination service on my on-premise backend.

If I try to execute the same application on the local tomee server the on-premise backend system is not reached.

My destination on my subaccount looks like this:

If I pass all the information (URL,User,Password) to the local destination it is not working...

The same erroppr apperas on executing the integration tests.

What must I do to access my on-premise backlend from localhost?

Best regards,

Chris

Andy1
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Chris,

I also follow this blog, in cloud connector Cloud To On-Premise, configured HTTPS protocol to s4hana op system, then configure HTTP destination in BTP and check connection works(and use this HTTP destination to do other testing such as call s4hana data from postman, it works).

But i follow the blog, after deployment to BTP, the hello world servlet can be called, but cannot call the data

. It just gives error internal server error.

And also try to run locally and also set the local destination variable to follow the blog, but face error environment variable vcap_services is not defined. Do you have any idea?

Thanks lot.

Accepted Solutions (0)

Answers (18)

Answers (18)

former_member186608
Active Participant

Hi Chris,

connecting to the on-premise ERP system through the Cloud Connector is not possible from local deployment, regardless of running the app locally or executing integration tests.

Can your local application or your integration tests reach the on-premise ERP system directly, from a network perspective? If so, you can just populate the real host name in your environment variable. Currently you use the virtual host name in your environment variable.

Best regards

Marco

christoffer_fuss
Participant
0 Kudos

Hi Marco,

are you sure about that? I can reach my backend system with a open VPN connection. With this URL my local sercer is connecting but my integration test gets still a "connection refused". My systems.yml looks like this:

---
erp:
  default: "saperp"
  systems:
    - alias: "saperp"
      uri: "http://dt1.datatrain...."
      systemId: "DT1"           # optional, defaults to ""
      sapClient: "100"                 # optional, defaults to default SAP client
      locale: "de"                     # optional, defaults to English (US)
      #erpEdition: "cloud"              # optional, defaults to "cloud"

What is missing? The uri is as I said working o local tomee server.

Best Regards,

Chris

christoffer_fuss
Participant
0 Kudos

Hi Marco,

sry for the late answer, I was quite busy last days. But I finally found the problem: Just a ittle copy/paste error.

Here I must call the "TPServlet" instead of the "TPServletTest".

Many Thanks for your help.

The next step is to call a BAPI in my R3 system 🙂

Best Regrads,

Chris

former_member186608
Active Participant
0 Kudos

Glad to hear that you figured it out

former_member186608
Active Participant
0 Kudos

Hi Christoffer,

I do not need a user in your system, I will try to run that project against our own systems. Also, I would then replace your VDM call to another one targeting a standard service, or you do it already for me.

I am afraid I cannot further help you without receiving your project.

Thanks

Marco

christoffer_fuss
Participant
0 Kudos

I think that is not really helpful to post my code because you dont have a user in my system? and this servie is a cutom service and will not work in your system....maybe I shoul switch to a standard service?

former_member186608
Active Participant
0 Kudos

Hi Christoffer,

could you package your app and upload it here so that I can reproduce the problem on my machine? Sharing code pieces via comments here is very error-prone.

Make sure that you omit any confidential source code and information from your application before uploading it here.

Thanks

Marco

christoffer_fuss
Participant
0 Kudos

the connection is working now, dont know why but the integration test is still not working:

I check in the integration test for the tiles request the status code 200 but I get 404 (not found).

In the localhost I get the status 200 but not in the integration test. Here is then log:

[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 8.018 s <<< FAILURE! - in de.datatrain.TPServletTest
[ERROR] testService(de.datatrain.TPServletTest)  Time elapsed: 1.872 s  <<< FAILURE!
java.lang.AssertionError:
1 expectation failed.
Expected status code <200> but was <404>.

        at de.datatrain.TPServletTest.testService(TPServletTest.java:57)

Dez 08, 2019 1:31:41 PM org.apache.coyote.AbstractProtocol stop
INFORMATION: Stopping ProtocolHandler ["http-nio-56655"]
Dez 08, 2019 1:31:41 PM org.apache.coyote.AbstractProtocol pause
INFORMATION: Pausing ProtocolHandler ["http-nio-56655"]
Dez 08, 2019 1:31:41 PM org.apache.catalina.core.StandardService stopInternal
INFORMATION: Stopping service [Tomcat]
[main] INFO org.apache.cxf.management.jmx.InstrumentationManagerImpl - unregistering MBean org.apache.cxf:bus.id=openejb.cxf.bus,type=Bus,instance.id=1907808127
Dez 08, 2019 1:31:41 PM org.apache.coyote.AbstractProtocol destroy
INFORMATION: Destroying ProtocolHandler ["http-nio-56655"]
[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures: 
[ERROR]   TPServletTest.testService:57 1 expectation failed.
Expected status code <200> but was <404>.

[INFO]
[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for jcocf - Root 1.0-SNAPSHOT:
[INFO]
[INFO] jcocf - Root ....................................... SUCCESS [  0.547 s]
[INFO] jcocf - Application ................................ SUCCESS [ 13.939 s]
[INFO] jcocf - Unit Tests ................................. SUCCESS [  3.722 s]
[INFO] jcocf - Integration Tests .......................... FAILURE [ 22.132 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  40.557 s
[INFO] Finished at: 2019-12-08T13:31:41+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.0.0-M3:test (default-test) on project jcocf-integration-tests: There are test failures.
[ERROR]
[ERROR] Please refer to H:\dev\jcocf\integration-tests\target\surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <goals> -rf :jcocf-integration-tests
former_member186608
Active Participant
0 Kudos

Can you kindly post the entire log output between those two points:

Begin:

[INFO] --- maven-surefire-plugin:3.0.0-M3:test (default-test) @ integration-tests --
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------

End:

INFO: Destroying ProtocolHandler ["http-nio-53950"]

Ensure that you do not post any confidential data here.

The point is I guess there is more promising information in the stacktrace(s).

christoffer_fuss
Participant
0 Kudos

Yes you are right 🙂 Thank you very much for helping 🙂

Best regards,

Chris

former_member186608
Active Participant
0 Kudos

OK thanks, I'll try to reproduce that with your code.

I assume you're using the scp-cf-tomee archetype, right?

christoffer_fuss
Participant
0 Kudos

I have not implemented unit tsts at the moment.

Here is the code for the integration test:

package de.datatrain;

import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.module.jsv.JsonSchemaValidator;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URL;
import com.sap.cloud.sdk.testutil.MockUtil;

import static io.restassured.RestAssured.when;

@RunWith(Arquillian.class)
public class TPServletTest {
    private static final MockUtil mockUtil = new MockUtil();
    private static final Logger logger = LoggerFactory.getLogger(TPServletTest.class);

    @ArquillianResource
    private URL baseUrl;

    @Deployment
    public static WebArchive createDeployment() {
        return TestUtil.createDeployment(TPServletTest.class);
    }

    @BeforeClass
    public static void beforeClass() {
        mockUtil.mockDefaults();
        mockUtil.mockErpDestination("saperp", "saperp");
    }

    @Before
    public void before() {
        RestAssured.baseURI = baseUrl.toExternalForm();
    }

    @Test
    public void testService() {
        // JSON schema validation from resource definition
        final JsonSchemaValidator jsonValidator = JsonSchemaValidator
                .matchesJsonSchemaInClasspath("tiles-schema.json");

        // HTTP GET response OK, JSON header and valid schema
        when()
                .get("/tiles")
        .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body(jsonValidator);
    }
}
former_member186608
Active Participant
0 Kudos

Can you pls post your entire integration test class? Above you truncated few, but maybe important pieces.

Also, I assume that your unit tests do work, right?

christoffer_fuss
Participant
0 Kudos

Hi Marco,

here ist the Servlet:

@WebServlet("/tiles")
public class TPServlet extends HttpServlet{
    
         private static final long serialVersionUID = 1L;
        private static final Logger logger = LoggerFactory.getLogger(TPServlet.class);

        private final ErpHttpDestination destination = DestinationAccessor.getDestination("saperp").asHttp().decorate(DefaultErpHttpDestination::new);

        @Override
        protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
                throws ServletException, IOException {
            try {
                final List<Tile> tiles =
                        new DefaultTpsrvService()
                                .getAllTile()
                                .orderBy(Tile.SORT, Order.ASC)
                                .top(200)
                                .execute(destination);

                response.setContentType("application/json");
                response.getWriter().write(new Gson().toJson(tiles));
            } catch (final ODataException e) {
                logger.error(e.getMessage(), e);
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.getWriter().write(e.getMessage());
            }

        }

}

Best Regards and thnaks for helping,

Chris

former_member186608
Active Participant
0 Kudos

Looks to me as if the call to the ERP system is not triggered, but rather the access to your servlet or controller does not work. Would you mind showing us your servlet or controller that listens to the relative path "/tiles"?

christoffer_fuss
Participant
0 Kudos

Hi Marco,

summary: the local host is connected by using the real host name instead of Cloud Connector.
Enviroment variable looks like this:

set destinations=[{name: "saperp", url: "http://dt1.datatrain-....de:8000", username: "user", password: "password"}]

If I use the same url in my systems.yml, the integraion test is failing because the connection is revoked. The systems.yml looks like this:

---
erp:
  default: "saperp"
  systems:
    - alias: "saperp"
      uri: "http://dt1.datatrain-....de:8000"
      systemId: "DT1"           # optional, defaults to ""
      sapClient: "100"                 # optional, defaults to default SAP cl
      locale: "de"                     # optional, defaults to English (US)
      erpEdition: "on-premise"         # optional, defaults to "cloud"

credentials.yml looks like this:

---
credentials:
- alias: "saperp"
  username: "user"
  password: "password"

The integration test looks like this:

 @BeforeClass
    public static void beforeClass() {
        mockUtil.mockDefaults();
        mockUtil.mockErpDestination("saperp", "saperp");
    }

    @Before
    public void before() {
        //RestAssured.baseURI = baseUrl.toExternalForm();
    }

    @Test
    public void testService() {
        // JSON schema validation from resource definition
        final JsonSchemaValidator jsonValidator = JsonSchemaValidator
                .matchesJsonSchemaInClasspath("tiles-schema.json");

        // HTTP GET response OK, JSON header and valid schema
        when()
                .get("/tiles")
        .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body(jsonValidator);
    }

Here is a part of the log:

[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 11.98 s <<< FAILURE! - in de.datatrain.TPServletTest
[ERROR] testService(de.datatrain.TPServletTest)  Time elapsed: 5.819 s  <<< ERROR!
java.net.ConnectException: Connection refused: connect
        at de.datatrain.TPServletTest.testService(TPServletTest.java:55)

Any idea what is getting wrong?

Thank you very much for helping.

Best regrads,

Chris

former_member186608
Active Participant
0 Kudos

Hi Chris,

can you please summarize the current state?

You wrote that your local server can now connect to your on-premise ERP. Is that the case?

Pls show us your environment variable then.

Also share the latest state of your systems.yml please.

Thanks

Marco

christoffer_fuss
Participant
0 Kudos

Hi Matthias,

thnaks for helping 🙂

I am using the newest version 3.8.0. of the SDK.

I changed the enviroment variable to this:

set destinations=[{name: "saperp", url: "http://dt1.https:11", username: "USER", password: "PASSWORD","proxyType": "on-premise"}]

It is still not working that way. Or must I pass the "proxyType" in the properties array?
The proxy server is specified in the Cloud Connector and I thought this information is taken.
Should I pass the proxy information again in the enviorment varaible?

The code for the destination was copied from the blog:

 private final ErpHttpDestination destination = DestinationAccessor.getDestination("saperp").asHttp().decorate(DefaultErpHttpDestination::new);

Best Regards,

Chris

mkuhr-test
Advisor
Advisor
0 Kudos

Hi Chris,

I think you might need to not use quotes for the proxyType. Could you check that? If that dosen't do the trick we'll need to debug into the application and see which values are stored in the destination once it's loaded and what the exact error + stack trace is.

Best, Matthias

christoffer_fuss
Participant
0 Kudos

Hi Matthias,

I tried it again without the quotes and it is still not working. Have you seen the answer from Marco? He is saying that this scenario is not possible. Are you sure that your way should work?

Best regards,

Chris

mkuhr-test
Advisor
Advisor
0 Kudos

Hi Chris,

yes Marco is right, I wasn't aware of the Cloud Connector.

mkuhr-test
Advisor
Advisor
0 Kudos

As my edits don't seem to appear on my initial answer:

Ignore the note on the blog post, I overlooked that you actually referenced a tutorial which is targeting for the current SDK version.

Also: you should be able to specify an on-premise destination by adding the following to your environment variable:

"proxyType": "on-premise" 
mkuhr-test
Advisor
Advisor
0 Kudos

Hi Chris,

as you can see in your CF destination you set the proxy type explicitly to on-premise. That information is lacking in the environment variable of your local deployment.

Could you please share the version of the SDK that you are using together with the code snippet where you load the destination? Then I can help you more specifically with how to pass that information via environment variables.

Best, Matthias