Skip to content

CAP Java: Migration Guide 3 to 4 #1824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
7 changes: 0 additions & 7 deletions guides/security/authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -516,13 +516,6 @@ Supported features are:
* Value references to constants, [user attributes](#user-attrs), and entity data (elements including [paths](#association-paths))
* [Exists predicate](#exists-predicate) based on subselects.


<div class="impl java">

CAP Java offers the option to enable rejection conditions for `UPDATE`, `DELETE` and custom events. Enable it using the configuration option <Config java keyOnly label="reject-selected-unauthorized-entity">cds.security.authorization.instance-based.reject-selected-unauthorized-entity.enabled: true</Config>.

</div>

::: info Avoid enumerable keys
In case the filter condition is not met in an `UPDATE` or `DELETE` request, the runtime rejects the request (response code 403) even if the user is not even allowed to read the entity. To avoid to disclosure the existence of such entities to unauthorized users, make sure that the key is not efficiently enumerable.
:::
Expand Down
2 changes: 1 addition & 1 deletion java/cqn-services/persistence-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Advise the CDS Compiler to generate _tables without associations_, as associatio

#### SQL Optimization Mode

By default, the SAP HANA adapter in CAP Java generates SQL that is optimized for the new [HEX engine](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-performance-guide-for-developers/query-execution-engine-overview) in SAP HANA Cloud. To generate SQL that is compatible with SAP HANA 2.x ([HANA Service](https://help.sap.com/docs/HANA_SERVICE_CF/6a504812672d48ba865f4f4b268a881e/08c6e596b53843ad97ae68c2d2c237bc.html)) and [SAP HANA Cloud](https://www.sap.com/products/technology-platform/hana.html), set the [CDS property](../developing-applications/properties#cds-properties):
By default, the SAP HANA adapter in CAP Java generates SQL that is optimized for the new [HEX engine](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-performance-guide-for-developers/query-execution-engine-overview) in SAP HANA Cloud. To generate SQL that is compatible with SAP HANA 2.x ([HANA Service](https://help.sap.com/docs/HANA_SERVICE_CF/6a504812672d48ba865f4f4b268a881e/08c6e596b53843ad97ae68c2d2c237bc.html)) and [SAP HANA Cloud](https://www.sap.com/products/technology-platform/hana.html), set the (deprecated) [CDS property](../developing-applications/properties#cds-properties):

```yaml
cds.sql.hana.optimizationMode: legacy
Expand Down
6 changes: 4 additions & 2 deletions java/event-handlers/changeset-contexts.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,15 @@ public class SessionContextHandler implements EventHandler {
## Avoiding Transactions for Select { #avoid-transactions }

CAP ensures that every interaction with a service is inside of a ChangeSet Context. However transactions are not started at that point in time yet.
By default, any kind of first interaction with the Persistence Service will begin the transaction. Once a transaction has been started, a connection for that transaction is reserved from the connection pool. This connection is only returned to the connection pool on commit or rollback of the transaction.
Upon first interaction with the Persistence Service CAP will start the transaction. Once a transaction has been started, a connection for that transaction is reserved from the connection pool. This connection is only returned to the connection pool on commit or rollback of the transaction.

However, `READ` events which run simple Select queries don't actually require transactions in most cases. When setting the property `cds.persistence.changeSet.enforceTransactional` to `false` most Select queries do not cause a transaction to be started any longer. A connection for these queries is obtained from the connection pool and returned immediately after executing the queries on the database. This can increase throughput of an application, by making connections available for concurrent requests faster. As soon as a modifying statement is executed on the Persistence Service, a transaction is started. All subsequent Select queries will participate in that transaction. Note, that this behaviour is only transparent when using the default transaction isolation level "Read Committed".
However, `READ` events which run simple Select queries don't actually require transactions in most cases, thus CAP doesn't start a transaction in these cases. A connection for these queries is obtained from the connection pool and returned immediately after executing the queries on the database. This can increase throughput of an application, by making connections available for concurrent requests faster. As soon as a modifying statement is executed on the Persistence Service, a transaction is started. All subsequent Select queries will participate in that transaction. Note, that this behaviour is only transparent when using the default transaction isolation level "Read Committed".

A ChangeSet Context can always be marked as requiring a transaction, by calling the `markTransactional` on the `ChangeSetContext` or `ChangeSetContextRunner`. The next interaction with the Persistence Service will guarantee to start a transaction in that case. Alternatively, Spring Boot annotations `@Transactional` can be used to eagerly start a transaction.

Some Select queries will still require a transaction:

- Select queries with a lock: These are treated like a modifying statement and will start a transaction.
- Select queries reading streamed media data: These are currently not automatically detected. The surrounding ChangeSet Context needs to be marked as transactional explicitly. If not done, `InputStream`s might be corrupted or closed when trying to read them after the connection was returned to the connection pool already.

You can enforce transaction also for `READ` events by setting the property `cds.persistence.changeSet.enforceTransactional` to `false`.
6 changes: 3 additions & 3 deletions java/event-handlers/indicating-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The OData adapters turn all exceptions into an OData error response to indicate

## Messages

The [Messages](https://www.javadoc.io/doc/com.sap.cds/cds-services-api/latest/com/sap/cds/services/messages/Messages.html) API allows event handlers to add errors, warnings, info, or success messages to the currently processed request. Adding info, warning or success messages doesn't affect the event processing or the transaction. For error messages by default a `ServiceException` is thrown at the end of the `Before` handler phase. You can change this by setting [`cds.errors.combined`](../developing-applications/properties#cds-errors-combined) to `false`.
The [Messages](https://www.javadoc.io/doc/com.sap.cds/cds-services-api/latest/com/sap/cds/services/messages/Messages.html) API allows event handlers to add errors, warnings, info, or success messages to the currently processed request. Adding info, warning or success messages doesn't affect the event processing or the transaction. For error messages by default a `ServiceException` is thrown at the end of the `Before` handler phase.

The `Messages` interface provides a logger-like API to collect these messages. Additional optional details can be added to the [Message](https://www.javadoc.io/doc/com.sap.cds/cds-services-api/latest/com/sap/cds/services/messages/Message.html) using a builder API.
You can access the `Messages` API from the Event Context:
Expand Down Expand Up @@ -82,7 +82,7 @@ messages.throwIfError();
If there are any collected error messages, this method creates a [ServiceException](https://www.javadoc.io/doc/com.sap.cds/cds-services-api/latest/com/sap/cds/services/ServiceException.html) from _one_ of these error messages.
The OData adapter turns this exception into an OData error response to indicate the error to the client. The remaining error messages are written into the `details` section of the error response.

If the CDS property [`cds.errors.combined`](../developing-applications/properties#cds-errors-combined) is set to true (default), `Messages.throwIfError()` is automatically called at the end of the `Before` handler phase to abort the event processing in case of errors. It is recommended to use the Messages API for validation errors and rely on the framework calling `Messages.throwIfError()` automatically, instead of throwing a `ServiceException`.
`Messages.throwIfError()` is automatically called at the end of the `Before` handler phase to abort the event processing in case of errors. It is recommended to use the Messages API for validation errors and rely on the framework calling `Messages.throwIfError()` automatically, instead of throwing a `ServiceException`.


## Formatting and Localization
Expand Down Expand Up @@ -127,7 +127,7 @@ throw new ServiceException(ErrorStatuses.BAD_REQUEST, "my.message.key", paramNum
CAP Java provides out-of-the-box translation for error messages that originate from input validation annotations such as `@assert...` or `@mandatory` and security annotations `@requires` and `@restrict`.

The error messages are optimized for UI scenarios and avoid any technical references to entity names or element names. Message targets are used where appropriate to allow the UI to show the error message next to the affected UI element.
You can enable these translated error messages by setting [<Config java>cds.errors.defaultTranslations.enabled: true</Config>](../developing-applications/properties#cds-errors-defaultTranslations-enabled).
You can disable these translated error messages by setting [<Config java>cds.errors.defaultTranslations.enabled: false</Config>](../developing-applications/properties#cds-errors-defaultTranslations-enabled).

### Exporting the Default Messages

Expand Down
101 changes: 101 additions & 0 deletions java/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,107 @@ uacp: Used as link target from Help Portal at https://help.sap.com/products/BTP/

[[toc]]

## CAP Java 3.10 to CAP Java 4.0 { #three-to-four }

### New License

The license of CAP Java 4.0 has changed and it's released under the new [SAP Developer License Agreement for CAP](https://cap.cloud.sap/resources/license/developer-license-3_2_CAP.txt).

### Minimum Versions

CAP Java 4.0 increased some minimum required versions:

| Dependency | Minimum Version |
| --- | --- |
| @sap/cds-dk | ^8 |

CAP Java 4.0 no longer supports @sap/cds-dk ^7.

### Removed feature `cds-feature-event-hub`

The feature `cds-feature-event-hub` has been removed from CAP Java. The successor of this feature is the [CDS Plugin for SAP Cloud Application Event Hub](https://github.com/cap-java/cds-feature-event-hub). This new CAP Java Plugin is published independently of CAP Java and is open source. It however has the same Maven group ID and artifact ID as the previous CAP Java feature and starts versioning with `4.0.0`.

### Changes in goal `generate` of the `cds-maven-plugin`

1. Removed already deprecated properties:
- sharedInterfaces
- uniqueEventContexts

2. Deprecated properties and marked for removal:
- eventContext
- cqnService

3. Changed default value of properties:
- excludes: "localized.**" -> null

### Removed unstructured messages from MessagingService { #removed-unstructured }

The deprecated `cds.messaging.services.<key>.structured` property, which allowed to handle messages as (unstructured) plain strings has now been completely removed.
Messaging services always represent data in a structured way by using a `Map`. Headers are represented in a separate `Map`.

With this change the following deprecated methods have been removed:
- `void MessagingService.emit(String, String)`
- `String TopicMessageEventContext.getData()`

When publishing a unstructured String-based message, wrap the message into a Map:

```java
// instead of
messagingService.emit("myTopic", "unstructured message");
// use
messagingService.emit("myTopic", Map.of("message", "unstructured message")); // [!code focus]
```

In case you receive a unstructured String-based message from a message broker, it is also wrapped into a structured message with a `message` property:

```java
@On(event = "myTopic")
void handleMyTopic(TopicMessageEventContext context) {
// instead of
String message = context.getData();
// use
String message = (String) context.getDataMap().get("message"); // [!code focus]
}
```

This change has no effect on CDS modelled events, as these have always been structured.

### Adjusted Property Defaults

Some property defaults have been adjusted:

| Property | Old Value | New Value | Explanation |
| --- | --- | --- | --- |
| `cds.security.authorization.deep.enabled` | false | true | [Deep Authorization](./security#deep-auth) is now enabled by default. |
| `cds.security.authorization.instanceBased.rejectSelectedUnauthorizedEntity.enabled` | false | true | Requests that violate instance-based authorization conditions now fail with 403, instead of 404. |
| `cds.security.authorization.instanceBased.checkInputData.enabled` | false | true | [Authorization Checks On Input Data](./security#input-data-auth) are now enabled by default. |
| `cds.persistence.changeSet.enforceTransactional` | true | false | [Avoiding Transactions for Select queries](./event-handlers/changeset-contexts#avoid-transactions) is now enabled by default. |
| `cds.errors.defaultTranslations.enabled` | false | true | [Translations for Validation Error Messages](./event-handlers/indicating-errors#ootb-translated-messages) are now enabled by default. |
| `cds.taskScheduler.enabled` | false | true | The new optimized outbox message collector implementation is now enabled by default. |

### Deprecated Properties

The following properties have been deprecated and might be removed in a future major version:

- `cds.errors.combined`
- `cds.sql.hana.optimizationMode`
- `cds.outbox.services.<key>.storeLastError.enabled`

The functionality provided by these properties is enabled by default and there is no reason to switch these off.

### Removed Properties

The following table gives an overview about the removed properties:

| Removed Property | Replacement / Explanation |
| --- | --- |
| `cds.messaging.services.`<br>`<key>.structured` | [Use structured messages.](#removed-unstructured) |
| `cds.security.authorization.`<br>`emptyAttributeValuesAreRestricted` | [Use conditions with explicit checks for empty attributes.](../guides/security/authorization#user-attrs) |
| `cds.odataV4.serializer.buffered` | OData V4 responses are now always streamed while serialized. |
| `cds.environment.k8s` | Use service bindings from SAP BTP Operator on Kyma. |
| `cds.multiTenancy.subscriptionManager.`<br>`clientCertificateHeader` | `cds.security.authentication.`<br>`clientCertificateHeader` |
| `cds.multiTenancy.security.`<br>`internalUserAccess.enabled` | `cds.security.authentication.`<br>`internalUserAccess.enabled` |

## CAP Java 2.10 to CAP Java 3.0 { #two-to-three }

### Minimum Versions
Expand Down
8 changes: 2 additions & 6 deletions java/outbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,18 @@ cds:
services:
DefaultOutboxOrdered:
maxAttempts: 10
storeLastError: true
# ordered: true
DefaultOutboxUnordered:
maxAttempts: 10
storeLastError: true
# ordered: false
```
:::
You have the following configuration options:
- `maxAttempts` (default `10`): The number of unsuccessful emits until the message is ignored. It still remains in the database table.
- `storeLastError` (default `true`): If this flag is enabled, the last error that occurred, when trying to emit the message
of an entry, is stored. The error is stored in the element `lastError` of the entity `cds.outbox.Messages`.
- `ordered` (default `true`): If this flag is enabled, the outbox instance processes the entries in the order they have been submitted to it. Otherwise, the outbox may process entries randomly and in parallel, by leveraging outbox processors running in multiple application instances. This option can't be changed for the default persistent outboxes.

The persistent outbox stores the last error that occurred, when trying to emit the message of an entry. The error is stored in the element `lastError` of the entity `cds.outbox.Messages`.

### Configuring Custom Outboxes { #custom-outboxes}

Custom persistent outboxes can be configured using the `cds.outbox.services` section, for example in the _application.yaml_:
Expand All @@ -94,10 +92,8 @@ cds:
services:
MyCustomOutbox:
maxAttempts: 5
storeLastError: false
MyOtherCustomOutbox:
maxAttempts: 10
storeLastError: true
```
:::
Afterward you can access the outbox instances from the service catalog:
Expand Down
Loading