Content Navigation
Part 1: A simple UI5 app that runs in the SAP Build Work Zone Service
Part 2: Multiple Apps with a Shared Reuse Library
Part 3:Splitting bigger projects (Current post)
Part 4:Advanced splits (Planned)
Splitting Bigger Projects
In the last posts, you have learnt how to build multiple apps and move common parts of them into a reusable library. Everything is deployed using one MTA.
In this part, we will have a look at how to split this into smaller parts. This enables us to have independent lifecycles and helps distribute responsibilities between different developer groups.
For example, the reusable library might have a different lifecycle than the apps and is not changed frequently. Maybe they are also maintained by other developers and should be stored in a separate Git repository.
The sample code can be found in the GitHub repository.
Current State
Let us have a quick look at the starting point. There are three HTML5 apps, which are all deployed to the same app-host. There is one XSUAA and one set of runtime/design-time destinations for the integration into SAP Build Work Zone. All sap.cloud/service names in manifest.json files ([Shared], [App1], [App2]) are the same and the DT destination refers to it as well:
“sap.cloud”: {
“public”: true,
“service”: “btp.samples.cdm.multiple.apps“
}URL: https://html5-apps-repo-rt.${default-domain}/applications/cdm/btp.samples.cdm.multiple.apps
In their manifest.json the apps declare a dependency to the reuse library ([App1], [App2]).
“sap.ui5”: {
“dependencies”: {
“libs”: {
“btp.samples.cdm.multiple.apps.lib”: {}
…
The corresponding MTA looks like this:
A First Split for the App-Hosts
The first split you would do, is to use multiple HTML5 app-hosts and distribute the HTML5 apps to them.
Since this is an intermediate step, there is no sample code available.
Deployment
Both apps are moved to their own app-host while the shared library stays on the previously used app-host. If you have more apps, you can distribute them across app-hosts as needed.
Every app-host is connected to the same XSUAA and all apps on the app-hosts use the same cloud service name, specified by the DT destination.
There are no changes for the apps themselves and for the content of the cdm.json.
For now, the cdm.json remains on the shared app-host. In be consistent, the shared app-host additionally depends on the app-hosts with the consuming apps.
This way the platform understands that the content of these app-hosts is relevant for the content of the cdm.json and that the apps which are specified inside can be found and the library dependencies of the apps can be resolved as well.
MTA
The corresponding MTA would look like this:
There are now three managed resources for the app-hosts and Three HTML5 app content deployers. The deployer of the shared app-host additionally requires the app-hosts of the apps. This will establish the needed dependencies between them and binds them together.
Problems
Only splitting the app-hosts as we have done until now does not add real value because everything is still contained in one MTA.
It’s also not ideal that the shared app-host depends on the app-hosts containing the apps. A successful deployment requires to first deploy the apps and then the shared app-host. Otherwise, the contained CDM would not be consistent.
You might have noticed that there is even a circular dependency because the apps itself depend on the shared library.
Nevertheless, it is a good starting point for the next step.
Split the CDM Model
We are now going to split the cdm.json. With this, we can avoid the bad structuring of dependencies and the circular dependencies between the app-hosts caused by the single shared cdm.json. This will also inverse the dependencies.
Since this is an intermediate step, there is no sample code available.
Deployment
The new deployment would look like this:
We now have a cdm.json on all three app-hosts ([Shared, App1, App2]). The shared cdm.json contains common definitions. The two app-specific ones extend them by adding the apps. Because all three app-hosts have the same sap.cloud/service, which is specified in the DT destination, they will all be merged together. We will take a closer look at this below.
Note that now the dependencies between the app-hosts have been inverted and the app-hosts holding the apps depend on the shared app-host. There is no longer one leading app-host which binds them all together but independent groups which are still consistent. For example, app-host 1 is bound together with the shared app-host. Therefore, the cdm.json of app-host 1 can find the defined app 1 and the library dependency of the app can be resolved. However, the cdm.json of app-host 1 cannot refer to app 2, because the app-host containing is not bound to it.
This way you achieve good isolation between independent applications.
MTA
The corresponding MTA would look like this:
There is only a slight change in the requirements of the HTML5 app deployer. Now the deployer modules for the apps require the shared app-host, whereas the shared module deployer no longer requires the app-hosts of the apps.
How to split the cdm.json
Before we split the CDM model into multiple parts we must understand how it is structured. In the CDM model, we have different types of entities like catalogs, groups, and roles.
They all have some header attributes like an ID, a translatable title, and a description. Additionally, they have references to other entities or apps. E.g., catalogs and groups refer to the tiles of the included apps (which is defined in the app manifest). Roles also refer to the contained apps as well as to the contained groups and catalogs.
For the full CDM model please refer to About the Common Data Model.
When splitting the model there can be different cases:
If the CDM Models of your apps are completely independent of each other, which means they have their own roles catalogs and groups, you can just move them accordingly.
However, in most cases you want to have common entities or even just one catalog, role and group which contain all apps.
In this case you can split the definition of the entities across the different cdm.json file. E.g. The shared cdm.json just describes the connection of role, catalog, and group and the cdm.json of the apps describe that the app is contained there. The platform will merge them together.
The merge of cdm.json files will collect the entities of all files. Then it will match them by type and ID and merge the matching ones by merging their references.
However, there is currently an inconvenient limitation:
While the merge works fine for references, for simple header attributes like the title and description it will pick one of the matched entities randomly and take its definition. This means that currently the header definitions of the split entities must be exactly the same in all cdm.json files to avoid unpredictable behavior.
In the samples the 2nd case has been modeled in the [shared cdm.json], [app1 cdm.json] and [app2 cdm.json] (The links refer to the sample of the next split)
How to verify the final CDM model
You might want to verify how the final MTA of your solution looks like and whether the CDM content has been merged as you expect.
After you have deployed the MTAs, you can access it the same way as SAP Build Work Zone will do it, which is configured in the design-time destination.
You will need an HTTP REST client to do this. SAP Business Application Studio or MS Visual Studio Code provide a REST Client extension which is installed by default.
You can find the created design-time destination in the BTP Cockpit in your sub account under Connectivity -> Destinations.
Here you will find the target URL which looks as follows:
https://html5-apps-repo-rt.cfapps.<landscape domain>.hana.ondemand.com/applications/cdm/<sap.cloud/service name>
The destination also specifies everything that is needed to obtain an access token. This information is taken from a service key of the HTML5 app-runtime instance. It consists of
a token URL which looks like
https://<subaccount domain>.authentication.<landscape domain>.hana.ondemand.com/oauth/tokena client IDa client secret. You will not be able to retrieve the client secret from the destination, therefore you must retrieve this from the service key of the app-runtime instance instead.
To retrieve the CDM model you have to first retrieve an access token from the token URL using the client credentials and then use the token to call the target URL.
The following code can be used in the REST Client extension to do this:
# @name getToken
GET https://<subaccount domain>.authentication.<landscape domain>.hana.ondemand.com/oauth/token?grant_type=client_credentials HTTP/1.1
Authorization: Basic <client ID>:<client secret>
###
GET https://html5-apps-repo-rt.cfapps.<landscape domain>.hana.ondemand.com/applications/cdm/<sap.cloud/service name> HTTP/1.1
Authorization: Bearer {{getToken.response.body.$.access_token}}
The response will provide the fully merged CDM model of your solution. It also includes more information about the contained apps and their visualizations which is derived from the defined navigation inbounds in the manifest.json.
Problems
We have now solved the bad structuring of dependencies, but still everything is contained inside a single MTA file.
Split the MTAs
In the next step, we will split the single MTA into multiple ones.
The sample code can be found here
Deployment
Every app and app-host will be moved to a separate MTA. The XSUAA and the destination service will still be shared by all and therefore move to the MTA containing the shared library. The result of the deployment will not change at all. Below, the colors indicate which MTA will deploy which content.
The cloud service name will still be the same everywhere.
MTAs
The MTAs [Shared, App1, App2] will look like this.
Note that the XSUAA service and the shared app-host resources in the app MTAs are of the type “existing service”. Only the shared MTA defines it as a “managed service” because this MTA owns the service instance and will create it. Therefore, the shared MTA must be deployed first.
This setup already fulfils most use cases. The apps and shared library can now be developed and deployed independently. They can also be moved to different Git repositories.
Split the XSUAAs
Until now, the MTA projects are already quite independent, but they still share the same XSUAA and the contained authorization objects. However, your apps might contain complex back-end services and have complex authorization objects. In that case, developers would not want to maintain the xs-security.json files in the central MTA but move the app-specific parts to the MTA of the app. This is a good reason to split the XSUAAs.
Deployment
Now we have three XSUAA instances. Each one is deployed by one MTA. Each app-host binds against its corresponding XSUAA instance. This way the authorization handling is bound to the correct XSUAA, and its authorization model applies. Example: If you have routes in xs-app.json that require a given scope, they are defined by the corresponding XSUAA. The same would happen for any back-end apps that are possibly contained in your MTA.
Previously the connection between the app-host and the XSUAAwas based on the cloud service name. Therefore, in the former version of this blog it has been necessary to split the cloud service name at this point. This is no longer needed here and even has a different effect, which is needed for splitting the service provider.
The MTAs [Shared, App1, App2] will look like this:
MTAs
Every MTA now contains its own xs-security.json [Shared, App1, App2] with its own unique xsappname.
Next Steps
Now you know about the most relevant splits for your use cases.
A more advanced use case which also requires splitting the destination service instance is described in Part 4 of this blog.
Content NavigationPart 1: A simple UI5 app that runs in the SAP Build Work Zone ServicePart 2: Multiple Apps with a Shared Reuse LibraryPart 3:Splitting bigger projects (Current post)Part 4:Advanced splits (Planned)Splitting Bigger ProjectsIn the last posts, you have learnt how to build multiple apps and move common parts of them into a reusable library. Everything is deployed using one MTA.In this part, we will have a look at how to split this into smaller parts. This enables us to have independent lifecycles and helps distribute responsibilities between different developer groups.For example, the reusable library might have a different lifecycle than the apps and is not changed frequently. Maybe they are also maintained by other developers and should be stored in a separate Git repository. The sample code can be found in the GitHub repository.Current StateLet us have a quick look at the starting point. There are three HTML5 apps, which are all deployed to the same app-host. There is one XSUAA and one set of runtime/design-time destinations for the integration into SAP Build Work Zone. All sap.cloud/service names in manifest.json files ([Shared], [App1], [App2]) are the same and the DT destination refers to it as well:”sap.cloud”: {
“public”: true,
“service”: “btp.samples.cdm.multiple.apps”
}URL: https://html5-apps-repo-rt.${default-domain}/applications/cdm/btp.samples.cdm.multiple.appsIn their manifest.json the apps declare a dependency to the reuse library ([App1], [App2]).”sap.ui5″: {
“dependencies”: {
“libs”: {
“btp.samples.cdm.multiple.apps.lib”: {}
… The corresponding MTA looks like this: A First Split for the App-HostsThe first split you would do, is to use multiple HTML5 app-hosts and distribute the HTML5 apps to them.Since this is an intermediate step, there is no sample code available.Deployment Both apps are moved to their own app-host while the shared library stays on the previously used app-host. If you have more apps, you can distribute them across app-hosts as needed.Every app-host is connected to the same XSUAA and all apps on the app-hosts use the same cloud service name, specified by the DT destination.There are no changes for the apps themselves and for the content of the cdm.json.For now, the cdm.json remains on the shared app-host. In be consistent, the shared app-host additionally depends on the app-hosts with the consuming apps.This way the platform understands that the content of these app-hosts is relevant for the content of the cdm.json and that the apps which are specified inside can be found and the library dependencies of the apps can be resolved as well.MTAThe corresponding MTA would look like this: There are now three managed resources for the app-hosts and Three HTML5 app content deployers. The deployer of the shared app-host additionally requires the app-hosts of the apps. This will establish the needed dependencies between them and binds them together.ProblemsOnly splitting the app-hosts as we have done until now does not add real value because everything is still contained in one MTA.It’s also not ideal that the shared app-host depends on the app-hosts containing the apps. A successful deployment requires to first deploy the apps and then the shared app-host. Otherwise, the contained CDM would not be consistent.You might have noticed that there is even a circular dependency because the apps itself depend on the shared library.Nevertheless, it is a good starting point for the next step.Split the CDM ModelWe are now going to split the cdm.json. With this, we can avoid the bad structuring of dependencies and the circular dependencies between the app-hosts caused by the single shared cdm.json. This will also inverse the dependencies.Since this is an intermediate step, there is no sample code available.DeploymentThe new deployment would look like this: We now have a cdm.json on all three app-hosts ([Shared, App1, App2]). The shared cdm.json contains common definitions. The two app-specific ones extend them by adding the apps. Because all three app-hosts have the same sap.cloud/service, which is specified in the DT destination, they will all be merged together. We will take a closer look at this below.Note that now the dependencies between the app-hosts have been inverted and the app-hosts holding the apps depend on the shared app-host. There is no longer one leading app-host which binds them all together but independent groups which are still consistent. For example, app-host 1 is bound together with the shared app-host. Therefore, the cdm.json of app-host 1 can find the defined app 1 and the library dependency of the app can be resolved. However, the cdm.json of app-host 1 cannot refer to app 2, because the app-host containing is not bound to it.This way you achieve good isolation between independent applications.MTAThe corresponding MTA would look like this:There is only a slight change in the requirements of the HTML5 app deployer. Now the deployer modules for the apps require the shared app-host, whereas the shared module deployer no longer requires the app-hosts of the apps.How to split the cdm.jsonBefore we split the CDM model into multiple parts we must understand how it is structured. In the CDM model, we have different types of entities like catalogs, groups, and roles.They all have some header attributes like an ID, a translatable title, and a description. Additionally, they have references to other entities or apps. E.g., catalogs and groups refer to the tiles of the included apps (which is defined in the app manifest). Roles also refer to the contained apps as well as to the contained groups and catalogs.For the full CDM model please refer to About the Common Data Model.When splitting the model there can be different cases:If the CDM Models of your apps are completely independent of each other, which means they have their own roles catalogs and groups, you can just move them accordingly.However, in most cases you want to have common entities or even just one catalog, role and group which contain all apps.In this case you can split the definition of the entities across the different cdm.json file. E.g. The shared cdm.json just describes the connection of role, catalog, and group and the cdm.json of the apps describe that the app is contained there. The platform will merge them together.The merge of cdm.json files will collect the entities of all files. Then it will match them by type and ID and merge the matching ones by merging their references.However, there is currently an inconvenient limitation:While the merge works fine for references, for simple header attributes like the title and description it will pick one of the matched entities randomly and take its definition. This means that currently the header definitions of the split entities must be exactly the same in all cdm.json files to avoid unpredictable behavior.In the samples the 2nd case has been modeled in the [shared cdm.json], [app1 cdm.json] and [app2 cdm.json] (The links refer to the sample of the next split) How to verify the final CDM modelYou might want to verify how the final MTA of your solution looks like and whether the CDM content has been merged as you expect.After you have deployed the MTAs, you can access it the same way as SAP Build Work Zone will do it, which is configured in the design-time destination.You will need an HTTP REST client to do this. SAP Business Application Studio or MS Visual Studio Code provide a REST Client extension which is installed by default.You can find the created design-time destination in the BTP Cockpit in your sub account under Connectivity -> Destinations.Here you will find the target URL which looks as follows:https://html5-apps-repo-rt.cfapps.<landscape domain>.hana.ondemand.com/applications/cdm/<sap.cloud/service name>The destination also specifies everything that is needed to obtain an access token. This information is taken from a service key of the HTML5 app-runtime instance. It consists ofa token URL which looks likehttps://<subaccount domain>.authentication.<landscape domain>.hana.ondemand.com/oauth/tokena client IDa client secret. You will not be able to retrieve the client secret from the destination, therefore you must retrieve this from the service key of the app-runtime instance instead.To retrieve the CDM model you have to first retrieve an access token from the token URL using the client credentials and then use the token to call the target URL.The following code can be used in the REST Client extension to do this:# @name getToken
GET https://<subaccount domain>.authentication.<landscape domain>.hana.ondemand.com/oauth/token?grant_type=client_credentials HTTP/1.1
Authorization: Basic <client ID>:<client secret>
###
GET https://html5-apps-repo-rt.cfapps.<landscape domain>.hana.ondemand.com/applications/cdm/<sap.cloud/service name> HTTP/1.1
Authorization: Bearer {{getToken.response.body.$.access_token}} The response will provide the fully merged CDM model of your solution. It also includes more information about the contained apps and their visualizations which is derived from the defined navigation inbounds in the manifest.json.ProblemsWe have now solved the bad structuring of dependencies, but still everything is contained inside a single MTA file.Split the MTAsIn the next step, we will split the single MTA into multiple ones.The sample code can be found hereDeploymentEvery app and app-host will be moved to a separate MTA. The XSUAA and the destination service will still be shared by all and therefore move to the MTA containing the shared library. The result of the deployment will not change at all. Below, the colors indicate which MTA will deploy which content.The cloud service name will still be the same everywhere.MTAsThe MTAs [Shared, App1, App2] will look like this.Note that the XSUAA service and the shared app-host resources in the app MTAs are of the type “existing service”. Only the shared MTA defines it as a “managed service” because this MTA owns the service instance and will create it. Therefore, the shared MTA must be deployed first.This setup already fulfils most use cases. The apps and shared library can now be developed and deployed independently. They can also be moved to different Git repositories.Split the XSUAAsUntil now, the MTA projects are already quite independent, but they still share the same XSUAA and the contained authorization objects. However, your apps might contain complex back-end services and have complex authorization objects. In that case, developers would not want to maintain the xs-security.json files in the central MTA but move the app-specific parts to the MTA of the app. This is a good reason to split the XSUAAs.DeploymentNow we have three XSUAA instances. Each one is deployed by one MTA. Each app-host binds against its corresponding XSUAA instance. This way the authorization handling is bound to the correct XSUAA, and its authorization model applies. Example: If you have routes in xs-app.json that require a given scope, they are defined by the corresponding XSUAA. The same would happen for any back-end apps that are possibly contained in your MTA.Previously the connection between the app-host and the XSUAAwas based on the cloud service name. Therefore, in the former version of this blog it has been necessary to split the cloud service name at this point. This is no longer needed here and even has a different effect, which is needed for splitting the service provider.The MTAs [Shared, App1, App2] will look like this:MTAsEvery MTA now contains its own xs-security.json [Shared, App1, App2] with its own unique xsappname.Next StepsNow you know about the most relevant splits for your use cases.A more advanced use case which also requires splitting the destination service instance is described in Part 4 of this blog. Read More Technology Blogs by SAP articles
#SAP
#SAPTechnologyblog