SAP Cloud Platform Java Entwicklung – Teil 2

Zugriff auf SAP HANA in der NEO Umgebung

Im ersten Teil der Blogserie habe ich Sie in die Java Entwicklung auf Basis des Spring Frameworks eingeführt. Anhand eines einfachen RestControllers wurden die Grundlagen gezeigt.

Was wäre eine Applikation ohne Zugriff auf eine Datenbank. Im SAP Cloud Kontext ist es natürlich naheliegend dass SAP HANA als Datenbank verwendet wird. In diesem Teil der Blogserie zeige ich Ihnen wie auf die Datenbank in der NEO Umgebung zugegriffen werden kann.

JNDI – Die gelben Seiten

Der Zugriff auf die HANA Datenbank erfolgt über JNDI, aus meiner Sicht eine der spannendsten Technologien im Java Umfeld. Mit einem JNDI Lookup können von der Laufzeitumgebung verwaltete Resourcen geladen werden. Die Idee dahinter ist sehr einfach – die Laufzeitumgebung kümmert sich um das Instanzieren der benötigten Klassen und stellt diese der Applikation bereit.

Damit die hier vorgestellte Applikation JNDI unterstützt müssen einige Tätigkeiten durchgeführt werden. Im ersten Schritt ist es erforderlich dass im Verzeichnis src > main eine Unterverzeichnis namens webapp und darin in Unterverzeichnis namens WEB-INF angelegt wird. Im Verzeichnis src > main > webapp > WEB-INF ist es nur erforderlich eine Datei namens web.xml anzulegen.

Verzeichnisstruktur

Verzeichnisstruktur für web.xml

Jene Resourcen die mittels JNDI verwaltet werden, müssen in der Datei web.xml als Resource Reference (resource-ref) angeführt werden. Darin muss der Name (res-ref-name) definiert werden unter dem die Resource angesprochen wird sowie die dahinterliegende Java Klasse (res-type) auf die typisiert wird.

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<resource-ref>
<res-ref-name>jdbc/DefaultDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
</resource-ref>
</web-app>

Spring Data Dependency deklarieren

Damit ist der erste Schritt bereits erledigt. Nachdem wir den Zugriff auf die Datenbank nicht mittels SQL Kommandos selbst implementieren, sondern auf Spring Data zurückgreifen, muss im pom.xml noch eine entsprechende Dependency definiert werden.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Nachdem Spring Data eine Vielzahl an Datenbanken unterstützt ist es erforderlich, der Laufzeitumgebung mitzuteilen welche Datenbank zu verwenden ist. Das passiert über die Datei application.properties. Falls diese noch nicht existiert muss sie im Verzechnis src > main > resources angelegt werden. Der vollqualifizierte Klassenname des HANA Treibers lautet com.sap.db.jdbc.Driver

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.HANAColumnStoreDialect
spring.jpa.properties.hibernate.connection.pool_size = 10
spring.datasource.driverClassName=com.sap.db.jdbc.Driver

@Configuration

Spring @Configuration-Annotation ist Teil des Spring Core Frameworks. Die Spring-Annotation weist darauf hin, dass die Klasse über eine @Bean-Definitionsmethoden verfügt. Der Spring-Container kann dadurch die Klasse verarbeiten und Spring Beans zur Laufzeit generieren, die in der Anwendung verwendet werden können.

Für die Verwendung im Neo Stack muss die Datasource mittels JNDI geladen werden. Dazu muss eine entsprechende Klasse erstellt werden. Ich nachfolgenden Code-Snippet wird die vollständige Klasse dargestellt.

Neo Datasource Configuration
package at.clouddna.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
@Profile({"neo"})
public class NeoConfig 
{	
	@Bean(destroyMethod="")
	public DataSource jndiDataSource() throws IllegalArgumentException, SQLException
	{
		JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
		DataSource ds = dataSourceLookup.getDataSource("java:comp/env/jdbc/DefaultDB");
		return ds;
	}
}

Der JNDI-Lookup zielt auf den Namen java:comp/env/jdbc/DefaultDB ab. Der Prefix java:comp/env/ ist in der SAP Cloud Platform immer derselbe. Der dahinter definierte Name jdbc/DefaultDB entspricht dem res-ref-name in der web.xml

Entwicklung einer Entity-Klasse

Die Verwendung von Spring-Data ermöglicht eine sehr effiziente Entwicklung der Persistenzschicht. Spring-Data basiert auf dem Hibernate Framework. Sobald wir eine Klasse anlegen und diese mit der Annotation @Entity versehen, wird auf der darunterliegenden Datenbank eine zugehörige Tabelle angelegt. Im nachfolgende Code-Snippet zeige ich Ihnen eine einfach User Klasse.

User.java
package at.clouddna.demo.model;

import javax.persistence.*;

@Entity
public class User {

    @Column(nullable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;

    private String firstname;
    private String lastname;

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getFirstname() {
        return this.firstname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getLastname() {
        return this.lastname;
    }
}

CRUD Methoden

Das geniale an Spring-Data ist die Out-of-the-box Verfügbarkeit von CRUD Methoden. Dazu muss lediglich ein Interface erstellt werden das vom JpaRespository erbt. Dies wird für die User Entity im nachfolgenden Code-Snippet dargestellt.

package at.clouddna.demo.repository;

import at.clouddna.demo.model.User;

public interface IUserRepository extends JpaRepository<User, Long> {

}

Das Respository kann nun direkt im Controller verwendet werden indem über Autowiring darauf zugegriffen wird. Mein Unternehmen sieht davon jedoch ab. Wir erstellen für jede Entity-Klasse immer ein zugehöriges DTO (Data Transfer Object) und erstellen zusätzlich eine Serivce-Klasse, die mit der @Service Annotation versehen wird, welche die Verwendung des Repository kapselt. Die Service-Klasse kann im Controller über die @Autowired Annotation injiziert werden.

Selbstverständlich zeige ich Ihnen wie das funktioniert.

ServiceBase Klasse und Model Mapper

Das Mapping der Entity-Klasse auf das DTO und umgekehrt führen wir nicht manuell sondern mittels ModelMapper durch. Der Modelmapper muss ins pom.xml als Dependency aufgenommen werden.

<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
ServiceBase.java
package at.clouddna.codegenerator.service.da;

import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public abstract class ServiceBase {

    private ModelMapper modelMapper;

    public ServiceBase(){
        this.modelMapper = new ModelMapper();
        this.modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STANDARD);
    }

    public <D, T> D map(T entity, Class<D> outClass) {
        return modelMapper.map(entity, outClass);
    }

    public <D, T> List<D> mapAll(Collection<T> entityList, Class<D> outCLass) {
        return entityList.stream()
                .map(entity -> map(entity, outCLass))
                .collect(Collectors.toList());
    }

    protected void writeToFile(String fileName, String content) throws IOException {
        FileOutputStream outputStream = new FileOutputStream(fileName);
        byte[] strToBytes = content.getBytes();
        outputStream.write(strToBytes);
        outputStream.close();
    }

    protected void writeToFile(String fileName, byte[] content) throws IOException {
        FileOutputStream outputStream = new FileOutputStream(fileName);
        outputStream.write(content);
        outputStream.close();
    }
}

Service Klasse

Die Service Klasse erbt von der ServiceBase Klasse und kapselt den Zugriff auf die Datenbank. Nachfolgendes Code-Snippet zeigt die UserService Klasse. Wichtig ist dabei dass die Klasse mit der Annotation @Service versehen wird. Dadurch kann sie im Controller mittels Autowiring verwendet werden.

UserService.java
package at.clouddna.demo.service;

import at.clouddna.demo.dto.UserDto;
import at.clouddna.demo.model.User;
import at.clouddna.demo.respository.IUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class UserService extends ServiceBase {

    @Autowired
    private IUserRepository repository;

    public UserDto create(UserDto userDto) {
        return map(repository.save(map(userDto, User.class)), UserDto.class);
    }

    public UserDto update(UserDto userDto) {
        return map(repository.save(map(userDto, User.class)), UserDto.class);
    }

    public boolean delete(Long id) {
        repository.deleteById(id);
        return true;
    }

    public UserDto findById(Long id) {
        Optional<User> userOptional = repository.findById(id);
        if(!userOptional.isPresent()) {
            return null;
        }
        return map(userOptional.get(), UserDto.class);
    }

    public List<UserDto> findAll() {
        return mapAll(repository.findAll(), UserDto.class);
    }
}

RestController

Abschließend zeige ich Ihnen wie der zuvor entwickelte Service im RestController vollumfänglich für alle CRUD-Methoden verwendet werden kann. Sie werden überrascht sein wie einfach das möglich ist!

UserController.java
package at.clouddna.demo.controller;

import at.clouddna.demo.dto.UserDto;
import at.clouddna.demo.model.User;
import at.clouddna.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public ResponseEntity getAll() {
        return ResponseEntity.ok(userService.findAll());
    }

    @GetMapping("/{id}")
    public ResponseEntity getById(@PathVariable("id") Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }

    @PostMapping
    public ResponseEntity create(@RequestBody UserDto body) {
        return ResponseEntity.ok(userService.create(body));
    }

    @PutMapping("/{id}")
    public ResponseEntity update(@PathVariable("id") Long id,
                                 @RequestBody UserDto body) {
        body.setId(id);
        return ResponseEntity.ok(userService.update(body));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity delete(@PathVariable("id") Long id) {
        return ResponseEntity.ok(userService.delete(id));
    }
}

Fazit

Ich hoffe dass ich Ihnen in diesem Teil die Java Entwicklung in der SAP Cloud Platform schmackhaft gemacht habe. Wie Sie hoffentlich erkannt haben handelt es sich um kein Hexenwerk und keine Weltraumwissenschaft. Einen Tipp möchte ich Ihnen noch mitgeben – achten Sie bereits in der Planung des Projekts darauf dass alles sauber strukturiert ist und Sie jeweils ein eigenes Paket für Entity, DTO, Repository, Service und Controller definieren.

SAP Cloud Platform Java Entwicklung – Teil 1

SAP Cloud Platform Java Entwicklung – Teil 1

In dieser Blogreihe zeige ich Ihnen wie die Java Entwicklung für die SAP Cloud Plaform auf Basis von Spring Boot durchgeführt wird. Spring Boot ist das defacto Standard Framework wenn es um die Entwicklung von Java Applikationen in der Cloud / bei Software-as-a-Service geht. Zur Entwicklung mit Spring Boot gibt es eine Vielzahl an Resourcen im Internet, jedoch blieben die SAP Cloud Platform Spezifika dabei meist auf der Strecke. SAP bietet im Neo Stack der SAP Cloud Platform ein SDK dass die Verwendung von SAP-eigenen Funktionalitäten in Java ermöglicht. Dieser Blog fokusiert sich auf die allgemeinen Entwickleraufgaben in der Entwicklung von Java Applikationen. Dabei wird der Aufbau der pom.xml gezeigt und ein einfacher RestController implementiert. Folgende Inhalte werde ich in zukünftigen Blogs zeigen:
  • Zugriff auf HANA DB mittels JNDI
  • Zugriff auf Destinations mittels JNDI
  • Zugriff auf Tenant Informationen mittels JNDI
  • Zugriff auf User Informationen

Aufbau der pom.xml

Die pom.xml beinhaltet alle relevanten Informationen die für den Build der Applikation erforderlich sind.

Parent

Nachdem wir auf Spring Boot setzen muss dies als parent definiert werden.
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.1.RELEASE</version>
  <relativePath />
</parent>

Properties

In den properties werden die Java Version sowie die Version des SAP Cloud SDK definiert.
<properties>
  <java.version>1.8</java.version>
  <sap.cloud.sdk.version>3.107.18</sap.cloud.sdk.version>
</properties>

Dependencies

In den dependencies werden die Abhängigkeiten definiert. Dabei wird u.a. auf SpringBoot Starter Web verwiesen und auch auf das SAP Cloud SDK. Beim SAP Cloud SDK ist es wichtig, dass auf die in den properties definierte Version verlinkt wird, und dass der scope auf den Wert provided gesetzt wird. Damit wird diese Abhängigkeit nicht in das WAR file gepackt und auf als dem Server bereitgestellt betrachtet.
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId> 
</dependency>

<dependency> 
  <groupId>com.sap.cloud</groupId>
  <artifactId>neo-java-web-api</artifactId>
  <version>${sap.cloud.sdk.version}</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.6</version>
</dependency>

Profile

In diesem Beispiel wird für das Deployment auf den Neo Stack ein eigenen Profil angelegt. Darin wird definiert, dass bestimmte Abhängigkeiten vom Server bereitgestellt werden und diese nicht in das WAR file eingebettet werden. Andernfalls würde der Start der Applikation fehlschlagen.
<profile>
  <id>neo</id>
  <activation>
    <activeByDefault>true</activeByDefault>
  </activation>
  <properties>
    <packaging.type>war</packaging.type>
  </properties> 
  <dependencies> 
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <scope>provided</scope>
    </dependency>  
  </dependencies>
</profile>

Build Plugins

Abschließend muss im Build noch das Spring Boot Maven Plugin definiert werden.
<plugins>
  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
  </plugin>
</plugins>

Build der Applikation für die SAP Cloud Platform

Der Build der Applikation kann über die CommandLine mit folgenden Befehl durchgeführt werden mvn clean package -Pneo Damit die Applikation innerhalb vom Tomcat erfolgreich gestartet werden kann, muss die configure Methode aus dem SpringBootServletInitializer redefiniert werden. Dies kann entweder direkt in der Hauptklasse der Applikation erfolgen oder in einer eigenen Klasse. Ich persönlich bevorzuge an dieser Stelle die Verwendung einer eigenen Klasse.
package at.clouddna.demo;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(DocmgmtApplication.class);
  }
}

Implementierung eines einfachen Rest Controllers

Damit ein Funktionstest durchgeführt werden kann, implementiere ich immer eine Ping Methode in einem eigenen Controller.
package at.clouddna.docmgmt.controller; 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 
import org.springframework.http.ResponseEntity; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RestController; 

@RestController 
@RequestMapping({ "/ping" }) 
public class PingController { 
  private static final Logger logger = LoggerFactory.getLogger(PingController.class); 

  @GetMapping
  public ResponseEntity<?> ping() { 
    logger.debug("ping called"); 
    return ResponseEntity.ok("Hello World"); 
  }
}
Damit sind wir mit einer einfachen Applikation bereits fertig. Beim Deployment über das SAP Cloud Platform Cockpit ist darauf zu achten, dass die Runtime Java Web Tomcat 8 ausgewählt wird und dass das Profile als JVM Parameter wie folgt übergeben wird.
-Dspring.profiles.active=neo
Der Ping Controller kann direkt aus dem Browser heraus getestet werden, da die entsprechende Methode über einen HTTP GET Request aufgerufen wird.

OData ABAP Backend Exception

State-of-the-Art SAPUI5 / Fiori Apps erfordern ein sauber implementiertes Error Handling. Sind OData Services in einem SAP NetWeaver ABAP Stack implementiert, gibt es zwei ABAP Klassen die für Exceptions verwendet werden:

  • /IWBEP/CX_MGW_BUSI_EXCEPTION für Business / Logische Fehler
  • /IWBEP/CX_MGW_TECH_EXCEPTION für Technische Fehler

Fehler können auf verschieden Arten geworfen werden. Nachfolgend zeigen wir Ihnen unterschiedliche Optionen.

Ein Möglichkeit ist es, über den MessageContainer den Fehlertext direkt zurückzuliefern. Diese Methode hat den Nachteil, dass die Fehlertexte hartkodiert sind und somit eine Übersetzung in unterschiedliche Sprachen nicht möglich ist.

METHOD customerset_get_entity.
  SELECT SINGLE * FROM zcustomer where ...
  IF sy-subrc NE 0.
    mo_context->get_message_container( )->add_message_text_only( 
iv_msg_type = 'E'                                                       
iv_msg_text = |Der angeforderte Datensatz wurde nicht gefunden.| ).
  
    RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
      EXPORTING
        message_container = mo_context->get_message_container( ).
  ENDIF.
ENDMETHOD.

Eine weitere Möglichkeit besteht in der Verwendung einer Nachrichtenklasse. Damit können alle bekannten ABAP Tools wie z.B. die SE91 verwendet werden.

METHOD customerset_get_entity.
  SELECT SINGLE * FROM zcustomer where ...
  IF sy-subrc <> 0.
    mo_context->get_message_container( )->add_message( iv_msg_type   = 'E'
                                                       iv_msg_id     = 'SY'
                                                       iv_msg_number = '100'
                                                       iv_msg_text   = |Der angeforderte Datensatz wurde nicht gefunden.| ).
  
    RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
      EXPORTING
        message_container = mo_context->get_message_container( ).
  ENDIF.
ENDMETHOD.

Eine weitere Möglichkeit in Kombination mit dem Message Container bietet sich, wenn Fehler in Form eine BABIRET2 Struktur vorliegen.

METHOD xyz_get_entity.
  DATA: lt_return TYPE bapirettab.
   
  CALL FUNCTION 'BAPI_CALL_XYZ'
    ...
    TABLES
      return = lt_return.
   
  IF lt_return IS NOT INITIAL.
    mo_context->get_message_container( )->add_messages_from_bapi( it_bapi_messages = lt_return ).
 
    RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
      EXPORTING
        message_container = mo_context->get_message_container( ).
  ENDIF.
ENDMETHOD.

Es gibt in diesem Szenario auch die Option die Leading Message zu bestimmen. In diesem Fall muss das Coding leicht abgeändert werden.

METHOD xyz_get_entity.
  DATA: lt_return TYPE bapirettab.
   
  CALL FUNCTION 'BAPI_CALL_XYZ'
    ...
    TABLES
      return = lt_return.
   
  IF lt_return IS NOT INITIAL.
    mo_context->get_message_container( )->add_messages_from_bapi( it_bapi_messages = lt_return
                                                                  iv_determine_leading_msg = /iwbep/if_message_container=>gcs_leading_msg_search_option-first ).
 
    RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
      EXPORTING
        message_container = mo_context->get_message_container( ).
  ENDIF.
ENDMETHOD.

Exceptions können auch direkt ohne Verwendung des Message Containers geworfen werden.

METHOD customerset_get_entity.
  SELECT SINGLE * FROM zcustomer where ...
  IF sy-subrc NE 0.
    RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
      EXPORTING
        textid  = /iwbep/cx_mgw_busi_exception=>business_error
        message = |Der angeforderte Datensatz wurde nicht gefunden.|.
  ENDIF.
ENDMETHOD.

Eine weitere Option besteht darin, der Exception eine Struktur vom Typ scx_t100key mitzugeben.

METHOD customerset_get_entity.
  SELECT SINGLE * FROM zcustomer where ...
  IF sy-subrc NE 0.
    DATA(lv_message) = VALUE scx_t100key( msgid = 'SY'
                                          msgno = '001'
                                          attr1 = |Der angeforderte Datensatz wurde nicht gefunden.| ).
 
    RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
      EXPORTING
        textid  = lv_message.
  ENDIF.
ENDMETHOD.

Die letzte in diesem Blog dargestellte Option ist es, eine Exception abzufangen, und den Exceptiontext durchzureichen.

METHOD customerset_get_entity.
  TRY.
      ...
    CATCH cx_root INTO DATA(lr_ex).
      RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
        EXPORTING
          textid  = /iwbep/cx_mgw_busi_exception=>business_error
          message = |{ lr_ex->get_text( ) }|.
  ENDTRY.
ENDMETHOD.

SAP Cloud Connector

Einsatzszenarien

Der SAP Cloud Connector spielt eine zentrale Rolle, wenn es um die Verbindung zwischen der SAP Cloud Platform und einer OnPremise Landschaft geht. Er ermöglicht, sowohl die SAP Cloud Platform Neo Environment als auch die SAP Cloud Platform Cloud Foundry Environment anzubinden. Typischerweise wird er für die Kommunikation Cloud-2-OnPremise verwendet, es ist aber für bestimmte Szenarien auch möglich den SAP Cloud Connector für die Kommunikation OnPremise-2-Cloud zu verwenden.

Typischerweise erfolgt die Installation des Cloud Connectors in der DMZ. Es gibt zwei wesentliche Anforderungen an den SAP Cloud Connector:

  • Der SAP Cloud Connector muss netzwerktechnisch eine Verbindung ins Internet herstellen können. Es spielt keine Rolle ob die Verbindung direkt oder über einen Proxy Server erfolgt
  • Der SAP Cloud Connector muss netzwerktechnisch einen Zugriff auf die anzubindenden OnPremise Systeme haben

 

Installationsoptionen

Der SAP Cloud Connector kann auf Windows, MacOS und Linux ausgeführt werden und kann über https://tools.hana.ondemand.com/#cloud bezogen werden. Eine Installation kann sowohl Standalone als auch Hochverfügbar mit Master und Shadow Nodes erfolgen.

 

Zugriff / SSL Zertifikat

Das Administrations User Interface des SAP Cloud Connector ist ausschließlich über https erreichbar und wird bei einer Standardinstallation an den Port 8443 gebunden. Der Port kann jederzeit über das Skript changeport.bat bzw. changeport.sh geändert werden. Der SAP Cloud Connector wird mit einem selbstsignierten SSL Zertifikat ausgeliefert. Wir empfehlen dieses Zertifikat durch ein offizielles Zertifikat zu ersetzen. Im SAP Cloud Connector kann dafür direkt ein Certificate Signing Request (CSR) erstellt werden.

 

Benutzerauthentifizierung

Im Standard wird der Cloud Connector als Single-User Instanz ausgeführt. Den SAP Cloud Connector müssen ausschließlich Administratoren erreichen. Der Standard-Benutzername lautet Administrator und das Kennwort lautet manage. Das Kennwort muss bei der ersten Installation geändert werden. Wir empfehlen eine Anbindung  an ein LDAP. Dadurch können unterschiedliche Administratoren gleichzeitig mit dem SAP Cloud Connector arbeiten und es kann im Audit Log festgestellt werden welcher User Änderungen durchgeführt hat. Bei der Authentifizierung mittels LDAP stehen vier Rollen zur Verfügung:

  • Administrator
  • Display
  • Monitor
  • Support

In einer Serie an Videos erklären wir typische Einsatzszenarien des SAP Cloud Connectors