Skip to content

Commit

Permalink
Merge branch 'main' into andre/operators-functions-cds
Browse files Browse the repository at this point in the history
  • Loading branch information
renejeglinsky authored Jan 25, 2024
2 parents 1a63219 + a91c891 commit 0d06712
Show file tree
Hide file tree
Showing 18 changed files with 528 additions and 334 deletions.
20 changes: 14 additions & 6 deletions .github/etc/create-review.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const createSuggestContainerTypeText = (suggestion) => createSuggestionText(sugg

module.exports = async ({ github, require, exec, core }) => {
const { readFileSync, existsSync } = require('fs')
const { join } = require('path')
const { join, extname } = require('path')
const { SHA, BASE_DIR, BASE_SHA, PULL_NUMBER, HEAD_SHA, REPO, REPO_OWNER } = process.env

const cspellLogFile = join(BASE_DIR, 'CSPELL.log')
Expand Down Expand Up @@ -76,9 +76,10 @@ module.exports = async ({ github, require, exec, core }) => {
})

const diffs = {}
data.forEach(obj => {
diffs[obj.filename.replace('./', '')] = obj.patch.split('\n')
})
data.filter(obj => extname(obj.filename) === '.md')
.forEach(obj => {
diffs[obj.filename.replace('./', '')] = obj.patch.split('\n')
})

if (existsSync(markdownlintLogFile)) {
const matches = readFileSync(markdownlintLogFile, 'utf-8')
Expand Down Expand Up @@ -124,7 +125,12 @@ module.exports = async ({ github, require, exec, core }) => {
}

if (rule === 'MD042/no-empty-links') {
const link = context.match(/\[Context: "(\[.*?\]\(\))"/)[1]
let link = context.match(/\[Context: "(\[.*?)"\]/)[1]

// if the context is too long, markdownlint-cli will truncate the string and append "..." at the end
if (link.endsWith('...')) {
link = link.substring(0, link.length - 3)
}

contextText = `[Context: "${escapeMarkdownlink(link)}"]`

Expand Down Expand Up @@ -289,7 +295,9 @@ module.exports = async ({ github, require, exec, core }) => {
}

function getDiff(file) {
return diffs[file.replace('./', '')]
const k = file.replace('./', '')
if (!(k in diffs)) throw new Error(`There is no diff for file ${file}.`)
return diffs[k]
}

async function findPositionInDiff(context, file) {
Expand Down
13 changes: 0 additions & 13 deletions advanced/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,9 @@ In Node.js apps, the standard Swagger UI can be served with the help of the [`cd
npm add --save-dev cds-swagger-ui-express
```

You need a [`server.js`](../node.js/cds-serve#custom-server-js) file to integrate it in the bootstrap process:

```js
const cds = require ('@sap/cds')
module.exports = cds.server

if (process.env.NODE_ENV !== 'production') {
const cds_swagger = require ('cds-swagger-ui-express')
cds.on ('bootstrap', app => app.use (cds_swagger()) )
}
```

Swagger UI is then served at `$api-docs/...`. Just follow the _Open API preview_ links on the index page:
![A screenshot showing the link to the Swagger UI.](assets/swagger-link.png){style="margin:5px auto;width:50%" .adapt}

[Learn more about the `cds-swagger-ui-express`.](https://www.npmjs.com/package/cds-swagger-ui-express){.learn-more}

#### Embedded in Java

Expand Down
2 changes: 1 addition & 1 deletion cds/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Language Reference Documentation

CDS is the backbone of the SAP Cloud Application Programming Model (CAP). It provides the means to declaratively capture service definitions and data models, queries, and expressions in plain (JavaScript) object notations. CDS features to parse from a variety of source languages and to compile them into various target languages.

<img src="./assets/csn.drawio.svg"/>
<img src="./assets/csn.drawio.svg" alt="The graphic is explained in the accompanying text."/>

CDS models are plain JavaScript objects complying to the _[Core Schema Notation (CSN)](./csn)_, an open specification derived from [JSON Schema](https://json-schema.org/). You can easily create or interpret these models, which foster extensions by 3rd-party contributions. Models are processed dynamically at runtime and can also be created dynamically.

Expand Down
22 changes: 21 additions & 1 deletion get-started/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ module.exports = cds.server

[Watch the video to learn more about **Best Practices for CAP Node.js Apps**.](https://www.youtube.com/watch?v=WTOOse-Flj8&t=87s){.learn-more}

### Why are long running requests rejected with status `502` after 30 seconds even though the application continues processing the request?
### Why are long running requests rejected with status `504` after 30 seconds even though the application continues processing the request?

| | Explanation |
| --- | ---- |
Expand Down Expand Up @@ -195,8 +195,28 @@ A new option `privilegedUser()` can be leveraged when [defining](../java/request
| _Root Cause_ | You've [explicitly configured a mock](../java/security#explicitly-defined-mock-users) user with a name that is already used by a [preconfigured mock user](../java/security#preconfigured-mock-users).
| _Solution_ | Rename the mock user and build your project again.

### Why do I get an "Error on server start"?

There could be a mismatch between your locally installed Node.js version and the version that is used by the `cds-maven-plugin`. The result is an error similar to the following:

```sh
❗️ ERROR on server start: ❗️
Error: The module '/home/user/....node'
was compiled against a different Node.js version using
```

To fix this, either switch the Node.js version using a Node version manager, or add the Node version to your _pom.xml_ as follows:

```xml
<properties>
<!-- ... -->
<cds.install-node.nodeVersion>v20.11.0</cds.install-node.nodeVersion>
<!-- ... -->
</properties>

```

[Learn more about the install-node goal.](https://cap.cloud.sap/docs/java/assets/cds-maven-plugin-site/install-node-mojo.html){.learn-more}

### How can I expose custom REST APIs with CAP?

Expand Down
3 changes: 2 additions & 1 deletion guides/databases-hana.md
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,8 @@ By default, `cds add hana` creates an `undeploy.json` like this:
[
"src/gen/**/*.hdbview",
"src/gen/**/*.hdbindex",
"src/gen/**/*.hdbconstraint"
"src/gen/**/*.hdbconstraint",
"src/gen/**/*_drafts.hdbtable"
]
```

Expand Down
26 changes: 15 additions & 11 deletions java/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@ status: released
uacp: Used as link target from Help Portal at https://help.sap.com/products/BTP/65de2977205c403bbc107264b8eccf4b/9186ed9ab00842e1a31309ff1be38792.html
---

# Modular Architecture
# Open Architecture
<style scoped>
h1:before {
content: "Java"; display: block; font-size: 60%; margin: 0 0 .2em;
}
</style>

One of the key [CAP design principles](../about/#open-and-opinionated) is to be an opinionated but yet open framework. Giving a clear guidance for cutting-edge technologies on the one hand and still keeping the door wide open for custom choice on the other hand, demands a highly flexible CAP Java SDK.
The [stack architecture](#modular_architecture) reflects this requirement, allowing fine-grained [stack configuration](#stack_configuration) and custom extensions.
Section [Architecture Overview](#modular_architecture) explains how the basic architecture of CAP Java meets this requirement, allowing a fine-grained stack [Configuration](#stack_configuration) and extensions with custom modules.


## Stack Architecture { #modular_architecture}

### Overview
## Architecture Overview { #modular_architecture}

One of the basic design principle of the CAP Java SDK is to keep orthogonal functionality separated in independent components. The obvious advantage of this decoupling is that it makes concrete components exchangeable independently.
Hence, it reduces the risk of expensive adaptions in custom code, which can be necessary due to new requirements with regards to the platform environment or used version of platform services. Hence, the application is [platform **and** service agnostic](../about/#agnostic-approach).
Expand All @@ -36,7 +34,7 @@ Alternatively, you can even configure test on integration level to be executed l

The following diagram illustrates the modular stack architecture and highlights the generic components:

<img src="./assets/modularized-architecture.png" width="600px">
<img src="./assets/modularized-architecture.png" width="600px" alt="The graphic is explained in the accompanying text.">

You can recognize five different areas of the stack, which comprise components according to different tasks:

Expand All @@ -60,7 +58,6 @@ As all other components in the different layers of the CAP Java SDK are decouple

### Protocol Adapters { #protocol-adapters}


The CAP runtime is based on an [event](../about/#events) driven approach. Generally, [Service](../about/#services) providers are the consumers of events, that means, they do the actual processing of events in [handlers](../guides/providing-services#event-handlers). During execution, services can send events to other service providers and consume the results. The native query language in CAP is [CQN](../cds/cqn), which is accepted by all services that deal with data query and manipulation. Inbound requests therefore need to be mapped to corresponding CQN events, which are sent to an accepting Application Service (see concept [details](../about/#querying)) afterwards. Mapping the ingress protocol to CQN essentially summarizes the task of protocol adapters depicted in the diagram. Most prominent example is the [OData V4](https://www.odata.org/documentation/) protocol adapter, which is fully supported by the CAP Java SDK. Further HTTP-based protocols can be added in future, but often applications require specific protocols, most notably [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) ones. Such application-specific protocols can easily be implemented by means of Spring RestControllers.

The modular architecture allows to add custom protocol adapters in a convenient manner, which can be plugged into the stack at runtime. Note that different endpoints can be served by different protocol adapters at the same time.
Expand All @@ -84,9 +81,9 @@ The overall architecture of the CAP Java SDK allows additional components to be

CAP Java makes use of [features](#standard-modules) itself to provide optional functionality, examples are [SAP Event Mesh](./messaging-foundation) and [Audit logging](./auditlog) integration.

## Stack Configuration { #stack_configuration}
## Configuration { #stack_configuration}

As outlined in section [Modular Architecture](#modular_architecture), the CAP Java SDK is highly flexible. You can choose among modules prepared for different environments and in addition also include optional or custom extensions.
As outlined in section [Architecture Overview](#modular_architecture), the CAP Java SDK is highly flexible. You can choose among modules prepared for different environments and in addition also include optional or custom extensions.
Which set of modules is active at runtime is a matter of compile time and runtime configuration.

At compile time, you can assemble modules from the different layers:
Expand All @@ -95,7 +92,7 @@ CAP Java makes use of [features](#standard-modules) itself to provide optional f
* The core [service providers](#service-providers)
* [Application features](#application-features) to optionally extend the application or adapt to a specific environment

### Module Configuration
### Wiring Modules { #module-configuration }

All CAP Java SDK modules are built as [Maven](https://maven.apache.org/) artifacts and are available on [Apache Maven Central Repository](https://search.maven.org/search?q=com.sap.cds). They've `groupId` `com.sap.cds`.
Beside the Java libraries (Jars) reflecting the modularized functionality, the group also contains a "bill of materials" (BOM) pom named `cds-services-bom`, which is recommended especially for multi-project builds. It basically helps to control the dependency versions of the artifacts and should be declared in dependency management of the parent `pom`:
Expand Down Expand Up @@ -186,7 +183,7 @@ Additional application features you want to use are added as additional dependen
Choosing a feature by adding the Maven dependency *at compile time* enables the application to make use of the feature *at runtime*. If a chosen feature misses the required environment at runtime, the feature won't be activated. Together with the fact that all features have a built-in default implementation ready for local usage, you can run the application locally with the same set of dependencies as for productive mode.
For instance, the authentication feature `cds-feature-hana` requires a valid `hana` binding in the environment. Hence, during local development without this binding, this feature gets deactivated and the stack falls back to default feature adapted for SQLite.

### CAP Java Standard Modules { #standard-modules }
### Standard Modules { #standard-modules }

CAP Java comes with a rich set of prepared modules in all different layers of the stack:

Expand Down Expand Up @@ -248,3 +245,10 @@ An example of a CAP application with OData V4 on Cloud Foundry environment:
</dependency>
</dependencies>
```

### Custom Modules { #custom-modules }

The plugin technique for the [standard modules](#standard-modules) can be used for custom modules in the same way.
By adding an additional dependency in the application project to the custom Maven module, the loaded module automatically adds functionality (usually handlers or providers) or extensions to the CDS model.

[Learn more about the CAP Java plugin technique.](../java/plugins){ .learn-more}
30 changes: 30 additions & 0 deletions java/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,36 @@ The name of the CDS element referred to by a getter or setter, is defined throug

For all structured types of the CDS model, accessor interfaces can be generated using the [CDS Maven Plugin](./advanced#staticmodel). The generated accessor interfaces allow for hybrid access and easy serialization to JSON.

By default, the accessor interfaces provide the setter and getter methods inspired by the JavaBeans specification.

Following example uses accessor interfaces that have been generated with the default (JavaBeans) style:

```java
Authors author = Authors.create();
author.setName("Emily Brontë");

Books book = Books.create();
book.setAuthor(authors);
book.setTitle("Wuthering Heights");
```

Alternatively, you can generate accessor interfaces in _fluent style_. In this mode, the getter methods are named after the property names. To enable fluent chaining, the setter methods return the accessor interface itself.

Following is an example of the fluent style:

```java
Authors author = Authors.create().name("Emily Brontë");
Books.create().author(author).title("Wuthering Heights");
```

The generation mode is configured by the property [`<methodStyle>`](./assets/cds-maven-plugin-site/generate-mojo.html#methodstyle) of the goal `cds:generate` provided by the CDS Maven Plugin. The selected `<methodStyle>` affects all entities and event contexts in your services. The default value is `BEAN`, which represents JavaBeans-style interfaces.

Once, when starting a project, decide on the style of the interfaces that is best for your team and project. We recommend the default JavaBeans style.

The way the interfaces are generated determines only how data is accessed by custom code. It does not affect how the data is represented in memory and handled by the CAP Java runtime.

Moreover, it doesn't change the way how event contexts and entities, delivered by CAP, look like. Such interfaces from CAP are always modelled in the default JavaBeans style.

#### Renaming Elements in Java

Element names used in the CDS model might conflict with reserved [Java keywords](https://docs.oracle.com/javase/specs/jls/se13/html/jls-3.html#jls-3.9) (`class`, `private`, `transient`, etc.). In this case, the `@cds.java.name` annotation must be used to specify an alternative property name that will be used for the generation of accessor interfaces and [static model](./advanced#staticmodel) interfaces. The element name used as key in the underlying map for [dynamic access](#entities-and-structured-types) isn't affected by this annotation.
Expand Down
4 changes: 3 additions & 1 deletion java/development/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,13 @@ The CAP Java SDK uses various dependencies that are also used by the application
| @sap/cds-compiler | 3 | latest |
| Spring Boot | 3.0 | latest |
| XSUAA | 3.0 | latest |
| SAP Cloud SDK | 4.24 | latest |
| SAP Cloud SDK | 4.24 | latest<sup>2</sup> |
| Java Logging | 3.7 | latest |

<sup>1</sup> When using the SAP Business Application Studio JDK 17 is recommended.

<sup>2</sup> Cloud SDK 5 is recommended. Refer to necessary steps for [adoption of Cloud SDK 5](../migration.md#cloudsdk5)

::: warning
The Cloud SDK BOM `sdk-bom` manages XSUAA until version 2.x, which isn't compatible with CAP Java 2.x.
You have two options:
Expand Down
2 changes: 1 addition & 1 deletion java/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ In older workspaces it might be necessary to explicitly set the JDK to version 1

Take the following steps to set up a new CAP Java application based on Spring Boot from scratch. As a prerequisite, you've set up your [development environment](#local).
### Run the CAP Java Maven Archetype
### Run the Maven Archetype { #run-the-cap-java-maven-archetype }
Use the [CAP Java Maven archetype](./development/#the-maven-archetype) to bootstrap a new CAP Java project:
Expand Down
2 changes: 1 addition & 1 deletion java/messaging-foundation.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The described messaging features are available from version `[email protected]`.

In a publish-subscribe-based messaging scenario (pub-sub messaging), senders send a message tagged with a topic to a message broker. Receivers can create queues at the message broker and subscribe these queues to the topics they're interested in. The message broker will then copy incoming messages matching the subscribed topics to the corresponding queues. Receivers can now consume these messages from their queues. If the receiver is offline, no messages will be lost as the message broker safely stores messages in the queue until a receiver consumes the messages. After the receiver acknowledges the successful processing of a message, the message broker will delete the acknowledged message from the queue.

<img src="./assets/messaging_foundation.png" width="700px">
<img src="./assets/messaging_foundation.png" width="700px" alt="The graphic is explained in the accompanying text.">

CAP makes sending and receiving messages easy by providing an API agnostic from specific message brokers, and taking care of broker-specific mechanics like connection handling, protocols to use, creating queues, subscriptions, etc. The API seamlessly blends into the common event API of CAP services, so that event messages can be sent using `emit` and handlers to execute when receiving event messages can be declared with the `@On` annotation.

Expand Down
13 changes: 13 additions & 0 deletions java/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1043,3 +1043,16 @@ After rebuilding and restarting your application, your Application Services are
<!-- TODO: Move this to "Development" section -->

<span id="afterenablingodata" />

## Cloud SDK 4 to 5 { #cloudsdk5 }

CAP Java `2.6.0` and higher is compatible with Cloud SDK in version 4 and 5. For reasons of backward compatibility, CAP Java assumes Cloud SDK 4 as the default. However, we highly recommend to use at least version `5.2.0` of Cloud SDK. To upgrade your CAP Java application to Cloud SDK 5, in most cases, you don't need to adapt any code if you rely on the Cloud SDK integration package (`cds-integration-cloud-sdk`). In these cases, it's sufficient to add the following maven dependency to your CAP Java application:

```xml
<dependency>
<groupId>com.sap.cloud.sdk.cloudplatform</groupId>
<artifactId>connectivity-apache-httpclient4</artifactId>
</dependency>
```


Loading

0 comments on commit 0d06712

Please sign in to comment.