Technology Blog Posts by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
xuelong
Associate
Associate
1,394

Introduction

In this blog post, we will guide you through the process of creating a multitenant SaaS application with a shared database architecture, combining CAP Java and Node.js projects into a mono repository.

Step 1: Initialize the Project

1. Initialize the main project:

 

cds init onboarding 
rm -rf app srv​​

 

2. Initialize sub-module projects within the main project:

 

cds init node_project 
cds init java_project --java​​

 

3. Set up the workspace:

 

npm init -w ./node_project -w ./java_project

 

Step 2: Configure Multitenancy and HANA:

1. add multitenancy & hana

2. inside onboarding/mtx/sidecar/package.json, add build command in scripts.

 

"scripts": {
    "start": "cds-serve",
    "build": "cds build ../.. --for mtx-sidecar --ws --production && npm ci --prefix gen"
}

 

3. Create a .cdsrc.json file at the root of the onboarding project:

 

"build": {
    "target": "."
  }
}

 

4.inside node_project/mtx/sidecar/package.json and java_project/mtx/sidecar/package.json, disable cds.xt.SaasProvisioningService:

 

"cds": {
    "requires": {
      "multitenancy": true,
      "extensibility": false,
      "toggles": false,
      "cds.xt.SaasProvisioningService": false,
      "db": {
        "kind": "hana-mt",
        "deploy-format": "hdbtable"
      }
}

 

5. Change the port of java_project/mtx/sidecar for local testing, e.g. 4006. Also change it in application.yaml.

 

"server": { 
      "port": 4006
}
cds:
  multi-tenancy:
    sidecar:
      url: http://localhost:4006/

 

6. Execute the build command in onboarding/mtx/sidecar. This will compose all DB artifacts from each workspace into the obboarding/db folder:

 

npm run build

 

Step 3: Deploy Database Artifacts

You can deploy the whole db artifacts with/without multitenancy.

1. For single tenant deployment:

 

cds build --ws --production
cds deploy --to hana:${hdi-name} --no-build

 

2. For multi-tenant deployment:

 

cds watch mtx/sidecar 
cds subscribe ${tenant_id} --to http://localhost:4005 -u name:password

 

Step 4: Start the Projects

1. Start java_project and java_project-mtx:

 

# run java mtx first 
cd java_project/mtx/sidecar 
npm run build 
cds watch 

# run java second 
cd java_project 
mvn spring-boot:run -Dspring-boot.run.profiles=default

 

2. Start node_project and (using onboarding-mtx or start node_project-mtx):

 

# start node_project-mtx(optional) 
cd node_project 
cds build --production 
cds watch mtx/sidecar 

# start node_project 
cd node_project 
cds watch

 

Step 5: Local Testing

You can now test both the Node.js and Java applications locally.

Step 6: Add MTA Configuration and Deploy to BTP

1.Add the build:cf command to the package.json file of each workspace:

 

"build:cf": "cds build --production"

 

2. Create an mta.yaml file with the following content:

 

ID: com.sap.onboarding-mtxs
_schema-version: 3.3.0
version: 0.0.1
description: "Onboarding Service"

build-parameters:
  before-all:
    - builder: custom
      commands:
        - npm ci
        - npm run build:cf --workspace=node_project
        - npm run build:cf --workspace=java_project
modules:
  - name: node-mtxs-srv
    type: nodejs
    path: node_project/gen/srv
    parameters:
      buildpack: nodejs_buildpack
      readiness-health-check-type: http
      readiness-health-check-http-endpoint: /health
    properties:
      DEBUG: all
    build-parameters:
      builder: npm
    provides:
      - name: srv_api # required by consumers of CAP services (e.g. approuter)
        properties:
          url: ${default-url}
    requires:
      - name: onboarding-mtxs-service-manager
      - name: node-model-provider
        properties:
          CDS_MODEL_PROVIDER_URL: ~{url}
          CDS_MULTITENANCY_SIDECAR_URL: ~{url}
      - name: provisioning-service
        properties:
          CDS_MULTITENANCY_PROVISIONING_URL: ~{url}
          CDS_MULTITENANCY_PROVISIONING_POLLINGINTERVAL: 5s
          CDS_MULTITENANCY_PROVISIONING_POLLINGTIMEOUT: 5m
      - name: onboarding-mtxs-uaa
      - name: onboarding-mtxs-saas-registry

  - name: java-mtxs-srv
    type: java
    path: java_project/srv
    parameters:
      memory: 1024M
      disk-quota: 1024M
      buildpack: sap_java_buildpack
    properties:
      DEBUG: all
      JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"
      JBP_CONFIG_SAP_MACHINE_JDK: '{ use_offline_repository: false, version: 21.+ }'
      JBP_CONFIG_JAVA_OPTS: "[java_opts: '-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n,onjcmd=y']"
      SPRING_PROFILES_ACTIVE: cloud
      CDS_MULTITENANCY_MTXS_ENABLED: true
    build-parameters:
      ignore: [ "*.md" ]
      build-result: target/*.jar
    provides:
      - name: srv_java_api
        properties:
          url: '${default-url}'
    requires:
      - name: onboarding-mtxs-service-manager
      - name: java-model-provider
        properties:
          CDS_MODEL_PROVIDER_URL: ~{url}
          # CDS_MULTITENANCY_SIDECAR_URL: ~{url}
      - name: provisioning-service
        properties:
          CDS_MULTITENANCY_PROVISIONING_URL: ~{url}
          CDS_MULTITENANCY_PROVISIONING_POLLINGINTERVAL: 5s
          CDS_MULTITENANCY_PROVISIONING_POLLINGTIMEOUT: 5m
      - name: onboarding-mtxs-uaa

  - name: onboarding-mtxs-mtx
    type: nodejs
    path: mtx/sidecar
    parameters:
      memory: 512M
      disk-quota: 512M
    build-parameters:
      builder: custom
      build-result: gen
      commands:
        - npm run build
    properties:
      DEBUG: all
    requires:
      - name: onboarding-mtxs-uaa
      - name: onboarding-mtxs-service-manager
      - name: onboarding-mtxs-saas-registry
    provides:
      - name: provisioning-service
        properties:
          url: ${default-url}

  - name: onboarding-mtxs-node-model-provider
    type: nodejs
    path: node_project/gen/mtx/sidecar
    parameters:
      memory: 512M
      disk-quota: 512M
    build-parameters:
      builder: npm-ci
      # builder: custom
      # build-result: gen
      # commands:
      #   - npm run build
    properties:
      DEBUG: all
    requires:
      - name: onboarding-mtxs-uaa
      - name: onboarding-mtxs-service-manager
    provides:
      - name: node-model-provider
        properties:
          url: ${default-url}

  - name: onboarding-mtxs-java-model-provider
    type: nodejs
    path: java_project/mtx/sidecar
    parameters:
      memory: 512M
      disk-quota: 512M
    build-parameters:
      builder: custom
      build-result: gen
      commands:
        - npm run build
    properties:
      DEBUG: all
    requires:
      - name: onboarding-mtxs-uaa
      - name: onboarding-mtxs-service-manager
    provides:
      - name: java-model-provider
        properties:
          url: ${default-url}

resources:
  - name: onboarding-mtxs-service-manager
    type: org.cloudfoundry.managed-service
    parameters:
      service: service-manager
      service-plan: container

  - name: onboarding-mtxs-uaa
    type: org.cloudfoundry.managed-service
    parameters:
      service: xsuaa
      service-plan: broker
      config:
        xsappname: onboarding-mtxs-${org}-${space}
        tenant-mode: shared
        scopes:
          - name: $XSAPPNAME.mtcallback
            description: Multi Tenancy Callback Access
            grant-as-authority-to-apps:
              - $XSAPPNAME(application,sap-provisioning,tenant-onboarding)
          - name: $XSAPPNAME.mtdeployment
          - name: $XSAPPNAME.ExtendCDS
            description: Extend tenant models
          - name: $XSAPPNAME.ExtendCDSdelete
            description: Undeploy extensions
        authorities:
          - $XSAPPNAME.mtcallback
          - $XSAPPNAME.mtdeployment
        role-templates:
          - name: admin
            description: Admin
            scope-references:
              - $XSAPPNAME.mtcallback
              - $XSAPPNAME.mtdeployment
          - name: ExtensionDeveloper
            scope-references:
              - $XSAPPNAME.ExtendCDS
              - uaa.user
            description: CDS Extension Developer
          - name: ExtensionDeveloperUndeploy
            scope-references:
              - $XSAPPNAME.ExtendCDSdelete
              - $XSAPPNAME.ExtendCDS
              - uaa.user
            description: CDS Extension Developer with DB extension undeploy privilege (potential data loss!)              -
  #   generate a user and password for dynamic hdi deployer
  - name: onboarding-mtxs-saas-registry
    type: org.cloudfoundry.managed-service
    parameters:
      service: saas-registry
      service-plan: application
      config:
        appName: onboarding-mtxs-${org}-${space} # this is the text on the tile
        xsappname: onboarding-mtxs-${org}-${space} # this is exactly the value from xsuaa.parameters.config.xsappname
        appUrls:
          # getDependencies: ~{srv_api/url}/mt/v1.0/subscriptions/dependencies
          # onSubscription: ~{srv_api/url}/mt/v1.0/subscriptions/tenants/{tenantId}
          getDependencies: ~{provisioning-service/url}/-/cds/saas-provisioning/dependencies
          onSubscription: ~{provisioning-service/url}/-/cds/saas-provisioning/tenant/{tenantId}
          onSubscriptionAsync: true
          onUnSubscriptionAsync: true
          onUpdateSubscriptionParametersAsync: true
          callbackTimeoutMillis: 300000
    requires:
      - name: provisioning-service

 

3. mbt build & cf deploy app.

4. Subscribe to this SaaS application in the Service Marketplace on BTP.

By following these steps, you should be able to successfully create and deploy a multitenant SaaS application with a mixed CAP Java/Node.js mono repository and a shared database architecture. If you encounter any issues or have any questions, please leave a comment below. I hope you find this guide helpful!

1 Comment