diff --git a/.gitignore b/.gitignore index ea6ef67..c2658d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ -models/ -embeddings/ node_modules/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 6207bfc..645bbf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). The format is based on [Keep a Changelog](http://keepachangelog.com/). +## Version 0.0.4 - 2025-09-25 + +### Changed + +- Vendor embeddings and model to not require internet access + ## Version 0.0.3 - 2025-09-22 ### Changed diff --git a/README.md b/README.md index 14e2657..dbef34b 100644 --- a/README.md +++ b/README.md @@ -165,5 +165,6 @@ Copyright 2025 SAP SE or an SAP affiliate company and @cap-js/cds-mcp contributo ## Acknowledgments - **onnxruntime-web** is used for creating embeddings locally. +- **Xenova/all-MiniLM-L6-v2** is used as the embeddings model. - **@huggingface/transformers.js** is used to compare the output of the WordPiece tokenizer. - **@modelcontextprotocol/sdk** provides the SDK for MCP. diff --git a/embeddings/code-chunks.bin b/embeddings/code-chunks.bin new file mode 100644 index 0000000..67c7633 Binary files /dev/null and b/embeddings/code-chunks.bin differ diff --git a/embeddings/code-chunks.etag b/embeddings/code-chunks.etag new file mode 100644 index 0000000..50bbcd4 --- /dev/null +++ b/embeddings/code-chunks.etag @@ -0,0 +1 @@ +W/"13f5a6-19962049eb0" \ No newline at end of file diff --git a/embeddings/code-chunks.json b/embeddings/code-chunks.json new file mode 100644 index 0000000..b6afc1c --- /dev/null +++ b/embeddings/code-chunks.json @@ -0,0 +1,2689 @@ +{ + "dim": 384, + "count": 2683, + "chunks": [ + " Getting Started > Initial Setup > Installation\ninstallation, cds toolkit, npm, Node.js, CLI\nThis command installs the @sap/cds-dk toolkit globally using npm. The toolkit provides the 'cds' command line interface required for SAP Cloud Application Programming Model (CAP) development.\n\n```shell\nnpm add -g @sap/cds-dk\n```\n", + " Getting Started > Initial Setup > Installation\ninstallation, verify, cds CLI\nRunning this command verifies that the 'cds' command line interface has been installed successfully. The output displays usage information and available commands for CAP projects.\n\n```shell\ncds\n```\n", + " Getting Started > Starting Projects\ninit, project setup, cds CLI\nInitializes a new CAP project named 'bookshop' with the required directory structure and configuration files. This is the entry point for starting CAP-based projects.\n\n```shell\ncds init bookshop\n```\n", + " Getting Started > Starting Projects\neditor, VS Code, project open\nOpens the newly initialized 'bookshop' CAP project in Visual Studio Code. Assumes you have set up the 'code' command for VS Code.\n\n```shell\ncode bookshop\n```\n", + " Getting Started > Project Structure\nproject structure, scaffolding\nShows the default folder structure of a CAP project generated by 'cds init'. Directories include app, srv, db, and configuration files like package.json and readme.md.\n\n```shell\nbookshop/ # Your project's root folder\n├─ app/ # UI-related content\n├─ srv/ # Service-related content\n├─ db/ # Domain models and database-related content\n├─ package.json # Configuration for cds + cds-dk\n└─ readme.md # A readme placeholder\n```\n", + " Getting Started > Project Structure\nconfiguration, package.json, custom project layout\nThis JSON snippet demonstrates how to override the default CAP project folder layout by specifying custom directories for db, srv, and app through the 'cds.folders' property in package.json.\n\n```json\n{ ...\n \"cds\": {\n \"folders\": {\n \"db\": \"database/\",\n \"srv\": \"services/\",\n \"app\": \"uis/\"\n }\n }\n}\n```\n", + " Getting Started > Project Structure\ncds CLI, environment, defaults, list\nLists the default environment configurations and directory structure used by cds in the current CAP project. Useful for exploring and understanding CAP project conventions.\n\n```shell\ncds env ls defaults\n```\n", + "Jumpstart & Grow As You Go... > Jumpstarting Projects\nCLI, cds CLI, init, project setup, verify\nThese two shell commands are used to rapidly initialize and start a new CAP (Cloud Application Programming Model) project. 'cds init' scaffolds a minimalistic new project with default configuration, while 'cds watch' starts a server with live reload for fast development. Used to jumpstart CAP development by following the convention over configuration principle.\n\n```shell\ncds init\ncds watch\n```\n", + "Jumpstart & Grow As You Go... > Growing as You Go...\nCLI, cds CLI, add, project setup, configuration, environment\nThis shell command allows you to add features or integrations to a CAP project only as needed. Common options include database adapters (hana, redis), deployed artifact types (mta, helm), and capabilities like multitenancy or extensibility. This approach supports incremental project evolution and iterative workflow in CAP projects, avoiding premature decisions.\n\n```shell\ncds add hana,redis,mta,helm,mtx,multitenancy,extensibility...\n```\n", + " Best Practices > Single-Purposed Services > DO: One Service Per Use Case\nservice definition, srv/catalog-service.cds, Books, Orders, projection, authorization, entities, projection, readonly, insertonly\nDefines a CatalogService for browsing books and placing orders. The Books entity is exposed as readonly with selected fields, while Orders is exposed as insertonly for authenticated users. Each entity is projected from the domain model.\n\n```cds\nusing { my.domain as my } from './db/schema';\n\n/** Serves end users browsing books and place orders */\nservice CatalogService {\n @readonly entity Books as select from my.Books {\n ID, title, author.name as author\n };\n @requires: 'authenticated-user'\n @insertonly entity Orders as projection on my.Orders;\n}\n```\n", + " Best Practices > Single-Purposed Services > DO: One Service Per Use Case\nservice definition, srv/users-service.cds, Orders, projection, authorization, actions, restrict, readonly\nDefines a UsersService for registered users to manage their own orders. Only orders belonging to the authenticated user can be read, and an action 'cancelOrder' is provided to allow users to cancel their orders.\n\n```cds\n/** Serves registered users managing their account and their orders */\n@requires: 'authenticated-user'\nservice UsersService {\n @restrict: [{ grant: 'READ', where: 'buyer = $user' }] // limit to own ones\n @readonly entity Orders as projection on my.Orders;\n action cancelOrder ( ID:Orders.ID, reason:String );\n}\n```\n", + " Best Practices > Single-Purposed Services > DO: One Service Per Use Case\nservice definition, srv/admin-service.cds, Books, Authors, Orders, projection, authorization\nDefines an AdminService for administrators to manage all aspects of the application. The service exposes Books, Authors, and Orders entities as projections for full administrative access, restricted to authenticated users.\n\n```cds\n/** Serves administrators managing everything */\n@requires: 'authenticated-user'\nservice AdminService {\n entity Books as projection on my.Books;\n entity Authors as projection on my.Authors;\n entity Orders as projection on my.Orders;\n}\n```\n", + " Transaction Management > Automatic Transactions\nautomatic transactions, db.read, Service-managed Transactions, cds CLI, SQL\nExample of an automatic transaction using CAP's db.read API in JavaScript. The CAP framework manages transaction boundaries automatically, including connection acquisition and release, so no explicit transaction code is needed.\n\n```js\nawait db.read('Books')\n```\n", + " Transaction Management > Automatic Transactions\nautomatic transactions, SQL, connection pool\nSQL-level representation of a transaction managed automatically by CAP when executing a db.read('Books') operation. Illustrates connection pooling, transaction begin/commit, and release.\n\n```sql\n-- ACQUIRE connection from pool\nCONNECT; -- if no pooled one\nBEGIN;\nSELECT * from Books;\nCOMMIT;\n-- RELEASE connection to pool\n```\n", + " Transaction Management > Nested Transactions\nevent handler, nested transactions, service-to-service calls\nShows handling of nested transactions inside an event handler for a bank transfer scenario. CAP runtime manages a root transaction for the event and nested ones for DB and log service interactions.\n\n```js\nconst log = cds.connect.to('log')\nconst db = cds.connect.to('db')\n\nBankingService.on ('transfer', req => {\n let { from, to, amount } = req.data\n await db.update('BankAccount',from).set('balance -=', amount),\n await db.update('BankAccount',to).set('balance +=', amount),\n await log.insert ({ kind:'Transfer', from, to, amount })\n})\n```\n", + " Transaction Management > Manual Transactions\nmanual transactions, cds.tx, transaction handling\nManually starting and committing a transaction using cds.tx() to insert an author and a book in a single transactional context. CAP will handle commit/rollback for all operations within the supplied function.\n\n```js\ncds.tx (async ()=>{\n const [ Emily ] = await db.insert (Authors, {name:'Emily Brontë'})\n await db.insert (Books, { title: 'Wuthering Heights', author: Emily })\n})\n```\n", + " Transaction Management > Background Jobs\nbackground jobs, cds.spawn, async operations\nCreates a background job using cds.spawn() to process outbox mails periodically under a privileged user. Each run executes in a fresh transaction, independent of the main event context.\n\n```js\ncds.spawn ({ user: cds.User.privileged, every: 1000 /* ms */ }, async ()=>{\n const mails = await SELECT.from('Outbox')\n await MailServer.send(mails)\n await DELETE.from('Outbox').where (`ID in ${mails.map(m => m.ID)}`)\n})\n```\n", + " Transaction Management > cds. context {event-contexts .property} > Accessing Context\ncontext, cds.context, user, tenant\nAccesses the current user from cds.context to check for admin role. Demonstrates accessing runtime event context for authorization and logic branching.\n\n```js\nconst { user } = cds.context\nif (user.is('admin')) ...\n```\n", + " Transaction Management > cds. context {event-contexts .property} > Accessing Context\ncontext, cds.context, http, request, response\nShows how to access HTTP request and response objects from cds.context in CAP. Can be used for content negotiation and protocol-level handling within service operations or handlers.\n\n```js\nconst { req, res } = cds.context.http\nif (!req.is('application/json')) res.send(415)\n```\n", + " Transaction Management > cds. context {event-contexts .property} > Setting Contexts\ncontext, cds.context, middleware, custom authentication\nExample of custom Express middleware that sets cds.context based on incoming HTTP headers for tenant and user. Used for custom authentication or context propagation in CAP applications.\n\n```js\napp.use ((req, res, next) => {\n const { 'x-tenant':tenant, 'x-user-id':user } = req.headers\n cds.context = { tenant, user } // Setting cds.context\n next()\n})\n```\n", + " Transaction Management > cds. context {event-contexts .property} > Context Propagation\ncontext propagation, transaction context, cds.tx, user, tenant\nIllustrates how a new transaction context inherits properties from cds.context, and how you can override some (like user) while maintaining others (like tenant). Shows transaction and context independence.\n\n```js\ncds.context = { tenant:'t1', user:'u1' }\ncds.context.user.id === 'u1' //> true\nlet tx = cds.tx({ user:'u2' })\ntx.context !== cds.context //> true\ntx.context.tenant === 't1' //> true\ntx.context.user.id === 'u2' //> true\ntx.context.user !== cds.context.user //> true\ncds.context.user.id === 'u1' //> true\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method}\ncds.tx, srv.tx, method signature, service, transaction\nTypeScript signatures for CAP's srv.tx method showing function overloads for starting transactions manually and optionally providing a context and/or a function to execute transactional code.\n\n```ts\nfunction srv.tx ( ctx?, fn? : tx => {...} ) => Promise\nfunction srv.tx ( ctx? ) => tx\nvar ctx : { tenant, user, locale }\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method}\nsrv.tx, manual transaction, transaction object, commit, rollback\nManual transaction management with srv.tx(): creates a transaction object used to run several queries, with explicit commit/rollback handling.\n\n```js\nconst tx = srv.tx()\ntry {\n let exists = await tx.run ( SELECT(1).from(Books,201).forUpdate() )\n if (exists) await tx.update (Books,201).with(data)\n else await tx.create (Books,{ ID:201,...data })\n await tx.commit()\n} catch(e) {\n await tx.rollback(e)\n}\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method} > srv.tx (context?, fn?) → tx \nsrv.tx, db.tx, manual transaction, commit, rollback, Service API\nStarts a manual transaction on a database service, executes multiple operations, and manages commit/rollback explicitly. Demonstrates proper lifecycle management for transactions outside of event handlers.\n\n```js\nlet db = await cds.connect.to('db')\nlet tx = db.tx()\ntry {\n await tx.run (SELECT.from(Foo))\n await tx.create (Foo, {...})\n await tx.read (Foo)\n await tx.commit()\n} catch(e) {\n await tx.rollback(e)\n}\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method} > srv.tx ({ tenant?, user?, ... }) → tx {srv-tx-ctx}\nsrv.tx, context, user, tenant\nCreates a new transaction (tx) on the database service with a specific tenant and user context, overriding any ambient context.\n\n```js\nlet tx = db.tx ({ tenant:'t1' user:'u2' })\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method} > srv.tx ((tx)=>{...}) → tx {srv-tx-fn}\nsrv.tx, function callback, auto commit, auto rollback\nRuns a transaction using db.tx with an async function argument: automatically commits if the function completes, or rolls back if there's an error.\n\n```js\nawait db.tx (async tx => {\n await tx.run (SELECT.from(Foo))\n await tx.create (Foo, {...})\n await tx.read (Foo)\n})\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method} > srv.tx ((tx)=>{...}) → tx {srv-tx-fn}\nsrv.tx, manual transaction, commit, rollback\nEquivalent manual transaction management using db.tx: explicit try/catch with commit/rollback, functionally similar to the auto-commit variant but with more control over error handling.\n\n```js\nlet tx = db.tx()\ntry {\n await tx.run (SELECT.from(Foo))\n await tx.create (Foo, {...})\n await tx.read (Foo)\n await tx.commit()\n} catch(e) {\n await tx.rollback(e)\n}\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method} > srv.tx (ctx) → tx {srv-tx-context}\ncds.tx, context, nested transaction, root transaction\nCreates a new root transaction with CDS, inheriting context properties from cds.context. Useful for performing work under explicit context.\n\n```js\ncds.context = { tenant:'t1', user:'u2' }\nconst tx = cds.tx (cds.context)\n//> tx is a new root transaction\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method} > srv.tx (ctx) → tx {srv-tx-context}\ncds.tx, nested transaction, context propagation\nDemonstrates creating a nested transaction with explicit event context. Shows how nested transactions are created and how context is handled.\n\n```js\nconst tx = cds.context = cds.tx ({ tenant:'t1', user:'u2' })\nconst tx1 = cds.tx (cds.context)\n//> tx1 is a new nested transaction to tx\n```\n", + " Transaction Management > cds/srv. tx() {srv-tx .method} > _↳_ tx.commit (res?) ⇢ res {commit }\ntransaction object, commit, rollback, promise chaining\nShows use of promise chaining for commit and rollback methods on a transaction object (tx), which are both bound to the transaction instance and return or propagate their argument.\n\n```js\nlet tx = cds.tx()\ntx.run(...) .then (tx.commit, tx.rollback)\n```\n", + " Transaction Management > cds.spawn() {cds-spawn .method}\nbackground jobs, cds.spawn, periodic task, event context\nSpawns a periodic background job in a specific tenant context using cds.spawn(). Each execution receives its own root transaction and runs isolated from the main event processing.\n\n```js\ncds.spawn ({ tenant:'t0', every: 1000 /* ms */ }, async (tx) => {\n const mails = await SELECT.from('Outbox')\n await MailServer.send(mails)\n await DELETE.from('Outbox').where (`ID in ${mails.map(m => m.ID)}`)\n})\n```\n", + " Transaction Management > cds.spawn() {cds-spawn .method}\nbackground jobs, cds.spawn, event emitter, interval control\nDemonstrates starting a recurring job with cds.spawn and programmatically stopping it using clearInterval on the job's timer property.\n\n```js\nlet job = cds.spawn({ every:111 }, ...)\nawait sleep (11111)\nclearInterval (job.timer) // stops the background job loop\n```\n", + " Transaction Management > DEPRECATED APIs\nDEPRECATED, srv.tx, context propagation, event handler\nLegacy/deprecated usage for transaction/context propagation in event handlers, where you manually created a transaction per request. This approach is no longer necessary from CAP v5 onwards.\n\n```js\nthis.on('READ','Books', req => {\n const tx = cds.tx(req)\n return tx.read ('Books')\n})\n```\n", + " Authentication > cds. User\ncds.User, custom authentication, user instantiation\nExample showing how to set cds.context.user with a custom user instance in custom authentication middleware. Here, DummyUser is a subclass of cds.User that always returns true for 'is', bypassing role checks.\n\n```js\nconst cds = require('@sap/cds')\nconst DummyUser = new class extends cds.User { is:()=>true }\nmodule.exports = (req,res,next) => {\n cds.context.user = new DummyUser('dummy')\n next()\n}\n```\n", + " Authentication > cds. User\ncds.User, user instantiation, user id, roles, attributes\nShows multiple ways to create user instances using cds.User: directly with an id, cloning an existing user, or initializing from an object with id, roles, and attributes. Used to populate cds.context.user or for manual checks.\n\n```js\nconst cds = require('@sap/cds')\n// with user ID as string\nconst user = new cds.User('userId')\n// a user instance\nconst anotherUser = new cds.User(user)\n// a user instance like object\nconst yetAnotherUser = new cds.User({id: user.id, roles: user.roles, attr: user.attr})\n```\n", + " Authentication > cds. User > .is (role)\nauthorization, user role check, .is, cds.User\nChecks if the current user has the 'admin' role using the .is method on a cds.User instance. Used in hooks or logic that needs role-based access enforcement.\n\n```js\nif (req.user.is('admin')) ...\n```\n", + " Authentication > cds.User.Privileged\nUser.Privileged, authorization bypass, local service, transaction\nCreates and uses a privileged user for a service transaction, bypassing authorization checks. Used for special flows like local logs or system-level inserts in event handlers.\n\n```js\nthis.before('*', function (req) {\n const user = new cds.User.Privileged\n return this.tx({ user }, tx => tx.run(\n INSERT.into('RequestLog').entries({\n url: req._.req.url,\n user: req.user.id\n })\n )\n})\n```\n", + " Authentication > cds.User.Privileged\nUser.Privileged, authorization bypass, privileged instance\nShows how to use the built-in ready-to-use privileged user instance cds.User.privileged, which allows operations without standard authorization.\n\n```js\nconst user = cds.User.privileged\n```\n", + " Authentication > cds.User.Anonymous\nUser.Anonymous, anonymous user\nCreate a new anonymous user instance. Useful for custom authentication flows where an unidentified user context is needed.\n\n```js\nconst user = new cds.User.Anonymous\n```\n", + " Authentication > cds.User.Anonymous\nUser.Anonymous, anonymous user, predefined instance\nShows how to use the built-in anonymous user instance cds.User.anonymous for requests with no authenticated user.\n\n```js\nconst user = cds.User.anonymous\n```\n", + " Authentication > cds.User.default\nUser.default, fallback user, unauthenticated\nRefers to the default user instance used as a fallback if requests cannot be authenticated. Usually points to Anonymous, but can be changed as needed.\n\n```js\ncds.User.default\n```\n", + " Authentication > Authorization Enforcement\nauthorization enforcement, cds.context.user, programmatic enforcement, service\nDemonstrates how to enforce authorization logic in hook handlers using cds.context.user. It checks role and attribute-based access before proceeding with service operations.\n\n```js\nconst cds = require('@sap/cds')\ncds.serve ('CustomerService') .with (function(){\n this.before ('*', req =>\n req.user.is('authenticated') || req.reject(403)\n )\n this.before (['READ', 'CREATE'], 'Orders', req =>\n req.user.is('admin') || req.reject(403)\n )\n this.before ('*', 'Approval', req =>\n req.user.attr.level > 2 || req.reject(403)\n )\n})\n```\n", + " Authentication > Authentication Strategies > JWT-based Authentication\nauthentication strategy, cds.env, jwt, mocked, configuration\nConfigures CAP to use JWT authentication strategy by setting the 'auth' property in cds.requires section in package.json or .cdsrc.json files.\n\n```json\n\"cds\": {\n \"requires\": {\n \"auth\": \"jwt\"\n }\n}\n```\n", + " Authentication > Authentication Strategies > Mocked Authentication\nauthentication strategy, mocked, development, package.json, users\nDemonstrates how to set the authentication strategy to 'mocked' in the cds.requires section, enabling basic authentication with mock users in development.\n\n```json\n\"cds\": {\n \"requires\": {\n \"auth\": \"mocked\"\n }\n}\n```\n", + " Authentication > Authentication Strategies > Mocked Authentication > Pre-defined Mock Users\nauthentication strategy, mocked, users, default configuration\nThe default user mapping shipped for mocked authentication strategy. Provides users (alice, bob, etc.) with specified tenants and roles.\n\n```jsonc\n\"users\": {\n \"alice\": { \"tenant\": \"t1\", \"roles\": [ \"admin\" ] },\n \"bob\": { \"tenant\": \"t1\", \"roles\": [ \"cds.ExtensionDeveloper\" ] },\n \"carol\": { \"tenant\": \"t1\", \"roles\": [ \"admin\", \"cds.ExtensionDeveloper\", \"cds.UIFlexDeveloper\" ] },\n \"dave\": { \"tenant\": \"t1\", \"roles\": [ \"admin\" ], \"features\": [] },\n \"erin\": { \"tenant\": \"t2\", \"roles\": [ \"admin\", \"cds.ExtensionDeveloper\", \"cds.UIFlexDeveloper\" ] },\n \"fred\": { \"tenant\": \"t2\", \"features\": [ \"isbn\" ] },\n \"me\": { \"tenant\": \"t1\", \"features\": [ \"*\" ] },\n \"yves\": { \"roles\": [ \"internal-user\" ] },\n \"*\": true\n}\n```\n", + " Authentication > Authentication Strategies > Mocked Authentication > Pre-defined Mock Users\nauthentication strategy, mocked, users, overwrite\nOverrides the default mocked users configuration to explicitly restrict which users are allowed to log in.\n\n```jsonc\n\"users\": {\n \"alice\": { \"roles\": [] },\n \"bob\": { \"roles\": [] },\n \"*\": false\n}\n```\n", + " Authentication > Authentication Strategies > Basic Authentication\nauthentication strategy, basic, users, package.json\nSets the CAP authentication strategy to use HTTP basic auth with potential mock users. No default users will be provisioned automatically.\n\n```json\n\"cds\": {\n \"requires\": {\n \"auth\": \"basic\"\n }\n}\n```\n", + " Authentication > Authentication Strategies > Basic Authentication\nauthentication strategy, basic, users, custom users\nShows how to configure HTTP basic authentication with custom user credentials, roles, and attributes in the CAP configuration.\n\n```json\n\"cds\": {\n \"requires\": {\n \"auth\": {\n \"kind\": \"basic\",\n \"users\": {\n \"\": {\n \"password\": \"\",\n \"roles\": [ \"\", ... ],\n \"attr\": { ... }\n }\n }\n }\n }\n}\n```\n", + " Authentication > Authentication Strategies > IAS-based Authentication > Token Validation\nauthentication strategy, ias, jwt, token validation\nDisables x5t and proofToken validation for IAS-based authentication strategy by updating validation parameters in custom configuration.\n\n```json\n\"requires\": {\n \"auth\": {\n \"kind\": \"ias\",\n \"config\": {\n \"validation\": {\n \"x5t\": { \"enabled\": false },\n \"proofToken\": { \"enabled\": false }\n }\n }\n }\n}\n```\n", + " Authentication > Authentication Strategies > Custom Authentication\nauthentication strategy, custom authentication, cds.context.user, cds.context.tenant\nSample implementation for a custom authentication middleware setting cds.context.user and cds.context.tenant for multi-tenant scenarios in CAP.\n\n```js\nmodule.exports = function custom_auth (req, res, next) {\n // do your custom authentication\n cds.context.user = new cds.User({\n id: '',\n roles: ['', ''],\n attr: {\n : '',\n : ''\n }\n })\n cds.context.tenant = ''\n}\n```\n", + " Authentication > Authentication Strategies > Custom Authentication\nauthentication strategy, custom authentication, cds.context.user, typescript, default export\nTypeScript version of a custom authentication handler for CAP, using default export and typed request object including user and tenant.\n\n```ts\nimport cds from \"@sap/cds\";\nimport {Request, Response, NextFunction} from \"express\";\ntype Req = Request & { user: cds.User, tenant: string };\n\nexport default function custom_auth(req: Req, res: Response, next: NextFunction) {\n // do your custom authentication ...\n}\n```\n", + " Authentication > Authentication Strategies > JWT-based Authentication\nxsuaa, Cloud Foundry, local development, service instance, npm\nInstalls the SAP authorization middleware dependency needed for JWT, XSUAA, or IAS-based authentication strategies in a CAP Node.js project.\n\n```shell\nnpm add @sap/xssec\n```\n", + " Authentication > XSUAA in Hybrid Setup > Prepare Local Environment\nxsuaa, Cloud Foundry, local development, cf CLI\nLogs in to Cloud Foundry with the provided API endpoint using the cf CLI. Needed to prepare the environment for XSUAA authentication.\n\n```shell\ncf l -a \n```\n", + " Authentication > XSUAA in Hybrid Setup > Prepare Local Environment\nhybrid, xsuaa, local development, CAP CLI\nAdds XSUAA support for hybrid development setup in a CAP project. Generates xs-security.json and updates package dependencies.\n\n```shell\ncds add xsuaa --for hybrid\n```\n", + " Authentication > XSUAA in Hybrid Setup > Prepare Local Environment\nxsuaa, xs-security.json, tenant-mode, configuration\nExample excerpt for xs-security.json ensuring a dedicated tenant mode for XSUAA service configuration.\n\n```json\n{\n \"xsappname\": \"bookshop-hybrid\",\n \"tenant-mode\": \"dedicated\",\n ...\n }\n```\n", + " Authentication > XSUAA in Hybrid Setup > Prepare Local Environment\nxsuaa, xs-security.json, redirect-uris, oauth2-configuration\nConfigures allowed OAuth2 redirect URIs for local development in xs-security.json. Required for using App Router with local CAP services.\n\n```json\n\"oauth2-configuration\": {\n \"redirect-uris\": [\n \"http://localhost:5000/login/callback\"\n ]\n}\n```\n", + " Authentication > XSUAA in Hybrid Setup > Prepare Local Environment\nxsuaa, service instance, cf CLI\nCreates a new XSUAA service instance in Cloud Foundry, binding it with the provided xs-security.json for authentication setup.\n\n```shell\ncf create-service xsuaa application bookshop-uaa -c xs-security.json\n```\n", + " Authentication > XSUAA in Hybrid Setup > Configure the Application\nxsuaa, service key, cf CLI\nCreates a service key for the XSUAA instance, enabling local CAP app access to service credentials.\n\n```shell\ncf create-service-key bookshop-uaa bookshop-uaa-key\n```\n", + " Authentication > XSUAA in Hybrid Setup > Configure the Application\nxsuaa, cds bind, service binding, CAP CLI\nBinds XSUAA service credentials to the local environment using cds bind, so that CAP app and tools can authenticate using local or hybrid profile.\n\n```shell\ncds bind -2 bookshop-uaa\n```\n", + " Authentication > XSUAA in Hybrid Setup > Configure the Application\nxsuaa, cds CLI, configuration check\nDisplays the authentication configuration, including resolved service bindings, for the hybrid profile in a CAP application.\n\n```shell\ncds env list requires.auth --resolve-bindings --profile hybrid\n```\n", + " Authentication > Authentication Enforced in Production\ncds CLI, authorization enforcement, env, feature flag\nFeature flag to disable automatic authorization enforcement on all services, making endpoints accessible unless explicitly restricted.\n\n```txt\nConfig>cds.requires.auth.restrict_all_services: false\n```\n", + " Authentication > XSUAA in Hybrid Setup > Running App Router\napprouter, CAP, cds add, hybrid, shell\nAdds App Router to the app folder of the project. App Router is used for authentication user flows (OAuth2) when connecting frontend and backend in hybrid or production setups.\n\n```shell\ncds add approuter\n```\n", + " Authentication > XSUAA in Hybrid Setup > Running App Router\napprouter, CAP, npm, install\nInstalls npm dependencies for App Router in the specified app/router folder.\n\n```shell\nnpm install --prefix app/router\n```\n", + " Authentication > XSUAA in Hybrid Setup > Running App Router\napprouter, CAP, cds bind --exec, hybrid\nRuns App Router with the appropriate VCAP_SERVICES environment variable for hybrid authentication integration with CAP, using the cds bind --exec command.\n\n```shell\ncds bind --exec -- npm start --prefix app/router\n```\n", + " Authentication > XSUAA in Hybrid Setup > Running App Router\nCAP, hybrid, cds watch\nStarts the CAP backend service with the 'hybrid' profile to use local XSUAA or other hybrid settings for authentication.\n\n```shell\ncds watch --profile hybrid\n```\n", + " Authentication > XSUAA in Hybrid Setup > Running App Router\napprouter, xs-app.json, disable authentication, development\nDisables any authentication requirement for App Router by setting authenticationMethod to 'none' in xs-app.json, useful for local UI testing.\n\n```json\n\"authenticationMethod\": \"none\"\n```\n", + " Testing with `cds.test` > Overview\ninstallation, npm, cds.test\nInstalls the '@cap-js/cds-test' library as a development dependency in your CAP Node.js project. This provides test utilities and helpers designed specifically for CAP applications.\n\n```shell\nnpm add -D @cap-js/cds-test\n```\n", + " Testing with `cds.test` > Running a CAP Server\nproject setup, test file, cds.test, server\nStarts the CAP server from the project's root directory for test purposes. Use this snippet in your test files located under the 'test' folder to programmatically launch and shut down the server using cds.test.\n\n```js\nconst cds = require('@sap/cds')\ndescribe(()=>{\n const test = cds.test(__dirname+'/..')\n})\n```\n", + " Testing with `cds.test` > Testing Service APIs\nverify, Node.js Service APIs, programmatic testing, cds.connect\nDemonstrates unit-testing service APIs by connecting to an internal service and verifying that different ways of data retrieval yield equivalent results. This is a pattern to test programmatic APIs in CAP.\n\n```js\nit('Allows testing programmatic APIs', async () => {\n const AdminService = await cds.connect.to('AdminService')\n const { Authors } = AdminService.entities\n expect (await SELECT.from(Authors))\n .to.eql(await AdminService.read(Authors))\n .to.eql(await AdminService.run(SELECT.from(Authors)))\n})\n```\n", + " Testing with `cds.test` > Testing HTTP APIs\nHTTP, sample request, integration testing, cds.test, GET, POST\nMakes HTTP GET and POST requests via the test instance, simulating calls to your API endpoints. Use GET and POST for integration-style tests of exposed HTTP endpoints.\n\n```js\nconst { GET, POST } = cds.test(...)\nconst { data } = await GET ('/browse/Books')\nawait POST (`/browse/submitOrder`, { book: 201, quantity: 5 })\n```\n", + " Testing with `cds.test` > Testing HTTP APIs > Authenticated Endpoints\nHTTP, authentication, mock user, Authenticated Endpoints\nPerforms an authenticated HTTP GET request using mock user credentials, which maps to basic authentication in tests for authenticated endpoints.\n\n```js\nawait GET('/admin/Books', { auth: { username: 'alice', password: '' } })\n```\n", + " Testing with `cds.test` > Testing HTTP APIs > Authenticated Endpoints\nHTTP, sample request, authentication, curl, test.http\nSimulates a raw HTTP GET request with a basic authentication header, corresponding to the JavaScript mock user test.\n\n```http\nGET http://localhost:4004/admin/Books\nAuthorization: Basic alice:\n```\n", + " Testing with `cds.test` > Using Jest or Mocha\nJest, Mocha, test runner, chai, portable tests\nShows how to structure CAP tests that work with both Jest and Mocha by using portable APIs and the Chai assertion library. Enables flexible test execution with either runner.\n\n```js\ndescribe('my test suite', ()=>{\n const { GET, expect } = cds.test(...)\n it ('should test', async ()=>{ // Jest & Mocha\n const { data } = await GET ('/browse/Books')\n expect(data.value).to.eql([ // chai style expect\n { ID: 201, title: 'Wuthering Heights', author: 'Emily Brontë' },\n { ID: 252, title: 'Eleonora', author: 'Edgar Allen Poe' },\n //...\n ])\n })\n})\n```\n", + " Testing with `cds.test` > Using Test Watchers\ntest watcher, Jest, continuous testing\nRuns Jest in watch mode to continually re-run tests on changes, recommended for test-driven development and rapid feedback when working in cap/samples.\n\n```shell\njest --watchAll\n```\n", + " Testing with `cds.test` > Using Test Watchers\ntest watcher, Mocha, continuous testing\nRuns Mocha in watch mode for continuous testing, automatically rerunning tests when changes are detected.\n\n```shell\nmocha -w\n```\n", + " Testing with `cds.test` > Class `cds.test.Test`\ncds.test, class, Test, programmatic API\nShows how to directly instantiate and use the cds.test.Test class for custom test setups, including running the test server inside a specific directory.\n\n```js\nconst { Test } = cds.test\nlet test = new Test\ntest.run().in(_dirname)\n```\n", + " Testing with `cds.test` > cds.test() {.method}\ncds.test, utility, test server, convenience\nDefines cds.test as a convenience factory function to create and run a Test instance, simplifying the process of starting a test server for each test file.\n\n```js\nconst { Test } = cds.test\ncds.test = (...args) => (new Test).run(...args)\n```\n", + " Testing with `cds.test` > .chai, ... {.property}\nchai, assertion, expect, setup\nInstalls the Chai assertion library with commonly used plugins for expect-based assertions in both Mocha and Jest CAP tests.\n\n```shell\nnpm add -D chai@4 chai-as-promised@7 chai-subset jest\n```\n", + " Testing with `cds.test` > .expect { .property}\nchai, expect, assertion\nDemonstrates using Chai's expect style for assertions within CAP Node.js tests, recommended for compatibility between Mocha and Jest.\n\n```js\nconst { expect } = cds.test(), foobar = {foo:'bar'}\nit('should support chai.except style', ()=>{\n expect(foobar).to.have.property('foo')\n expect(foobar.foo).to.equal('bar')\n})\n```\n", + " Testing with `cds.test` > .expect { .property}\nchai, expect, jest, assertion\nUsing Jest's global expect() assertions directly as an alternative to Chai's expect in CAP Node.js testing scenarios.\n\n```js\ncds.test()\nit('should use jest.expect', ()=>{\n expect({foo:'bar'}).toHaveProperty('foo')\n})\n```\n", + " Testing with `cds.test` > .assert { .property}\nchai, assert, assertion\nUsing Chai's assert style for assertions in CAP Node.js tests.\n\n```js\nconst { assert } = cds.test(), foobar = {foo:'bar'}\nit('should use chai.assert style', ()=>{\n assert.property(foobar,'foo')\n assert.equal(foobar.foo,'bar')\n})\n```\n", + " Testing with `cds.test` > .should { .property}\nchai, should, assertion\nDemonstrates the usage of Chai's should assertion style in CAP tests.\n\n```js\nconst { should } = cds.test(), foobar = {foo:'bar'}\nit('should support chai.should style', ()=>{\n foobar.should.have.property('foo')\n foobar.foo.should.equal('bar')\n should.equal(foobar.foo,'bar')\n})\n```\n", + " Testing with `cds.test` > .chai {.property}\nchai, plugin, setup\nProvides a getter for the Chai assertion library, pre-configured with the chai-subset and chai-as-promised plugins for extended assertion capabilities in CAP tests.\n\n```js\nget chai() {\n return require('chai')\n .use (require('chai-subset'))\n .use (require('chai-as-promised'))\n}\n```\n", + " Testing with `cds.test` > .axios {.property}\naxios, setup, dependency\nInstalls Axios as a development dependency to allow HTTP requests to be made within CAP tests.\n\n```shell\nnpm add -D axios\n```\n", + " Testing with `cds.test` > GET / PUT / POST ... {http-bound .method}\nHTTP, bound function, test helpers, GET, POST\nShows usage of bound HTTP helper methods provided by cds.test for concise HTTP API testing; supports tagged template strings for URLs as well.\n\n```js\nconst { GET, POST } = cds.test()\nconst { data } = await GET('/browse/Books')\nawait POST('/browse/submitOrder',\n { book:201, quantity:1 },\n { auth: { username: 'alice' }}\n)\n```\n", + " Testing with `cds.test` > test. get/put/post/...() {http-methods .method}\naxios, test helpers, HTTP methods, GET, POST\nUtilizes the underlying Axios instance methods provided by the test object for making HTTP requests to endpoints of the running CAP test server.\n\n```js\nconst test = cds.test() //> served at localhost with an arbitrary port\nconst { data } = await test.get('/browse/Books')\nawait test.post('/browse/submitOrder',\n { book:201, quantity:1 },\n { auth: { username: 'alice' }}\n)\n```\n", + " Testing with `cds.test` > test .data .reset() {.method}\ntest data, database, reset, test lifecycle\nUses the bound reset method to reset and redeploy the database automatically before each test case, ensuring state isolation in tests.\n\n```js\nconst { test } = cds.test()\nbeforeEach (test.data.reset)\n```\n", + " Testing with `cds.test` > test .data .reset() {.method}\ntest data, database, reset, test lifecycle\nExplicitly resets test data with await inside a beforeEach hook, for more flexible or additional logic around database resets between tests.\n\n```js\nbeforeEach (async()=>{\n await test.data.reset()\n //...\n})\n```\n", + " Testing with `cds.test` > test. log() {.method}\nlogging, test log, capture, console output\nShows how to use cds.test.log() to capture console output within test scopes, clear logs, and release capture. Useful for testing logging behavior.\n\n```js\ndescribe('cds.test.log()', ()=>{\n let log = cds.test.log()\n\n it ('should capture log output', ()=>{\n expect (log.output.length).to.equal(0)\n console.log('foo',{bar:2})\n expect (log.output.length).to.be.greaterThan(0)\n expect (log.output).to.contain('foo')\n })\n\n it('should support log.clear()', ()=> {\n log.clear()\n expect (log.output).to.equal('')\n })\n\n it('should support log.release()', ()=> {\n log.release() // releases captured log\n console.log('foobar') // not captured\n expect (log.output).to.equal('')\n })\n})\n```\n", + " Testing with `cds.test` > test. run (...) {.method}\ncds.test, programmatic API, test server, run\nTwo equivalent ways to launch the CAP test server. The run method creates and starts a new Test instance with the provided arguments.\n\n```js\ncds.test(...)\n// or\n'test = new cds.test.Test().run(...)'\n```\n", + " Testing with `cds.test` > test. run (...) {.method}\ncds.test, CLI, serve, custom service\nShows how to start a specific service or file when spinning up a test server using the 'serve' command.\n\n```js\ncds.test('serve','srv/cat-service.cds')\ncds.test('serve','CatalogService')\n```\n", + " Testing with `cds.test` > test. run (...) {.method}\ncds.test, project structure, test in folder, custom root\nStarts the test server for a specific service file and sets the working directory as the root, allowing context-sensitive testing against different application folders.\n\n```js\ncds.test('serve','srv/cat-service.cds').in('/cap/samples/bookshop')\n```\n", + " Testing with `cds.test` > test. run (...) {.method}\ncds.test, project structure, test in folder, custom root\nA shortcut to start a CAP test server in a specific directory, equivalent to running cds.test().in(target_folder), for quick tests in sample projects.\n\n```js\ncds.test('/cap/samples/bookshop')\n```\n", + " Testing with `cds.test` > test. in (folder, ...) {.method}\ncds.test, project structure, test in folder, custom root\nSafely sets the cds.root context to the specified folder, usually combined with running tests or loading configuration from the project structure.\n\n```js\ncds.test.in(__dirname)\n```\n", + " Testing with `cds.test` > `CDS_TEST_ENV_CHECK`\nenvironment, CDS_TEST_ENV_CHECK, debug, cds.env\nEnables environment checking for correct loading of cds.env in tests, helping to detect hard-to-debug environment/configuration issues.\n\n```shell\nCDS_TEST_ENV_CHECK=y jest cds.test.test.js\n```\n", + " Testing with `cds.test` > `CDS_TEST_ENV_CHECK`\nenvironment, CDS_TEST_ENV_CHECK, execution order\nEnsures correct execution order so that the test server is started and cds.env is loaded from the right folder before accessing any global services or configuration.\n\n```js\ncds.test(__dirname) //> always should go first\n// anything else goes after that:\ncds.env.fiori.lean_draft = true // [!code ++]\nclass MyService extends cds.Service {} // [!code ++]\n```\n", + " Testing with `cds.test` > Best Practices > Check Status Codes Last\nbest practices, status code, error handling, HTTP, expect\nBest practice snippet showing how to assert on HTTP status codes after asserting on the response data, leading to better error diagnostics in tests.\n\n```js\nconst { data, status } = await GET `/catalog/Books`\nexpect(status).to.equal(200) //> DON'T do that upfront // [!code --]\nexpect(data).to.equal(...) //> do this to see what's wrong\nexpect(status).to.equal(200) //> Do it at the end, if at all // [!code ++]\n```\n", + " Testing with `cds.test` > Best Practices > Minimal Assumptions\nbest practices, error handling, minimal assertion, expect\nPreferred style for asserting on expected error messages using regular expressions, to make tests robust against changes in error text formatting.\n\n```js\nawait expect(POST(`/catalog/Books`,...)).to.be.rejectedWith(\n /readonly/i\n)\n```\n", + " Testing with `cds.test` > Best Practices > Keep Test Code Environment Agnostic\ntest code, environment-agnostic, best practices\nAdvocates for keeping environment setup outside of test files to ensure reusable and isolated tests, delegating such configuration to CI/CD scripts.\n\n```js\ndescribe(() => { cds.test(...) })\n// NO service bindings, env. variables, profiles, etc. here\n```\n", + " Testing with `cds.test` > Using `cds.test` in REPL\nREPL, interactive shell, cds.test\nShows how to start the CAP test environment programmatically in the Node.js REPL (via cds repl), enabling interactive experimentation with a running CAP server.\n\n```js\nvar test = await cds.test('bookshop')\n```\n", + " Testing with `cds.test` > Using `cds.test` in REPL\nsql, js, REPL, SELECT, querying\nExecutes a SELECT query in the CAP REPL environment, verifying the presence of books whose authors' names match a pattern. Useful for interactive and integration test scenarios.\n\n```js\nawait SELECT `title` .from `Books` .where `exists author[name like '%Poe%']`\n```\n", + " Testing with `cds.test` > Using `cds.test` in REPL\nREPL, service API, read, querying\nReads book titles and authors from a service API in the REPL environment, illustrating programmatic testing and interaction with the CAP runtime for manual exploration or debugging.\n\n```js\nvar { CatalogService } = cds.services\nawait CatalogService.read `title, author` .from `ListOfBooks`\n```\n", + " Best Practices > Managing Dependencies > Always Use the _Latest Minor_ Releases\ndependencies, package.json, npm, versioning, best practices\nDemonstrates package.json dependencies using the caret (^) to specify the latest minor versions for both SAP and open source packages. This practice allows receiving feature and security updates automatically and leverages npm's deduplication for minimal bundle sizes.\n\n```json\n\"dependencies\": {\n \"@sap/cds\": \"^9.1.0\",\n \"@sap/some-reuse-package\": \"^1.1.0\",\n \"express\": \"^4.17.0\"\n}\n```\n", + " Best Practices > Managing Dependencies > Keep Open Ranges When *Publishing* for Reuse > Bad\ndependencies, package.json, reuse, bad example, exact versions\nShows a bad practice for reusable packages: declaring exact versions for dependencies. This leads to duplicate dependencies, inhibits receiving fixes, and makes model sharing impossible when consumed in other projects.\n\n```json\n\"name\": \"@sap/your-reuse-package\",\n\"version\": \"1.1.2\",\n\"dependencies\": {\n \"@sap/cds\": \"3.0.3\",\n \"@sap/foundation\": \"2.0.1\",\n \"express\": \"4.16.3\"\n}\n```\n", + " Best Practices > Managing Dependencies > Lock Dependencies Before *Deploying*\ndependencies, npm, deployment, package-lock.json, best practices\nOutlines the recommended steps before deploying CAP applications: ensure package-lock.json is enabled, update dependencies, and add the lock file to version control. This practice guarantees a reproducible deployment matching your tested environment.\n\n```shell\nnpm config set package-lock true # enables package-lock.json\nnpm update # update it with latest versions\ngit add package-lock.json # add it to version control\n```\n", + "Securing Your Application\nexpress, security, middleware, helmet, bootstrap, Node.js, cds server, example\nShows how to apply security best practices by mounting the 'helmet' Express middleware during the CAP bootstrapping phase. This is implemented in a local server.js file, and is recommended for securing Node.js applications built with CAP.\n\n```js\n// local ./server.js\nconst cds = require('@sap/cds')\nconst helmet = require('helmet')\n\ncds.on('bootstrap', app => {\n app.use(helmet())\n})\n\nmodule.exports = cds.server // > delegate to default server.js\n```\n", + "Securing Your Application > Content Security Policy (CSP)\nhelmet, Content Security Policy, CSP, express, Node.js, security, customization\nCustomizes the Content Security Policy (CSP) using helmet's CSP middleware during CAP app bootstrapping. Allows extending or overriding the default CSP directives for enhanced security.\n\n```js\ncds.on('bootstrap', app => {\n app.use(\n helmet({\n contentSecurityPolicy: {\n directives: {\n ...helmet.contentSecurityPolicy.getDefaultDirectives()\n // custom settings\n }\n }\n })\n )\n})\n```\n", + "Securing Your Application > Cross-Site Request Forgery (CSRF) Token > Manual Implementation\ncsrf, security, express, cookie-parser, manual implementation, App Router, backend, Node.js\nImplements manual CSRF token handling for Express in CAP apps. Protects endpoints by requiring a CSRF token, sets appropriate cache-control headers, and handles token errors by responding with status 403 and appropriate headers. Shows use of csurf, cookie-parser, and error handling middleware.\n\n```js\nconst csrfProtection = csrf({ cookie: true })\nconst parseForm = express.urlencoded({ extended: false })\n\ncds.on('bootstrap', app => {\n app.use(cookieParser())\n\n // Must: Provide actual s of served services.\n // Optional: Adapt for non-Fiori Elements UIs.\n .head('/', csrfProtection, (req, res) => {\n res.set({\n 'X-CSRF-Token': req.csrfToken(),\n 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate'\n }).send()\n })\n\n // Must: Provide actual s of served services.\n // Optional: Adapt for non-Fiori Elements UIs.\n .post('//$batch', parseForm, csrfProtection, (req, res, next) => next())\n\n .use((err, req, res, next) => {\n if (err.code !== 'EBADCSRFTOKEN') return next(err)\n res.status(403).set('X-CSRF-Token', 'required').send()\n })\n})\n```\n", + "Securing Your Application > Cross-Origin Resource Sharing (CORS) > Custom CORS Implementation\nCORS, Cross-Origin Resource Sharing, express, Node.js, security, custom implementation\nCustom CORS implementation for Express/CAP server. Restricts allowed origins and handles preflight (OPTIONS) requests with appropriate 'access-control-allow-methods' headers. Intended for production use for managing which domains can access the API.\n\n```js\nconst ORIGINS = { 'https://example.com': 1 }\ncds.on('bootstrap', app => app.use ((req, res, next) => {\n if (req.headers.origin in ORIGINS) {\n res.set('access-control-allow-origin', req.headers.origin)\n if (req.method === 'OPTIONS') // preflight request\n return res.set('access-control-allow-methods', 'GET,HEAD,PUT,PATCH,POST,DELETE').end()\n }\n next()\n})\n```\n", + "Availability Checks > Anonymous Ping\nhealth check, availability, monitoring, /health endpoint, express, cds server\nOverrides the default /health endpoint for availability monitoring in a CAP Node.js server. Responds with a plain text message and HTTP status 200. Allows customizing the health check route as needed.\n\n```js\ncds.on('bootstrap', app => app.get('/health', (_, res) => {\n res.status(200).send(`I'm fine, thanks.`)\n}))\n```\n", + "Error Handling > Don't Hide Origins of Errors\nerror handling, Error augmentation, re-throw, exception, best practice, Node.js\nShows the best practice for handling exceptions in Node.js: augment the error with additional context but re-throw the same error object, preserving the stack trace and original details.\n\n```js\ntry {\n // something\n} catch (e) {\n // augment instead of replace details\n e.message = 'Oh no! ' + e.message\n e.additionalInfo = 'This is just an example.'\n // re-throw same object\n throw e\n}\n```\n", + "Timestamps\ntimestamps, req.timestamp, managed dates, Node.js, CAP, CDS, Date handling\nDemonstrates usage of req.timestamp property in CAP service handlers to set managed dates/timestamps using a consistent Date instance per request, improving reliability in update or audit scenarios.\n\n```js\nsrv.before(\"UPDATE\", \"EntityName\", (req) => {\n const now = req.timestamp;\n req.data.createdAt = now;\n});\n```\n", + "Custom Streaming \nCDS, media data, custom streaming, stream.Readable, content disposition, Node.js, response headers\nServes media data (e.g., images) for entity 'Books' in a CAP service read handler. Uses req.reply with a Readable stream and content metadata such as mimetype and filename, controlling response headers.\n\n```js\nsrv.on('READ', 'Books', (req, next) => {\n req.reply(myReadable, {\n mimetype: 'image/jpeg', // > optional\n filename: 'cover.jpg', // > optional\n })\n})\n```\n", + "Custom Streaming \nCDS, media data, stream.Readable, content disposition, Node.js, response headers, alternative\nAlternative approach for streaming custom media data in a CAP service, directly assigning mimetype and filename properties to a stream.Readable instance within a handler for custom response headers.\n\n```js\nsrv.on('READ', 'Books', (req, next) => {\n if (coverImageIsRequested) {\n return Object.assign(myReadable, {\n mimetype: 'image/jpeg', // > optional\n filename: 'cover.jpg', // > optional\n })\n }\n return next()\n})\n```\n", + "Custom Streaming \nCDS, media data, compatibility, stream.Readable, content disposition, Node.js\nServes a media response object for compatibility, specifying the content type and content disposition alongside the stream value. Used in custom CDS function on-handlers, especially where explicit headers are needed.\n\n```js\nsrv.on('getCoverImageFunction', 'Books', (req) => {\n return {\n value: myReadable,\n $mediaContentType: 'image/jpeg',\n $mediaContentDispositionFilename: 'cover.jpg', // > optional\n $mediaContentDispositionType: 'inline' // > optional\n }\n})\n```\n", + "Custom Streaming \nCDS, media data, custom headers, Node.js, streaming, response headers\nDemonstrates manually setting HTTP headers for content-type and content-disposition before returning a custom stream in a CAP unbound action handler. Allows explicit control over streaming response headers.\n\n```js\nsrv.on('unboundAction', (req) => {\n cds.context.http?.res.setHeader('content-type', 'image/jpeg')\n cds.context.http?.res.setHeader('content-disposition', 'inline; filename=\"cover.jpg\"')\n\n return myReadable\n})\n```\n", + "Custom $count\nCDS, custom $count, odata, READ handler, list count, Node.js\nImplements support for custom $count requests in a CAP READ on-handler. Handles both direct '/$count' and query parameter-based cases, ensuring correct OData response for entity set size queries.\n\n```js\nsrv.on('READ', 'Books', function (req) {\n // simple '/$count' request\n if (req.query.SELECT.columns?.length === 1 && req.query.SELECT.columns[0].as === '$count')\n return [{ $count: 100 }]\n // support other '/$count' requests\n ...\n\n const resultSet = [ ... ]\n\n // request contains $count=true \n if (req.query.SELECT.count === true) resultSet.$count = 100\n\n return resultSet\n})\n```\n", + "Custom Streaming \ncds, Core.MediaType, media data, csv, action, function, annotation, CDS modeling\nCDS model declaration with action 'csvExport' that returns media data of type LargeBinary, annotated for CSV export and with a specific MIME type and filename using Core.MediaType and ContentDisposition annotations.\n\n```cds\n@(Core.MediaType: 'text/csv', Core.ContentDisposition.Filename: 'Books.csv')\ntype csv: LargeBinary;\nentity Books { ... } actions {\n function csvExport () returns csv;\n}\n```\n", + "Custom Streaming \ncds, media data, function, annotation, Core.MediaType\nDefines a CDS function for exporting media data with an inline Core.MediaType annotation, specifying the data will be served with an appropriate MIME type.\n\n```cds\nfunction csvExport () returns @Core.MediaType LargeBinary;\n```\n", + " Getting Started > Setting Up Local Development\nverify, cds toolkit, Java, Maven, CLI, setup\nVerifies that CDS tools, Java (at least version 17), and Maven (at least version 3.6.3) are correctly installed and available in your environment for CAP Java development.\n\n```shell\ncds --version\njava --version\nmvn --version\n```\n", + " Getting Started > Starting a New Project > Run the Maven Archetype\nproject setup, Maven, init, CAP Java, CLI\nBootstraps a new CAP Java project using the CAP Java Maven archetype. This generates a new Maven-based project structure and prompts you for the group ID and artifact ID.\n\n```shell\nmvn archetype:generate -DarchetypeArtifactId=\"cds-services-archetype\" -DarchetypeGroupId=\"com.sap.cds\" -DarchetypeVersion=\"RELEASE\" -DinteractiveMode=true\n```\n", + " Getting Started > Starting a New Project > Run the Maven Archetype\nproject setup, cds toolkit, init, CAP Java, CLI\nInitializes a new CAP Java project using the CDS CLI. The placeholder specifies the root directory name. Afterwards, switch to the created directory before proceeding.\n\n```shell\ncds init --java\n```\n", + " Getting Started > Starting a New Project > Add a Sample CDS Model\ncds modeling, samples, Maven, CLI, cds-maven-plugin\nAdds a sample CDS model to your CAP Java project using the CDS Maven plugin. Run this command from your project root to generate an example domain model for quick evaluation.\n\n```shell\nmvn com.sap.cds:cds-maven-plugin:add -Dfeature=TINY_SAMPLE\n```\n", + " Getting Started > Starting a New Project > Add CloudFoundry target platform\nconfiguration, Cloud Foundry, Maven, cds-maven-plugin, platform support, pom.xml\nEnhances a CAP Java project with Cloud Foundry as a deployment target. This adds the necessary dependencies for Cloud Foundry support using the CDS Maven plugin.\n\n```shell\nmvn com.sap.cds:cds-maven-plugin:add -Dfeature=CF\n```\n", + " Getting Started > Starting a New Project > Add CloudFoundry target platform\nconfiguration, Cloud Foundry, pom.xml, dependencies\nDependency snippet added to pom.xml to enable Cloud Foundry support in your CAP Java project. This is automatically inserted by the previous Maven command.\n\n```xml\n\n\tcom.sap.cds\n\tcds-starter-cloudfoundry\n\n```\n", + " Getting Started > Starting a New Project > Project Layout\nproject structure, scaffolding, CAP Java\nLayout of the generated CAP Java project showing the main folders for database artifacts, service code, generated sources, and dependencies.\n\n```txt\n/\n├─ db/\n└─ srv/\n ├─ src/main/java/\n ├─ src/gen/java/\n └─ node_modules/\n```\n", + " Getting Started > Starting a New Project > Add an Integration Test Module (Optional)\ntesting, Maven, integration tests, cds-maven-plugin, project structure\nAdds a new Maven module to your CAP Java project for integration testing. This creates an integration-tests folder with example test classes in src/test/java.\n\n```shell\nmvn com.sap.cds:cds-maven-plugin:add -Dfeature=INTEGRATION_TEST\n```\n", + " Getting Started > Starting a New Project > Build and Run\nbuild, run server, Maven, Spring Boot, CLI\nBuilds and runs the CAP Java project using Spring Boot. This launches the application locally on http://localhost:8080.\n\n```shell\nmvn spring-boot:run\n```\n", + " Getting Started > Starting a New Project > Source Path Configuration and CDS build\ncompilation, IDE, Maven, Java, generated sources\nRuns a full build of your CAP Java project, including CDS model compilation, code generation, and Java compilation. Necessary to resolve missing generated files in IDEs.\n\n```shell\nmvn compile\n```\n", + " Versions & Dependencies > Maintain Dependencies > Consistent Versions\nmaven, BOM, dependencies, bill of material, consistent versions, CAP Java, Cloud SDK, SAP Cloud Security, pom.xml\nThis snippet shows how to import BOM (Bill of Material) poms for com.sap.cds, com.sap.cloud.sdk, and com.sap.cloud.security into your project's parent pom.xml file using Maven's . This ensures consistent versioning for all artifacts provided by these SDKs in CAP Java projects.\n\n```xml\n\n\t\n\t\t\n\t\t\n\t\t\tcom.sap.cds\n\t\t\tcds-services-bom\n\t\t\t${cds.services.version}\n\t\t\tpom\n\t\t\timport\n\t\t\n\n\t\t\n\t\t\n\t\t\tcom.sap.cloud.sdk\n\t\t\tsdk-modules-bom\n\t\t\t${cloud.sdk.version}\n\t\t\tpom\n\t\t\timport\n\t\t\n\n\t\t\n\t\t\n\t\t\tcom.sap.cloud.security\n\t\t\tjava-bom\n\t\t\t${xsuaa.version}\n\t\t\tpom\n\t\t\timport\n\t\t\n\t\n\n```\n", + " Versions & Dependencies > Maintain Dependencies > Update Versions\nmaven, update, dependency, pom.xml, versions\nThis Maven pom.xml snippet demonstrates how to explicitly specify a dependency version in your application's dependencyManagement section. It can be used to override a transitive dependency version, for example to resolve a security vulnerability before an upstream fix is released.\n\n```xml\n\n […]\n \n \n \n \n \n\n```\n", + " Working with CDS Models > The CDS Model\nJava, CDS model, EventContext, dependency injection, model reflection, Spring\nShows two ways to obtain the CdsModel in CAP Java: (1) from the EventContext within an event handler, and (2) via dependency injection in a Spring context.\n\n```java\nimport com.sap.cds.services.handler.annotations.On;\nimport com.sap.cds.services.EventContext;\nimport com.sap.cds.reflect.CdsModel;\n\n@On(event = \"READ\", entity = \"CatalogService.Books\")\npublic void readBooksVerify(EventContext context) {\n CdsModel model = context.getModel();\n ...\n}\n\n// or, in Spring, be injected:\n\n@Autowired\nCdsModel model;\n```\n", + " Working with CDS Models > The CDS Model\nCDS model, Java, InputStream, CSN, model reflection\nDemonstrates reading a CDS model programmatically from a CSN InputStream, bypassing the context-based approaches.\n\n```java\nInputStream csnJson = ...;\nCdsModel model = CdsModel.read(csnJson);\n```\n", + " Working with CDS Models > Examples\ncds modeling, domain model, Books, Authors, Orders, sample\nSample CDS model defining Books, Authors, and Orders entities, used for demonstration of reflection API usage.\n\n```cds\nnamespace my.bookshop;\n\nentity Books {\n title : localized String(111);\n author : Association to Authors;\n ...\n}\n\nentity Authors {\n key ID : Integer;\n ...\n}\n\nentity Orders {\n OrderNo : String @title:'Order Number';\n ...\n}\n```\n", + " Working with CDS Models > Examples > Get and Inspect an Element of an Entity\nCDS model, Java, element, type, inspect, reflection\nExample of Java reflection for a CDS entity element: checks key status, localization, simple type details, and access to meta-properties like length.\n\n```java\nCdsEntity books = model.getEntity(\"my.bookshop.Books\");\nCdsElement title = books.getElement(\"title\");\n\nboolean key = title.isKey(); // false\nboolean localized = title.isLocalized(); // true\nCdsType type = title.getType(); // CdsSimpleType\n\nif (type.isSimple()) { // true\n CdsSimpleType simple = type.as(CdsSimpleType.class);\n\n String typeName = simple.getQualifiedName(); // \"cds.String\"\n CdsBaseType baseType = simple.getType(); // CdsBaseType.STRING\n Class javaType = simple.getJavaType(); // String.class\n Integer length = simple.get(\"length\"); // 111\n}\n```\n", + " Working with CDS Models > Examples > Get and Inspect All Elements of an Entity\nCDS model, Java, elements, stream\nRetrieves all elements of a CDS entity as a stream; order is stable on repeated reads but not guaranteed to match CSN source.\n\n```java\nCdsEntity books = model.getEntity(\"my.bookshop.Books\");\nStream elements = books.elements();\n```\n", + " Working with CDS Models > Examples > Get and Inspect an Association Element of an Entity\nCDS model, Java, association, inspect, reflection, Cardinality\nAnalyzes a CDS association, retrieves its target entity, checks type (association/composition), extracts cardinality, and keys of the association.\n\n```java\nCdsElement authorElement = book.getAssociation(\"author\");\nCdsAssociationType toAuthor = authorElement.getType();\n\nCdsEntity author = toAuthor.getTarget(); // Entity: my.bookshop.Authors\nboolean association = toAuthor.isAssociation(); // true\nboolean composition = toAuthor.isComposition(); // false\n\nCardinality cardinality = toAuthor.getCardinality();\nString sourceMax = cardinality.getSourceMax(); // \"*\"\nString targetMin = cardinality.getTargetMin(); // \"0\"\nString targetMax = cardinality.getTargetMax(); // \"1\"\n\nStream keys = toAuthor.keys(); // Stream: [ ID ]\nOptional onCondition = toAuthor.onCondition(); // empty\n```\n", + " Working with CDS Models > Examples > Find an Annotation by Name and Get Its Value\nCDS model, Java, annotation, read annotation, OrderNo\nReads a specific annotation (title) on a CDS entity element and uses its value or falls back to the element name.\n\n```java\nCdsEntity order = model.getEntity(\"my.bookshop.Orders\");\nCdsElement orderNo = order.getElement(\"OrderNo\");\n\nOptional> annotation = orderNo\n .findAnnotation(\"title\");\nString displayName = annotation.map(CdsAnnotation::getValue)\n .orElse(orderNo.getName()); // \"Order Number\"\n```\n", + " Working with CDS Models > Examples > Filter a Stream of Entities by Namespace\nCDS model, Java, namespace, filter, stream\nFilters a stream of CDS entities to include only those from a particular namespace using a static predicate utility.\n\n```java\nimport static com.sap.cds.reflect.CdsDefinition.byNamespace;\n...\nStream entities = model.entities()\n .filter(byNamespace(\"my.bookshop\"));\n```\n", + " Working with CDS Models > Examples > Get All Elements with Given Annotation\nCDS model, Java, annotation, filter, stream\nShows how to filter a stream of elements in a CDS entity to only those that have a certain annotation, using a provided static predicate.\n\n```java\nimport static com.sap.cds.reflect.CdsAnnotatable.byAnnotation;\n...\nCdsEntity order = model.getEntity(\"my.bookshop.Orders\");\nStream elements = order.elements()\n .filter(byAnnotation(\"title\"));\n```\n", + " Working with CDS Models > Feature Toggles > Feature Toggles and Active Feature Set > From Mock User Configuration\nfeature toggles, Spring, mock user, application.yaml, yaml, features, user\nYAML configuration for CAP Java that assigns feature toggles to mock users to simulate feature availability during development/testing.\n\n```yaml\ncds:\n security:\n mock:\n users:\n - name: Bob\n tenant: CrazyCars\n features:\n - wobble\n - name: Alice\n tenant: SmartCars\n features:\n - cruise\n - parking\n```\n", + " Working with CDS Models > Feature Toggles > Feature Toggles and Active Feature Set > Custom Implementation\nfeature toggles, Java, custom provider, role-based, Spring, FeatureTogglesInfoProvider\nImplements a custom FeatureTogglesInfoProvider to assign features based on user role. Used in Spring as a component, allowing per-request feature availability logic.\n\n```java\n@Component\npublic class DemoFTProvider implements FeatureTogglesInfoProvider {\n @Override\n public FeatureTogglesInfo get(UserInfo userInfo, ParameterInfo paramInfo) {\n Map featureToggles = new HashMap<>();\n if (userInfo.hasRole(\"expert\")) {\n featureToggles.put(\"isbn\", true);\n }\n return FeatureTogglesInfo.create(featureToggles);\n }\n}\n```\n", + " Working with CDS Models > Feature Toggles > Feature Toggles and Active Feature Set > Defining Feature Toggles for Internal Service Calls\nfeature toggles, Java, thread, request context, runtime, manual, FeatureTogglesInfo\nShows how to define feature toggles explicitly on a manually created request context, e.g., when running code in a new thread outside the scope of the main request.\n\n```java\n@Autowired\nCdsRuntime runtime;\n\n@Autowired\nPersistenceService db;\n\nFeatureTogglesInfo isbn = FeatureTogglesInfo.create(Collections.singletonMap(\"isbn\", true));\n\n...\n\nFuture result = Executors.newSingleThreadExecutor().submit(() -> {\n return runtime.requestContext().featureToggles(isbn).run(rc -> {\n return db.run(Select.from(Books_.CDS_NAME));\n });\n});\n```\n", + " Working with CDS Models > Feature Toggles > Using Feature Toggles in Custom Code\nfeature toggles, Java, RequestContext, EventContext, custom code, isEnabled\nChecks in custom code whether a feature is active using FeatureTogglesInfo, and conditionally executes logic depending on the toggle status.\n\n```java\n@After\nprotected void subtractDiscount(CdsReadEventContext context) {\n if (context.getFeatureTogglesInfo().isEnabled(\"discount\")) {\n // Custom coding executed when feature \"discount\" is active\n // ...\n }\n}\n```\n", + " Working with CDS Data > Structured Data\ncds modeling, samples, entity, association, composition, aspect\nSample CDS model demonstrating bidirectional associations and compositions between Books, Authors, Orders, OrderHeaders, and the use of managed aspects for OrderItems. Used to illustrate structured data and relationships in CAP Java.\n\n```cds\nentity Books {\n key ID : Integer;\n title : String;\n author : Association to one Authors;\n}\n\nentity Authors {\n key ID : Integer;\n name : String;\n books : Association to many Books on books.author = $self;\n}\n\nentity Orders {\n key ID : Integer;\n header : Composition of one OrderHeaders;\n items : Composition of many OrderItems;\n}\n\nentity OrderHeaders {\n key ID : Integer;\n status : String;\n}\n\naspect OrderItems {\n key ID : Integer;\n book : Association to one Books;\n}\n```\n", + " Working with CDS Data > Entities and Structured Types\nstructured data, entity, java, Map\nJava code to construct a simple entity (Book) as a Map mirroring its JSON structure. Shows basic population of entity attributes for use in CAP Java.\n\n```java\nMap book = new HashMap<>();\nbook.put(\"ID\", 97);\nbook.put(\"title\", \"Dracula\");\n```\n", + " Working with CDS Data > Nested Structures and Associations\nstructured data, nested, association, java, Map, CdsData\nConstructs nested data for a Book entity referencing an Author entity via a map, illustrating how associations are represented in Java maps within CAP.\n\n```java\nMap author = new HashMap<>();\nauthor.put(\"ID\", 23);\nauthor.put(\"name\", \"Bram Stoker\");\n\nMap book = new HashMap<>();\nbook.put(\"ID\", 97);\nbook.put(\"author\", author);\n```\n", + " Working with CDS Data > Nested Structures and Associations\nstructured data, nested, association, CdsData, convenience API\nShows using CdsData and the putPath method to construct nested data and associations with path notation. Enables convenient, null-safe creation of deeply structured objects.\n\n```java\nCdsData book = Struct.create(CdsData.class);\nbook.put(\"ID\", 97);\nbook.putPath(\"author.ID\", 23);\nbook.putPath(\"author.name\", \"Bram Stoker\");\n```\n", + " Working with CDS Data > Nested Structures and Associations\nstructured data, nested, association, generated accessor interface\nDemonstrates use of generated accessor interfaces (Authors and Books) for constructing structured entities with associations. Provides typed, code-completion-friendly data access in CAP Java.\n\n```java\nAuthors author = Authors.create();\nauthor.setId(23);\nauthor.setName(\"Bram Stoker\");\nBooks book = Books.create();\nbook.setId(97);\nbook.setAuthor(author);\n```\n", + " Working with CDS Data > Nested Structures and Associations\nstructured data, association, to-many, java, List\nRepresents a to-many association (Author with many Books) using a List>. Illustrates JSON-to-Java construction of nested collections for associations in CAP Java.\n\n```java\nMap book1 = new HashMap<>();\nbook1.put(\"ID\", 97);\nbook1.put(\"title\", \"Dracula\");\n\nMap book2 = new HashMap<>();\nbook2.put(\"ID\", 98);\nbook2.put(\"title\", \"Miss Betty\");\n\nMap author = new HashMap<>();\nauthor.put(\"ID\", 23);\nauthor.put(\"name\", \"Bram Stoker\");\nauthor.put(\"books\", Arrays.asList(book1, book2));\n```\n", + " Working with CDS Data > CDS Data\nCdsData, struct, accessor, interface, conversion\nConverts an existing Map to a CdsData interface using Struct.access, allowing CAP Java convenience methods on arbitrary maps.\n\n```java\nMap map = new HashMap<>();\nCdsData data = Struct.access(map).as(CdsData.class);\n```\n", + " Working with CDS Data > CDS Data\nCdsData, struct, create, initialization\nCreates an empty CdsData map using Struct.create for straightforward data manipulation and path access in CAP Java.\n\n```java\nCdsData data = Struct.create(CdsData.class);\n```\n", + " Working with CDS Data > Path Access\nCdsData, putPath, nested, path access\nDemonstrates using putPath to create or update nested structure ('author' -> 'name') in CdsData. Automatically creates intermediate maps as needed. Useful for handling deeply nested entity data.\n\n```java\ndata.putPath(\"author.name\", \"Bram Stoker\");\n```\n", + " Working with CDS Data > Path Access\nCdsData, getPath, nested, read path\nReads a nested value (e.g., author name) from structured data using CdsData's getPath method in CAP Java.\n\n```java\nString authorName = data.getPath(\"author.name\");\n```\n", + " Working with CDS Data > Path Access\nCdsData, containsPath, nested, check path\nChecks if a nested property exists in a CdsData object using containsPath for convenient validation.\n\n```java\nboolean b = data.containsPath(\"author.name\");\n```\n", + " Working with CDS Data > Path Access\nCdsData, removePath, nested, remove\nRemoves a nested path from CdsData while also cleaning up empty nested maps. Supports deep structural modifications.\n\n```java\nString authorName = data.removePath(\"author.name\");\n```\n", + " Working with CDS Data > Serialization\nserialization, CdsData, toJson, debugging, nested\nExemplifies serialization of CdsData to JSON using toJson(), handy for debugging and logging structured/nested CAP Java data.\n\n```java\nCdsData person = Struct.create(CdsData.class);\nperson.put(\"salutation\", \"Mr.\");\nperson.putPath(\"name.first\", \"Frank\"); // path access\n\nperson.toJson(); // { \"salutation\" : \"Mr.\", name : { \"first\" : \"Frank\" } }\n```\n", + " Working with CDS Data > Vector Embeddings\nvector embeddings, cds.Vector, CdsVector, float[], string, SAP GenAI Hub, LangChain4j\nShows how to create vector embeddings in CAP Java as CdsVector objects, supporting float[] or JSON string representations for AI features such as semantic search.\n\n```java\nfloat[] embedding = embeddingModel.embed(bookDescription).content().vector();\n\nCdsVector v1 = CdsVector.of(embedding); // float[] format\nCdsVector v2 = CdsVector.of(\"[0.42, 0.73, 0.28, ...]\"); // String format\n```\n", + " Working with CDS Data > Vector Embeddings\nvector embeddings, CQL, similarity search, cosineSimilarity, query\nPerforms a semantic similarity search using vector embeddings in a CQL query with cosineSimilarity. Returns books with high similarity to a given embedding.\n\n```java\nCqnVector v = CQL.vector(embedding);\n\nResult similarBooks = service.run(Select.from(BOOKS).where(b ->\n CQL.cosineSimilarity(b.embedding(), v).gt(0.9))\n);\n```\n", + " Working with CDS Data > Vector Embeddings\nvector embeddings, CQL, parameterized query\nShows how to pass vector parameters into CQL queries for similarity computations, useful for AI/semantic queries in CAP Java.\n\n```java\nvar similarity = CQL.cosineSimilarity(CQL.get(Books.EMBEDDING), CQL.param(0).type(VECTOR));\n\nCqnSelect query = Select.from(BOOKS)\n .columns(b -> b.title(), b -> similarity.as(\"similarity\"))\n .where(b -> b.ID().ne(bookId).and(similarity.gt(0.9)))\n .orderBy(b -> b.get(\"similarity\").desc());\n\nResult similarBooks = db.run(select, CdsVector.of(embedding));\n```\n", + " Working with CDS Data > Vector Embeddings\nvector embeddings, CQL, select list, explicit select\nIllustrates explicit selection of vector embedding field in a query; vector fields in CAP Java must be added explicitly to select lists.\n\n```java\nCdsVector embedding = service.run(Select.from(BOOKS).byId(101)\n .columns(b -> b.embedding())).single(Books.class).getEmbedding();\n```\n", + " Working with CDS Data > Data in CDS Query Language (CQL) > Deep Inserts through Compositions and Cascading Associations\ndeep insert, composition, Insert, Order, header, cascade\nDemonstrates how to construct a deep insert with compositions (Order and OrderHeader) where new related entities are created and inserted in one operation in CAP Java.\n\n```java\nOrderHeaders header = OrderHeaders.create();\nheader.setId(11);\nheader.setStatus(\"open\");\n\nOrders order = Orders.create();\norder.setId(1);\norder.setHeader(header);\n\nInsert insert = Insert.into(ORDERS).entry(order);\n```\n", + " Working with CDS Data > Data in CDS Query Language (CQL) > Setting Managed Associations to Existing Target Entities\nmanaged association, insert, flat, association to existing, Books, Authors\nHow to insert a book and set its managed association to an existing Author. Only association keys are provided; useful for flat inserts not cascading over associations.\n\n```java\nAuthors author = Authors.create();\nauthor.setId(100);\n\nBooks book = Books.create();\nbook.setId(101);\nbook.setAuthor(author);\n\nInsert insert = Insert.into(BOOKS).entry(book);\n```\n", + " Working with CDS Data > Data in CDS Query Language (CQL) > Inserts through Compositions via Paths\ncomposition, insert, path expression, OrderItems\nDemonstrates adding a child entity via a path expression through a composition, specifically inserting an order item for a given order by its Id.\n\n```java\nOrderItems orderItem = OrderItems.create();\norderItem.setId(1);\norderItem.putPath(\"book.ID\", 201); // set association to book 201\n\nInsert.into(ORDERS, o -> o.filter(o.Id().eq(100)).items())\n .entry(orderItem);\n```\n", + " Working with CDS Data > Data in CDS Query Language (CQL) > Select Managed Associations\nselect, managed association, query, access mapping element\nShows how to select managed association fields (e.g., Author ID from Book) with CQL by explicitly adding associations to the select list and reading the path via row.getPath().\n\n```java\nCqnSelect select = Select.from(BOOKS).byId(123)\n .columns(b -> b.author());\n\nRow row = persistence.run(select).single();\n\nInteger authorId = row.getPath(\"author.ID\");\n```\n", + " Working with CDS Data > Data in CDS Query Language (CQL) > Select with Paths in Matching\nselect, path matching, CqnSelect, status filter\nIllustrates how to use a path to match on a nested property (header.status='canceled') during a select query for filtering orders by status.\n\n```java\nMap order = new HashMap<>();\norder.put(\"header.status\", \"canceled\");\n\nCqnSelect select = Select.from(\"bookshop.Orders\").matching(order);\nResult canceledOrders = persistence.run(select);\n```\n", + " Working with CDS Data > Typed Access > Struct\ntyped access, accessor interface, Books, struct, hybrid access\nShows use of Struct.access to wrap a generic Map in a generated accessor interface for typed and code-completion-friendly read/write. Allows hybrid typed and map-based access.\n\n```java\nBooks book = access(data).as(Books.class);\n\nString title = book.getTitle(); // read the value of the element 'title' from the underlying map\nbook.setTitle(\"Miss Betty\"); // update the element 'title' in the underlying map\n\ntitle = data.get(\"title\"); // direct access to the underlying map\n\ntitle = book.get(\"title\"); // hybrid access to the underlying map through the accessor interface\n```\n", + " Working with CDS Data > Generated Accessor Interfaces > Renaming Elements in Java\naccessor interface, generation, annotation, name mapping\nExample accessor interface for an entity with an element named after a Java reserved keyword. It uses the @CdsName annotation to map CDS 'class' to Java 'clazz'.\n\n```java\ninterface Equity {\n\n @CdsName(\"class\")\n String getClazz();\n\n @CdsName(\"class\")\n void setClazz(String clazz);\n\n}\n```\n", + " Working with CDS Data > Generated Accessor Interfaces > Renaming Types in Java\naccessor interface, generation, annotation, type renaming\nExample of renaming structured types and entities in Java using @cds.java.this.name for accessor interface generation, keeping underlying map keys unchanged.\n\n```java\n@CdsName(\"Name\")\npublic interface MyName extends CdsData {\n // ...\n}\n\n@CdsName(\"Person\")\npublic interface Person extends CdsData {\n String PUBLIC_NAME = \"publicName\";\n String SECRET_NAME = \"secretName\";\n\n MyName getPublicName();\n void setPublicName(MyName publicName);\n\n MyName getSecretName();\n void setSecretName(MyName secretName);\n}\n```\n", + " Working with CDS Data > Generated Accessor Interfaces > Entity Inheritance in Java\naccessor interface, entity inheritance, aspect, extends annotation\nShows how to have a generated accessor interface for an entity extend an interface for an aspect using @cds.java.extends, for shared or common properties inclusion.\n\n```java\n@CdsName(\"AuthorManager\")\npublic interface AuthorManager extends CdsData, Temporal {\n String ID = \"ID\";\n String NAME = \"name\";\n\n @CdsName(ID)\n Integer getId();\n @CdsName(ID)\n void setId(Integer id);\n String getName();\n void setName(String name);\n\n static AuthorManager create() {\n return Struct.create(AuthorManager.class);\n }\n}\n```\n", + " Working with CDS Data > Creating a Data Container for an Interface\nstruct, create, data container, typed\nDemonstrates creation and usage of a typed data container with a generated accessor interface for a Book entity using Struct.create.\n\n```java\nimport static com.sap.cds.Struct.create;\n...\nBook book = create(Book.class);\n\nbook.setTitle(\"Dracula\");\nString title = book.getTitle(); // title: \"Dracula\"\n```\n", + " Working with CDS Data > Creating a Data Container for an Interface\ngenerated accessor interfaces, static factory, single key\nShows use of a static factory method on a generated accessor interface (Books) to instantiate a typed entity with a single key.\n\n```java\nBook book = Books.create(\"9780141439846\");\n\nString id = book.getId(); // id: \"9780141439846\"\n```\n", + " Working with CDS Data > Read-Only Access\naccess, read-only, Struct, Exception\nIllustrates the creation of a typed, read-only proxy for a data map using Struct.asReadOnly, providing immutable access and throwing exceptions on setter calls.\n\n```java\nBook book = access(data).asReadOnly(Book.class);\n\nString title = book.getTitle();\nbook.setTitle(\"CDS4j\"); // throws Exception\n```\n", + " Working with CDS Data > Typed Streaming of Data\nstream, typed streaming, data, Iterable, Collectors\nDemonstrates how to create a typed Java Stream out of a collection of entity data using stream().as(.class), enabling idiomatic Java stream processing in CAP.\n\n```java\nStream books = stream(data).as(Book.class);\n\nList bookList = books.collect(Collectors.toList());\n```\n", + " Working with CDS Data > Data Processor\nCdsDataProcessor, validator, converter, generator, processing, data validation\nShows how to use CdsDataProcessor in CAP Java to validate data structure, here warning for negative quantity values. Demonstrates registration of a custom validator.\n\n```java\nCdsDataProcessor processor = CdsDataProcessor.create();\n\nprocessor.addValidator(\n (path, element, type) -> element.getName().equals(\"quantity\"), // filter\n (path, element, value) -> { // validator\n if ((int) value < 0) {\n log.warn(\"Negative quantity: \" + path.toRef());\n }\n });\n```\n", + " Working with CDS Data > Data Processor\nCdsDataProcessor, data converter, remove association values\nIllustrates adding a data converter to remove association/composition values from structured data, using the Converter.REMOVE return value.\n\n```java\nprocessor.addConverter(\n (path, element, type) -> element.getType().isAssociation(), // filter\n (path, element, value) -> Converter.REMOVE); // remover\n```\n", + " Working with CDS Data > Data Processor\nCdsDataProcessor, generator, UUID, random value\nDefines a generator for UUID elements missing from the data, supplying a random UUID if a field is missing or null.\n\n```java\nprocessor.addGenerator(\n (path, element, type) -> type.isSimpleType(UUID), // filter\n (path, element, isNull) -> isNull ? null : randomUUID()); // generator\n```\n", + " Working with CDS Data > Diff Processor\nCdsDiffProcessor, diff, processing, comparison\nShows initialization and execution of CdsDiffProcessor to detect differences (additions, removals, changes) between two sets of structured data following a certain type.\n\n```java\nCdsDiffProcessor diff = CdsDiffProcessor.create();\n\nList> newImage;\nList> oldImage;\nCdsStructuredType type;\n\ndiff.process(newImage, oldImage, type);\n```\n", + " Working with CDS Data > Diff Processor\nCdsDiffProcessor, visitor, change detection\nImplements a DiffVisitor for CdsDiffProcessor to react to changes, additions, or removals between two entity snapshots or images.\n\n```java\ndiff.add(new DiffVisitor() {\n @Override\n public void changed(Path newPath, Path oldPath, CdsElement element, Object newValue, Object oldValue) {\n // changes\n }\n\n @Override\n public void added(Path newPath, Path oldPath, CdsElement association, Map newValue) {\n // additions\n }\n\n @Override\n public void removed(Path newPath, Path oldPath, CdsElement association, Map oldValue) {\n // removals\n }\n});\n```\n", + " Working with CDS Data > Filtering for DiffVisitor\nCdsDiffProcessor, filter, Authors, association\nDefines an element filter for a CdsDiffProcessor that restricts change detection to associations targeting Authors or paths within the Authors type.\n\n```java\ndiff.add(new Filter() {\n @Override\n public boolean test(Path path, CdsElement element, CdsType type) {\n return element.getType().isAssociation()\n && element.getType().as(CdsAssociationType.class).getTarget().getQualifiedName().equals(Authors_.CDS_NAME)\n || path.target().type().equals(Authors_.CDS_NAME);\n }\n}, ...);\n```\n", + " Working with CDS Data > Media Type Processing > Pre- or Post-Processing Using a Stream Proxy > Media Upload\nmedia type, InputStream, custom event handler, before event\nShows how to wrap an original media stream (InputStream) with a custom FilterInputStream (CoverImagePreProcessor) in a Before handler for upload pre-processing.\n\n```java\n@Before(event = CqnService.EVENT_UPDATE)\npublic void preProcessCoverImage(CdsUpdateEventContext context, List books) {\n\tbooks.forEach(book -> {\n\t\tbook.setCoverImage(new CoverImagePreProcessor(book.getCoverImage()));\n\t});\n}\n```\n", + " Working with CDS Data > Media Type Processing > Pre- or Post-Processing Using a Stream Proxy > Media Upload\nmedia type, InputStream, custom event handler, on event\nImplements custom upload handler for media type properties, wrapping the stream for custom processing, and persists via CQN service run in CAP Java.\n\n```java\n@On(event = CqnService.EVENT_UPDATE)\npublic Result processCoverImage(CdsUpdateEventContext context, List books) {\n\tbooks.forEach(book -> {\n\t\tbook.setCoverImage(new CoverImagePreProcessor(book.getCoverImage()));\n\t});\n\n\t// example for invoking some CQN-based service\n\treturn service.run(Update.entity(Books_.CDS_NAME).entries(books));\n}\n```\n", + " Working with CDS Data > Media Type Processing > Pre- or Post-Processing Using a Stream Proxy > Media Download\nmedia type, InputStream, custom event handler, after event, download\nDemonstrates a post-processing scenario for media download by wrapping the InputStream in an After handler with a custom FilterInputStream for CAP Java.\n\n```java\n@After(event = CdsService.EVENT_READ)\npublic void preProcessCoverImage(CdsReadEventContext context, List books) {\n\tbooks.forEach(book -> {\n\t\tbook.setCoverImage(new CoverImagePreProcessor(book.getCoverImage()));\n\t});\n}\n```\n", + " Working with CDS Data > Media Type Processing > Pre- or Post-Processing Using a Stream Proxy\nmedia type, InputStream, FilterInputStream, custom proxy\nCustom FilterInputStream implementation (CoverImagePreProcessor) for pre- or post-processing bytes during InputStream read operations in upload/download handlers.\n\n```java\npublic class CoverImagePreProcessor extends FilterInputStream {\n\n\tpublic CoverImagePreProcessor(InputStream wrapped) {\n\t\tsuper(wrapped);\n\t}\n\n\t@Override\n\tpublic int read() throws IOException {\n\t\tint nextByte = super.read();\n\n\t\t// ... your custom processing code on nextByte\n\n\t\treturn nextByte;\n\t}\n\n\t@Override\n\tpublic int read(byte[] bts, int off, int len) throws IOException {\n\t\tint bytesRead = super.read(bts, off, len);\n\n\t\t// ... your custom processing code on bts array\n\n\t\treturn bytesRead;\n\t}\n}\n```\n", + " Install Dependencies\ninstallation, npm, Node.js, dependencies\nInstalls required Node.js dependencies for consuming remote services in a CAP project using the SAP Cloud SDK. This is necessary for enabling HTTP client, connectivity, and resilience features.\n\n```shell\nnpm add @sap-cloud-sdk/http-client@4.x @sap-cloud-sdk/connectivity@4.x @sap-cloud-sdk/resilience@4.x\n```\n", + " Get and Import an External Service API > For a Remote CAP Service\ncds CLI, compilation, EDMX, OData, export, project setup\nCompiles the 'OrdersService' CAP service to OData EDMX format. Produces an EDMX definition for sharing or importing into other projects, typically for remote service consumption or mocking.\n\n```shell\ncds compile srv -s OrdersService -2 edmx > OrdersService.edmx\n```\n", + " Get and Import an External Service API > Import API Definition\ncds CLI, import, API definition, project setup\nImports a service definition (OData EDMX, OpenAPI, or AsyncAPI) into a CAP project, converting it to a CDS file and placing it in the appropriate location (e.g. srv/external). Enables working with remote service APIs locally.\n\n```shell\ncds import --as cds\n```\n", + " Get and Import an External Service API > Import API Definition\nconfiguration, package.json, external service, OData, project setup\nDeclares an external OData service in package.json for Node.js CAP projects. Specifies service kind and CDS model location to enable connectivity and service wiring.\n\n```json\n{\n \"cds\": {\n \"requires\": {\n \"API_BUSINESS_PARTNER\": {\n \"kind\": \"odata-v2\",\n \"model\": \"srv/external/API_BUSINESS_PARTNER\"\n }\n }\n }\n}\n```\n", + " Get and Import an External Service API > Import API Definition\nconfiguration, .cdsrc.json, cds import, project setup\nSets options for the 'cds import' command in .cdsrc.json, controlling format, force-overwrite, and included namespaces for API imports.\n\n```json\n{\n \"import\": {\n \"as\": \"cds\",\n \"force\": true,\n \"include_namespaces\": \"sap,c4c\"\n }\n}\n```\n", + " Get and Import an External Service API > Import API Definition\nconfiguration, application.yaml, Java, Spring Boot, external service\nConfigures the remote service 'API_BUSINESS_PARTNER' as OData v2 in Spring Boot application.yaml, for use with CAP Java projects.\n\n```yaml\nspring:\n config.activate.on-profile: cloud\ncds:\n remote.services:\n API_BUSINESS_PARTNER:\n type: \"odata-v2\"\n```\n", + " Get and Import an External Service API > Import API Definition\ndependency, pom.xml, Java, external service\nAdds the SAP CAP Java dependency needed for consuming remote OData services, to be included with runtime scope in Maven projects.\n\n```xml\n\n com.sap.cds\n cds-feature-remote-odata\n runtime\n\n```\n", + " Local Mocking > Add Mock Data\ncsv, mock data, initial data, testing, external service\nSample CSV mock data for the 'A_BusinessPartner' entity in a remote service, used for local design-time mocking.\n\n```csv\nBusinessPartner;BusinessPartnerFullName;BusinessPartnerIsBlocked\n1004155;Williams Electric Drives;false\n1004161;Smith Batteries Ltd;false\n1004100;Johnson Automotive Supplies;true\n```\n", + " Local Mocking > Mock Associations\ncds, association, mock, editing external service\nShows an imported external service CDS model with an association lacking ON condition (empty key group), typical after import. Used to explain why associations must be enriched for proper mocking.\n\n```cds\nentity API_BUSINESS_PARTNER.A_BusinessPartner {\n key BusinessPartner : LargeString;\n BusinessPartnerFullName : LargeString;\n BusinessPartnerType : LargeString;\n ...\n to_BusinessPartnerAddress :\n Association to many API_BUSINESS_PARTNER.A_BusinessPartnerAddress { }; // Association lacks ON condition\n};\n\nentity API_BUSINESS_PARTNER.A_BusinessPartnerAddress {\n key BusinessPartner : String(10);\n key AddressID : String(10);\n ...;\n};\n```\n", + " Local Mocking > Mock Associations\ncds CLI, import, association, editing, mock\nRe-imports an EDMX to a new CDS file to update associations. Used as a step before merging association ON conditions for proper mocking.\n\n```shell\ncds import ~/Downloads/API_BUSINESS_PARTNER.edmx --keep-namespace \\\n --as cds --out srv/external/API_BUSINESS_PARTNER-new.cds\n```\n", + " Local Mocking > Mock Associations\ncds, association, ON condition, mock, editing external service\nDemonstrates how to add an ON condition to an association in an imported CDS model, necessary for mocking associations between imported entities.\n\n```cds\nentity API_BUSINESS_PARTNER.A_BusinessPartner {\n // ...\n to_BusinessPartnerAddress :\n Association to many API_BUSINESS_PARTNER.A_BusinessPartnerAddress\n on to_BusinessPartnerAddress.BusinessPartner = BusinessPartner;\n};\n```\n", + " Execute Queries > Execute Queries with Node.js\nservice consumer, Node.js, connect, querying, CQN, OData\nConnects to the remote 'API_BUSINESS_PARTNER' service in a CAP Node.js application, preparing for sending queries.\n\n```js\nconst bupa = await cds.connect.to('API_BUSINESS_PARTNER');\n```\n", + " Execute Queries > Execute Queries with Node.js\nservice consumer, Node.js, querying, CQN, OData\nQueries the remote 'A_BusinessPartner' entity and limits the results to 100 records. Exemplifies how to use CAP's querying API for remote OData services.\n\n```js\nconst { A_BusinessPartner } = bupa.entities;\nconst result = await bupa.run(SELECT(A_BusinessPartner).limit(100));\n```\n", + " Execute Queries > Execute Queries with Node.js\nservice consumer, Node.js, querying, associations, OData\nQueries the remote OData service's 'A_BusinessPartner' entity and expands associated 'A_BusinessPartnerAddress' records. Demonstrates association traversal for remote APIs.\n\n```js\nconst { A_BusinessPartner } = bupa.entities;\nconst result = await bupa.run(SELECT.from(A_BusinessPartner, bp => {\n bp('BusinessPartner'),\n bp.to_BusinessPartnerAddress(addresses => {\n addresses('*')\n })\n }).limit(100));\n```\n", + " Execute Queries > Execute Queries with Java\nservice consumer, Java, Spring, dependency injection, OData, CQN\nShows usage of dependency injection in CAP Java to access the remote service 'API_BUSINESS_PARTNER' as a CqnService. Prerequisite for executing queries against the remote entity.\n\n```java\n@Autowired\n@Qualifier(ApiBusinessPartner_.CDS_NAME)\nCqnService bupa;\n```\n", + " Execute Queries > Execute Queries with Java\nservice consumer, Java, querying, CQN, OData\nExample query to a remote OData service in CAP Java, fetching up to 100 business partners, leveraging the querying API with CQN.\n\n```java\nCqnSelect select = Select.from(ABusinessPartner_.class).limit(100);\nList businessPartner = bupa.run(select).listOf(ABusinessPartner.class);\n```\n", + " Execute Queries > Model Projections\ncds modeling, projection, remote service, OData, mashup\nDefines a CDS projection 'Suppliers' on a remote OData entity, aliasing fields for local use. This encapsulates the remote API, decoupling the local model.\n\n```cds\nusing {  API_BUSINESS_PARTNER as bupa } from '../srv/external/API_BUSINESS_PARTNER';\n\nentity Suppliers as projection on bupa.A_BusinessPartner {\n key BusinessPartner as ID,\n BusinessPartnerFullName as fullName,\n BusinessPartnerIsBlocked as isBlocked,\n}\n```\n", + " Execute Queries > Execute Queries on Projections to a Remote Service\nservice consumer, Node.js, projection, querying, OData\nQueries the remote service via a projection entity, mapping conditions and results transparently for the developer. The projection hides remote field names and schemas.\n\n```js\nconst suppliers = await bupa.run(SELECT(Suppliers).where({ID}));\n```\n", + " Execute Queries > Building Custom Requests with Node.js\nservice consumer, Node.js, custom request, HTTP, OData\nShows how to build and send a custom HTTP request (PATCH) to a remote OData service when CAP's querying API is insufficient. Useful for advanced or non-standard API operations.\n\n```js\nbupa.send({\n method: 'PATCH',\n path: A_BusinessPartner,\n data: {\n BusinessPartner: 1004155,\n BusinessPartnerIsBlocked: true\n }\n})\n```\n", + " Expose Remote Services with Associations\ncds modeling, projection, remote service, association, redirection\nDefines projections with redirected associations for exposure in a CAP service, mapping and renaming associations from the remote OData service to custom local names.\n\n```cds\nusing { API_BUSINESS_PARTNER as bupa } from '../srv/external/API_BUSINESS_PARTNER';\n\nextend service RiskService with {\n entity Suppliers as projection on bupa.A_BusinessPartner {\n key BusinessPartner as ID,\n BusinessPartnerFullName as fullName,\n BusinessPartnerIsBlocked as isBlocked,\n to_BusinessPartnerAddress as addresses: redirected to SupplierAddresses\n }\n\n entity SupplierAddresses as projection on bupa.A_BusinessPartnerAddress {\n BusinessPartner as bupaID,\n AddressID as ID,\n CityName as city,\n StreetName as street,\n County as county\n }\n}\n```\n", + " Expose Remote Services\nservice implementation, Node.js, handler, projection, remote service\nDefines a CAP Node.js service handler that proxies READ events for 'BusinessPartners' to the remote API. Required for entities whose data source is remote, not local DB.\n\n```js\nmodule.exports = cds.service.impl(async function() {\n const bupa = await cds.connect.to('API_BUSINESS_PARTNER');\n\n this.on('READ', 'BusinessPartners', req => {\n return bupa.run(req.query);\n });\n});\n```\n", + " Integrate and Extend > Mashing up with Remote Services > Integrate Remote into Local Services\ncds modeling, mashup, association, managed association, integration\nDemonstrates a CAP service with a managed association from a local entity ('Risks') to a projection on a remote OData entity ('Suppliers'), integrating local and remote data models.\n\n```cds\n@path: 'service/risk'\nservice RiskService {\n entity Risks : managed {\n key ID : UUID @(Core.Computed : true);\n title : String(100);\n prio : String(5);\n supplier : Association to Suppliers;\n }\n\n entity Suppliers as projection on BusinessPartner.A_BusinessPartner {\n key BusinessPartner as ID,\n BusinessPartnerFullName as fullName,\n BusinessPartnerIsBlocked as isBlocked,\n };\n}\n```\n", + " Integrate and Extend > Mashing up with Remote Services > Extend a Remote by a Local Service\ncds modeling, mashup, association, extension, remote service, local service\nExtends a projection on a remote OData entity by adding an association ('risks') back to a local entity, mashing up remote and local service data.\n\n```cds\nentity Suppliers as projection on bupa.A_BusinessPartner {\n key BusinessPartner as ID,\n BusinessPartnerFullName as fullName,\n BusinessPartnerIsBlocked as isBlocked,\n risks : Association to many Risks on risks.supplier.ID = ID,\n};\n```\n", + " Connect to Remote Services Locally > Bind to Remote Destinations\nconnectivity, cds CLI, hybrid testing, BTP, destination, local development\nCloud Foundry commands to setup necessary service instances (XSUAA and Destination), create service keys, and bind them to the local CAP application for hybrid testing scenarios.\n\n```shell\ncf create-service xsuaa application cpapp-xsuaa\ncf create-service-key cpapp-xsuaa cpapp-xsuaa-key\ncf create-service destination lite cpapp-destination\ncf create-service-key cpapp-destination cpapp-destination-key\ncds bind -2 cpapp-xsuaa,cpapp-destination\n```\n", + " Connect to Remote Services Locally > Run a Node.js Application with a Destination\nconnectivity, Node.js, configuration, hybrid testing, cdsrc-private.json\nConfigures the remote destination for the 'API_BUSINESS_PARTNER' service in a hybrid profile, used for local development and testing.\n\n```json\n{\n \"requires\": {\n \"[hybrid]\": {\n \"auth\": {\n /* ... */\n },\n \"destinations\": {\n /* ... */\n },\n \"API_BUSINESS_PARTNER\": {\n \"credentials\": {\n \"path\": \"/sap/opu/odata/sap/API_BUSINESS_PARTNER\",\n \"destination\": \"cpapp-bupa\"\n }\n }\n }\n }\n}\n```\n", + " Connect to Remote Services Locally > Run a Node.js Application with a Destination\nconnectivity, Node.js, cds CLI, hybrid testing, local development\nRun CAP Node.js application with the 'hybrid' profile enabled, using the locally bound destination for remote service consumption.\n\n```shell\ncds watch --profile hybrid\n```\n", + " Connect to an Application Using the Same XSUAA (Forward Authorization Token) > Forward Authorization Token with Node.js\nauthorization, connectivity, Node.js, forwardAuthToken, OData, configuration\nEnables forwarding of the authorization token when connecting from one CAP Node.js microservice to another using OData; avoids the need for an SAP BTP destination in certain microservice architectures.\n\n```json\n{\n \"requires\": {\n \"kind\": \"odata\",\n \"model\": \"./srv/external/OrdersService\",\n \"credentials\": {\n \"url\": \"\",\n \"forwardAuthToken\": true\n }\n }\n}\n```\n", + " Connect to an Application Using the Same XSUAA (Forward Authorization Token) > Forward Authorization Token with Java\nauthorization, connectivity, Java, forwardAuthToken, OData, configuration\nConfigures a remote OData destination in CAP Java to use token forwarding for authentication, useful for mutual trust between microservices sharing the same XSUAA.\n\n```yaml\ncds:\n remote.services:\n order-service:\n type: \"odata-v4\"\n destination:\n properties:\n url: \"\"\n authentication: TokenForwarding\n```\n", + " Deployment > Add Required Services to MTA Deployments\ndeployment, MTA, xsuaa, destination, connectivity, manifest, Cloud Foundry\nAdds required backing services (XSUAA, Destination, and Connectivity) to your MTA yaml configuration for deploying a CAP application to Cloud Foundry with external connectivity.\n\n```shell\ncds add xsuaa,destination,connectivity\n```\n", + " Building CQL Statements > The CQL Statement Builders\nCQL, Java, Select, builder, columns, byId, dynamic\nDemonstrates how to use the CQL Select builder in Java to construct a dynamic query selecting the column 'title' from the entity 'bookshop.Books' with key ID 101. This is the dynamic, string-based approach.\n\n```java\nSelect.from(\"bookshop.Books\").columns(\"title\").byId(101);\n```\n", + " Building CQL Statements > The CQL Statement Builders\nCQL, Java, Select, builder, columns, byId, static, static model\nShows the static style usage of the Select builder in Java, referencing entities and elements using constants and interfaces generated from the CDS model. The query selects the 'title' of Books with ID 101.\n\n```java\nimport static bookshop.Bookshop_.BOOKS;\nSelect.from(BOOKS).columns(b -> b.title()).byId(101);\n```\n", + " Building CQL Statements > Lambda Expressions\nCQL, Java, Select, lambda, predicate, where, columns, alias\nIllustrates use of lambda expressions in the CQL Select builder for projecting columns with aliasing and specifying complex predicates in the where clause.\n\n```java\nSelect.from(BOOKS)\n .columns(b -> b.title().as(\"Book\"))\n .where(b -> b.year().lt(2000));\n```\n", + " Building CQL Statements > Path Expressions\nCQL, Java, Select, static, dynamic, path expression, where, to, get\nDemonstrates accessing related entity elements via path expressions in both the static and dynamic styles of Java CQL statement building, including filtering on associated elements.\n\n```java\n// Java CQL (static)\nSelect.from(BOOKS)\n .columns(b -> b.title(), b -> b.author().name().as(\"author\"))\n .where(b -> b.author().name().startsWith(\"A\"));\n\n// Java CQL (dynamic)\nSelect.from(\"bookshop.Books\")\n .columns(b -> b.get(\"title\"), b -> b.get(\"author.name\").as(\"author\"))\n .where(b -> b.to(\"author\").get(\"name\").startsWith(\"A\"));\n```\n", + " Building CQL Statements > Target Entity Sets\nCQL, Java, Insert, Update, Select, target entity set, entity reference, infix filter\nShows how to specify the target entity set in CQL statements for Select, Insert, and Update by referencing the entity directly, both statically and dynamically.\n\n```java\nimport static bookshop.Bookshop_.BOOKS;\n\n// static\nSelect.from(BOOKS);\n\n// dynamic\nInsert.into(\"bookshop.Books\").entry(book);\n\nUpdate.entity(\"bookshop.Authors\").data(author);\n```\n", + " Building CQL Statements > Target Entity Sets\nCQL, Java, Select, entity reference, infix filter, path expression, filter\nShows how to use an infix filter to define the entity reference for the target set in a Select CQL statement in Java, targeting items of a specific order (where ID = 3).\n\n```java\nSelect.from(ORDERS, o -> o.filter(o.id().eq(3)).items())\n .columns(i -> i.quantity(),\n i -> i.book().title().as(\"book\"));\n```\n", + " Building CQL Statements > Filters > Using `where`\nCQL, Java, Select, filter, where, complex predicate\nDemonstrates advanced filtering using the 'where' clause with composed predicates combining AND, OR for element comparison in CQL Java statements.\n\n```java\nSelect.from(BOOKS)\n .where(b -> b.author().name().eq(\"Twain\")\n .and(b.title().startsWith(\"A\").or(b.title().endsWith(\"Z\"))));\n```\n", + " Building CQL Statements > Filters > Using `byID`\nCQL, Java, Select, byId, single key\nExample of using 'byId' for retrieving an entity with a single key in a dynamic CQL Select statement in Java.\n\n```java\nSelect.from(\"bookshop.Authors\").byId(101);\n```\n", + " Building CQL Statements > Filters > Using `matching`\nCQL, Java, Select, matching, filter map, query-by-example\nDefines a filter using a key-value map for matching elements and path expressions, and applies it to a CQL Select in Java with the 'matching' method.\n\n```java\nMap filter = new HashMap<>();\nfilter.put(\"author.name\", \"Edgar Allen Poe\");\nfilter.put(\"stock\", 0);\n\nSelect.from(\"bookshop.Books\").matching(filter);\n```\n", + " Building CQL Statements > Filters > Using `byParams`\nCQL, Java, Select, byParams, parameterized query\nCompares two ways to define parameterized filters in a Java CQL Select, explicitly with 'where' and implicitly with 'byParams', supporting named placeholders for parameterized execution.\n\n```java\nimport static bookshop.Bookshop_.BOOKS;\n\n// using where\nSelect.from(BOOKS)\n .where(b -> b.title().eq(param(\"title\"))\n .and(b.author().name().eq(param(\"author.name\"))));\n\n// using byParams\nSelect.from(BOOKS).byParams(\"title\", \"author.name\");\n```\n", + " Building CQL Statements > Parameters\nCQL, Java, Select, parameters, param, execute\nShows how to use positional parameters in a Java CQL Select statement for parameterized execution with the underlying data store.\n\n```java\nimport static com.sap.cds.ql.CQL.param;\n\nCqnSelect q = Select.from(BOOKS).where(b -> b.author().name().eq(param(0)));\ndataStore.execute(q, \"Jules Verne\");\n```\n", + " Building CQL Statements > Parameters\nCQL, Java, Insert, parameters, byParams, execute\nDemonstrates use of 'byParams' for named parameter substitution in a CQL Select statement in Java, followed by execution with the parameter map.\n\n```java\nCqnSelect q = Select.from(BOOKS).byParams(\"author.name\");\ndataStore.execute(q, singletonMap(\"author.name\", \"Jules Verne\"));\n```\n", + " Building CQL Statements > Parameters\nCQL, Java, Select, parameters, infix filter, filterByParams\nShows parameterized infix filters using 'filterByParams' method in path expressions, then executing the query with provided parameter values.\n\n```java\nCqnSelect q = Select.from(AUTHORS, o -> o.filterByParams(\"ID\").books());\ndataStore.execute(q, singletonMap(\"ID\", 101));\n```\n", + " Building CQL Statements > Constant and Non-Constant Literal Values\nCQL, Java, Select, literal values, constant, val\nDemonstrates using literal values in Java CQL statements; 'val()' for design-time known values that may vary at runtime, useful for SQL binding parameters.\n\n```java\nimport static com.sap.cds.ql.CQL.val;\n\nSelect.from(BOOKS).columns(b -> b.title(), val(\"available\").as(\"status\"))\n\t.where(b -> b.stock().gt(0));\n```\n", + " Building CQL Statements > Constant and Non-Constant Literal Values\nCQL, Java, Select, constant, constant literal\nShows use of 'CQL.constant()' to inject a constant literal at query construction time which is directly inlined into generated SQL and must not include external input.\n\n```java\nimport static com.sap.cds.ql.CQL.constant;\n\nSelect.from(BOOKS).columns(b -> b.title())\n\t.where(b -> b.cover().eq(constant(\"paperback\")));\n```\n", + " Building CQL Statements > Select > Projections\nCQL, Java, Select, columns, projection, dynamic usage\nIllustrates basic projection using the columns method in dynamic Java CQL Select statements, fetching 'title' and nested 'author.name'.\n\n```java\nCqnSelect query = Select.from(\"bookshop.Books\")\n .columns(\"title\", \"author.name\");\n```\n", + " Building CQL Statements > Select > Projections\nCQL, Java, Select, columns, projection, dynamic, lambda\nDemonstrates projecting columns with custom aliases using lambda expressions and dot-paths for nested properties in dynamic Java CQL.\n\n```java\nSelect.from(\"bookshop.Books\")\n .columns(b -> b.get(\"title\"),\n b -> b.get(\"author.name\").as(\"authorName\"));\n```\n", + " Building CQL Statements > Select > Projections\nCQL, Java, Select, columns, projection, static, lambda\nShows type-safe, code-completion-enabled static column projection and aliasing in a Java CQL Select statement using lambda expressions.\n\n```java\nimport static bookshop.Bookshop_.BOOKS;\n\nSelect.from(BOOKS)\n .columns(b -> b.title(),\n b -> b.author().name().as(\"authorName\"));\n```\n", + " Building CQL Statements > Select > Deep Read with `expand`\nCQL, Java, expand, deep read, columns, association, substructure\nDemonstrates deep reads using expand to include associated entities as substructures in the query result, showing books of an author.\n\n```java\nimport static bookshop.Bookshop_.AUTHORS;\n\nSelect.from(AUTHORS)\n .columns(a -> a.name().as(\"author\"),\n a -> a.books().expand(\n b -> b.title().as(\"book\"),\n b -> b.year()));\n```\n", + " Building CQL Statements > Select > Deep Read with `expand`\nCQL, Java, expand, infix filter, columns\nShows how to use infix filters on associations during expansion to filter sub-entities before expanding them in the result structure.\n\n```java\nSelect.from(AUTHORS)\n .columns(a -> a.name(),\n a -> a.books()\n .filter(b -> b.year().eq(1897))\n .expand(b -> b.title()))\n .where(a -> name().in(\"Bram Stroker\", \"Edgar Allen Poe\"));\n```\n", + " Building CQL Statements > Select > Deep Read with `expand`\nCQL, Java, expand, association, nested substructure\nIllustrates nested expand to return multi-level deep structured results, expanding from authors to books to publishers.\n\n```java\nSelect.from(AUTHORS)\n .columns(a -> a.name(),\n a -> a.books().as(\"novels\").expand(\n b -> b.title(),\n b -> b.publisher().expand(p -> p.name())));\n```\n", + " Building CQL Statements > Select > Deep Read with `expand`\nCQL, Java, expand, all elements, association\nExpands all non-association elements of an associated entity in the result for a single association.\n\n```java\nSelect.from(BOOKS)\n .columns(b -> b.title(),\n b -> b.author().expand());\n```\n", + " Building CQL Statements > Select > Deep Read with `expand`\nCQL, Java, expand, entity level, all associations\nExpands all first-level associations of an entity using expand on the entity itself.\n\n```java\nSelect.from(BOOKS).columns(b -> b.expand());\n```\n", + " Building CQL Statements > Select > Flattened Results with `inline`\nCQL, Java, inline, flattened result, columns, association\nDemonstrates how to use 'inline' on association columns to flatten associated entity fields into the root result set.\n\n```java\nSelect.from(AUTHORS)\n .columns(a -> a.name(),\n a -> a.books().inline(\n b -> b.title().as(\"book\"),\n b -> b.year()));\n```\n", + " Building CQL Statements > Select > Managed Associations on the Select List\nCQL, Java, managed association, columns, select key elements\nSelecting managed to-one associations in the select list automatically includes the key elements of the target entity as structured results.\n\n```java\n// dynamic\nSelect.from(\"bookshop.Books\")\n .columns(b -> b.get(\"author\"));\n\n// static\nimport static bookshop.Bookshop_.BOOKS;\nCqnSelect q = Select.from(BOOKS)\n .columns(b -> b.author());\n\nRow book = dataStore.execute(q).single();\nObject authorId = book.get(\"author.Id\"); // path access\n```\n", + " Building CQL Statements > Filtering and Searching\nCQL, Java, Select, search, search term, search expression\nAdds a full-text search predicate searching for a term ('Allen') over all searchable fields of the 'bookshop.Books' entity.\n\n```java\nSelect.from(\"bookshop.Books\")\n .columns(\"id\", \"name\")\n .search(\"Allen\");\n```\n", + " Building CQL Statements > Filtering and Searching\nCQL, Java, Select, search, search expression, has, or\nBuilds a complex search expression with multiple terms combined by logical OR using 'search' in Java CQL.\n\n```java\nSelect.from(\"bookshop.Books\")\n .columns(\"id\", \"name\")\n .search(term -> term.has(\"Allen\").or(term.has(\"Heights\")));\n```\n", + " Building CQL Statements > Filtering and Searching > Using `where` Clause\nCQL, Java, Select, where, or, predicate\nComposes complex WHERE clause predicates using OR, matching either on ID or on a title prefix.\n\n```java\nSelect.from(\"bookshop.Books\")\n\t.where(b -> b.get(\"ID\").eq(251).or(\n b.get(\"title\").startsWith(\"Wuth\")));\n```\n", + " Building CQL Statements > Grouping > Group By\nCQL, Java, Select, groupBy, aggregate function, count\nGroups records by author name and counts how many authors have each name using groupBy and count aggregate function.\n\n```java\nimport com.sap.cds.ql.CQL;\n\nSelect.from(\"bookshop.Authors\")\n\t.columns(c -> c.get(\"name\"), c -> CQL.count(c.get(\"name\")).as(\"count\"))\n\t.groupBy(g -> g.get(\"name\"));\n```\n", + " Building CQL Statements > Grouping > Having\nCQL, Java, Select, groupBy, having, aggregate, filter\nSelects authors grouped by name and filters to those where the count of each group is greater than 2, using having.\n\n```java\nSelect.from(\"bookshop.Authors\")\n .columns(c -> c.get(\"name\"), c -> func(\"count\", c.get(\"name\")).as(\"count\"))\n .groupBy(c -> c.get(\"name\"))\n .having(c -> func(\"count\", c.get(\"name\")).gt(2));\n```\n", + " Building CQL Statements > Ordering and Pagination > Order By\nCQL, Java, Select, orderBy, asc, desc, nulls\nShows ordering the result by ID descending and title ascending using orderBy with multiple columns.\n\n```java\nSelect.from(\"bookshop.Books\")\n .columns(c -> c.get(\"ID\"), c -> c.get(\"title\"))\n .orderBy(c -> c.get(\"ID\").desc(), c -> c.get(\"title\").asc());\n```\n", + " Building CQL Statements > Ordering and Pagination > Order By\nCQL, Java, Select, orderBy, alias, columns\nDemonstrates using a column alias in orderBy for sorting and referencing that alias in the sort specification.\n\n```java\nSelect.from(\"bookshop.Person\")\n .columns(p -> p.get(\"name\").toUpper().as(\"aliasForName\"))\n .orderBy(p -> p.get(\"aliasForName\").asc());\n```\n", + " Building CQL Statements > Ordering and Pagination > Order By\nCQL, Java, Select, orderBy, nulls, ascNullsLast\nSpecifies custom sort order for columns including controlling the sort position of null values using ascNullsLast.\n\n```java\nSelect.from(\"bookshop.Person\")\n .orderBy(p -> p.get(\"name\").asc(), p -> c.get(\"nickname\").ascNullsLast());\n```\n", + " Building CQL Statements > Ordering and Pagination > Pagination\nCQL, Java, Select, limit, pagination\nImplements result set pagination, skipping the first 20 rows and returning the next 10 in a query.\n\n```java\nSelect.from(\"bookshop.Books\").limit(10, 20);\n```\n", + " Building CQL Statements > Pessimistic Locking\nCQL, Java, Select, lock, pessimistic locking, update\nDemonstrates pessimistic locking in a select statement followed by an update, acquiring an exclusive lock with a timeout.\n\n```java\nSelect.from(\"bookshop.Books\").byId(1).lock(5);\n...\nUpdate.entity(\"bookshop.Books\").data(\"price\", 18).byId(1);\n```\n", + " Building CQL Statements > Pessimistic Locking\nCQL, Java, Select, lock, shared, locking mode\nAcquires a shared (read) row-level lock on selected entity using the SHARED lock mode.\n\n```java\nimport static com.sap.cds.ql.cqn.CqnLock.Mode.SHARED;\n\nSelect.from(\"bookshop.Books\").byId(1).lock(SHARED);\n```\n", + " Building CQL Statements > Insert > Single Insert\nCQL, Java, Insert, entry, single insert\nShows creating a single insert statement with input data as a map for the target entity.\n\n```java\nMap book = new HashMap<>();\nbook.put(\"ID\", 101);\nbook.put(\"title\", \"Capire\");\n\nCqnInsert insert = Insert.into(\"bookshop.Books\").entry(book);\n```\n", + " Building CQL Statements > Insert > Bulk Insert\nCQL, Java, Insert, entries, bulk insert, List, static model\nPerforms a bulk insert, passing an iterable list of records to insert multiple entities in one statement.\n\n```java\nimport static bookshop.Bookshop_.BOOKS;\n\nvar data = List.of(\n\tMap.of(\"ID\", 101, \"title\", \"Capire\"),\n\tMap.of(\"ID\", 103, \"title\", \"CAP Java\"));\n\nCqnInsert insert = Insert.into(BOOKS).entries(data);\n```\n", + " Building CQL Statements > Insert > Deep Insert\nCQL, Java, Insert, deep insert, compositions\nShows a deep insert operation where nested composition entities are included in the insert data map.\n\n```java\nimport static bookshop.Bookshop_.ORDERS;\n\nvar items = List.of(Map.of(\"ID\", 1, \"book_ID\", 101, \"quantity\", 1));\nvar order = Map.of(\"OrderNo\", \"1000\", \"Items\", items);\n\nCqnInsert insert = Insert.into(ORDERS).entry(order);\n```\n", + " Building CQL Statements > Upsert > Single Upsert\nCQL, Java, Upsert, entry, single upsert, static model\nPerforms a single upsert (update or insert) for a record using a statically typed accessor for the entity.\n\n```java\nimport static bookshop.Bookshop_.BOOKS;\nimport bookshop.Books;\n\nBooks book = Books.create();\nbook.setId(101);\nbook.setTitle(\"CAP for Beginners\");\n\nCqnUpsert upsert = Upsert.into(BOOKS).entry(book);\n```\n", + " Building CQL Statements > Upsert > Bulk Upsert\nCQL, Java, Upsert, entries, bulk upsert, static model\nExecutes a bulk upsert for multiple statically typed entity records in the database.\n\n```java\nimport static bookshop.Bookshop_.BOOKS;\nimport bookshop.Books;\n\nBooks b1 = Books.create(101);\nb1.setTitle(\"Odyssey\");\n\nBooks b2 = Books.create(103);\nb2.put(\"title\", \"Ulysses\");\n\nList data = Arrays.asList(b1, b2);\n\nCqnUpsert upsert = Upsert.into(BOOKS).entries(data);\n```\n", + " Building CQL Statements > Update > Updating Individual Entities\nCQL, Java, Update, entity, static model, data\nUpdates an entity by passing update data including key (ID) using statically typed entity interface, with implicit filter derived from keys.\n\n```java\nimport static bookshop.Bookshop_.BOOKS;\nimport bookshop.Books;\n\nBooks book = Books.create();\nbook.setId(100); // key value filter in data\nbook.setTitle(\"CAP Matters\");\n\nCqnUpdate update = Update.entity(BOOKS).data(book);\n```\n", + " Building CQL Statements > Update > Updating Individual Entities\nCQL, Java, Update, where, byId, matching, set\nShows alternate way of updating a single entity by using 'byId' filter explicitly, applicable for entities with a single key.\n\n```java\nUpdate.entity(BOOKS)\n .data(\"title\", \"CAP Matters\").byId(100);\n```\n", + " Building CQL Statements > Update > Update with Expressions\nCQL, Java, Update, where, set, expression\nUpdates a record using an expression (decrementing stock) with the set method, both for dynamic and static styles.\n\n```java\n// dynamic\nUpdate.entity(BOOKS).byId(101).set(\"stock\", CQL.get(\"stock\").minus(1));\n\n// static\nUpdate.entity(BOOKS).byId(101).set(b -> b.stock(), s -> s.minus(1));\n```\n", + " Building CQL Statements > Update > Bulk Update\nCQL, Java, Update, bulk update, entries, static model\nIllustrates updating multiple records with individual update data—possibly deep updates—using entries with statically generated accessor interfaces.\n\n```java\nOrders o1 = Orders.create(1);\no1.setStatus(\"canceled\");\n\nOrders o2 = Orders.create(2);\no2.setStatus(\"in process\");\n\nOrders o3 = Orders.create(3);\no3.put(\"header.comment\", \"Deliver with Order 2\");\n\nList orders = Arrays.asList(o1, o2, o3);\nCqnUpdate update = Update.entity(ORDERS).entries(orders);\n```\n", + " Building CQL Statements > Update > Searched Update\nCQL, Java, Update, searched update, where, data\nPerforms a searched/batch update, setting the same value ('stock' = 100) for all matching records whose title contains 'CAP'.\n\n```java\nUpdate.entity(BOOKS).data(\"stock\", 100)\n .where(b -> b.title().contains(\"CAP\"));\n```\n", + " Building CQL Statements > Update > Parameterized Batch Update\nCQL, Java, Update, parameterized batch update, byParams, where, execute\nShows constructing a parameterized batch update, with parameter placeholders in 'where' or with 'byParams', and running the statement with multiple parameter sets.\n\n```java\n// using where\nCqnUpdate update = Update.entity(BOOKS).data(\"stock\", 0)\n .where(b -> b.title().eq(CQL.param(\"title\"))\n .and(b.author().name().eq(CQL.param(\"author.name\"))));\n\n// using byParams\nCqnUpdate update = Update.entity(BOOKS).data(\"stock\", 0)\n .byParams(\"title\", \"author.name\");\n\nMap paramSet1 = new HashMap<>();\nparamSet1.put(\"author.name\", \"Victor Hugo\");\nparamSet1.put(\"title\", \"Les Misérables\");\nMap paramSet2 = new HashMap<>();\nparamSet2.put(\"author.name\", \"Emily Brontë\");\nparamSet2.put(\"title\", \"Wuthering Heights\");\n\nResult result = service.run(update, asList(paramSet1, paramSet2));\n```\n", + " Building CQL Statements > Delete\nCQL, Java, Delete, where, static, dynamic, composition\nIllustrates how to construct delete statements using where filters, both dynamically and with static model referencing.\n\n```java\n// dynamic\nCqnDelete delete = Delete.from(\"my.bookshop.Orders\")\n .where(b -> b.get(\"OrderNo\").eq(1000));\n\n// static\nimport static bookshop.Bookshop_.ORDERS;\n\nCqnDelete delete = Delete.from(ORDERS)\n .where(b -> b.OrderNo().eq(1000));\n```\n", + " Building CQL Statements > Delete > Using `matching`\nCQL, Java, Delete, matching, composite primary key, parameters\nDeletes records based on composite key using either 'matching' or 'where', then executes with multiple parameter sets.\n\n```java\nimport static com.sap.cds.ql.CQL.param;\n\nMap params = new HashMap<>();\nparams.put(\"ID\", param(\"ID\"));\nparams.put(\"journalID\", 101);\n\n// using matching\nCqnDelete delete = Delete.from(\"bookshop.Article\").matching(params);\n\n// using where\nCqnDelete delete = Delete.from(\"bookshop.Article\")\n\t.where(t -> t.get(\"ID\").eq(param(\"ID\"))\n\t.and(t.get(\"journalID\").eq(101)));\n\n// execution\nMap row1 = singletonMap(\"ID\", 1);\nMap row2 = singletonMap(\"ID\", 2);\ndataStore.execute(delete, asList(row1, row2));\n```\n", + " Executing CQL Statements > Query Execution\nquery execution, CQL, CQN, Java, select, Result, run\nExecutes a CQL (CDS Query Language) select statement on a CqnService in Java. Returns a Result object after fetching title and price columns from 'bookshop.Books'. Core example on how to submit CQN queries with CAP Java.\n\n```java\nCqnService service = ...\n\nCqnSelect query = Select.from(\"bookshop.Books\")\n .columns(\"title\", \"price\");\n\nResult result = service.run(query);\n```\n", + " Executing CQL Statements > Parameterized Execution > Named Parameters\nparameterized execution, named parameters, CQL, CQN, Java, delete\nPerforms a parameterized batch delete on 'bookshop.Books' using named parameters. Parameter values are supplied as a Map. Demonstrates safe, reusable query operations with named parameter binding in Java.\n\n```java\nimport static com.sap.cds.ql.CQL.param;\n\nCqnDelete delete = Delete.from(\"bookshop.Books\")\n .where(b -> b.get(\"ID\").eq(param(\"id1\"))\n .or(b.get(\"ID\").eq(param(\"id2\"))));\n\nMap paramValues = new HashMap<>();\nparamValues.put(\"id1\", 101);\nparamValues.put(\"id2\", 102);\n\nResult result = service.run(delete, paramValues);\n```\n", + " Executing CQL Statements > Parameterized Execution > Indexed Parameters\nparameterized execution, indexed parameters, CQL, CQN, Java, delete\nShows how to execute a delete statement using indexed parameters (param(0), param(1)) in Java with the CAP CQN API. Multiple indexed input values are passed for parameter binding.\n\n```java\nimport static com.sap.cds.ql.CQL.param;\n\nCqnDelete delete = Delete.from(\"bookshop.Books\")\n .where(b -> b.get(\"ID\").in(param(0), param(1)));\n\nResult result = service.run(delete, 101, 102);\n```\n", + " Executing CQL Statements > Parameterized Execution > Batch Execution\nparameterized execution, batch, delete, CQL, CQN, Java\nExecutes a batch delete operation on 'bookshop.Books'. A statement is executed multiple times with different named parameter sets using a batch list. The total number of deleted rows is retrieved from result.rowCount().\n\n```java\nimport static com.sap.cds.ql.CQL.param;\n\nCqnDelete delete = Delete.from(\"bookshop.Books\").byParams(\"ID\");\n\nMap paramSet1 = singletonMap(\"ID\", 101);\nMap paramSet2 = singletonMap(\"ID\", 102);\n\nResult result = service.run(query, asList(paramSet1, paramSet2));\nlong deletedRows = result.rowCount();\n```\n", + " Executing CQL Statements > Parameterized Execution > Querying Parameterized Views on SAP HANA\nparameterized execution, SAP HANA, views, named parameter, select, CQL, CQN, Java\nExecutes a select query against a parameterized view ('BooksView') on SAP HANA, passing named parameter values for the view's input parameters. Shows correct usage of view parameters on CAP Java.\n\n```java\nCqnSelect query = Select.from(\"BooksView\");\nvar params = Map.of(\"minStock\", 100);\n\nResult result = service.run(query, params);\n```\n", + " Executing CQL Statements > Query Hints\nSAP HANA, query hints, CQL, hint, Java\nAdds SAP HANA-specific query hints to a CQN Select statement in CAP Java by prefixing hint names with 'hdb.'. This allows optimization or diagnostic hints to be included in generated SQL for SAP HANA.\n\n```java\nSelect.from(BOOKS).hints(\"hdb.USE_HEX_PLAN\", \"hdb.ESTIMATION_SAMPLES(0)\");\n```\n", + " Executing CQL Statements > Data Manipulation > Update\ndata manipulation, update, CQL, CQN, Java\nPerforms an update on the 'bookshop.Books' entity setting the title to 'CAP' for id 101. The returned Result object represents the outcome of the update operation.\n\n```java\nMap book = Map.of(\"title\", \"CAP\");\n\nCqnUpdate update = Update.entity(\"bookshop.Books\").data(book).byId(101);\nResult updateResult = service.run(update);\n```\n", + " Executing CQL Statements > Data Manipulation > Update\ndata manipulation, row count, update, CQL, Java\nRetrieves the number of rows affected by an update operation using rowCount() on the Result. Used after executing a CQN update to confirm how many rows were updated.\n\n```java\nCqnUpdate update = ...;\n\nlong rowCount = service.run(update).rowCount();\n```\n", + " Executing CQL Statements > Structured Documents > Deep Insert / Upsert\ndeep insert, deep upsert, compositions, cascading, insert, upsert, CQL, Java\nDemonstrates deep insert and upsert operations in CAP Java. Cascading is supported by including composition targets in the inserted/upserted data structure.\n\n```java\nIterable> books;\n\nCqnInsert insert = Insert.into(\"bookshop.Books\").entries(books);\nResult result = service.run(insert);\n\nCqnUpsert upsert = Upsert.into(\"bookshop.Books\").entries(books);\nResult result = service.run(upsert);\n```\n", + " Executing CQL Statements > Structured Documents > Cascading Delete\ncascading delete, compositions, delete, CQL, Java\nPerforms a cascading delete operation on 'bookshop.Orders' by OrderNo, deleting the order and all composition targets (e.g., items) in a single step.\n\n```java\nCqnDelete delete = Delete.from(\"bookshop.Orders\").matching(singletonMap(\"OrderNo\", 1000));\nlong deleteCount = service.run(delete).rowCount();\n```\n", + " Executing CQL Statements > Concurrency Control > Optimistic Locking > The ETag Predicate\noptimistic concurrency, etag, update, CQN, Java\nShows how to use an ETag predicate to enable optimistic concurrency control for an update statement in Java. The update only succeeds if the expected timestamp (ETag) matches, protecting data against concurrent modifications.\n\n```java\nPersistenceService db = ...;\nInstant expectedLastModification = ...;\nCqnUpdate update = Update.entity(ORDER).entry(newData)\n .where(o -> o.id().eq(85).and(\n o.eTag(expectedLastModification)));\n\nResult rs = db.execute(update);\n\nif (rs.rowCount() == 0) {\n // order 85 does not exist or was modified concurrently\n}\n```\n", + " Executing CQL Statements > Concurrency Control > Optimistic Locking > Optimistic Concurrency Control in OData\noptimistic concurrency, etag, @cds.on.update, cds model, Java\nCAP CDS model for the Order entity with a managed ETag. The 'modifiedAt' field is automatically updated on each update due to @cds.on.update annotation. Used for optimistic concurrency via ETag in OData and Java.\n\n```cds\nentity Order : cuid {\n @odata.etag\n @cds.on.update : $now\n @cds.on.insert : $now\n modifiedAt : Timestamp;\n product : Association to Product;\n}\n```\n", + " Executing CQL Statements > Concurrency Control > Optimistic Locking > Runtime-Managed Versions \noptimistic concurrency, version, @cds.java.version, cds model, Java\nCDS model for runtime-managed versioning with @cds.java.version, which supports optimistic concurrency using a version field (integer counter) as ETag.\n\n```cds\nentity Order : cuid {\n @odata.etag\n @cds.java.version\n version : Int32;\n product : Association to Product;\n}\n```\n", + " Executing CQL Statements > Concurrency Control > Optimistic Locking > Expected Version from Data\noptimistic concurrency, versioned update, Java\nUpdates an order using a version element (optimistic locking): if the version value is outdated, the update affects no rows, allowing detection of concurrent updates. The version value is populated from previously selected data.\n\n```java\nPersistenceService db = ...;\nCqnSelect select = Select.from(ORDER).byId(85);\nOrder order = db.run(select).single(Order.class);\n\norder.setAmount(5000);\n\nCqnUpdate update = Update.entity(ORDER).entry(order);\nResult rs = db.execute(update);\n\nif (rs.rowCount() == 0) {\n // order 85 does not exist or was modified concurrently\n}\n```\n", + " Executing CQL Statements > Concurrency Control > Optimistic Locking > Expected Version from Data\noptimistic concurrency, bulk update, versioned, Java\nPerforms a bulk update using optimistic locking via version elements. Each update's rowCount is checked to confirm successful update per row, detecting concurrent modifications or missing rows.\n\n```java\nCqnSelect select = Select.from(ORDER).where(o -> amount().gt(1000));\nList orders = db.run(select).listOf(Order.class);\n\norders.forEach(o -> o.setStatus(\"cancelled\"));\n\nResult rs = db.execute(Update.entity(ORDER).entries(orders));\n\nfor(int i = 0; i < orders.size(); i++) if (rs.rowCount(i) == 0) {\n // order does not exist or was modified concurrently\n}\n```\n", + " Executing CQL Statements > Concurrency Control > Pessimistic Locking\npessimistic locking, lock, select, update, CQN, Java\nDemonstrates pessimistic locking by acquiring a lock on a book entity (ID=1) before updating its title in the same transaction. Shows use of lock() in select and protected update.\n\n```java\n// Start transaction\n// Obtain and set a write lock on the book with id 1\n\tservice.run(Select.from(\"bookshop.Books\").byId(1).lock());\n\t...\n// Update the book locked earlier\n\tMap data = Collections.singletonMap(\"title\", \"new title\");\n\tservice.run(Update.entity(\"bookshop.Books\").data(data).byId(1));\n// Finish transaction\n```\n", + " Executing CQL Statements > Using I/O Streams in Queries\nI/O streams, media, insert, LargeBinary, Java, coverImage\nShows how to insert a book with a binary cover image using java.io.InputStream for a @Core.MediaType annotated LargeBinary element ('coverImage'). Demonstrates data streaming capabilities for media types in CAP Java.\n\n```java\n// Transaction started\n\nResult result;\ntry (InputStream resource = getResource(\"IMAGE.PNG\")) {\n Map book = new HashMap<>();\n book.put(\"title\", \"My Fancy Book\");\n book.put(\"coverImage\", resource);\n\n CqnInsert insert = Insert.into(\"bookshop.Books\").entry(book);\n result = service.run(insert);\n}\n\n// Transaction finished\n```\n", + " Executing CQL Statements > Query Result Processing\nresult processing, Result, Row, Java, iterating\nIterates over the Result object returned from a query, printing the 'title' property of each row. Shows the basic iteration pattern of result processing.\n\n```java\nResult result = ...;\n\nfor (Row row : result) {\n System.out.println(row.get(\"title\"));\n}\n```\n", + " Executing CQL Statements > Query Result Processing\nresult processing, stream API, Result, Java\nProcesses the Result set using Java's Stream API: prints the 'title' field for each row both with forEach and stream-map patterns.\n\n```java\nResult result = ...;\n\nresult.forEach(r -> System.out.println(r.get(\"title\")));\n\nresult.stream().map(r -> r.get(\"title\")).forEach(System.out::println);\n```\n", + " Executing CQL Statements > Query Result Processing\nresult processing, single row, Java\nFetches a single row from a Result set, typically used for queries expected to return exactly one result row.\n\n```java\nResult result = ...;\n\nRow row = result.single();\n```\n", + " Executing CQL Statements > Query Result Processing\nresult processing, optional row, first, Java\nFetches the first row (if any) from a query result using Optional. Useful for queries which may or may not yield results.\n\n```java\nResult result = ...;\n\nOptional row = result.first();\nrow.ifPresent(r -> System.out.println(r.get(\"title\")));\n```\n", + " Executing CQL Statements > Query Result Processing\nnested result, getPath, to-one, expand, Java\nSelects a book and its expanded author, retrieving a nested property ('author.name') using getPath(). Demonstrates simple navigation in nested query results.\n\n```java\nCqnSelect select = Select.from(BOOKS).columns(\n b -> b.title(), b -> b.author().expand()).byId(101);\nRow book = dataStore.execute(select).single();\n\nString author = book.getPath(\"author.name\");\n```\n", + " Executing CQL Statements > Query Result Processing > Null Values\nresult processing, null values, Java\nHandles null values in result rows by explicitly checking for null with row.get(). Recommended approach to safely access result data that might be absent.\n\n```java\nif (row.get(\"name\") == null) {\n // handle mising value for name\n}\n```\n", + " Executing CQL Statements > Query Result Processing > Typed Result Processing\ntyped result, interface, typed access, Java\nDefines a typed Java interface for query projection, and maps an untyped Row to the interface for strongly-typed property access (property getters).\n\n```java\ninterface Book {\n String getTitle();\n Integer getStock();\n}\n\nRow row = ...;\nBook book = row.as(Book.class);\n\nString title = book.getTitle();\nInteger stock = book.getStock();\n```\n", + " Executing CQL Statements > Query Result Processing > Typed Result Processing\ntyped result, list, interface, Java\nShows how to retrieve a list of typed results and use streamOf for mapping results to a custom map using Java's Stream collectors.\n\n```java\nResult result = ...;\n\nList books = result.listOf(Book.class);\n\nMap titleToDescription =\n result.streamOf(Book.class).collect(Collectors.toMap(Book::getTitle, Book::getDescription));\n```\n", + " Executing CQL Statements > Query Result Processing > Entity References\nentity reference, ref, typed, Java\nShows how to obtain a typed entity reference from a query result, after retrieving the Author[101] data. The reference (author.ref()) can be used for building further queries.\n\n```java\n// SELECT from Author[101]\nCqnSelect query = Select.from(AUTHOR).byId(101);\nAuthor authorData = service.run(query).single(Author.class);\n\nString authorName = authorData.getName(); // data access\nAuthor_ author = authorData.ref(); // typed reference to Author[101]\n```\n", + " Executing CQL Statements > Query Result Processing > Entity References\nentity reference, ref, untyped, Java\nRetrieves an untyped entity reference from a result Row for further CQN query composition.\n\n```java\nRow authorData = service.run(query).single();\nStructuredType author = authorData.ref(); // untyped reference to Author[101]\n```\n", + " Executing CQL Statements > Query Result Processing > Entity References\nentity reference, insert, update, ref, Java\nDemonstrates obtaining a typed entity reference from the result of an update operation, useful for chained query construction.\n\n```java\nCqnUpdate update = Update.entity(AUTHOR).data(\"name\", \"James Joyce\").byId(101);\nAuthor_ joyce = service.run(update).single(Author.class).ref();\n```\n", + " Executing CQL Statements > Query Result Processing > Entity References\nentity reference, proceed, follow-up query, Java\nDemonstrates the use of an entity reference to perform follow-up select, insert, update, and delete operations scoped to a specific entity instance.\n\n```java\n// SELECT from Author[101].books { sum(stock) as stock }\nCqnSelect q = Select.from(joyce.books())\n .columns(b -> func(\"sum\", b.stock()).as(\"stock\"));\n\nCqnInsert i = Insert.into(joyce.books())\n .entry(\"title\", \"Ulysses\");\n\nCqnUpdate u = Update.entity(joyce.biography())\n .data(\"price\", 29.95);\n\nCqnDelete d = Delete.from(joyce.address())\n .where(b -> b.stock().lt(1));\n```\n", + " Executing CQL Statements > Query Result Processing > Introspecting the Row Type\nrow type introspection, rowType, CdsStructuredType, Java\nShows how to use the rowType method on a Result to introspect field names and types of the result structure after a query. Useful for dynamic/runtime inspection of result metadata.\n\n```java\nCqnSelect query = Select.from(AUTHOR)\n .columns(a -> a.name().as(\"authorName\"), a -> a.age());\n\nResult result = service.run(query);\n\nCdsStructuredType rowType = result.rowType();\nrowType.elements(); // \"authorName\", \"age\"\nrowType.getElement(\"age\").getType().getQualifiedName(); // \"cds.Integer\"\nrowType.findElement(\"ID\"); // Optional.empty()\n```\n", + " Introspecting CQL Statements > CqnAnalyzer\nCqnAnalyzer, CDS model, API, Java, introspection, cds modeling\nInstantiate a CqnAnalyzer for analyzing CQL statements, based on a given CDS model. Used in handler implementations to introspect and extract structural and value information from CQN queries.\n\n```java\nimport com.sap.cds.ql.cqn.CqnAnalyzer;\n\nCdsModel cdsModel = context.getModel();\nCqnAnalyzer cqnAnalyzer = CqnAnalyzer.create(cdsModel);\n```\n", + " Introspecting CQL Statements > CqnAnalyzer\nCqnAnalyzer, isCountQuery, count, CQL, Java, utility\nCheck if a given CQL query only returns a single count using the static isCountQuery method of CqnAnalyzer. Useful for query optimizations or flow control in handlers.\n\n```java\n// cqn: Select.from(\"Books\").columns(CQL.count().as(\"bookCount\"));\nboolean isCount = CqnAnalyzer.isCountQuery(cqn); // true\n```\n", + " Introspecting CQL Statements > CqnAnalyzer\nCqnAnalyzer, analyze, CQN, analysis, Java\nAnalyze a CQN statement using the analyze() method of CqnAnalyzer. Produces an AnalysisResult object for further introspection of CDS entities, keys, and filter values.\n\n```java\nCqnStatement cqn = context.getCqn();\n\nAnalysisResult result = cqnAnalyzer.analyze(cqn.ref());\n```\n", + " Introspecting CQL Statements > CqnAnalyzer > Resolving CDS Entities\nCqnAnalyzer, CDS entities, Reflection API, rootEntity, targetEntity, CDS model, Java\nUse the AnalysisResult to access the root and target CDS entities referenced by the analyzed CQN statement using the Reflection API.\n\n```java\nCdsEntity order = result.rootEntity(); // Orders\nCdsEntity item = result.targetEntity(); // OrderItems\n```\n", + " Introspecting CQL Statements > CqnAnalyzer > Extracting Filter Values\nCqnAnalyzer, filter extraction, rootKeys, targetKeys, targetValues, filters, Java\nExtract key and filter values from an AnalysisResult after analyzing a CQN statement using CqnAnalyzer. Supports rootKeys, targetKeys, and complete filterValues extraction for use in handler logic.\n\n```java\nMap rootKeys = result.rootKeys();\nString orderNo = (String) rootKeys.get(\"OrderNo\"); // 42\n\nMap targetKeys = result.targetKeys();\nInteger itemId = (Integer) targetKeys.get(\"ID\"); // 1\n\nMap filterValues = result.targetValues();\n```\n", + " Introspecting CQL Statements > CqnAnalyzer > Extracting Filter Values\nCqnAnalyzer, where clause, filter extraction, CqnSelect, CQL, Java\nDemonstrates extracting key and additional filter values for CqnSelect/CqnUpdate/CqnDelete statements with a WHERE clause using CqnAnalyzer's AnalysisResult methods.\n\n```java\nCqnSelect select = context.getCqn();\nAnalysisResult result = cqnAnalyzer.analyze(select);\n\nMap targetKeys = result.targetKeys();\nInteger itemId = (Integer) targetKeys.get(\"ID\"); // 3\n\nMap filterValues = result.targetValues();\nString status = (String) filterValues.get(\"status\"); // 'open'\n```\n", + " Introspecting CQL Statements > CqnAnalyzer > Using the Iterator\nCqnAnalyzer, ResolvedSegment, iterator, reference segment, Java\nUse AnalysisResult's iterator to traverse and analyze each resolved segment (entity or reference) of a multi-segment CQN statement.\n\n```java\nIterator iterator = result.iterator();\nCdsEntity order = iterator.next().entity();\nCdsEntity item = iterator.next().entity();\nCdsEntity book = iterator.next().entity();\n```\n", + " Introspecting CQL Statements > CqnAnalyzer > Using the Iterator\nCqnAnalyzer, ResolvedSegment, reverse traversal, reference segment, Java\nTraverse resolved segments of a CQN reference in reverse order using AnalysisResult's reverse iterator. Useful for handling nested or deeply referenced queries.\n\n```java\nIterator iterator = result.reverse();\nCdsEntity book = iterator.next().entity();\nCdsEntity item = iterator.next().entity();\nCdsEntity order = iterator.next().entity();\n```\n", + " Introspecting CQL Statements > CqnVisitor > Usage\nCqnVisitor, Visitor Pattern, CQL, predicate evaluation, Java\nA CqnVisitor implementation to evaluate if a given data entry matches a filter predicate by maintaining a stack for intermediate results. The class can be extended to stack and evaluate CQN trees.\n\n```java\nclass CheckDataVisitor implements CqnVisitor {\n private final Map data;\n private final Deque stack = new ArrayDeque<>();\n\n CheckDataVisitor(Map data) {\n this.data = data;\n }\n\n boolean matches() {\n return (Boolean) stack.pop();\n }\n ...\n}\n```\n", + " Introspecting CQL Statements > CqnVisitor > Usage\nCqnVisitor, element reference, CQL, predicate tree, Java\nOverrides for CqnVisitor to handle leaf nodes: element references (extract value from data) and literals (push value), building the basis for evaluating predicates.\n\n```java\n@Override\npublic void visit(CqnElementRef ref) {\n Object dataValue = data.get(ref.displayName());\n stack.push(dataValue);\n}\n\n@Override\npublic void visit(CqnLiteral literal) {\n stack.push(literal.value());\n}\n```\n", + " Introspecting CQL Statements > CqnVisitor > Usage\nCqnVisitor, predicate evaluation, comparison, IN, stack, Java\nImplement visit methods to perform IN and comparison predicate evaluation by popping stack values and pushing result. Allows runtime evaluation of CQN filters against in-memory data.\n\n```java\n@Override\npublic void visit(CqnInPredicate in) {\n List values = in.values().stream()\n .map(v -> stack.pop()).collect(toList());\n Object value = stack.pop();\n stack.push(values.stream().anyMatch(value::equals));\n}\n\n@Override\npublic void visit(CqnComparisonPredicate comparison) {\n Comparable rhs = (Comparable) stack.pop();\n Comparable lhs = (Comparable) stack.pop();\n int cmp = lhs.compareTo(rhs);\n switch (comparison.operator()) {\n case EQ:\n stack.push(cmp == 0);\n break;\n case GT:\n stack.push(cmp > 0);\n break;\n // ...\n }\n}\n```\n", + " Introspecting CQL Statements > CqnVisitor > Usage\nCqnVisitor, connective predicate, logical AND/OR, predicate evaluation, stack, Java\nImplements the visit method for logical connective predicates (AND/OR) in CqnVisitor, combining results from stack-popped child evaluations. Used in evaluating complex filter trees.\n\n```java\n@Override\npublic void visit(CqnConnectivePredicate connect) {\n Boolean rhs = (Boolean) stack.pop();\n Boolean lhs = (Boolean) stack.pop();\n switch (connect.operator()) {\n case AND:\n stack.push(lhs && rhs);\n break;\n case OR:\n stack.push(lhs || rhs);\n break;\n }\n}\n```\n", + " Introspecting CQL Statements > CqnVisitor > Usage\nCqnVisitor, predicate evaluation, usage example, Java, in-memory filtering\nExample of using a CqnVisitor implementation to iterate and evaluate a filter expression against a list of data. Shows how to traverse and reduce a predicate tree for in-memory filtering.\n\n```java\nfor (Map book : books) {\n CheckDataVisitor v = new CheckDataVisitor(book);\n filter.accept(v);\n System.out.println(book.get(\"title\") + \" \" +\n (v.matches() ? \"match\" : \"no match\"));\n}\n```\n", + " Services > Using Services\nservice catalog, ServiceCatalog, Java, lookup, ApplicationService, service discovery\nThis snippet demonstrates how to access the ServiceCatalog from an EventContext, retrieve all services, and filter services by type (e.g., ApplicationService) in CAP Java SDK. Useful for dynamic service discovery and interaction.\n\n```java\nServiceCatalog catalog = context.getServiceCatalog();\nStream allServices = catalog.getServices();\nStream appServices = catalog.getServices(ApplicationService.class);\n```\n", + " Services > Using Services\nservice catalog, ApplicationService, lookup, Java, service name\nShows how to look up an ApplicationService by its CDS name in the ServiceCatalog. Essential when you know the CDS definition service name and want to obtain a typed reference.\n\n```java\nApplicationService adminService = catalog.getService(ApplicationService.class, \"AdminService\");\n```\n", + " Services > Using Services\nservice catalog, AdminService, specific interface, Java, typed services\nIllustrates using a generated specific service interface (AdminService) from the CAP Java SDK Maven Plugin to retrieve the typed service from the ServiceCatalog by name.\n\n```java\nAdminService adminService = catalog.getService(AdminService.class, \"AdminService\");\n```\n", + " Services > Using Services\nPersistenceService, service catalog, DEFAULT_NAME, Java, database service\nDemonstrates how to retrieve the default PersistenceService from the ServiceCatalog using the DEFAULT_NAME constant. Generic approach for built-in technical services.\n\n```java\nPersistenceService db = catalog.getService(PersistenceService.class, PersistenceService.DEFAULT_NAME);\n```\n", + " Services > Using Services\nSpring, dependency injection, PersistenceService, ApplicationService, Java, service access\nShows dependency injection of CAP services in a Spring component. PersistenceService and a named ApplicationService (with @Qualifier) are injected as Spring beans for convenient access.\n\n```java\n@Component\npublic class EventHandlerClass implements EventHandler {\n\n @Autowired\n private PersistenceService db;\n\n @Autowired\n @Qualifier(\"AdminService\")\n private ApplicationService adminService;\n\n}\n```\n", + " Services > Using Services\nSpring, dependency injection, PersistenceService, AdminService, Java, specific interface injection\nDepicts dependency injection in a Spring-managed bean using the specific AdminService interface. @Qualifier is not required for specific interfaces; injection is resolved by type.\n\n```java\n@Component\npublic class EventHandlerClass implements EventHandler {\n\n @Autowired\n private PersistenceService db;\n\n @Autowired\n private AdminService adminService;\n\n}\n```\n", + " CQN Services > Application Services\njava, CQN, Application Service, service implementation, event handler\nDefines a custom event handler class for an Application Service in CAP Java. Demonstrates how to handle CQN-based read (SELECT) events. Additional business logic or validation can be added inside the handler. Application Services expose APIs from CDS models and only accept CQN targeting their defined entities.\n\n```java\nimport com.sap.cds.services.cds.ApplicationService;\nimport com.sap.cds.services.handler.EventHandler; // marker annotation\nimport com.sap.cds.services.handler.EventListener;\nimport com.sap.cds.ql.cqn.CqnSelect;\nimport com.sap.cds.Result;\n\n@EventHandler(service = ApplicationService.class)\npublic class MyApplicationServiceHandler {\n @EventListener\n public void onRead(CqnSelect select, ApplicationService srv) {\n Result result = srv.run(select);\n // custom logic or validation can be added here\n }\n}\n```\n", + " CQN Services > Persistence Services\njava, CQN, Persistence Service, transaction, database, service implementation\nShows how to use the Persistence Service in CAP Java to handle CQN-based UPDATE events. The Persistence Service is a CQN client to the database, not limited to a specific CDS service definition and supports transactions. Useful for adding custom data operations or implementing event handlers for Application Services.\n\n```java\nimport com.sap.cds.services.persistence.PersistenceService;\nimport com.sap.cds.ql.cqn.CqnUpdate;\nimport com.sap.cds.Result;\n\npublic class MyPersistenceServiceHandler {\n private final PersistenceService db;\n public MyPersistenceServiceHandler(PersistenceService db) {\n this.db = db;\n }\n public void onUpdate(CqnUpdate update) {\n db.run(update);\n }\n}\n```\n", + " CQN Services > Application Services > Draft Services\njava, CQN, Draft Service, draft entity, fiori\nIllustrates how to obtain and use the DraftService in CAP Java when the service definition contains draft-enabled entities. DraftService provides APIs for managing Fiori draft-enabled entities, e.g., creating drafts, patching, saving, and canceling.\n\n```java\nimport com.sap.cds.services.draft.DraftService;\nimport com.sap.cds.services.cds.ApplicationService;\n\npublic class MyDraftHandler {\n private final DraftService draftService;\n public MyDraftHandler(ApplicationService appService) {\n // If the service definition has a draft-enabled entity, it also offers DraftService\n this.draftService = appService.draft();\n }\n public void createDraftEntity() {\n // Example of creating a draft, refer to DraftService API for details\n draftService.newDraftEntity(/* ... */);\n }\n}\n```\n", + " CQN Services > Remote Services\njava, CQN, Remote Service, OData, service integration\nDemonstrates how to connect to a remote API using CAP Java's RemoteService, executing a CQN SELECT statement against a remote OData or similar endpoint. Remote Services are configured explicitly, based on imported CDS service definitions, and are used for synchronous or asynchronous service integration.\n\n```java\nimport com.sap.cds.services.cds.RemoteService;\nimport com.sap.cds.ql.cqn.CqnSelect;\nimport com.sap.cds.Result;\n\npublic class MyRemoteServiceHandler {\n private final RemoteService remote;\n public MyRemoteServiceHandler(RemoteService remote) {\n this.remote = remote;\n }\n public Result fetchRemoteData(CqnSelect select) {\n return remote.run(select);\n }\n}\n```\n", + " Persistence Services > Database Support > SAP HANA Cloud\nCDS modeling, SAP HANA, collation, annotation\nDefines a CDS entity 'Books' where the 'isbn' element disables locale-specific collation by using '@cds.collate: false'. This is essential for performance optimization in SAP HANA when locale-sensitive ordering is not required for specific String fields.\n\n```cds\nentity Books : cuid {\n title : localized String(111);\n descr : localized String(1111);\n @cds.collate : false // [!code focus]\n isbn : String(40); // does not require locale-specific handling // [!code focus]\n}\n```\n", + " Persistence Services > Datasource Configuration\nconfiguration, application.yaml, connection pool, HikariCP\nConfigures the HikariCP connection pool with a maximum pool size of 20 for a datasource named 'my-service-instance'. This snippet is part of controlling database connection pooling in Spring Boot for CAP Java.\n\n```yaml\ncds:\n dataSource:\n my-service-instance:\n hikari:\n maximum-pool-size: 20\n```\n", + " Persistence Services > Datasource Configuration\nconfiguration, application.yaml, HANA, connection, JDBC\nAdds a SAP HANA-specific JDBC property 'packetSize' (set to 300000) to a datasource configuration using the Hikari pool in application.yaml. Used to fine-tune the SAP HANA connection from CAP Java.\n\n```yaml\ncds:\n dataSource:\n my-service-instance:\n hikari:\n data-source-properties:\n packetSize: 300000\n```\n", + " Persistence Services > SAP HANA > Configure the DDL generation\nconfiguration, CDS compiler, SAP HANA, .cdsrc.json\nConfigures the CDS compiler to not generate native SAP HANA associations in the SQL model, as associations are not utilized natively by CAP Java for SAP HANA. Placed in .cdsrc.json.\n\n```json\n{ \"sql\": { \"native_hana_associations\" : false } }\n```\n", + " Persistence Services > SAP HANA > SQL Optimization Mode\nconfiguration, application.yaml, sql.hana.optimizationMode\nYAML configuration to set the SAP HANA SQL optimization mode to 'legacy', allowing generation of SQL statements compatible with HANA 2.x or SAP HANA Cloud environments when using CAP Java.\n\n```yaml\ncds.sql.hana.optimizationMode: legacy\n```\n", + " Persistence Services > PostgreSQL > Initial Database Schema\nschema generation, PostgreSQL, schema.sql, cds-maven-plugin, Maven\nConfigures the cds-maven-plugin in pom.xml to generate a schema.sql for PostgreSQL by running 'cds deploy --to postgres --dry'. The output file will be placed in 'src/main/resources/schema.sql'.\n\n```xml\n\n\tschema.sql\n\t\n\t\tcds\n\t\n\t\n\t\t\n\t\t\tdeploy --to postgres --dry --out \"${project.basedir}/src/main/resources/schema.sql\"\n\t\t\n\t\n\n```\n", + " Persistence Services > PostgreSQL > Initial Database Schema\nnpm, CLI, postgres, cds-dk\nShell command using CDS CLI to add PostgreSQL support to a CAP Java project. Installs all necessary dependencies and configuration.\n\n```shell\ncds add postgres\n```\n", + " Persistence Services > PostgreSQL > Configure the Connection Data Explicitly\nconfiguration, application.yaml, PostgreSQL, JDBC\nExplicitly configures connection data for PostgreSQL in application.yaml for a specific profile. This includes URL, credentials, and the JDBC driver class name.\n\n```yaml\n---\nspring:\n config.activate.on-profile: postgres\n datasource:\n url: \n username: \n password: \n driver-class-name: org.postgresql.Driver\n```\n", + " Persistence Services > H2\nschema generation, H2, schema.sql, cds-maven-plugin\nConfigures the cds-maven-plugin to generate H2 database schema (schema.sql) by running a dry run deployment for the 'h2' dialect.\n\n```xml\n\n\tschema.sql\n\t\n\t\tcds\n\t\n\t\n\t\t\n\t\t\tdeploy --to h2 --dry --out \"${project.basedir}/src/main/resources/schema.sql\"\n\t\t\n\t\n\n```\n", + " Persistence Services > H2\nnpm, CLI, H2, cds-dk\nCLI command to add H2 in-memory/database support to CAP Java project with the CDS toolkit.\n\n```shell\ncds add h2\n```\n", + " Persistence Services > SQLite > Initial Database Schema\nschema generation, SQLite, schema.sql, cds-maven-plugin\nMaven configuration for the cds-maven-plugin to generate a schema.sql file for SQLite by performing a dry deployment.\n\n```xml\n\n\tschema.sql\n\t\n\t\tcds\n\t\n\t\n\t\t\n\t\t\tdeploy --to sqlite --dry --out \"${project.basedir}/src/main/resources/schema.sql\"\n\t\t\n\t\n\n```\n", + " Persistence Services > SQLite > Initial Database Schema\nnpm, CLI, SQLite, cds-dk\nCLI command for adding SQLite database support to your CAP Java project using the CDS toolkit.\n\n```shell\ncds add sqlite\n```\n", + " Persistence Services > SQLite > File-Based Storage\nconfiguration, application.yaml, SQLite, file-based\nConfigures SQLite in file-based mode for a CAP Java Spring Boot application. Disables automatic schema initialization and uses a single connection in the Hikari pool. Database file is 'sqlite.db'.\n\n```yaml\n---\nspring:\n config.activate.on-profile: sqlite\n sql:\n init:\n mode: never\n datasource:\n url: \"jdbc:sqlite:sqlite.db\"\n driver-class-name: org.sqlite.JDBC\n hikari:\n maximum-pool-size: 1\n```\n", + " Persistence Services > SQLite > In-Memory Storage\nconfiguration, application.yaml, SQLite, in-memory\nConfigures SQLite to run as an in-memory database for local development and testing. Uses Spring Boot, Hikari pool (max 1, no lifetime limit), and schema is initialized automatically.\n\n```yaml\n---\nspring:\n config.activate.on-profile: default\n sql:\n init:\n mode: always\n datasource:\n url: \"jdbc:sqlite:file::memory:?cache=shared\"\n driver-class-name: org.sqlite.JDBC\n hikari:\n maximum-pool-size: 1\n max-lifetime: 0\n```\n", + " Persistence Services > Additional Persistence Services\nconfiguration, application.yaml, Persistence Service, Multiple Databases\nMaps a logical Persistence Service name (\"my-ps\") to a database service binding (\"my-hana-hdi\"). Allows explicit naming and selection of additional (non-default) persistence services for multi-database scenarios.\n\n```yaml\ncds:\n persistence.services:\n my-ps:\n binding: \"my-hana-hdi\"\n```\n", + " Persistence Services > Additional Persistence Services\nconfiguration, application.yaml, Persistence Service, disable\nDisables automatic creation of a Persistence Service for the service binding named 'my-hana-hdi'. Useful for fine-grained control over which database bindings have services exposed in CAP Java.\n\n```yaml\ncds:\n persistence.services:\n my-hana-hdi:\n enabled: false\n```\n", + " Persistence Services > Additional Persistence Services\nJava, Spring, DataSource, bean, custom datasource\nDemonstrates creating a custom DataSource bean in Java (Spring). Can be used for registering additional non-default datasources in CAP Java applications.\n\n```java\n@Configuration\npublic class DataSourceConfig {\n\n @Bean\n public DataSource customDataSource() {\n return DataSourceBuilder.create()\n .url(\"jdbc:sqlite:sqlite.db\")\n .build();\n }\n\n}\n```\n", + " Persistence Services > Additional Persistence Services\nconfiguration, application.yaml, Persistence Service, custom datasource\nBinds a logical Persistence Service ('my-ps') to a custom DataSource bean ('customDataSource'). Needed for linking non-default data sources registered as Spring beans in CAP Java.\n\n```yaml\ncds:\n persistence.services:\n my-ps:\n dataSource: \"customDataSource\"\n```\n", + " Persistence Services > Example: Multitenant Application with Tenant-independent Datasource\nconfiguration, application.yaml, multitenancy, Persistence Service, Service Manager\nConfigures the Service Manager binding as the primary datasource in a multitenant CAP Java application, ensuring the default Persistence Service is created from it.\n\n```yaml\nspring:\n config.activate.on-profile: cloud\ncds:\n dataSource:\n binding: \"my-service-manager-binding\"\n```\n", + " Persistence Services > Example: Multitenant Application with Tenant-independent Datasource > Local Development and Testing with MTX\nJava, Spring, DataSource, multitenancy, DataSourceInitializer\nConfigures an in-memory, tenant-independent datasource for local development/testing in CAP Java multitenancy. Initializes the schema using schema.sql on startup using Spring DataSourceInitializer.\n\n```java\n@Configuration\npublic class DataSourceConfig {\n\n @Bean\n @ConfigurationProperties(\"app.datasource.tenant-independent\")\n public DataSourceProperties tenantIndependentDataSourceProperties() {\n return new DataSourceProperties();\n }\n\n @Bean\n public DataSource tenantIndependentDataSource() {\n return tenantIndependentDataSourceProperties()\n .initializeDataSourceBuilder()\n .build();\n }\n\n @Bean\n public DataSourceInitializer tenantIndependentInitializer() {\n ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();\n resourceDatabasePopulator.addScript(new ClassPathResource(\"schema.sql\"));\n\n DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();\n dataSourceInitializer.setDataSource(tenantIndependentDataSource());\n dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);\n return dataSourceInitializer;\n }\n\n}\n```\n", + " Persistence Services > Example: Multitenant Application with Tenant-independent Datasource > Local Development and Testing with MTX\nconfiguration, application.yaml, Persistence Service, tenant-independent\nBinds the 'tenant-independent' Persistence Service to the 'tenantIndependentDataSource' bean and marks 'mtx-sqlite' as the primary datasource for a local MTX development/testing environment.\n\n```yaml\nspring:\n config.activate.on-profile: local-mtxs\ncds:\n persistence.services:\n tenant-independent:\n dataSource: \"tenantIndependentDataSource\"\n dataSource:\n binding: \"mtx-sqlite\"\n```\n", + " Persistence Services > Example: Multitenant Application with Tenant-independent Datasource > Local Development and Testing without MTX\nJava, Spring, DataSource, multitenancy, transaction manager\nDefines two in-memory datasources and transaction manager beans using Spring Boot Java Config for single-tenant (without MTX) testing in CAP Java: one as primary for tenant-dependent data and another for tenant-independent persistence. Ensures both are initialized with the schema.\n\n```java\n@Configuration\npublic class DataSourceConfig {\n\n /**\n * Configuration of tenant-dependant persistence\n */\n\n @Bean\n @Primary\n @ConfigurationProperties(\"app.datasource.tenant-dependent\")\n public DataSourceProperties tenantDependentDataSourceProperties() {\n return new DataSourceProperties();\n }\n\n @Bean\n @Primary\n public DataSource tenantDependentDataSource() {\n return tenantDependentDataSourceProperties()\n .initializeDataSourceBuilder()\n .build();\n }\n\n @Bean\n @Primary\n public DataSourceTransactionManager tenantDependentTransactionManager() {\n return new DataSourceTransactionManager(tenantDependentDataSource());\n }\n\n /**\n * Configuration of tenant-independent persistence\n */\n\n @Bean\n @ConfigurationProperties(\"app.datasource.tenant-independent\")\n public DataSourceProperties tenantIndependentDataSourceProperties() {\n return new DataSourceProperties();\n }\n\n @Bean\n public DataSource tenantIndependentDataSource() {\n return tenantIndependentDataSourceProperties()\n .initializeDataSourceBuilder()\n .build();\n }\n\n @Bean\n public DataSourceInitializer tenantIndependentInitializer() {\n ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();\n resourceDatabasePopulator.addScript(new ClassPathResource(\"schema.sql\"));\n\n DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();\n dataSourceInitializer.setDataSource(tenantIndependentDataSource());\n dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);\n return dataSourceInitializer;\n }\n\n}\n```\n", + " Persistence Services > Example: Multitenant Application with Tenant-independent Datasource > Local Development and Testing without MTX\nconfiguration, application.yaml, Persistence Service, tenant-independent\nConfigures the 'tenant-independent' Persistence Service to use the 'tenantIndependentDataSource' bean for a single-tenant local testing scenario (no MTX) in CAP Java.\n\n```yaml\nspring:\n config.activate.on-profile: local\ncds:\n persistence.services:\n tenant-independent:\n dataSource: \"tenantIndependentDataSource\"\n```\n", + " Persistence Services > Native SQL > Native SQL with JDBC Templates\nJava, Spring, jdbcTemplate, native SQL\nIllustrates using Spring's JdbcTemplate for native SQL execution and stored procedure calls in a CAP Java handler. Operations are managed within Spring's transaction context.\n\n```java\n@Autowired\nJdbcTemplate jdbcTemplate;\n...\n\npublic void setStockForBook(int id, int stock) {\n jdbcTemplate.update(\"call setStockForBook(?,?)\", id, stock); // Run the stored procedure `setStockForBook(id in number, stock in number)`\n}\n\npublic int countStock(int id) {\n SqlParameterSource namedParameters = new MapSqlParameterSource().addValue(\"id\", id);\n return jdbcTemplate.queryForObject(\n \"SELECT stock FROM Books WHERE id = :id\", namedParameters, Integer.class); // Run native SQL\n}\n```\n", + " Persistence Services > Using CQL with a Static CDS Model > Model Interfaces\nCDS modeling, Java, static model, accessor interfaces\nDefines CDS entities Books and Authors with associations, to demonstrate the static model interface and accessor interface generation in CAP Java.\n\n```cds\nnamespace my.bookshop;\n\nentity Books {\n key ID : Integer;\n title : String(111);\n author : Association to Authors;\n}\n\nentity Authors {\n key ID : Integer;\n name : String(111);\n books : Association to many Books on books.author = $self;\n}\n```\n", + " Persistence Services > Using CQL with a Static CDS Model > Model Interfaces\nJava, static model, model interface\nA generated static model interface (Books_) for a CDS entity, enabling type-safe CQL query construction for 'Books' in CAP Java.\n\n```java\n@CdsName(\"my.bookshop.Books\")\npublic interface Books_ extends StructuredType {\n ElementRef ID();\n ElementRef title();\n Authors_ author();\n Authors_ author(Function filter);\n}\n```\n", + " Persistence Services > Using CQL with a Static CDS Model > Model Interfaces\nJava, static model, model interface\nGenerated static model interface (Authors_) for describing entity structure and providing type-safe query capabilities for 'Authors' entity in CAP Java.\n\n```java\n@CdsName(\"my.bookshop.Authors\")\npublic interface Authors_ extends StructuredType {\n ElementRef ID();\n ElementRef name();\n Books_ books();\n Books_ books(Function filter);\n}\n```\n", + " Persistence Services > Using CQL with a Static CDS Model > Accessor Interfaces\nJava, accessor interface, static model\nAccessor interface generated for the 'Books' entity in static model; provides getters and setters matching the CDS structure, enabling conversion of query results to typed Java objects.\n\n```java\n@CdsName(\"my.bookshop.Books\")\npublic interface Books extends CdsData {\n\n String ID = \"ID\";\n String TITLE = \"title\";\n String AUTHOR = \"author\";\n\n Integer getID();\n void setID(Integer id);\n\n String getTitle();\n void setTitle(String title);\n\n Authors getAuthor();\n void setAuthor(Map author);\n}\n```\n", + " Persistence Services > Using CQL with a Static CDS Model > Javadoc comments\nCDS modeling, Javadoc comments, Java, static model\nCDS entity model (Authors) with doc comments. These Javadoc comments are carried to the generated Java accessor interfaces for enhanced documentation.\n\n```cds\nnamespace my.bookshop;\n/**\n * The creator/writer of a book, article, or document.\n */\nentity Authors {\n key ID : Integer;\n /**\n * The name of the author.\n */\n name : String(30);\n}\n```\n", + " Persistence Services > Using CQL with a Static CDS Model > Javadoc comments\nJava, accessor interface, Javadoc comments\nGenerated Java accessor interface, complete with transferred Javadoc comments, for a CDS entity with doc comments in the model (Authors).\n\n```java\n/**\n * The creator/writer of a book, article, or document.\n */\n@CdsName(\"my.bookshop.Authors\")\npublic interface Authors extends CdsData {\n\n String ID = \"ID\";\n String NAME = \"name\";\n\n Integer getId();\n void setId(Integer id);\n /**\n * The name of the author.\n */\n String getName();\n /**\n * The name of the author.\n */\n void setName(String name);\n}\n```\n", + " Persistence Services > Using CQL with a Static CDS Model > Usage\nJava, static model, query builder, type safe, query\nShows how to build a type-safe CQL query using static model interfaces (Books_) and execute it, converting the result to a list of the accessor interface (Books) in CAP Java.\n\n```java\n// Note the usage of model interface `Books_` here\nSelect query = Select.from(Books_.class)\n .columns(book -> book.title())\n .where (book -> book.author().name().eq(\"Edgar Allan Poe\"));\n\n// After executing the query the result can be converted to\n// a typed representation List of Books.\nList books = dataStore.execute(query).listOf(Books.class);\n```\n", + " Application Services > Handling CRUD Events\nJava, event handler, CRUD, application service, CqnService, Books, create event, event context\nRegisters a 'before CREATE' event handler for the 'Books' entity in an Application Service. Receives the CdsCreateEventContext and a list of Books entities, enabling business logic extension before entity creation.\n\n```java\n@Before(event = CqnService.EVENT_CREATE, entity = Books_.CDS_NAME)\npublic void createBooks(CdsCreateEventContext context, List books) { }\n```\n", + " Application Services > Handling CRUD Events > OData Requests\nOData, URL, service endpoint, configuration\nShows the generic access URL pattern for OData APIs exposed by CAP Java Application Services. The can be configured by properties, and is the fully qualified CDS service name or overridden via @path.\n\n```txt\nhttp(s):////\n```\n", + " Application Services > Handling CRUD Events > Deeply Structured Documents\nJava, deep validation, composition, event handler, CRUD, order validation, OrderItems, Orders\nImplements deep validation by registering handlers for parent ('Orders') and composed child ('OrderItems') entities. Custom logic walks through order items during order creation, and invalid business data (e.g., quantity <= 0) is rejected with an exception.\n\n```java\n@Before(event = CqnService.EVENT_CREATE, entity = Orders_.CDS_NAME)\npublic void validateOrders(List orders) {\n for(Orders order : orders) {\n if (order.getItems() != null) {\n validateItems(order.getItems());\n }\n }\n}\n\n@Before(event = CqnService.EVENT_CREATE, entity = OrderItems_.CDS_NAME)\npublic void validateItems(List items) {\n for(OrderItems item : items) {\n if (item.getQuantity() <= 0) {\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid quantity\");\n }\n }\n}\n```\n", + " Application Services > Result Handling > READ Result\nJava, READ handler, count, OData $count, CqnAnalyzer, event context, result\nCustom READ event handler for handling OData $count requests in CAP Java. When an inline count request is detected via CqnAnalyzer, returns the count as a Map with key 'count'.\n\n```java\n@On(entity = MyEntity_.CDS_NAME)\nList> readMyEntity(CdsReadEventContext context) {\n\tif (CqnAnalyzer.isCountQuery(context.getCqn())) {\n\t\tint count = 100; // determine correct count value\n\t\treturn List.of(Collections.singletonMap(\"count\", count));\n\t}\n\t// handle non /$count requests\n}\n```\n", + " Application Services > Result Handling > Result Builder\nJava, ResultBuilder, selectedRows, read result, setResult, hashmap, event context\nIllustrates using the ResultBuilder.selectedRows to construct and set a result for a READ event handler in CAP Java. Returns a single row result with field 'title'.\n\n```java\nimport static java.util.Arrays.asList;\nimport static com.sap.cds.ResultBuilder.selectedRows;\n\nMap row = new HashMap<>();\nrow.put(\"title\", \"Capire\");\nResult res = selectedRows(asList(row)).result();\ncontext.setResult(res); // CdsReadEventContext\n```\n", + " Application Services > Result Handling > Result Builder\nJava, ResultBuilder, inlineCount, read result, OData $count\nShows setting the inline count property on a Result object for query results with inlined entity counts, important for OData $count scenarios.\n\n```java\nResult r = selectedRows(asList(row)).inlineCount(inlineCount).result();\n```\n", + " Application Services > Result Handling > Result Builder\nJava, ResultBuilder, updatedRows, update result\nCreates a result for an UPDATE event handler, including the number of updated rows and the updated data. Uses ResultBuilder.updatedRows.\n\n```java\nimport static com.sap.cds.ResultBuilder.updatedRows;\n\nint updateCount = 1; // number of updated rows\nMap data = new HashMap<>();\ndata.put(\"title\", \"CAP Java\");\nResult r = updatedRows(updateCount, data).result();\n```\n", + " Application Services > Result Handling > Result Builder\nJava, ResultBuilder, deletedRows, delete result\nShows how to create a result representing the number of rows deleted in a custom DELETE event handler, using ResultBuilder.deletedRows.\n\n```java\nimport static com.sap.cds.ResultBuilder.deletedRows;\n\nint deleteCount = 7;\nResult r = deletedRows(deleteCount).result();\n```\n", + " Application Services > Actions and Functions > Implement Event Handler\ncds modeling, actions, functions, review action, CatalogService, bound action\nDefines a CAP CatalogService with an entity Books and a bound custom action 'review' that takes an integer parameter and returns Reviews. The action is attached to the Books entity.\n\n```cds\nservice CatalogService {\n entity Books {\n key ID: UUID;\n title: String;\n } actions {\n action review(stars: Integer) returns Reviews;\n };\n\n entity Reviews {\n book : Association to Books;\n stars: Integer;\n }\n}\n```\n", + " Application Services > Actions and Functions > Implement Event Handler\nJava, event context, action handler, review, bound action, ReviewEventContext\nRegisters and implements a handler for the custom 'review' action on Books. Accesses the parameter and result through the generated ReviewEventContext interface. Used for adding custom business logic to a bound action.\n\n```java\n@Component\n@ServiceName(CatalogService_.CDS_NAME)\npublic class CatalogServiceHandler implements EventHandler {\n\n @On(event = \"review\", entity = Books_.CDS_NAME)\n public void reviewAction(ReviewEventContext context) {\n CqnSelect selectBook = context.getCqn();\n Integer stars = context.getStars();\n Reviews review = ...; // create the review\n context.setResult(review);\n }\n\n}\n```\n", + " Application Services > Actions and Functions > Trigger Action or Function\nJava, service interface, CAP Java SDK, action, function, review, Books_ ref, generated API\nAuto-generated Java service interface for CatalogService. Provides a type-safe review method for the custom action. Incorporates typed access for bound actions/functions as of CAP Java SDK 2.4.0.\n\n```java\n@CdsName(CatalogService_.CDS_NAME)\npublic interface CatalogService extends CqnService {\n\n @CdsName(ReviewContext.CDS_NAME)\n Reviews review(Books_ ref, @CdsName(ReviewContext.STARS) Integer stars);\n\n interface Application extends ApplicationService, CatalogService {\n }\n\n interface Remote extends RemoteService, CatalogService {\n }\n}\n```\n", + " Application Services > Actions and Functions > Trigger Action or Function\nJava, action call, service injection, Books_ ref, catalog service, review\nDemonstrates calling a typed, bound action (review) on CatalogService from Java handler code, using generated API and reference entity. Illustrates programmatically triggering custom actions.\n\n```java\n@Autowired\nprivate CatalogService catService;\n...\nprivate void someCustomMethod() {\n String bookId = \"myBookId\";\n Books_ ref = CQL.entity(Books_.class).filter(b -> b.ID().eq(bookId));\n this.catService.review(ref, 5);\n}\n```\n", + " Application Services > Actions and Functions > Trigger Action or Function\nJava, event context, emit, action/function, generic API\nGeneric programmatic invocation of an action ('review') using EventContext and the emit method, useful for cases where generated typed interfaces are not available.\n\n```java\nEventContext context = EventContext.create(\"review\", \"CatalogService.Books\");\ncontext.put(\"cqn\", Select.from(\"CatalogService.Books\").byId(\"myBookId\"));\ncontext.put(\"rating\", review.getRating());\n\nthis.catService.emit(context);\n\nMap result = (Map) context.get(\"result\");\n```\n", + " Application Services > Serve Configuration > Configure Base Path\nyaml, application.yaml, OData base path, protocol adapter, cds.odataV4.endpoint.path, cds.odataV2.endpoint.path\nShows how to configure the base paths for OData V4 and V2 protocol adapters in application.yaml, overriding default values using cds.odataV4.endpoint.path and cds.odataV2.endpoint.path.\n\n```yaml\ncds:\n odataV4.endpoint.path: '/api'\n odataV2.endpoint.path: '/api-v2'\n\n```\n", + " Application Services > Serve Configuration > Configure Path and Protocol\ncds modeling, path, protocol, CatalogService, service annotation\nDefines service-level annotations in CDS to specify the relative URL path ('browse') and explicitly restrict serving to OData V4 and V2 protocol adapters for CatalogService.\n\n```cds\n@path : 'browse'\n@protocols: [ 'odata-v4', 'odata-v2' ]\nservice CatalogService {\n ...\n}\n```\n", + " Application Services > Serve Configuration > Configure Path and Protocol\nyaml, application.yaml, service path, protocols, serve configuration, CatalogService\nConfigures service path and protocols for a service at runtime in application.yaml under cds.application.services..serve. Controls which URL and which protocols will serve CatalogService.\n\n```yaml\ncds.application.services.CatalogService.serve:\n path: 'browse'\n protocols:\n - 'odata-v4'\n - 'odata-v2'\n\n```\n", + " Application Services > Serve Configuration > Configure Path and Protocol\ncds modeling, disable serving, protocol, internal service, path\nDisables serving of a CDS service by setting @protocol: 'none', regardless of path. Useful for internal or implementation services not meant to be exposed.\n\n```cds\n@path : 'browse'\n@protocol: 'none'\nservice InternalService {\n ...\n}\n```\n", + " Application Services > Serve Configuration > Configure Endpoints\ncds modeling, endpoints, protocol-specific path, CatalogService\nShows protocol-specific endpoint configuration in CDS using @endpoints annotation, so the same service is available at different paths depending on protocol adapter.\n\n```cds\n@endpoints: [\n {path : 'browse', protocol: 'odata-v4'},\n {path : 'list', protocol: 'odata-v2'}\n]\nservice CatalogService {\n ...\n}\n```\n", + " Application Services > Serve Configuration > Configure Endpoints\nyaml, application.yaml, endpoints, protocol-specific path, CatalogService\nConfigures service endpoints for different protocol adapters directly in application.yaml, mapping CatalogService to protocol-specific paths.\n\n```yaml\ncds.application.services.CatalogService.serve.endpoints:\n - path: 'browse'\n protocol: 'odata-v4'\n - path: 'list'\n protocol: 'odata-v2'\n\n```\n", + " Remote Services > Remote OData Services\ninstallation, Java, SAP Cloud SDK, remote service, OData\nAdd this Maven dependency to your project to enable Remote Services for OData V2 or V4 APIs in a CAP Java application. It provides core support for consuming OData remote APIs.\n\n```xml\n\n com.sap.cds\n cds-feature-remote-odata\n runtime\n\n```\n", + " Remote Services > Remote OData Services\nconfiguration, Spring Boot, application.yaml, remote service, OData, destination\nConfigures a Remote Service for the OData V2 API in Spring Boot's application.yaml. Specifies the CDS model service name and the destination name used for connection. The destination is typically defined in SAP BTP Destination Service.\n\n```yaml\ncds:\n remote.services:\n API_BUSINESS_PARTNER:\n type: \"odata-v2\"\n destination:\n name: \"s4-business-partner-api\"\n```\n", + " Remote Services > Remote OData Services > Configuring CDS Service Name\nconfiguration, custom project layout, Spring Boot, application.yaml, service definition, multiple destinations\nConfigures two distinct Remote Services, bupa-abc and bupa-def, both referring to the same CDS service definition (API_BUSINESS_PARTNER) but targeting different destinations. Useful for consuming the same remote API via multiple endpoints (destinations).\n\n```yaml\ncds:\n remote.services:\n bupa-abc:\n model: \"API_BUSINESS_PARTNER\"\n destination:\n name: \"s4-business-partner-api-abc\"\n bupa-def:\n model: \"API_BUSINESS_PARTNER\"\n destination:\n name: \"s4-business-partner-api-def\"\n```\n", + " Remote Services > Using Service Bindings > Binding to a Reuse Service\nconfiguration, application.yaml, service binding, reuse service, BTP\nConfigures a Remote Service to bind to a BTP service instance by specifying the binding name in application.yaml. Used when consuming APIs exposed as BTP reuse services, relying on service binding metadata (like URL and authentication).\n\n```yaml\ncds:\n remote.services:\n SomeReuseService:\n binding:\n name: some-service-binding\n```\n", + " Remote Services > Using Service Bindings > Binding to a Reuse Service\nJava, Cloud SDK, PropertySupplier, customization, service binding\nRegisters a custom PropertySupplier for service bindings with a specific tag. This enables the SAP Cloud SDK to understand and map custom service bindings when the standard structure is insufficient.\n\n```java\nstatic {\n OAuth2ServiceBindingDestinationLoader.registerPropertySupplier(\n options -> options.getServiceBinding().getTags().contains(\"\"),\n SomeReuseServiceOAuth2PropertySupplier::new);\n}\n```\n", + " Remote Services > Using Service Bindings > Binding to a Service with Shared Identity\nconfiguration, service binding, IAS, XSUAA, application.yaml, shared identity\nConfigures a Remote Service using a shared identity service instance (such as XSUAA). Since the service binding does not contain the remote URL, the API URL is explicitly provided in the options section.\n\n```yaml\ncds:\n remote.services:\n OtherCapService:\n binding:\n name: shared-xsuaa\n options:\n url: https://url-of-the-second-cap-application\n```\n", + " Remote Services > Using Service Bindings > Configuring the Authentication Strategy\nconfiguration, service binding, authentication strategy\nDemonstrates setting the authentication strategy for a Remote Service via the 'onBehalfOf' property. Possible values include 'currentUser', 'systemUser', or 'systemUserProvider' to control user propagation and principal selection.\n\n```yaml\ncds:\n remote.services:\n SomeService:\n binding:\n onBehalfOf: currentUser\n```\n", + " Remote Services > Using Destinations\nconfiguration, destination, application.yaml, OData\nConfigures a Remote Service that connects to an OData V2 API using a named destination as registered in the SAP BTP Destination Service.\n\n```yaml\ncds:\n remote.services:\n API_BUSINESS_PARTNER:\n type: \"odata-v2\"\n destination:\n name: s4-business-partner-api\n```\n", + " Remote Services > Configuring the URL\nconfiguration, application.yaml, url suffix, endpoint\nAdds a URL suffix to the endpoint configuration in the Remote Service definition. The service URL is constructed from the destination base URL, optional suffix, and CDS service name.\n\n```yaml\ncds:\n remote.services:\n API_BUSINESS_PARTNER:\n http:\n suffix: \"/sap/opu/odata/sap\"\n destination:\n name: s4-business-partner-api\n```\n", + " Remote Services > Consuming Remote Services\nJava, API consumption, CQN, remote call\nShows how to inject and use a CqnService for a remote API. Executes a CQN SELECT statement against an OData Remote Service and fetches a single business partner address. Used for consuming Remote Services via the CQN API in a CAP Java application.\n\n```java\n@Autowired\n@Qualifier(ApiBusinessPartner_.CDS_NAME)\nCqnService bupa;\n\nCqnSelect select = Select.from(ABusinessPartnerAddress_.class)\n .where(a -> a.BusinessPartner().eq(\"4711\"));\n\nABusinessPartnerAddress address = bupa.run(select)\n .single(ABusinessPartnerAddress.class);\n```\n", + " Remote Services > Consuming Remote Services > Consuming Media Elements > Reading Media Elements\ncds modeling, media, LargeBinary, OData\nDefines a CDS entity that includes a media element. 'image' is annotated with @Core.MediaType, marking it as a media property (e.g., for OData media streaming).\n\n```cds\nentity Media {\n key ID: UUID;\n\n @Core.MediaType: 'image/png'\n image: LargeBinary;\n}\n```\n", + " Remote Services > Consuming Remote Services > Consuming Media Elements > Reading Media Elements\nJava, CQN, media, select, InputStream\nCreates a CQN SELECT to retrieve only the media element ('image') by primary key from a remote service. The result will be an InputStream for the media content.\n\n```java\nSelect.from(Media_.class, m -> m.filter(f -> f.ID().eq(\"...\"))).columns(Media_::image);\n```\n", + " Remote Services > Consuming Remote Services > Consuming Media Elements > Writing Media Elements\nJava, CQN, media, update\nShows how to update a media element in a remote service. Sets the media content and issues an Update statement using the CQN API. Setting the media value to null would trigger a delete request for that media element.\n\n```java\nMedia payload = Media.create();\npayload.setId(...);\npayload.setImage(...);\n\nUpdate.entity(Media_.class).entry(payload);\n```\n", + " Remote Services > Cloud SDK Integration > Maven Dependencies\ninstallation, Java, SAP Cloud SDK, BOM\nAdds the SAP Cloud SDK BOM to the Maven dependencyManagement section. This ensures version alignment for all SAP Cloud SDK dependencies in your project.\n\n```xml\n\n \n \n com.sap.cloud.sdk\n sdk-bom\n use-latest-version-here\n pom\n import\n \n \n\n```\n", + " Remote Services > Cloud SDK Integration > Maven Dependencies\ninstallation, Java, SAP Cloud SDK, connectivity, programmatic destination\nAdds the SAP Cloud SDK connectivity library to enable programmatic destination registration. Necessary for building and registering custom destinations at runtime.\n\n```xml\n\n com.sap.cloud.sdk.cloudplatform\n cloudplatform-connectivity\n\n```\n", + " Remote Services > Cloud SDK Integration > Maven Dependencies\ninstallation, Java, SAP Cloud SDK, destination service, Cloud Foundry\nAdds the SAP Cloud SDK support for SAP BTP Destination Service integration on Cloud Foundry environments.\n\n```xml\n\n com.sap.cloud.sdk.cloudplatform\n scp-cf\n\n```\n", + " Remote Services > Cloud SDK Integration > Configuring Destination Strategies\nconfiguration, destination, retrieval strategy, token exchange, application.yaml\nSets configuration for destination retrieval and token exchange strategies when resolving destinations from SAP BTP Destination Service. Controls the lookup scope and authentication token processing behavior.\n\n```yaml\ncds:\n remote.services:\n API_BUSINESS_PARTNER:\n destination:\n name: \"s4-business-partner-api\"\n retrievalStrategy: \"AlwaysProvider\"\n tokenExchangeStrategy: \"ExchangeOnly\"\n```\n", + " Remote Services > Cloud SDK Integration > Programmatic Destination Registration\nJava, programmatic API, destination registration, CAP lifecycle\nRegisters a new destination programmatically during CAP application startup. The created HTTP destination includes a custom API key header and is registered with the DestinationAccessor for subsequent remote service usage.\n\n```java\n@Component\n@ServiceName(ApplicationLifecycleService.DEFAULT_NAME)\npublic class DestinationConfiguration implements EventHandler {\n\n @Value(\"${api-hub.api-key:}\")\n private String apiKey;\n\n @Before(event = ApplicationLifecycleService.EVENT_APPLICATION_PREPARED)\n public void initializeDestinations() {\n if(apiKey != null && !apiKey.isEmpty()) {\n DefaultHttpDestination httpDestination = DefaultHttpDestination\n .builder(\"https://sandbox.api.sap.com/s4hanacloud\")\n .header(\"APIKey\", apiKey)\n .name(\"s4-business-partner-api\").build();\n\n DestinationAccessor.prependDestinationLoader(\n new DefaultDestinationLoader().registerDestination(httpDestination));\n }\n }\n\n}\n```\n", + " Remote Services > Native Service Consumption > Using Service Bindings\nJava, Cloud SDK, service binding, HttpClient\nShows how to use a service binding to create a Cloud SDK HttpDestination, which is then used to acquire an HttpClient for native API consumption, including OnBehalfOf options for token handling.\n\n```java\nServiceBinding binding = ...;\nHttpDestination destination = ServiceBindingDestinationLoader.defaultLoaderChain().getDestination(\n ServiceBindingDestinationOptions\n .forService(binding)\n .onBehalfOf(OnBehalfOf.TECHNICAL_USER_CURRENT_TENANT)\n .build());\n\nHttpClient httpClient = HttpClientAccessor.getHttpClient(destination);\n```\n", + " Remote Services > Native Service Consumption > Using Service Bindings\nJava, Cloud SDK, PropertySupplier, service binding\nRegisters a custom OAuth2PropertySupplier for a service binding with specific tags for Cloud SDK, enabling support for custom or unusual service bindings for authentication.\n\n```java\nstatic {\n OAuth2ServiceBindingDestinationLoader.registerPropertySupplier(\n options -> options.getServiceBinding().getTags().contains(\"\"),\n BizPartnerOAuth2PropertySupplier::new);\n}\n```\n", + " Remote Services > Native Service Consumption > Using Destinations\nJava, Cloud SDK, DestinationAccessor, HttpClient\nRetrieves a destination by name using Cloud SDK's DestinationAccessor and creates an HttpClient for native API requests. Shows versions for both v4 and v5 of the Cloud SDK.\n\n```java\n// Cloud SDK v4\nHttpDestination destination = DestinationAccessor.getDestination(\"\").asHttp();\nHttpClient httpClient = HttpClientAccessor.getHttpClient(destination);\n\n// Cloud SDK v5\nDestination destination = DestinationAccessor.getDestination(\"\");\nHttpClient httpClient = HttpClientAccessor.getHttpClient(destination);\n```\n", + " Remote Services > Native Service Consumption > Programmatic Destinations\nJava, Cloud SDK, destination, basic authentication\nProgrammatically creates a basic authentication destination for use with Cloud SDK API or as a Remote Service.\n\n```java\nDefaultHttpDestination\n .builder(\"https://example.org\")\n\t.basicCredentials(\"user\", \"password\")\n\t.name(\"my-destination\").build();\n```\n", + " Remote Services > Native Service Consumption > Programmatic Destinations\nJava, Cloud SDK, destination, token forwarding\nBuilds a destination using token forwarding based on the current security context for authentication when calling the remote API.\n\n```java\nDefaultHttpDestination\n .builder(\"https://example.org\")\n\t.authenticationType(AuthenticationType.TOKEN_FORWARDING)\n\t.name(\"my-destination\").build();\n```\n", + " Remote Services > Native Service Consumption > Programmatic Destinations\nJava, Cloud SDK, OAuth2, technical user, programmatic destination\nCreates an OAuth2 destination for using a technical user, suitable for connecting to APIs that require this authentication method.\n\n```java\nClientCredentials clientCredentials =\n new ClientCredentials(\"clientid\", \"clientsecret\");\n\nOAuth2DestinationBuilder\n .forTargetUrl(\"https://example.org\")\n .withTokenEndpoint(\"https://xsuaa.url\")\n .withClient(clientCredentials, OnBehalfOf.TECHNICAL_USER_CURRENT_TENANT)\n .property(\"name\", \"my-destination\")\n .build();\n```\n", + " Remote Services > Native Service Consumption > Programmatic Destinations\nJava, Cloud SDK, OAuth2, token exchange, named user, programmatic destination\nCreates an OAuth2 destination that performs token exchange for a named user in the current tenant. Used when a user token must be exchanged for an OAuth grant on outgoing API calls.\n\n```java\nClientCredentials clientCredentials =\n new ClientCredentials(\"clientid\", \"clientsecret\");\n\nOAuth2DestinationBuilder\n .forTargetUrl(\"https://example.org\")\n .withTokenEndpoint(\"https://xsuaa.url\")\n .withClient(clientCredentials, OnBehalfOf.NAMED_USER_CURRENT_TENANT)\n .property(\"name\", \"my-destination\")\n .build();\n```\n", + " Event Handlers > Event Contexts\nevent context, event handler, core API\nDemonstrates creating a generic EventContext, setting parameters, emitting an event to the service, and retrieving the result. Shows use of get/put for key-value access.\n\n```java\nEventContext context = EventContext.create(\"myEvent\", null);\n\n// set parameters\ncontext.put(\"parameter1\", \"MyParameter1\");\ncontext.put(\"parameter2\", 2);\n\nsrv.emit(context); // process event\n\n// access return value\nObject result = context.get(\"result\");\n```\n", + " Event Handlers > Event Contexts\nevent context, typed event context, CQN, CSN, Result\nShows overlaying a generic EventContext with an event-specific CdsReadEventContext for type-safe access to CQN statement and result objects.\n\n```java\nCdsReadEventContext context = genericContext.as(CdsReadEventContext.class);\nCqnSelect select = context.getCqn();\ncontext.setResult(Collections.emptyList());\nResult result = context.getResult();\n```\n", + " Event Handlers > Completing the Event Processing\nevent completion, On phase, setCompleted\nCompletes synchronous event processing for events without a return value. Should be called in On-phase handlers.\n\n```java\ncontext.setCompleted();\n```\n", + " Event Handlers > Completing the Event Processing\nevent completion, On phase, setResult\nSets the return value and completes the event processing for synchronous events with a return value.\n\n```java\ncontext.setResult(myResult);\n```\n", + " Event Handlers > Explicitly Proceeding the On Handler Execution\nOn phase, proceed, event handler chain\nIllustrates using proceed() to delegate processing to further On-phase handlers while enclosing pre/post logic. Useful for handler chaining and wrapping.\n\n```java\n@On(event = \"myEvent\")\nvoid wrapMyEvent(EventContext context) {\n context.put(\"param\", \"Adjusted\"); // pre-process\n context.proceed(); // delegate to underlying handler\n context.put(\"result\", 42); // post-process\n}\n```\n", + " Event Handlers > Defining Custom EventContext Interfaces\ncustom event context, EventContext interface, annotations, extensibility\nDefines a custom, event-specific EventContext interface for type-safe parameter and result access, using @EventName and @CdsName annotations.\n\n```java\n@EventName(\"myEvent\")\npublic interface MyEventContext extends EventContext {\n\n static MyEventContext create() {\n return EventContext.create(MyEventContext.class, null);\n }\n\n @CdsName(\"Param\")\n String getParam();\n void setParam(String param);\n\n void setResult(Integer result);\n Integer getResult();\n\n}\n```\n", + " Event Handlers > Event Handler Classes\nevent handler class, Spring Boot, Java, service mapping\nShows a typical Spring Boot event handler class for CAP: uses @Component for bean registration, @ServiceName for service binding, and implements EventHandler.\n\n```java\n@Component\n@ServiceName(\"AdminService\")\npublic class AdminServiceHandler implements EventHandler {\n // ...\n}\n```\n", + " Event Handlers > Event Handler Classes\nevent handler class, multi-service, service type\nDemonstrates annotating an event handler class with multiple services via @ServiceName.\n\n```java\n@ServiceName({\"AdminService\", \"CatalogService\"})\n```\n", + " Event Handlers > Event Handler Classes\nevent handler class, service type, wildcard\nRegisters the event handler on all services of the specified type (e.g., ApplicationService) using a wildcard.\n\n```java\n@ServiceName(value = \"*\", type = ApplicationService.class)\n```\n", + " Event Handlers > Event Handler Annotations\nannotations, event handler, event/entity registration\nDemonstrates different usages of event handler annotations: multiple events/entity, overriding service, and recommended use of constants.\n\n```java\n// registers on multiple events\n@Before(event = { \"CREATE\", \"UPDATE\" }, entity = \"AdminService.Books\")\n\n// overrides the default service on class-level\n// registers on any entity\n@On(service = \"CatalogService\", event = \"READ\")\n\n// usage of String constants is recommended\n@After(event = CqnService.EVENT_READ, entity = Books_.CDS_NAME)\n```\n", + " Event Handlers > Event Handler Method Signatures > Event Context Arguments\nevent context, handler signature\nMinimal event handler method signature using general EventContext for accessing event meta-data and state.\n\n```java\n@Before(event = CqnService.EVENT_READ, entity = Books_.CDS_NAME)\npublic void readBooks(EventContext context) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Event Context Arguments\ntyped event context, handler signature\nHandler signature with event-specific EventContext argument for type-safe data access (e.g., for READ events).\n\n```java\n@Before(event = CqnService.EVENT_READ, entity = Books_.CDS_NAME)\npublic void readBooks(CdsReadEventContext context) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Data Arguments\nentity data argument, CdsData, handler signature\nShows registering a handler with a generic access to entity data via a list of CdsData; suitable for CREATE and UPDATE.\n\n```java\n@Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPDATE },\n entity = Books_.CDS_NAME)\npublic void changeBooks(List data) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Data Arguments\nentity data argument, typed entity, handler signature\nHandler signature using generated entity accessor interface for typed access to Books records; more type safety.\n\n```java\n@Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPDATE },\n entity = Books_.CDS_NAME)\npublic void changeBooks(List books) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Data Arguments\nentity data argument, inferred entity, handler signature\nHandler with typed List argument, letting CAP infer the entity via the argument type.\n\n```java\n@Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPDATE })\npublic void changeBooks(List books) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Data Arguments\nentity data argument, stream\nUses Java Stream for accessing/updating Books data in the event handler, rather than a List.\n\n```java\n@Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPDATE })\npublic void changeBooks(Stream books) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Data Arguments\nentity data argument, single entity\nHandler method with argument for a single Book entity; throws if multiple data entries are present.\n\n```java\n@Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPDATE })\npublic void changeBook(Books book) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Reference Arguments\nentity reference argument, query builder\nHandler method argument for an entity reference reflecting the CQN statement, useful for further queries.\n\n```java\n@After(event = CqnService.EVENT_UPDATE, entity = Books_.CDS_NAME)\npublic void changedBook(CqnStructuredTypeRef ref) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Reference Arguments\nentity reference argument, typed query builder\nShows use of a generated query builder interface (Books_) as handler argument for type-safe queries.\n\n```java\n@After(event = CqnService.EVENT_UPDATE, entity = Books_.CDS_NAME)\npublic void changedBook(Books_ ref) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Reference Arguments\nentity reference argument, inferred entity\nLets CAP infer the entity for handler registration using the argument type (Books_).\n\n```java\n@After(event = CqnService.EVENT_UPDATE)\npublic void changedBook(Books_ ref) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Entity Reference Arguments\nentity reference argument, type-safe query, Select\nBuilds a type-safe query using the Books_ reference, within an event handler method.\n\n```java\n@After(event = CqnService.EVENT_UPDATE)\npublic void changedBook(Books_ ref) {\n var select = Select.from(ref).columns(b -> b.title());\n}\n```\n", + " Event Handlers > Event Handler Method Signatures > Service Arguments\nservice argument, service interface injection\nInjects a generated service interface (AdminService) to the handler method for accessing CAP service APIs.\n\n```java\n@After(event = CqnService.EVENT_UPDATE)\npublic void changedBook(Books book, AdminService service) { }\n```\n", + " Event Handlers > Event Handler Method Signatures > Return Values\nOn phase, return value, Result\nA typical On-phase handler that runs a CQN query and returns a Result, automatically completing the event.\n\n```java\n@On(entity = Books_.CDS_NAME)\npublic Result readBooks(CdsReadEventContext context) {\n return db.run(context.getCqn());\n}\n```\n", + " Event Handlers > Event Handler Method Signatures > Return Values\nOn phase, return value, typed result\nReturns a typed result (list of Books) from an On handler, matching the CRUD return type contract.\n\n```java\n@On(entity = Books_.CDS_NAME)\npublic List readBooks(CdsReadEventContext context) {\n Books book = Struct.create(Books.class);\n // ...\n return Arrays.asList(book);\n}\n```\n", + " Event Handlers > Event Handler Method Signatures > Return Values\nactions, functions, custom event handler\nShows defining a handler for a CDS-defined function, returning a String matching the function's return type.\n\n```java\n// CDS model\ndservice World {\n function hello() returns String;\n}\n\n// Handler implementation\n@On(event = \"hello\")\npublic String hello() {\n return \"Hello World\";\n}\n```\n", + " Event Handlers > Ordering of Event Handler Methods\nhandler order, HandlerOrder annotation\nDemonstrates how to explicitly control handler ordering within the same phase using @HandlerOrder(EARLY/LATE). Default is between early and late.\n\n```java\n@After(event = CqnService.EVENT_READ, entity = Books_.CDS_NAME)\n@HandlerOrder(HandlerOrder.EARLY)\npublic void firstHandler(EventContext context) {\n // This handler is executed first\n}\n\n@After(event = CqnService.EVENT_READ, entity = Books_.CDS_NAME)\npublic void defaultHandler(EventContext context) {\n // This one is the second\n}\n\n@After(event = CqnService.EVENT_READ, entity = Books_.CDS_NAME)\n@HandlerOrder(HandlerOrder.LATE)\npublic void lastHandler(EventContext context) {\n // This one is the last\n}\n\n```\n", + " Events and Messaging > Ubiquitous Events in CAP > Intrinsic Eventing in CAP Core\nevent handler, cds, intrinsic eventing, emit event, event listener\nDemonstrates intrinsic event handling in CAP core: registering event listeners with `srv.on` and emitting an event with `srv.emit`. Each listener is invoked when the event is emitted. Suitable for `cds repl` or as inline code in a CAP project.\n\n```js\nlet srv = new cds.Service\n// Receiving Events\nsrv.on ('some event', msg => console.log('1st listener received:', msg))\nsrv.on ('some event', msg => console.log('2nd listener received:', msg))\n// Emitting Events\nawait srv.emit ('some event', { foo:11, bar:'12' })\n```\n", + " Events and Messaging > Ubiquitous Events in CAP > Typical Emitter and Receiver Roles\nevent handler, emitter, receiver, class, emit event, event listener\nShows a CAP Service class implementation that emits an event named 'some event' to inform potential listeners. Typical use: generic emitter pattern decoupled from receivers.\n\n```js\nclass Emitter extends cds.Service { async someMethod() {\n // inform unknown receivers about something happened\n await this.emit ('some event', { some:'payload' })\n}}\n```\n", + " Events and Messaging > Ubiquitous Events in CAP > Typical Emitter and Receiver Roles\nevent handler, emitter, receiver, connect, event listener\nShows how a CAP Service acts as an event receiver. It connects to an external event emitter via `cds.connect.to()` and registers a handler for a specific event. Typical for cross-service/event-driven architectures.\n\n```js\nclass Receiver extends cds.Service { async init() {\n // connect to and register for events from Emitter\n const Emitter = await cds.connect.to('Emitter')\n Emitter.on ('some event', msg => {...})\n}}\n```\n", + " Events and Messaging > Books Reviews Sample > Declaring Events in CDS\ncds modeling, service definition, event, declaration, asynchronous API, srv/reviews-service.cds\nDefines a CAP service including both synchronous API (entity, actions) and an asynchronous API (event declaration). The asynchronous `reviewed` event communicates subject, count, and new average rating, to be emitted when ratings change.\n\n```cds\nservice ReviewsService {\n\n // Sync API\n entity Reviews as projection on my.Reviews excluding { likes }\n action like (review: Reviews:ID);\n action unlike (review: Reviews:ID);\n\n // Async API\n event reviewed : {\n subject : Reviews:subject;\n count : Integer;\n rating : Decimal; // new avg rating\n }\n\n}\n```\n", + " Events and Messaging > Books Reviews Sample > Emitting Events\nevent handler, service implementation, emit event, after, ReviewsService, srv/reviews-service.js\nImplements emission of the 'reviewed' event in ReviewsService after create/update/delete operations on the Reviews entity. It emits the event to notify listeners when a review changes.\n\n```js\nclass ReviewsService extends cds.ApplicationService { async init() {\n\n // Emit a `reviewed` event whenever a subject's avg rating changes\n this.after (['CREATE','UPDATE','DELETE'], 'Reviews', (_, req) => {\n let { subject } = req.data, count, rating //= ...\n return this.emit ('reviewed', { subject, count, rating })\n })\n\n}}\n```\n", + " Events and Messaging > Books Reviews Sample > Receiving Events\nevent handler, receive event, ReviewsService, integration, bookstore, srv/mashup.js\nEvent receiver code that updates books' average ratings upon receiving a 'reviewed' event from ReviewsService. The payload is extracted from `msg.data`. Intended for the bookstore service's integration with reviews.\n\n```js\n // Update Books' average ratings when reviews are updated\n ReviewsService.on ('reviewed', (msg) => {\n const { subject, count, rating } = msg.data\n // ...\n })\n```\n", + " Events and Messaging > In-Process Eventing > 1. Start a Single Server Process\nCLI, local server, watch, invoke, cds watch, run server\nStarts the CAP Bookstore app (with reviews) as an all-in-one development server. Useful to observe in-process eventing and local integration.\n\n```shell\ncds watch bookstore\n```\n", + " Events and Messaging > Using Message Channels > 1. Use `file-based-messaging` in Development\nmessaging, file-based-messaging, configuration, development, package.json, cds.env\nConfigures CAP to use the built-in file-based-messaging service for event transport in development, as set in `package.json` or `.cdsrc.json`. Enables testing message passing across separate processes.\n\n```json\n\"cds\": {\n \"requires\": {\n \"messaging\": {\n \"[development]\": { \"kind\": \"file-based-messaging\" }\n },\n }\n}\n```\n", + " Events and Messaging > Using Message Channels > 2. Start the `reviews` Service and `bookstore` Separately\nCLI, local server, watch, run server, reviews\nStarts the CAP Reviews service in a dedicated server process using file-based messaging (useful for simulating microservices and message queues in local development).\n\n```shell\ncds watch reviews\n```\n", + " Events and Messaging > Using Message Channels > 2. Start the `reviews` Service and `bookstore` Separately\nCLI, local server, watch, run server, bookstore\nStarts the CAP Bookstore service as a separate process. Demonstrates separation of emitter/receiver with message passing via file-based messaging. Should be started after the reviews service.\n\n```shell\ncds watch bookstore\n```\n", + " Events and Messaging > Using Multiple Channels > Configuring Individual Channels and Routes\nmessaging, composite-messaging, configuration, package.json, advanced messaging, channels\nShows advanced messaging setup in CAP using composite-messaging. Defines multiple channels and route event patterns to different message brokers/services. Enables complex message routing scenarios.\n\n```json\n\"cds\": {\n \"requires\": {\n \"messaging\": {\n \"kind\": \"composite-messaging\",\n \"routes\": {\n \"ChannelA\": [\"**/ReviewsService/*\"],\n \"ChannelB\": [\"**/sap/s4/**\"]\n \"ChannelC\": [\"**/bookshop/**\"]\n }\n },\n \"ChannelA\": {\n \"kind\": \"enterprise-messaging\", ...\n },\n \"ChannelB\": {\n \"kind\": \"enterprise-messaging\", ...\n },\n \"ChannelC\": {\n \"kind\": \"enterprise-messaging\", ...\n }\n }\n}\n```\n", + " Events and Messaging > Low-Level Messaging > Configure Messaging Services\nmessaging, cds.env, configuration, package.json, low-level messaging\nGeneric configuration snippet to define a messaging service in CAP. Set the `kind` property to the desired broker or implementation (e.g., enterprise-messaging, event-broker, file-based-messaging).\n\n```json\n\"cds\": {\n \"requires\": {\n \"messaging\": {\n \"kind\": // ...\n },\n }\n}\n```\n", + " Events and Messaging > Low-Level Messaging > Connect to the Messaging Service\nmessaging, service consumer, connect, cds.connect.to, low-level messaging\nEstablishes a client connection to the messaging service. Used for low-level messaging scenarios where events are sent or received via the messaging service directly, not through local service APIs.\n\n```js\nconst messaging = await cds.connect.to('messaging')\n```\n", + " Events and Messaging > Low-Level Messaging > Emit Events to Messaging Service\nmessaging, emit event, low-level messaging, topic, event emission\nEmits an event using the fully qualified event name to the messaging service. Used in low-level messaging scenarios for explicit topic-based event delivery.\n\n```js\nawait messaging.emit ('ReviewsService.reviewed', { ... })\n```\n", + " Events and Messaging > Low-Level Messaging > Receive Events from Messaging Service\nmessaging, event handler, receive event, low-level messaging, topic\nRegisters a handler for a specific event (with fully qualified event name) on the messaging service. Suitable for low-level, broker-centric event subscriptions.\n\n```js\nmessaging.on ('ReviewsService.reviewed', msg => console.log(msg))\n```\n", + " Events and Messaging > Low-Level Messaging > Declared Events and `@topic` Names\ncds modeling, service definition, event, topic, namespace, annotation, cds\nDeclares an event in a CAP service under a specific namespace. Used for integration with message brokers (topic names use the fully qualified name unless overridden).\n\n```cds\nnamespace my.namespace;\nservice SomeEventEmitter {\n event SomeEvent { ... }\n}\n```\n", + " Events and Messaging > Low-Level Messaging > Declared Events and `@topic` Names\ncds modeling, event, topic, annotation, custom topic name\nDemonstrates how to use the `@topic` annotation in CDS to specify a custom topic name for an event, overriding the default namespace-based topic.\n\n```cds\n//...\n@topic: 'some.very.different.topic-name'\nevent SomeEvent { ... }\n```\n", + " Events and Messaging > CloudEvents Standard\nmessaging, cloud events, configuration, cloudevents, cds.env, package.json\nConfigures the messaging service to use CloudEvents format for event data, automatically filling all standard CloudEvents headers and structuring the event payload as required by the CloudEvents standard.\n\n```json\n\"cds\": {\n \"requires\": {\n \"messaging\": {\n \"format\": \"cloudevents\"\n }\n }\n}\n```\n", + " Events and Messaging > [Using SAP Cloud Application Event Hub](./event-broker)\nmessaging, SAP Cloud Application Event Hub, event-broker, production, configuration, cds.env, package.json\nObtains SAP Cloud Application Event Hub integration by setting the messaging 'kind' to 'event-broker' for the production profile. Used for out-of-the-box event brokering in SAP BTP deployments.\n\n```json\n\"cds\": {\n \"requires\": {\n \"messaging\": {\n \"[production]\": {\n \"kind\": \"event-broker\"\n }\n }\n }\n}\n```\n", + " Events and Messaging > [Using SAP Event Mesh](./event-mesh)\nmessaging, SAP Event Mesh, enterprise-messaging, production, cloudevents, configuration, cds.env, package.json\nConfigures CAP to use SAP Event Mesh (enterprise-messaging) as its broker with CloudEvents payload format, active in the production profile, as recommended for BTP integration.\n\n```json\n\"cds\": {\n \"requires\": {\n \"messaging\": {\n \"[production]\": {\n \"kind\": \"enterprise-messaging\",\n \"format\": \"cloudevents\"\n }\n }\n }\n}\n```\n", + " Events and Messaging > [Events from SAP S/4HANA](./s4)\ncds modeling, external service, S/4HANA, event, extend, annotation, topic, integration, API_BUSINESS_PARTNER\nExtends an external S/4HANA BusinessPartner service definition to declare missing events with specific topic annotations, enabling SAP Event Mesh/Event Hub integration for receiving S/4HANA events in CAP.\n\n```cds\n// filling in missing events as found on SAP Business Accelerator Hub\nusing { API_BUSINESS_PARTNER as S4 } from './API_BUSINESS_PARTNER';\nextend service S4 with {\n event BusinessPartner.Created @(topic:'sap.s4.beh.businesspartner.v1.BusinessPartner.Created.v1') {\n BusinessPartner : String\n }\n event BusinessPartner.Changed @(topic:'sap.s4.beh.businesspartner.v1.BusinessPartner.Changed.v1') {\n BusinessPartner : String\n }\n}\n```\n", + " Events and Messaging > [Events from SAP S/4HANA](./s4)\nservice consumer, connect, external service, S/4HANA, event handler, API_BUSINESS_PARTNER\nShows how to connect to an imported S/4HANA OData API and register an event handler for BusinessPartner change events. Demonstrates event-driven S/4HANA integration in a CAP application.\n\n```js\nconst S4Bupa = await cds.connect.to ('API_BUSINESS_PARTNER')\nS4Bupa.on ('BusinessPartner.Changed', msg => {...})\n```\n", + " Indicating Errors > Exceptions\nexceptions, ServiceException, error status, error handling, CAP Java, event handler\nDemonstrates different ways of throwing a ServiceException in CAP Java event handlers, optionally specifying error statuses and including the causing exception. Exceptions abort the current event and roll back the transaction.\n\n```java\n// default error status\nthrow new ServiceException(\"An internal server error occurred\", originalException);\n// specifying an error status\nthrow new ServiceException(ErrorStatuses.CONFLICT, \"Not enough stock available\");\n// specifying an error status and the original exception\nthrow new ServiceException(ErrorStatuses.BAD_REQUEST, \"No book title specified\", originalException);\n```\n", + " Indicating Errors > Messages\nmessages, Messages API, event context, dependency injection, Spring, logging\nShows how to add a success message to the current request using the Messages API acquired from the event context in a handler.\n\n```java\n// Using Messages API from event context\ncontext.getMessages().success(\"The order was successfully placed\");\n```\n", + " Indicating Errors > Messages\nmessages, Messages API, event context, dependency injection, Spring, logging\nAccesses the Messages API via Spring Dependency Injection and adds warning and error messages. The error message includes extra metadata for code and documentation URL.\n\n```java\n@Autowired\nMessages messages;\n\nmessages.warn(\"No book title specified\");\nmessages.error(\"The book is no longer available\").code(\"BNA\").longTextUrl(\"/help/book-not-available\");\n```\n", + " Indicating Errors > Messages > Throwing a ServiceException from Error Messages\nmessages, throwIfError, ServiceException, validation, error aggregation\nThrows a ServiceException if error messages have been collected using the Messages API. Used for aggregated validation and cleanup after complex checks.\n\n```java\n// throw a ServiceException, if any error messages have been added to the current request\nmessages.throwIfError();\n```\n", + " Indicating Errors > Formatting and Localization\nformatting, localization, SLF4J, parameterized message, exception message\nShows how to use SLF4J-style placeholders in log and exception messages, supporting dynamic message formatting.\n\n```java\n// message with placeholders\nmessages.warn(\"Can't order {} books: Not enough on stock\", orderQuantity);\n// on ServiceException last argument can always be the causing exception\nthrow new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid number: '{}'\", wrongNumber, originalException);\n```\n", + " Indicating Errors > Formatting and Localization\nlocalization, properties file, message key, internationalization, messages.properties\nDefines a localized message with a placeholder in the default messages.properties. Used for internationalization with CAP Java's message handling.\n\n```properties\nmy.message.key = This is a localized message with {0} parameters\n```\n", + " Indicating Errors > Formatting and Localization\nlocalization, properties file, message key, internationalization, messages.properties\nDefines the German translation for a message key in messages_de.properties, enabling locale-specific messages in CAP Java.\n\n```properties\nmy.message.key = Das ist ein übersetzter Text mit {0} Parametern\n```\n", + " Indicating Errors > Formatting and Localization\nlocalization, parameterized messages, ServiceException, message key\nShows how to reference localized messages by key with parameters, in both info/warn and exception messages, using CAP Java's built-in i18n resource bundle support.\n\n```java\n// localized message with placeholders\nmessages.warn(\"my.message.key\", paramNumber);\n// localized message with placeholders and additional exception\nthrow new ServiceException(ErrorStatuses.BAD_REQUEST, \"my.message.key\", paramNumber, originalException);\n```\n", + " Indicating Errors > Target > CRUD Events\nServiceException, message target, CRUD events, CQN, target property\nDemonstrates different ways to attach a target property for an error message in CRUD event handlers, making errors show up next to the affected field in SAP Fiori UI.\n\n```java\n@Before\npublic void validateTitle(CdsCreateEventContext context, Books book) {\n // ...\n\n // implicitly referring to cqn\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"No title specified\")\n .messageTarget(b -> b.get(\"title\"));\n\n // which is equivalent to explicitly referring to cqn\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"No title specified\")\n .messageTarget(\"cqn\", b -> b.get(\"title\"));\n\n // which is the same as using plain string\n // assuming direct POST request\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"No title specified\")\n .messageTarget(\"title\");\n\n // which is the same as using plain string\n // assuming surrounding bound action request with binding parameter \"in\",\n // e.g. draftActivate\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"No title specified\")\n .messageTarget(\"in/title\");\n}\n```\n", + " Indicating Errors > Target > CRUD Events\nServiceException, message target, typed API, Books_, target property\nShows type-safe way to set error message target property to a field using the generated Books_ class, improving maintainability and refactoring support.\n\n```java\n@Before\npublic void validateTitle(CdsCreateEventContext context, Books book) {\n // ...\n\n // implicitly referring to cqn\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"No title specified\")\n .messageTarget(Books_.class, b -> b.title());\n}\n```\n", + " Indicating Errors > Target > CRUD Events\nServiceException, message target, typed API, association, nested path\nDemonstrates targeting nested fields via associations for error messages, both with the generic and typed (Books_) API.\n\n```java\n@Before\npublic void validateAuthorName(CdsCreateEventContext context, Books book) {\n // ...\n\n // using un-typed API\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"No title specified\")\n .messageTarget(b -> b.to(\"author\").get(\"name\"));\n\n // using typed API\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"No author name specified\")\n .messageTarget(Books_.class, b -> b.author().name());\n}\n```\n", + " Indicating Errors > Target > Bound Actions and Functions\nServiceException, message target, bound actions, function input parameter\nShows how to use message targets with action/function parameters, using both string and typed APIs, to display errors adjacent to input fields in Fiori.\n\n```java\n@Before\npublic void validateReview(BooksAddReviewContext context) {\n // ...\n\n // referring to action parameter \"reviewer\", targeting \"firstName\"\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid reviewer first name\")\n .messageTarget(\"reviewer\", r -> r.get(\"firstName\"));\n\n // which is equivalent to using the typed API\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid reviewer first name\")\n .messageTarget(BooksAddReviewContext.REVIEWER, Reviewer_.class, r -> r.firstName());\n\n // targeting \"rating\"\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid review rating\")\n .messageTarget(\"rating\");\n\n // targeting \"title\"\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid review title\")\n .messageTarget(\"title\");\n\n // targeting \"text\"\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid review text\")\n .messageTarget(\"text\");\n}\n```\n", + " Indicating Errors > Target > Bound Actions and Functions\nServiceException, message target, bound entity, CQN, typed API\nIllustrates how to set message targets for properties on a bound entity, using both generic and typed APIs, supporting Fiori's inline error display.\n\n```java\n@Before\npublic void validateReview(BooksAddReviewContext context) {\n // ...\n\n // referring to the bound entity `Books`\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid book description\")\n .messageTarget(b -> b.get(\"descr\"));\n\n // or (using the typed API, referring to \"cqn\" implicitly)\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid book description\")\n .messageTarget(Books_.class, b -> b.descr());\n\n // which is the same as using plain string\n throw new ServiceException(ErrorStatuses.BAD_REQUEST, \"Invalid book description\")\n .messageTarget(\"in/descr\");\n}\n```\n", + " Indicating Errors > Error Handler\nerror handler, ERROR_RESPONSE, lifecycle event, custom error message, authorization error\nOverrides the standard message for authorization errors by replacing the first error message with a custom text in the ERROR_RESPONSE event handler.\n\n```java\n@Component\n@ServiceName(ApplicationLifecycleService.DEFAULT_NAME)\npublic class SimpleExceptionHandler implements EventHandler {\n\n @After\n public void overrideMissingAuthMessage(ErrorResponseEventContext context) {\n if (context.getException().getErrorStatus().equals(CdsErrorStatuses.EVENT_FORBIDDEN)) {\n context.getResult().getMessages().set(0,\n Message.create(Message.Severity.ERROR,\n \"You cannot execute this action\"));\n }\n }\n}\n```\n", + " Indicating Errors > Error Handler\nerror handler, validation error, ERROR_RESPONSE, custom error messages, field-level error\nHandles the ERROR_RESPONSE event and customizes validation error messages for specific fields (price, stock) on the Books entity, while copying metadata for proper UI display.\n\n```java\n@Component\n@ServiceName(ApplicationLifecycleService.DEFAULT_NAME)\npublic class ExceptionServiceErrorMessagesHandler implements EventHandler {\n\n @After\n public void overrideValidationMessages(ErrorResponseEventContext context) {\n context.getException().getEventContexts().stream().findFirst().ifPresent(originalContext -> {\n if (Books_.CDS_NAME.equals(originalContext.getTarget().getQualifiedName())) { // filter by entity\n List messages = context.getResult().getMessages();\n for(int i=0; i Accessing Request Contexts\nJava, event handler, Request Context, UserInfo, ParameterInfo, AuthenticationInfo, FeatureTogglesInfo\nDemonstrates accessing Request Context data like user info, locale, authentication token, and feature toggles within a Java event handler. Use in a @Before event handler for CqnService events.\n\n```java\n@Before(event = CqnService.EVENT_READ)\npublic void beforeRead(CdsReadEventContext context) {\n UserInfo userInfo = context.getUserInfo();\n boolean isAuthenticated = userInfo.isAuthenticated();\n\n ParameterInfo parameterInfo = context.getParameterInfo();\n Locale locale = parameterInfo.getLocale();\n\n // OAuth2 authentication provided:\n AuthenticationInfo authInfo = context.getAuthenticationInfo();\n JwtTokenAuthenticationInfo jwtTokenInfo = authInfo.as(JwtTokenAuthenticationInfo.class);\n String jwtToken = jwtTokenInfo.getToken();\n\n FeatureTogglesInfo ftsInfo = context.getFeatureTogglesInfo();\n if (ftsInfo.isEnabled(\"experimental\")) {\n // ...\n }\n}\n```\n", + " Request Contexts > Accessing Request Contexts\nJava, Spring, Dependency Injection, UserInfo, ParameterInfo, AuthenticationInfo, FeatureTogglesInfo\nShows how to use Spring Dependency Injection to access UserInfo, ParameterInfo, AuthenticationInfo, and FeatureTogglesInfo in a CAP Java event handler. Use in Spring-based CAP Java projects.\n\n```java\n@Autowired\nUserInfo userInfo;\n\n@Autowired\nParameterInfo parameterInfo;\n\n@Autowired\nAuthenticationInfo authInfo;\n\n@Autowired\nFeatureTogglesInfo ftsInfo;\n\n@Before(event = CqnService.EVENT_READ)\npublic void beforeRead() {\n boolean isAuthenticated = userInfo.isAuthenticated();\n Locale locale = parameterInfo.getLocale();\n // ...\n}\n```\n", + " Request Contexts > Accessing Request Contexts\nJava, UserInfo, XsuaaUserInfo, type-safe access, CAP Java, authorization\nIllustrates how to access XSUAA-specific user attributes via type-safe XsuaaUserInfo in CAP Java for enhanced authorization or custom logic.\n\n```java\n@Autowired\nXsuaaUserInfo xsuaaUserInfo;\n\n@Before(event = CqnService.EVENT_READ)\npublic void beforeRead() {\n\tboolean isAuthenticated = xsuaaUserInfo.isAuthenticated();\n\tString email = xsuaaUserInfo.getEmail();\n\tString givenName = xsuaaUserInfo.getGivenName();\n\tString familyName = xsuaaUserInfo.getFamilyName();\n // ...\n}\n```\n", + " Request Contexts > Defining New Request Contexts > Switching to Technical User\nJava, RequestContextRunner, technical user, systemUser, After handler, CAP Java\nShows how to switch from a named user context to a technical user context using systemUser() in an After event handler. Useful for calling external technical services without user propagation.\n\n```java\n@After(entity = Books_.CDS_NAME)\npublic void afterHandler(EventContext context){\n runtime.requestContext().systemUser().run(reqContext -> {\n // call technical service\n ...\n });\n}\n```\n", + " Request Contexts > Defining New Request Contexts > Switching to Technical Provider Tenant\nJava, RequestContextRunner, technical provider tenant, systemUserProvider, CAP Java, action handler\nSwitches to a technical user context on the provider tenant for an action handler, enabling backend communication with internal pseudo-role endpoints.\n\n```java\n@On(entity = Books_.CDS_NAME)\npublic void onAction(AddToOrderContext context){\n runtime.requestContext().systemUserProvider().run(reqContext -> {\n // call remote CAP service\n ...\n });\n}\n```\n", + " Request Contexts > Defining New Request Contexts > Switching to a Specific Technical Tenant\nJava, RequestContextRunner, technical tenant, systemUser, background job, multi-tenant, CAP Java\nCreates a Request Context for a technical user for a specific tenant, e.g., for multi-tenant background job execution. Ensures correct tenant separation for DB queries.\n\n```java\nruntime.requestContext().systemUser(tenant).run(reqContext -> {\n return persistenceService.run(Select.from(Books_.class))\n .listOf(Books.class);\n});\n```\n", + " Request Contexts > Modifying Request Contexts\nJava, modifying request context, locale, parameters, nested context\nShows how to modify parameters when creating a nested Request Context, e.g., to temporarily remove locale information for unlocalized reads. Uses modifyParameters().\n\n```java\nList readBooksNotLocalized(EventContext context) {\n return context.getCdsRuntime().requestContext()\n .modifyParameters(param -> param.setLocale(null))\n .run(newContext -> {\n return persistenceService.run(Select.from(Books_.class))\n .listOf(Books.class);\n });\n}\n```\n", + " Request Contexts > Registering Global Providers\nJava, UserInfoProvider, custom provider, Spring, Header-based user, CAP Java\nDefines a custom UserInfoProvider in Spring to initialize UserInfo from custom HTTP headers, useful when authentication is handled externally.\n\n```java\n@Component\n@Order(1)\npublic class HeaderBasedUserInfoProvider implements UserInfoProvider {\n\n @Autowired\n HttpServletRequest req; // accesses current HTTP request\n\n @Override\n public UserInfo get() {\n if (RequestContextHolder.getRequestAttributes() != null) {\n // only within request thread req is available\n return UserInfo.create()\n .setTenant(req.getHeader(\"custom-tenant-header\"))\n .setName(req.getHeader(\"custom-username-header\"));\n }\n return UserInfo.create();\n }\n}\n```\n", + " Request Contexts > Registering Global Providers\nJava, UserInfoProvider, chaining, customization, user name normalization\nDemonstrates chaining UserInfoProviders and customizing UserInfo, e.g., normalizing user names. This pattern is used to augment or adjust user information based on previous providers' data.\n\n```java\n@Component\npublic class CustomUserInfoProvider implements UserInfoProvider {\n\n private UserInfoProvider previousProvider;\n\n @Override\n public UserInfo get() {\n ModifiableUserInfo userInfo = UserInfo.create();\n if (previousProvider != null) {\n UserInfo previous = previousProvider.get();\n if (previous != null) {\n userInfo = previous.copy();\n }\n }\n if (userInfo != null) {\n // Normalize user name\n userInfo.setName(userInfo.getName().toLowerCase(Locale.ENGLISH));\n }\n\n return userInfo;\n }\n\n @Override\n public void setPrevious(UserInfoProvider previous) {\n this.previousProvider = previous;\n }\n}\n```\n", + " Request Contexts > Passing Request Contexts to Threads\nJava, threading, RequestContext, RequestContextRunner, multi-threading\nDemonstrates how to propagate the Request Context to a child thread using RequestContextRunner. Necessary for multi-threaded service calls requiring contextual info such as tenant.\n\n```java\nRequestContextRunner runner = runtime.requestContext();\nFuture result = Executors.newSingleThreadExecutor().submit(() -> {\n\treturn runner.run(threadContext -> {\n\t\treturn persistenceService.run(Select.from(Books_.class));\n\t});\n});\n```\n", + " ChangeSet Contexts > Overview\nevent context, ChangeSetContext, transactional boundaries, change set, EventContext API\nAccess the currently active ChangeSet Context from the Event Context in CAP Java. Allows querying or interacting with the transactional boundaries for the current event.\n\n```java\ncontext.getChangeSetContext();\n```\n", + " ChangeSet Contexts > Defining ChangeSet Contexts\ndefining changeset context, ChangeSetContext, transactions, CdsRuntime API, nesting\nExplicitly define a new ChangeSet Context using the CdsRuntime API. Any code inside the provided lambda runs with its own transactional boundaries, supporting nested ChangeSet Contexts.\n\n```java\nruntime.changeSetContext().run(context -> {\n // executes inside a dedicated ChangeSet Context\n});\n```\n", + " ChangeSet Contexts > Reacting on ChangeSets\nChangeSetListener, register listener, transaction commit, rollback, beforeClose, afterClose\nRegister a ChangeSetListener on the ChangeSet Context to react to lifecycle events: before the changeset is closed or after it was committed/rolled back. Enables custom actions during transactional phases.\n\n```java\nChangeSetContext changeSet = context.getChangeSetContext();\nchangeSet.register(new ChangeSetListener() {\n\n @Override\n public void beforeClose() {\n // do something before changeset is closed\n }\n\n @Override\n public void afterClose(boolean completed) {\n // do something after changeset is closed\n }\n\n});\n```\n", + " ChangeSet Contexts > Cancelling ChangeSets\nChangeSetContext, cancel changeset, markForCancel, rollback transaction, beforeClose listener\nCancels the current ChangeSet Context programmatically, marking it for rollback without throwing an exception. Can be used inside ChangeSetListener.beforeClose() to roll back the transaction after processing.\n\n```java\nChangeSetContext changeSet = context.getChangeSetContext();\n// cancel changeset without throwing an exception\nchangeSet.markForCancel();\n```\n", + " ChangeSet Contexts > Database Transactions in Spring Boot\nSpring Boot, transaction, JdbcTemplate, DataSource, transaction management, PersistenceService, @Transactional, plain JDBC\nShows integration of Spring Boot transaction management with CAP Java using the @Transactional annotation and JDBC access via JdbcTemplate and DataSource. Ensures that plain JDBC ops run within a managed transaction context.\n\n```java\n@Autowired\nprivate JdbcTemplate jdbc;\n\n@Autowired\nprivate DataSource ds;\n\n@Before(event = CqnService.EVENT_CREATE, entity = Books_.CDS_NAME)\n@Transactional // ensure transaction is initialized\npublic void beforeCreateBooks(List books) {\n // JDBC template\n jdbc.queryForList(\"SELECT 1 FROM DUMMY\");\n\n // Connection object\n Connection conn = DataSourceUtils.getConnection(ds);\n conn.prepareCall(\"SELECT 1 FROM DUMMY\").executeQuery();\n}\n```\n", + " ChangeSet Contexts > Setting Session Context Variables\nSpring Boot, session context, custom event handler, PersistenceService, ChangeSetContext, ChangeSetListener, set session variable, DataSourceUtils\nA custom EventHandler for CAP Java (with Spring Boot) sets session context variables on a JDBC connection for the duration of a ChangeSet Context/transaction, clearing them before close. Useful for influencing database-level session properties per-transaction.\n\n```java\n@Component\n@ServiceName(value = \"*\", type = PersistenceService.class)\npublic class SessionContextHandler implements EventHandler {\n\n private final static Set handled = Collections.synchronizedSet(new HashSet<>());\n\n @Autowired\n private DataSource dataSource;\n\n @Before\n protected void setSessionContextVariables(EventContext context) {\n ChangeSetContext changeSet = context.getChangeSetContext();\n // handle every transaction only once\n if(handled.add(changeSet)) {\n // set the session variable\n setSessionContextVariable(\"foo\", \"bar\");\n\n changeSet.register(new ChangeSetListener(){\n\n @Override\n public void beforeClose() {\n // clear the session variable\n setSessionContextVariable(\"foo\", null);\n handled.remove(changeSet);\n }\n\n });\n }\n }\n\n private void setSessionContextVariable(String name, String value) {\n Connection con = null;\n try {\n // obtains the transaction connection\n con = DataSourceUtils.getConnection(dataSource);\n con.setClientInfo(name, value);\n } catch (SQLClientInfoException e) {\n // handle appropriately\n } finally {\n // only releases the obtained connection\n // the transaction connection is still kept open with the\n // session variables set\n DataSourceUtils.releaseConnection(con, dataSource);\n }\n }\n\n}\n```\n", + " Fiori Drafts > Reading Drafts\ndrafts, Java, event handler, remote service, ACTIVE_READ, draft persistence\nCustom @On event handler for reading active entities in draft-enabled scenarios with 'cds.drafts.persistence' set to 'split'. Delegates the read to a remote S/4HANA system. Useful when draft and active data are managed in different persistences (e.g., local draft, remote active entity). Should be combined with delegation of CREATE/UPDATE/DELETE events.\n\n```java\n@On(entity = MyRemoteDraftEnabledEntity_.CDS_NAME)\npublic Result delegateToS4(ActiveReadEventContext context) {\n return remoteS4.run(context.getCqn());\n}\n```\n", + " Fiori Drafts > Editing Drafts\ndrafts, Java, event handler, prefill, DRAFT_NEW\nRegisters a @Before handler for the DRAFT_NEW event, allowing default values to be set on a new draft entity before editing. Works for draft-enabled entities, kicking in as part of the draft-creation flow.\n\n```java\n@Before\npublic void prefillOrderItems(DraftNewEventContext context, OrderItems orderItem) {\n // Pre-fill fields with default values\n}\n```\n", + " Fiori Drafts > Activating Drafts\ndrafts, Java, event handler, CREATE, validation\nRegisters a @Before handler for the CREATE event. Used to validate user input or entity state before an active entity is created or updated as part of draft activation (Save action). Applies to activation flow of SAP Fiori draft-enabled entities.\n\n```java\n@Before\npublic void validateOrderItem(CdsCreateEventContext context, OrderItems orderItem) {\n // Add validation logic\n}\n```\n", + " Fiori Drafts > Working with Draft-Enabled Entities\nhttp, sample request, drafts, entity, read draft\nSample OData HTTP GET request to fetch an active entity by key, using the special IsActiveEntity=true key in draft-enabled services.\n\n```http\nGET /v4/myservice/myentity(IsActiveEntity=true,ID=);\n```\n", + " Fiori Drafts > Working with Draft-Enabled Entities\nhttp, sample request, drafts, entity, read draft\nSample OData HTTP GET request for retrieving the draft version of a specific entity, using IsActiveEntity=false in the key.\n\n```http\nGET /v4/myservice/myentity(IsActiveEntity=false,ID=);\n```\n", + " Fiori Drafts > Working with Draft-Enabled Entities\nhttp, sample request, drafts, entity, read active entities\nSample OData HTTP GET request using a $filter parameter to retrieve all active entities (where IsActiveEntity equals true) in a draft-enabled service.\n\n```http\nGET /v4/myservice/myentity?$filter=IsActiveEntity eq true\n```\n", + " Fiori Drafts > Draft Lock\nconfiguration, yaml, drafts, lock, timeout\nConfiguration property in application.yaml to set the draft lock timeout for draft-enabled entities. The example sets the lock release after 1 hour.\n\n```yaml\ncds.drafts.cancellationTimeout: 1h\n```\n", + " Fiori Drafts > Draft Lock\nconfiguration, yaml, drafts, lock, disable\nConfiguration property in application.yaml to completely disable draft protection (locking).\n\n```yaml\ncds.security.draftProtection.enabled: false\n```\n", + " Fiori Drafts > Draft Garbage Collection\nconfiguration, yaml, drafts, garbage collection, timeout\nSets the garbage collection timeout for stale drafts in application.yaml. This example configures drafts to be deleted after 8 weeks.\n\n```yaml\ncds.drafts.deletionTimeout: 8w\n```\n", + " Fiori Drafts > Draft Garbage Collection\nconfiguration, yaml, drafts, garbage collection, disable\nCompletely disables automatic garbage collection of drafts by setting the property to false in application.yaml.\n\n```yaml\ncds.drafts.gc.enabled: false\n```\n", + " Fiori Drafts > Overriding SAP Fiori's Draft Creation Behaviour\ncds modeling, cds, OData, actions, drafts, Fiori, entity\nDefines a draft-enabled Orders entity with a custom OData action 'createDraft', which can be invoked by SAP Fiori instead of the default POST for draft creation. 'NewAction' annotation tells Fiori to use this action.\n\n```cds\nservice AdminService {\n @odata.draft.enabled\n @Common.DraftRoot.NewAction: 'AdminService.createDraft'\n entity Orders as projection on my.Orders actions {\n action createDraft(in: many $self, orderNo: String) returns Orders;\n };\n}\n```\n", + " Fiori Drafts > Overriding SAP Fiori's Draft Creation Behaviour\nJava, drafts, action implementation, DraftService, createDraft\nImplements a custom Java handler for the createDraft action of a draft-enabled Orders entity. Uses the DraftService.newDraft API to create and return a draft instance with preset values. Part of custom draft creation with SAP Fiori.\n\n```java\n@On(entity = Orders_.CDS_NAME)\npublic void createDraft(CreateDraftContext context) {\n Orders order = Orders.create();\n order.setOrderNo(context.getOrderNo());\n context.setResult(adminService.newDraft(Insert.into(Orders_.class).entry(order)).single(Orders.class));\n}\n```\n", + " Fiori Drafts > Validating Drafts \nconfiguration, json, drafts, draftMessages, .cdsrc.json, state messages\nEnables draftMessages (state messages) support in CAP Java for immediate UI validation. Should be set in .cdsrc.json. Adds draft message persistence, enabling enhanced error message feedback for draft-enabled entities.\n\n```json\n{\n \"cdsc\": {\n \"draftMessages\": true\n }\n}\n```\n", + " Fiori Drafts > Validating Drafts \ncds modeling, cds, annotations, SideEffects, draftMessages\nDisables the side-effect annotation for always fetching messages in the EDMX for a specific entity (MyEntity). Prevents automatic reload of state messages after every PATCH request (OData).\n\n```cds\n// Setting `null` disables the side-effect annotation for always fetching messages.\nannotate MyService.MyEntity with @Common.SideEffects #alwaysFetchMessages: null;\n```\n", + " Fiori Drafts > Consuming Draft Services\ndrafts, Java, DraftService, API, usage, CQN\nDemonstrates usage of the CAP Java DraftService API: creating a draft, patching it, saving (activating) the draft, reading drafts and active entities, and putting drafts back into edit mode. Showcases interaction with draft-aware APIs in application/synchronous use cases.\n\n```java\nimport static bookshop.Bookshop_.ORDERS;\n\nDraftService adminService = ...;\n// create draft\nOrders order = adminService.newDraft(Insert.into(ORDERS)).single(Orders.class);\n// set values\norder.setOrderNo(\"DE-123456\");\n// patch draft\nadminService.patchDraft(Update.entity(ORDERS).data(order)\n .where(o -> o.ID().eq(order.getId()).and(o.IsActiveEntity().eq(false))));\n// save draft\nCqnSelect orderDraft = Select.from(ORDERS)\n .where(o -> o.ID().eq(order.getId()).and(o.IsActiveEntity().eq(false)));\nadminService.saveDraft(orderDraft);\n// read draft\nOrders draftOrder = adminService.run(orderDraft).single().as(Order.class);\n// put draft back to edit mode\nCqnSelect orderActive = Select.from(ORDERS)\n .where(o -> o.ID().eq(order.getId()).and(o.IsActiveEntity().eq(true)));\nadminService.editDraft(orderActive, true);\n// read entities in draft mode and activated entities\nadminService.run(Select.from(ORDERS).where(o -> o.ID().eq(order.getId())));\n```\n", + " Audit Logging > AuditLog Service > Use AuditLogService > Get AuditLogService Instance\naudit logging, AuditLogService, Spring Boot, service injection, service catalog, Java\nThis code snippet demonstrates how to inject the AuditLogService into a Spring Boot-based CAP Java application. The AuditLogService can be used for emitting audit log events. For non-Spring Boot projects, the service can be retrieved from the ServiceCatalog.\n\n```java\nimport com.sap.cds.services.auditlog.AuditLogService;\n\n@Autowired\nprivate AuditLogService auditLogService;\n```\n", + " Audit Logging > AuditLog Service > Use AuditLogService > Get AuditLogService Instance\naudit logging, AuditLogService, service catalog, Java\nThis code obtains an instance of the AuditLogService from the ServiceCatalog in a CAP Java context. Useful when injection is not available (e.g., in non-Spring Boot environments).\n\n```java\nServiceCatalog catalog = context.getServiceCatalog();\nauditLogService = (AuditLogService) catalog.getService(AuditLogService.DEFAULT_NAME);\n```\n", + " Audit Logging > AuditLog Service > Use AuditLogService > Emit Personal Data Access Event\naudit logging, personal data access, logDataAccess, AuditLogService, Java\nThis snippet emits a personal data access event using the logDataAccess() method of the AuditLogService. The Access object(s) should be filled with relevant data access details.\n\n```java\nList accesses = new ArrayList<>();\nAccess access = Access.create();\n// fill access object with data\naccesses.add(access);\nauditLogService.logDataAccess(accesses);\n```\n", + " Audit Logging > AuditLog Service > Use AuditLogService > Emit Personal Data Modification Event\naudit logging, personal data modification, logDataModification, AuditLogService, Java\nThis example shows how to emit a personal data modification event using logDataModification() on AuditLogService. Each DataModification object should be populated as appropriate.\n\n```java\nList dataModifications = new ArrayList<>();\nDataModification modification = DataModification.create();\n// fill data modification object with data\ndataModifications.add(modification);\nauditLogService.logDataModification(dataModifications);\n```\n", + " Audit Logging > AuditLog Service > Use AuditLogService > Emit Configuration Change Event\naudit logging, configuration change, logConfigChange, AuditLogService, Java\nThis shows how to emit a configuration change audit event using logConfigChange() of the AuditLogService. An action (like Action.UPDATE) and a list of ConfigChange objects are passed.\n\n```java\nList configChanges = new ArrayList<>();\nConfigChange configChange = ConfigChange.create();\n// fill config change object with data\nconfigChanges.add(configChange);\nauditLogService.logConfigChange(Action.UPDATE, configChanges);\n```\n", + " Audit Logging > AuditLog Service > Use AuditLogService > Emit Security Event\naudit logging, security event, logSecurityEvent, AuditLogService, Java\nEmit a security event audit log entry by calling logSecurityEvent() on AuditLogService with details about the action and related data.\n\n```java\nString action = \"login\";\nString data = \"user-name\";\nauditLogService.logSecurityEvent(action, data);\n```\n", + " Audit Logging > AuditLog Service > Deferred AuditLog Events\naudit logging, outbox, deferred, persistent outbox, data privacy, Java\nDeferred audit log events are stored in the outbox and sent asynchronously. Security events are always sent synchronously. Persistent outbox is preferred over in-memory for transactional guarantees. Be aware of compliance/data privacy when persisting audit entries with personal data.\n\n```txt\n\n```\n", + " Audit Logging > AuditLog Handlers > Default Handler\naudit logging, default handler, logging, application.yaml, YAML\nThis yaml snippet shows how to enable DEBUG log level for the default audit log handler. By default, audit logs are only output at DEBUG, so this increases visibility in the application log.\n\n```yaml\nlogging:\n level:\n com.sap.cds.auditlog: DEBUG\n```\n", + " Audit Logging > AuditLog Handlers > AuditLog v2 Handler\naudit logging, AuditLog v2 handler, cds-feature-auditlog-v2, pom.xml, dependency, Java\nAdd this dependency to pom.xml to enable the AuditLog v2 handler, which forwards audit log entries to the SAP Audit Log service via API v2.\n\n```xml\n\n com.sap.cds\n cds-feature-auditlog-v2\n runtime\n\n```\n", + " Audit Logging > AuditLog Handlers > AuditLog v2 Handler\naudit logging, AuditLog v2 handler, disable, cds.auditlog.v2.enabled, application.yaml, YAML\nTo disable the AuditLog v2 handler, set cds.auditlog.v2.enabled to false in application.yaml. By default the handler is enabled if all requirements are met.\n\n```yaml\ncds:\n auditlog.v2.enabled: false\n```\n", + " Audit Logging > AuditLog Handlers > Custom AuditLog Handler\naudit logging, custom handler, EventHandler, AuditLogService, Java, Spring Boot\nExample of a custom AuditLog event handler in a CAP Java Spring Boot project. Implements EventHandler, registers methods for each AuditLog event type (@On annotation), and can provide custom post-processing of audit log events.\n\n```java\nimport com.sap.cds.services.auditlog.*;\nimport com.sap.cds.services.handler.*;\nimport com.sap.cds.services.handler.annotations.*;\nimport org.springframework.stereotype.*;\n\n@Component\n@ServiceName(value = \"*\", type = AuditLogService.class)\nclass CustomAuditLogHandler implements EventHandler {\n\n\t@On\n\tpublic void handleDataAccessEvent(DataAccessLogContext context) {\n\t\t// custom handler code\n\t}\n\n\t@On\n\tpublic void handleDataModificationEvent(DataModificationLogContext context) {\n\t\t// custom handler code\n\t}\n\n\t@On\n\tpublic void handleConfigChangeEvent(ConfigChangeLogContext context) {\n\t\t// custom handler code\n\t}\n\n\t@On\n\tpublic void handleSecurityEvent(SecurityLogContext context) {\n\t\t// custom handler code\n\t}\n}\n```\n", + " Change Tracking > Enabling Change Tracking\ninstallation, dependency, cds-feature-change-tracking, pom.xml, enable\nThis XML code snippet shows how to add the cds-feature-change-tracking dependency to the srv/pom.xml file of a CAP Java project in order to enable change tracking. The dependency scope is set to 'runtime'.\n\n```xml\n\n com.sap.cds\n cds-feature-change-tracking\n runtime\n\n```\n", + " Change Tracking > Annotating Entities\ncds modeling, extend, aspect, change tracking, service definition\nThis CDS code demonstrates how to enable change tracking for an entity (model.Books) by extending it with the changelog.changeTracked aspect. The changelog model must be imported from the 'com.sap.cds/change-tracking' package.\n\n```cds\nusing {sap.changelog as changelog} from 'com.sap.cds/change-tracking';\nextend model.Books with changelog.changeTracked;\n```\n", + " Change Tracking > Annotating Entities\ncds modeling, annotation, changelog, projections, service definition\nThis code snippet shows how to use the @changelog annotation to indicate which elements (title and stock) of the service projection Bookshop.Books should be tracked for changes.\n\n```cds\nannotate Bookshop.Books {\n title @changelog;\n stock @changelog;\n};\n```\n", + " Change Tracking > Annotating Entities\ncds modeling, composition, changelog, deep update, order example\nThis CDS model shows how to apply change tracking to entities with compositions. The Orders entity and its items expose elements with the @changelog annotation so their changes are individually tracked, including in deep updates.\n\n```cds\nentity OrderItems : cuid {\n parent : Association to Orders;\n [...]\n quantity: Integer @changelog;\n}\n\nentity Orders : cuid {\n customerName: String @changelog;\n [...]\n items: Composition of many OrderItems on items.parent = $self;\n}\n```\n", + " Change Tracking > Identifiers for Entities\ncds modeling, entity identifier, changelog, annotation\nThis annotation defines a human-readable identifier for the change log by storing the 'title' element with each tracked change for the Book entity.\n\n```cds\nannotate Bookshop.Book with @changelog: [\n title\n];\n```\n", + " Change Tracking > Identifiers for Compositions\ncds modeling, composition identifier, changelog, deep update\nThese CDS annotations specify human-readable identifiers for Orders (using OrderNo) and OrderItems (using the parent Order's OrderNo and supplierName) to store with each change log entry.\n\n```cds\nannotate Orders with @changelog: [OrderNo];\n\nannotate OrderItems with @changelog: [\n parent.OrderNo,\n supplierName,\n];\n```\n", + " Change Tracking > Human-readable values for associations\ncds modeling, association, changelog, human-readable, foreign key\nThis annotation specifies that instead of storing the technical foreign key for the customer association in the changelog, the value of customer.name should be used for a more human-readable entry.\n\n```cds\nannotate Orders {\n customer @changelog: [ customer.name ]\n}\n```\n", + " Change Tracking > Displaying Changes\ncds modeling, UI, facet, display changelog, Bookshop.Books\nThis CDS annotation adds a facet for the change history to the UI of Bookshop.Books, allowing the change log to be displayed on the object page in the Fiori interface.\n\n```cds\nannotate Bookshop.Books with @(\n UI : { ...\n Facets : [ ...\n {\n $Type : 'UI.ReferenceFacet',\n ID : 'ChangeHistoryFacet',\n Label : '{i18n>ChangeHistory}',\n Target : 'changes/@UI.PresentationVariant',\n ![@UI.PartOfPreview]: false\n } ...\n ] ...\n } ...);\n```\n", + " Change Tracking > Reacting on Changes\njava, custom logic, event handler, change tracking, observe changelog\nThis Java code shows how to implement an event handler to observe new entries in the change log. The handler class listens to the CREATE_CHANGES event in the ChangeTrackingService and processes each new Changes entry.\n\n```java\nimport cds.gen.sap.changelog.Changes;\n\n@Component\n@ServiceName(ChangeTrackingService.DEFAULT_NAME)\npublic class ChangeTrackingHandler implements EventHandler {\n\n @After(event = ChangeTrackingService.CREATE_CHANGES)\n void afterCreate(CreateChangesEventContext context) {\n context.getResult().listOf(Changes.class).forEach(c -> {\n // Do something with the change log entry\n });\n }\n}\n```\n", + " Change Tracking > Reacting on Changes\ninstallation, dependency, cds-feature-change-tracking, pom.xml, react\nThis dependency declaration updates the scope of the change tracking feature to 'compile' in the POM file, which is needed for programmatically reacting to changes in Java code.\n\n```xml\n\n com.sap.cds\n cds-feature-change-tracking\n compile\n\n```\n", + " Transactional Outbox > Persistent Outbox\npersistent outbox, configuration, cds.requires, package.json, cdsrc.json\nConfigures the CAP Java application to use a persistent outbox by specifying the outbox service of kind 'persistent-outbox' in either package.json or cdsrc.json. Essential to enable transactional consistency for message emitting.\n\n```jsonc\n{\n // ...\n \"cds\": {\n \"requires\": {\n \"outbox\": {\n \"kind\": \"persistent-outbox\"\n }\n }\n }\n}\n```\n", + " Transactional Outbox > Persistent Outbox\npersistent outbox, configuration, YAML, application.yaml\nShows how to configure persistent outbox services in a CAP Java application using application.yaml. Sets maxAttempts for DefaultOutboxOrdered and DefaultOutboxUnordered, the two default persistent outbox services.\n\n```yaml\ncds:\n outbox:\n services:\n DefaultOutboxOrdered:\n maxAttempts: 10\n # ordered: true\n DefaultOutboxUnordered:\n maxAttempts: 10\n # ordered: false\n```\n", + " Transactional Outbox > Configuring Custom Outboxes\npersistent outbox, custom outbox, configuration, YAML, application.yaml\nExample configuration of custom persistent outbox services in application.yaml for CAP Java applications. Each custom outbox can have different maxAttempts settings.\n\n```yaml\ncds:\n outbox:\n services:\n MyCustomOutbox:\n maxAttempts: 5\n MyOtherCustomOutbox:\n maxAttempts: 10\n```\n", + " Transactional Outbox > Configuring Custom Outboxes\npersistent outbox, custom outbox, service catalog, Java, service access\nRetrieving custom OutboxService instances by name from the CAP Java service catalog, enabling further operations or outboxing on them.\n\n```java\nOutboxService myCustomOutbox = cdsRuntime.getServiceCatalog().getService(OutboxService.class, \"MyCustomOutbox\");\nOutboxService myOtherCustomOutbox = cdsRuntime.getServiceCatalog().getService(OutboxService.class, \"MyOtherCustomOutbox\");\n```\n", + " Transactional Outbox > Configuring Custom Outboxes\npersistent outbox, custom outbox, Spring, dependency injection, Java\nShows how to inject a custom OutboxService instance into a Spring component by name using the @Qualifier annotation in a CAP Java application.\n\n```java\n@Component\npublic class MySpringComponent {\n private final OutboxService myCustomOutbox;\n\n public MySpringComponent(@Qualifier(\"MyCustomOutbox\") OutboxService myCustomOutbox) {\n this.myCustomOutbox = myCustomOutbox;\n }\n}\n```\n", + " Transactional Outbox > Outbox Event Versions\nevent version, deployment, maven, filtering, pom.xml\nEnables Maven resource filtering to inject the Maven project version as deployment version for outbox event versioning in CAP Java. Required for version-based processing logic.\n\n```xml\n\n ...\n\t\n\t\t\n\t\t\tsrc/main/resources\n\t\t\ttrue\n\t\t\n\t\n ...\n```\n", + " Transactional Outbox > Outbox Event Versions\nevent version, deployment, startup log, version verification, shell\nExample log output at application startup showing the resolved application deployment version, which is used by the outbox for event versioning and compatibility checks.\n\n```shell\n2024-12-19T11:21:33.253+01:00 INFO 3420 --- [main] cds.services.impl.utils.BuildInfo : application.deployment.version: 1.0.0-SNAPSHOT\n```\n", + " Transactional Outbox > Outboxing CAP Service Events\noutbox service, decoupled event, outboxing CAP services, Java, AsyncCqnService\nWraps a target CAP (Cqn) service with outbox handling. All events triggered on 'outboxedS4' are stored in the outbox and executed asynchronously. Ensures decoupled processing of CAP service calls.\n\n```java\nOutboxService myCustomOutbox = ...;\nCqnService remoteS4 = ...;\nCqnService outboxedS4 = myCustomOutbox.outboxed(remoteS4);\n```\n", + " Transactional Outbox > Outboxing CAP Service Events\noutbox service, AsyncCqnService, outboxing CAP services, Java\nWraps a CqnService as an AsyncCqnService using outboxing. Calls to outboxedS4 are asynchronous, and API matches AsyncCqnService interface with void return types.\n\n```java\nOutboxService myCustomOutbox = ...;\nCqnService remoteS4 = ...;\nAsyncCqnService outboxedS4 = myCustomOutbox.outboxed(remoteS4, AsyncCqnService.class);\n```\n", + " Transactional Outbox > Outboxing CAP Service Events\noutbox service, AsyncCqnService, Java, factory method\nAlternative way to wrap a CqnService into an asynchronous outboxed variant using AsyncCqnService's static factory method. Supports flexible outboxing API creation.\n\n```java\nOutboxService myCustomOutbox = ...;\nCqnService remoteS4 = ...;\nAsyncCqnService outboxedS4 = AsyncCqnService.of(remoteS4, myCustomOutbox);\n```\n", + " Transactional Outbox > Technical Outbox API\noutbox service, technical API, submit, custom message, Java\nDemonstrates programmatic submission of a custom OutboxMessage with parameters to a named OutboxService. The message is stored and processed asynchronously via the outbox mechanism.\n\n```java\nOutboxService outboxService = runtime.getServiceCatalog().getService(OutboxService.class, \"\");\n\nOutboxMessage message = OutboxMessage.create();\nmessage.setParams(Map.of(\"name\", \"John\", \"lastname\", \"Doe\"));\n\noutboxService.submit(\"myEvent\", message);\n```\n", + " Transactional Outbox > Technical Outbox API\noutbox service, event handler, OutboxMessageEventContext, Java\nRegisters a handler for a custom outbox event, accesses parameters from the OutboxMessage, processes the event, and calls setCompleted() to signal completion to the outbox.\n\n```java\n@On(service = \"\", event = \"myEvent\")\nvoid processMyEvent(OutboxMessageEventContext context) {\n OutboxMessage message = context.getMessage();\n Map params = message.getParams();\n String name = (String) param.get(\"name\");\n String lastname = (String) param.get(\"lastname\");\n\n // Perform processing logic for myEvent\n\n context.setCompleted();\n}\n```\n", + " Transactional Outbox > Handling Outbox Errors\noutbox service, error handling, retry suppression, Java\nError handling pattern for outbox event processing. Retries only on recoverable errors by rethrowing the exception, while unrecoverable semantic errors are acknowledged with setCompleted() to prevent retry.\n\n```java\n@On(service = \"\", event = \"myEvent\")\nvoid processMyEvent(OutboxMessageEventContext context) {\n try {\n // Perform processing logic for myEvent\n } catch (Exception e) {\n if (isUnrecoverableSemanticError(e)) {\n // Perform application-specific counter-measures\n context.setCompleted(); // indicate message deletion to outbox\n } else {\n throw e; // indicate error to outbox\n }\n }\n}\n```\n", + " Transactional Outbox > Handling Outbox Errors\noutbox service, error handling, proceed, EventContext, Java\nShows how to add additional error handling around default outbox event processing using context.proceed(), selectively suppressing or allowing retries based on error type.\n\n```java\n@On(service = OutboxService.PERSISTENT_ORDERED_NAME, event = AuditLogService.DEFAULT_NAME)\nvoid handleAuditLogProcessingErrors(OutboxMessageEventContext context) {\n try {\n context.proceed(); // wrap default logic\n } catch (Exception e) {\n if (isUnrecoverableSemanticError(e)) {\n // Perform application-specific counter-measures\n context.setCompleted(); // indicate message deletion to outbox\n } else {\n throw e; // indicate error to outbox\n }\n }\n}\n```\n", + " Transactional Outbox > Outbox Dead Letter Queue > Define the Service\ndead letter queue, CDS, service definition, readonly, projection\nDefines a CDS service OutboxDeadLetterQueueService exposing a readonly entity DeadOutboxMessages, projecting cds.outbox.Messages and offering revive() and delete() actions for dead letter processing.\n\n```cds\nusing from '@sap/cds/srv/outbox';\n\n@requires: 'internal-user'\nservice OutboxDeadLetterQueueService {\n\n @readonly\n entity DeadOutboxMessages as projection on cds.outbox.Messages\n actions {\n action revive();\n action delete();\n };\n\n}\n```\n", + " Transactional Outbox > Outbox Dead Letter Queue > Filter for Dead Entries\ndead letter queue, Java, @After handler, read filter\nImplements an @After READ handler in CAP Java to filter only dead outbox entries for a Dead Letter Queue service. Compares entry attempts with configured maxAttempts to identify dead entries.\n\n```java\n@Component\n@ServiceName(OutboxDeadLetterQueueService_.CDS_NAME)\npublic class DeadOutboxMessagesHandler implements EventHandler {\n\n\t@After(entity = DeadOutboxMessages_.CDS_NAME)\n\tpublic void filterDeadEntries(CdsReadEventContext context) {\n\t\tCdsProperties.Outbox outboxConfigs = context.getCdsRuntime().getEnvironment().getCdsProperties().getOutbox();\n\t\tList deadEntries = context\n\t\t\t\t.getResult()\n\t\t\t\t.listOf(DeadOutboxMessages.class)\n\t\t\t\t.stream()\n\t\t\t\t.filter(entry -> entry.getAttempts() >= outboxConfigs.getService(entry.getTarget()).getMaxAttempts())\n\t\t\t\t.toList();\n\n\t\tcontext.setResult(deadEntries);\n\t}\n}\n```\n", + " Transactional Outbox > Outbox Dead Letter Queue > Implement Bound Actions\ndead letter queue, bound actions, Java, revive, delete, PersistenceService\nHandler implementations for revive and delete actions on DeadOutboxMessages. Revive resets the attempts count for retry; delete removes the entry from the outbox. Uses CqnAnalyzer for key extraction and PersistenceService for persistence operations.\n\n```java\n@Autowired\n@Qualifier(PersistenceService.DEFAULT_NAME)\nprivate PersistenceService db;\n\n@On\npublic void reviveOutboxMessage(DeadOutboxMessagesReviveContext context) {\n CqnAnalyzer analyzer = CqnAnalyzer.create(context.getModel());\n AnalysisResult analysisResult = analyzer.analyze(context.getCqn());\n Map key = analysisResult.rootKeys();\n Messages deadOutboxMessage = Messages.create((String) key.get(Messages.ID));\n\n deadOutboxMessage.setAttempts(0);\n\n this.db.run(Update.entity(Messages_.class).entry(key).data(deadOutboxMessage));\n context.setCompleted();\n}\n\n@On\npublic void deleteOutboxEntry(DeadOutboxMessagesDeleteContext context) {\n CqnAnalyzer analyzer = CqnAnalyzer.create(context.getModel());\n AnalysisResult analysisResult = analyzer.analyze(context.getCqn());\n Map key = analysisResult.rootKeys();\n\n this.db.run(Delete.from(Messages_.class).byId(key.get(Messages.ID)));\n context.setCompleted();\n}\n```\n", + " Multitenancy > React on Tenant Events > Subscribe Tenant\nmultitenancy, DeploymentService, event handler, subscription, custom logic, Java\nRegisters Java event handlers for the SUBSCRIBE event on DeploymentService in CAP Java, allowing custom logic during tenant onboarding. The @Before handler executes actions before the tenant database container is created. The @After handler can be used for post-processing such as notifications.\n\n```java\n@Before\npublic void beforeSubscription(SubscribeEventContext context) {\n // Activities before tenant database container is created\n}\n\n@After\npublic void afterSubscribe(SubscribeEventContext context) {\n // For example, send notification, ...\n}\n```\n", + " Multitenancy > React on Tenant Events > Subscribe Tenant > Defining a Database ID\nmultitenancy, database_id, subscription, DeploymentService, custom handler, Java\nShows how to set the target database_id in a custom @Before handler for tenant subscription, which is required when multiple SAP HANA instances are registered in a BTP space. This tells CAP Java where to create the tenant-specific container.\n\n```java\n@Before\npublic void beforeSubscription(SubscribeEventContext context) {\n context.getOptions().put(\"provisioningParameters\",\n Collections.singletonMap(\"database_id\", \"\"));\n}\n```\n", + " Multitenancy > React on Tenant Events > Unsubscribe Tenant\nmultitenancy, unsubscription, DeploymentService, event handler, Java\nRegisters event handlers for the UNSUBSCRIBE event in DeploymentService. Executes logic before and after the tenant's database container is deleted during offboarding of a tenant.\n\n```java\n@Before\npublic void beforeUnsubscribe(UnsubscribeEventContext context) {\n // Activities before offboarding\n}\n\n@After\npublic void afterUnsubscribe(UnsubscribeEventContext context) {\n // Notify offboarding finished\n}\n```\n", + " Multitenancy > React on Tenant Events > Unsubscribe Tenant > Skipping Deletion of Tenant Data\nmultitenancy, unsubscription, skip deletion, custom handler, DeploymentService, Java\nCustomizes the UNSUBSCRIBE behavior to conditionally skip deletion of tenant-specific resources (i.e., database containers). If keepResources returns true, the event is completed early and deletion is avoided.\n\n```java\n@Before\npublic void beforeUnsubscribe(UnsubscribeEventContext context) {\n if (keepResources(context.getTenant())) {\n context.setCompleted(); // avoid @On handler phase\n }\n}\n```\n", + " Multitenancy > React on Tenant Events > Define Dependent Services\nmultitenancy, dependencies, DeploymentService, custom handler, Java\nImplements a custom handler for the DEPENDENCIES event in DeploymentService for CAP Java multitenancy. This allows you to declare dependencies on SAP reuse services (e.g., for correct SaaS provisioning), returning required xsappnames. The handler uses DI for CdsRuntime and obtains service credentials programmatically.\n\n```java\n@Component\n@Profile(\"cloud\")\n@ServiceName(DeploymentService.DEFAULT_NAME)\npublic class SubscriptionHandler implements EventHandler {\n\tprivate static final String SERVICE_NAME = \"my-service\";\n\n\t@Autowired\n\tprivate CdsRuntime cdsRuntime;\n\n\t@On\n\tpublic void onDependencies(DependenciesEventContext context) {\n\t\tList> dependencies = new ArrayList<>();\n\t\tOptional service = cdsRuntime.getEnvironment().\n getServiceBindings().filter(binding -> binding.getServiceName().\n get().equals(SERVICE_NAME)).findFirst();\n\t\t\n\t\tif (service.isPresent()) {\n\t\t\tString xsappname = extractXsappname(service.get().getCredentials());\n\t\t\tdependencies.add(SaasRegistryDependency.create(xsappname));\n\t\t}\n\t\tcontext.setResult(dependencies);\n\t}\n\n\tprivate String extractXsappname(Map credentials) {\n\t\t// location of the `xsappname` in the credentials is service specific\n\t}\n}\n```\n", + " Multitenancy > Database Schema Update > Deploy Main Method\nmultitenancy, database schema update, upgrade, command line, database upgrade, main method, deployment, Java\nRuns the CAP Java Deploy main method to upgrade schema for tenants before starting new application code. Accepts optional tenant IDs as arguments (defaults to all tenants). For Spring Boot >= 3.2.0, uses PropertiesLauncher. Must be executed when CAP Java backend is stopped but MTX Sidecar is running.\n\n```shell\njava -cp -Dloader.main=com.sap.cds.framework.spring.utils.Deploy org.springframework.boot.loader.launch.PropertiesLauncher [] ... []\n```\n", + " Multitenancy > Database Schema Update > Deploy Main Method\nmultitenancy, database schema update, upgrade, Cloud Foundry, deployment, Java\nCloud Foundry command to run the Deploy main method or another custom command as a one-off task (e.g., for multi-tenant database schema upgrades or lifecycle tasks in the MTX scenario). The argument must be adapted to set the loader main and use the correct Spring Boot launcher.\n\n```shell\ncf run-task \"\"\n```\n", + " Multitenancy > Database Schema Update > Deploy Main Method\nmultitenancy, database schema update, upgrade, Cloud Foundry, Spring Boot, deployment, Java\nScript for running CAP Java's Deploy main method in Cloud Foundry, replacing the default startup with PropertiesLauncher and setting loader.main, suitable for Spring Boot >= 3.2.0. Used for upgrading tenants in MTX scenario on SAP BTP.\n\n```shell\nsed -i 's/org.springframework.boot.loader.launch.JarLauncher/org.springframework.boot.loader.launch.PropertiesLauncher/g' /home/vcap/staging_info.yml && \\\n sed -i 's/-Dsun.net.inetaddr.negative.ttl=0/-Dsun.net.inetaddr.negative.ttl=0 -Dloader.main=com.sap.cds.framework.spring.utils.Deploy/g' /home/vcap/staging_info.yml && \\\n jq -r .start_command /home/vcap/staging_info.yml | bash\n```\n", + " Multitenancy > Database Schema Update > Deploy Main Method\nmultitenancy, database schema update, upgrade, VS Code, Java\nVS Code launch configuration for running CAP Java Deploy main method, used for triggering tenant upgrades or schema changes in a developer environment. You can specify tenants and set required Spring profiles.\n\n```json\n{\n \"type\": \"java\",\n \"name\": \"MTX Update tenants\",\n \"request\": \"launch\",\n \"mainClass\": \"com.sap.cds.framework.spring.utils.Deploy\",\n \"args\": \"\", // optional: specify the tenants to upgrade, defaults to all\n \"projectName\": \"\",\n \"vmArgs\": \"-Dspring.profiles.active=local-mtxs\" // or any other profile required for MTX\n}\n```\n", + " Multitenancy > Development Aspects > Working with Tenants > Switching to Provider Tenant\nmultitenancy, tenant switch, RequestContextRunner, provider tenant, Java\nSwitches the RequestContext to the provider tenant ('technical tenant'), which is useful for cross-tenant operations or configuration tasks that require provider scope.\n\n```java\nruntime.requestContext().systemUserProvider().run(context -> {\n // call technical service\n ...\n});\n```\n", + " Multitenancy > Development Aspects > Working with Tenants > Switching to Subscriber Tenants\nmultitenancy, tenant switch, RequestContextRunner, subscriber tenant, Java\nExecutes code under a specific subscriber tenant by creating a nested RequestContext for that tenant, commonly used in background jobs or cross-tenant tasks.\n\n```java\nruntime.requestContext().systemUser(tenant).run(context -> {\n // call technical service\n ...\n});\n```\n", + " Multitenancy > Development Aspects > Working with Tenants > Enumerating Subscriber Tenants\nmultitenancy, tenant enumeration, TenantProviderService, Java\nUses TenantProviderService to enumerate all available business tenants, returning a list of TenantInfo. Useful for provider-tenant scoped overview or batch operations.\n\n```java\n@Autowired\nTenantProviderService tenantProvider;\n...\nList tenantInfo = tenantProvider.readTenants();\n```\n", + " Security > Authentication > Custom Authentication\nsecurity, authentication, custom authentication, UserInfoProvider, Java\nImplements a custom UserInfoProvider in CAP Java to adapt user information for incoming requests (e.g. setting a custom user name based on XSUAA claims). This example provides an overlay on top of the default XSUAA-based provider.\n\n```java\n@Component\npublic class CustomUserInfoProvider implements UserInfoProvider {\n\n private UserInfoProvider defaultProvider;\n\n @Override\n public UserInfo get() {\n ModifiableUserInfo userInfo = UserInfo.create();\n if (defaultProvider != null) {\n UserInfo prevUserInfo = defaultProvider.get();\n if (prevUserInfo != null) {\n userInfo = prevUserInfo.copy();\n }\n }\n if (userInfo != null) {\n XsuaaUserInfo xsuaaUserInfo = userInfo.as(XsuaaUserInfo.class);\n userInfo.setName(xsuaaUserInfo.getEmail() + \"/\" +\n xsuaaUserInfo.getOrigin()); // adapt name\n }\n\n return userInfo;\n }\n\n @Override\n public void setPrevious(UserInfoProvider prev) {\n this.defaultProvider = prev;\n }\n}\n```\n", + " Security > Authentication > Mock User Authentication with Spring Boot\nsecurity, mock user, test, Spring Boot, Java\nJunit test class using explicit mock users in Spring Boot for security tests. Demonstrates usage of @WithMockUser and verifies authorization behavior for a CAP Java service endpoint.\n\n```java\n@RunWith(SpringRunner.class)\n@SpringBootTest\n@AutoConfigureMockMvc\npublic class BookServiceOrdersTest {\n\tString ORDERS_URL = \"/odata/v4/BooksService/Orders\";\n\n\t@Autowired\n\tprivate MockMvc mockMvc;\n\n\t@Test\n\t@WithMockUser(username = \"Viewer-User\")\n\tpublic void testViewer() throws Exception {\n\t\tmockMvc.perform(get(ORDERS_URL)).andExpect(status().isOk());\n\t}\n\t@Test\n\tpublic void testUnauthorized() throws Exception {\n\t\tmockMvc.perform(get(ORDERS_URL)).andExpect(status().isUnauthorized());\n\t}\n}\n```\n", + " Security > Authentication > Mock User Authentication with Spring Boot > Explicitly Defined Mock Users\nsecurity, mock user, test, configuration, yaml, Spring Boot\nYAML configuration for defining explicit mock users with roles, tenants, user attributes, additional properties (e.g., email), and enabled features. Used for local testing or Spring Boot test profiles in CAP Java.\n\n```yaml\n---\nspring:\n config.activate.on-profile: test\ncds:\n security:\n mock:\n users:\n - name: Viewer-User\n password: viewer-pass\n tenant: CrazyCars\n roles:\n - Viewer\n attributes:\n Country: [GER, FR]\n additional:\n email: myviewer@crazycars.com\n features:\n - cruise\n - park\n\n - name: Privileged-User\n password: privileged-pass\n privileged: true\n features:\n - \"*\"\n```\n", + " Security > Authentication > Mock User Authentication with Spring Boot > Mock Tenants\nsecurity, mock tenant, test, configuration, yaml, Spring Boot\nYAML configuration for defining mock tenants and assigning features to them in CAP Java, used for feature toggles or custom test scenarios involving tenant-specific settings.\n\n```yaml\n---\nspring:\n config.activate.on-profile: test\ncds:\n security:\n mock:\n users:\n - name: Alice\n tenant: CrazyCars\n tenants:\n - name: CrazyCars\n features:\n - cruise\n - park\n```\n", + " Security > Authorization > Enforcement API & Custom Handlers\nsecurity, authorization, enforcement, UserInfo, custom handler, Java\nShows two approaches for accessing the authenticated user information within event handlers in CAP Java: a) via EventContext.getUserInfo(), b) via dependency injection, enabling fine-grained checks or custom logic.\n\n```java\nEventContext context;\nUserInfo user = context.getUserInfo();\n// ...\n@Autowired\nUserInfo user;\n// ...\n```\n", + " Security > Authorization > Enforcement API & Custom Handlers\nsecurity, authorization, privileged access, UserInfo, RequestContextRunner, Java\nDemonstrates executing service calls in a privileged mode in CAP Java. The code switches context to a privileged user so that inner service calls bypass generic authorization handlers.\n\n```java\ncdsRuntime.requestContext().privilegedUser().run(privilegedContext -> {\n\tassert privilegedContext.getUserInfo().isPrivileged();\n\t// ... Service calls in this scope pass generic authorization handler\n});\n```\n", + " IAS Authorization via AMS > Streamlined AMS Integration\nCLI, setup, IAS, AMS, configuration\nUse the CDS CLI to add IAS (Identity Authentication Service) and AMS (Authorization Management Service) integration to your CAP project. This sets up authentication and authorization configuration automatically.\n\n```shell\ncds add ias\ncds add ams\n```\n", + " IAS Authorization via AMS > Streamlined AMS Integration > Define your CDS model along with technical authorization rules\ncds modeling, authorization, restrict, aspect, entity\nDefines a CDS model with an `aspect` for a system type and an `Issues` entity using it. Enforces technical authorization with a restrict annotation, granting specific roles access to read or write issues.\n\n```cds\naspect fromSystem {\n  systemType : String enum { DEV; QS; PROD; };\n}\n\nentity Issues : fromSystem {\n key ID: UUID;\n description: String;\n resolved: Boolean;\n}\n\nannotate Issues with @(restrict: [\n    { grant: ['READ'], to: 'ReviewIssues' },\n    { grant: ['READ', 'WRITE'], to: 'ManageIssues' }\n]);\n```\n", + " IAS Authorization via AMS > Streamlined AMS Integration > Optionally, link your CDS model to AMS attributes by `@ams` annotation\ncds modeling, AMS, attributes, annotation\nLinks the `fromSystem` aspect property (`systemType`) in the CDS model to a business attribute (`SystemType`) for AMS by using the @ams.attributes annotation.\n\n```cds\nannotate fromSystem with @ams.attributes: {\n  SystemType: (systemType)\n};\n```\n", + " IAS Authorization via AMS > Streamlined AMS Integration > Define AMS policies that combine roles and attribute filters at business level\nAMS, policy, business authorization, yaml\nExample AMS policy definitions using DCL (Data Control Language): shows how to assign roles based on attributes like SystemType and how to restrict a policy to a specific system type.\n\n```yaml\nSCHEMA {\n SystemType : String\n}\n\nPOLICY QualityAuditor {\n ASSIGN ROLE ReviewIssues WHERE SystemType IS NOT RESTRICTED;\n}\n\nPOLICY SupportEngineer {\n USE QualityAuditor RESTRICT SystemType = 'PROD';\n}\n```\n", + " IAS Authorization via AMS > Setup > This adds the following... > Runtime plugins\nJava, AMS, pom.xml, dependency\nSpecifies the Maven dependencies and AMS plugin versions required for Java-based CAP applications. Integrates AMS client and CAP AMS support libraries for role injection and policy enforcement.\n\n```xml\n\n 3.3.0 \n\n\n \n com.sap.cloud.security.ams.client\n jakarta-ams\n ${sap.cloud.security.ams.version}\n \n \n com.sap.cloud.security.ams.client\n cap-ams-support\n ${sap.cloud.security.ams.version}\n \n\n```\n", + " IAS Authorization via AMS > Setup > This adds the following... > Development plugins\nNode.js, AMS, package.json, dependency\nAdds the @sap/ams development plugin to package.json. This plugin is used to validate AMS annotations, generate policies, and facilitate deployment of DCL (AMS policies) in Node.js projects.\n\n```json\n{\n \"devDependencies\": {\n \"@sap/ams\": \"^3\"\n }\n}\n```\n", + " IAS Authorization via AMS > Generate Policies > Role-based authorization\nrole-based authorization, cds modeling, requires, Books\nDefines that access to the `Books` entity requires the `Reader` role using the `@requires` annotation in CDS.\n\n```cds\nentity Books @(requires: 'Reader') {...}\n```\n", + " IAS Authorization via AMS > Generate Policies > Role-based authorization\nAMS, policy, DCL, role generation\nA generated AMS authorization policy in DCL format that assigns the 'Reader' role, corresponding to the CDS model's role requirement.\n\n```sql\nPOLICY Reader {\n ASSIGN ROLE Reader;\n}\n```\n", + " IAS Authorization via AMS > Build\nbuild, maven, Java\nExecutes a Maven build for the Java CAP project, which triggers policy and schema generation for AMS in the appropriate resource folder.\n\n```shell\nmvn clean install\n```\n", + " IAS Authorization via AMS > Build\nproject structure, build output, AMS, DCL policies\nShows the resulting folder structure after build, with DCL policies and schema generated for AMS integration under srv/src/main/resources/ams.\n\n```txt\n└─ ams\n ├─ cap\n │ └─ basePolicies.dcl\n └─ schema.dcl\n```\n", + " IAS Authorization via AMS > Prepare for Deployment\ndeployment, Cloud Foundry, setup, CLI\nConfigures a CAP project for Cloud Foundry deployment, adding necessary modules for database (hana), approuter, MTA, and AMS integration.\n\n```shell\ncds add hana,approuter,mta,ams\n```\n", + " Spring Boot Integration > Integration Configuration\nSpring Boot, pom.xml, dependency, integration, CAP Java\nThis XML snippet shows how to add the 'cds-framework-spring-boot' runtime dependency in your pom.xml to activate CAP Java integration with Spring Boot. Set '${cds.services.version}' accordingly. This is required for Spring Boot based CAP Java apps.\n\n```xml\n\n\tcom.sap.cds\n\tcds-framework-spring-boot\n\t${cds.services.version}\n\truntime\n\n```\n", + " Spring Boot Integration > Integration Configuration\nSpring Boot, pom.xml, dependency, integration, OData, CDS starter bundle, CAP Java\nThis XML snippet adds the 'cds-starter-spring-boot-odata' dependency to your pom.xml, which includes Spring Boot integration and OData V4 protocol setup for CAP Java. Recommended as an all-in-one starter for new Spring Boot-based CAP Java projects.\n\n```xml\n\n\tcom.sap.cds\n\tcds-starter-spring-boot-odata\n\t${cds.services.version}\n\n```\n", + " Spring Boot Integration > CDS Spring Beans\nSpring Boot, Spring Beans, dependency injection, CDS, beans, CAP Java\nExample showing how to inject various CAP Java SDK beans into Spring-managed classes using @Autowired or @Qualifier. Supported beans include technical services like CdsRuntime, CdsRuntimeConfigurer, ApplicationService, PersistenceService, ServiceCatalog, CdsModel, UserInfo, AuthenticationInfo, ParameterInfo, Messages, FeatureTogglesInfo, and CdsDataStore. Most are request-scoped or singleton.\n\n```java\n@Autowired\nCdsRuntime runtime;\n\n@Autowired\nCdsRuntimeConfigurer configurer;\n\n@Autowired\n@Qualifier(CatalogService_.CDS_NAME)\nprivate ApplicationService cs;\n\n@Autowired\nprivate PersistenceService ps;\n\n@Autowired\nServiceCatalog catalog;\n\n@Autowired\nCdsModel model;\n\n@Autowired\nUserInfo userInfo;\n\n@Autowired\nAuthenticationInfo authInfo;\n\n@Autowired\nParameterInfo paramInfo;\n\n@Autowired\nMessages messages;\n\n@Autowired\nFeatureTogglesInfo ftsInfo;\n\n@Autowired\nCdsDataStore ds;\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Configuration > Use `event-broker` in Node.js\ninstallation, Node.js, event-broker, npm, plugin\nInstalls the @cap-js/event-broker plugin for enabling SAP Cloud Application Event Hub messaging integration in a Node.js-based CAP project. Run this in your project root.\n\n```shell\nnpm add @cap-js/event-broker\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Configuration > Use `event-broker` in Node.js\nconfiguration, package.json, event-broker, cds.env, Node.js\nConfigures the CAP runtime in Node.js to use the SAP Cloud Application Event Hub by setting the 'kind' of messaging to 'event-broker' for the production profile in package.json. Ensures event messages are handled by the proper broker in production.\n\n```json\n\"cds\": {\n \"requires\": {\n \"messaging\": {\n // kind \"event-broker\" is derived from the service's technical name\n \"[production]\": { \"kind\": \"event-broker\" }\n }\n }\n}\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Configuration > Use `event-hub` in Java\ninstallation, Java, event-hub, dependency, pom.xml\nAdds the cds-feature-event-hub dependency to a Java application's pom.xml. This plugin provides support for SAP Cloud Application Event Hub messaging integration in CAP Java projects.\n\n```xml\n\n com.sap.cds\n cds-feature-event-hub\n ${latest-version}\n\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Configuration > Use `event-hub` in Java\nconfiguration, Java, application.yaml, event-hub, messaging\nSpecifies the configuration for using the SAP Cloud Application Event Hub as a messaging service within the CAP Java application's application.yaml. The kind 'event-hub' tells CAP to connect to the actual broker.\n\n```yaml\ncds:\n messaging.services:\n - name: \"messaging-name\"\n kind: \"event-hub\"\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Prepare for MTA Deployment\nMTA, deployment, Cloud Foundry, mta.yaml, application module, reference\nDefines the base MTA module for the CAP application in Cloud Foundry. 'incidents-srv' is provided and exposes its URL under 'incidents-srv-api' for references in dependent resources.\n\n```yaml\nmodules:\n - name: incidents-srv\n provides:\n - name: incidents-srv-api\n properties:\n url: ${default-url} #> needed in references below\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Prepare for MTA Deployment > Add SAP Cloud Application Event Hub Instance\nMTA, deployment, Cloud Foundry, Node.js, event-broker, resource, mta.yaml\nDefines an Event Hub instance resource for Node.js in mta.yaml. Sets a unique 'systemNamespace' and a webhook URL that receives events from SAP Cloud Application Event Hub, linking this resource to the service API.\n\n```yaml\nresources:\n - name: incidents-event-broker\n type: org.cloudfoundry.managed-service\n parameters:\n service: event-broker\n service-plan: event-connectivity\n config:\n # unique identifier for this event broker instance\n # should start with own namespace (i.e., \"foo.bar\") and may not be longer than 15 characters\n systemNamespace: cap.incidents\n webhookUrl: ~{incidents-srv-api/url}/-/cds/event-broker/webhook\n requires:\n - name: incidents-srv-api\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Prepare for MTA Deployment > Add SAP Cloud Application Event Hub Instance\nMTA, deployment, Cloud Foundry, Java, event-broker, resource, mta.yaml\nDefines an Event Hub instance resource for Java-based CAP apps in mta.yaml. Configuration sets the system namespace and points the webhook URL to the Java-specific endpoint for event reception, referencing the API.\n\n```yaml\nresources:\n - name: incidents-event-broker\n type: org.cloudfoundry.managed-service\n parameters:\n service: event-broker\n service-plan: event-connectivity\n config:\n # unique identifier for this event broker instance\n # should start with own namespace (i.e., \"foo.bar\") and may not be longer than 15 characters\n systemNamespace: cap.incidents\n webhookUrl: ~{incidents-srv-api/url}/messaging/v1.0/eb\n requires:\n - name: incidents-srv-api\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Prepare for MTA Deployment > Add Identity Authentication Service Instance\nMTA, identity, IAS, event-broker, Cloud Foundry, resource, mta.yaml\nConfigures the Identity Authentication Service (IAS) resource in the MTA for enabling secure communication with SAP Cloud Application Event Hub. It consumes the event broker, ensures creation order, and sets cross-consumption and display properties.\n\n```yaml\nresources:\n - name: incidents-ias\n type: org.cloudfoundry.managed-service\n requires:\n - name: incidents-srv-api\n processed-after:\n # for consumed-services (cf. below), incidents-event-broker must already exist\n # -> ensure incidents-ias is created after incidents-event-broker\n - incidents-event-broker\n parameters:\n service: identity\n service-plan: application\n config:\n consumed-services:\n - service-instance-name: incidents-event-broker\n xsuaa-cross-consumption: true #> if token exchange from IAS token to XSUAA token is needed\n display-name: cap.incidents #> any value, e.g., reuse MTA ID\n home-url: ~{incidents-srv-api/url}\n```\n", + " Using SAP Cloud Application Event Hub in Cloud Foundry > Prepare for MTA Deployment > Bind the Service Instances\nMTA, service binding, Cloud Foundry, IAS, event-broker, authentication, mta.yaml\nFinalizes service bindings for the app module in mta.yaml. Binds incidents-ias and incidents-event-broker to the application with security-sensitive parameters for X509/Gernerated credentials and X509_IAS-based authentication, enabling trusted communication.\n\n```yaml\nmodules:\n - name: incidents-srv\n provides:\n - name: incidents-srv-api\n properties:\n url: ${default-url} \n requires: #[!code focus:10]\n - name: incidents-ias #[!code ++]\n parameters: #[!code ++]\n config: #[!code ++]\n credential-type: X509_GENERATED #[!code ++]\n app-identifier: cap.incidents #> any value, e.g., reuse MTA ID [!code ++]\n - name: incidents-event-broker #[!code ++]\n parameters: #[!code ++]\n config: #[!code ++]\n authentication-type: X509_IAS #[!code ++]\n```\n", + " Building Applications > Stack Configuration > Module Dependencies\npom.xml, dependency, configuration, cds-services-bom, standard modules, application framework, protocol adapter, core runtime, plugins, starter bundles\nDefines the CAP Java BOM (bill of materials) using the cds-services-bom in the dependencyManagement section of pom.xml. This ensures all module versions are in sync in multi-module Maven projects.\n\n```xml\n\n\t2.6.0\n\n\n\n\t\n\t\t\n\t\t\tcom.sap.cds\n\t\t\tcds-services-bom\n\t\t\t${cds.services.version}\n\t\t\tpom\n\t\t\timport\n\t\t\n\t\n\n```\n", + " Building Applications > Stack Configuration > Module Dependencies\npom.xml, dependency, cds-framework-spring-boot, cds-adapter-odata-v4, cds-services-api, cds-services-impl, Spring Boot, OData\nSpecifies Maven dependencies in pom.xml to enable a CAP Java application with Spring Boot framework, OData V4 protocol adapter, and core CAP Java runtime. Ensures the application can expose endpoints and leverage the CAP runtime.\n\n```xml\n\n\t\n\t\tcom.sap.cds\n\t\tcds-framework-spring-boot\n\t\truntime\n\t\n\n\t\n\t\tcom.sap.cds\n\t\tcds-adapter-odata-v4\n\t\truntime\n\t\n\n\t\n\t\tcom.sap.cds\n\t\tcds-services-api\n\t\n\t\n\t\tcom.sap.cds\n\t\tcds-services-impl\n\t\truntime\n\t\n\n```\n", + " Building Applications > Stack Configuration > Module Dependencies\npom.xml, dependency, cds-feature-mt, multitenancy, plugins\nAdds the CAP Java multitenancy feature 'cds-feature-mt' as a runtime dependency. Enabling this plugin at compile-time allows the application to be aware of multitenancy at runtime if the environment is suitable.\n\n```xml\n\n\t\n\t\tcom.sap.cds\n\t\tcds-feature-mt\n\t\truntime\n\t\n\n```\n", + " Building Applications > Stack Configuration > Starter Bundles\npom.xml, starter bundle, cds-starter-spring-boot, cds-adapter-odata-v4, cds-starter-cloudfoundry, Cloud Foundry, OData, Spring Boot\nDefines a Maven dependency setup for a CAP application with OData V4, Spring Boot, and support for Cloud Foundry environment. Uses starter bundles to simplify configuration for these common use cases.\n\n```xml\n\n\t\t\n\t\t\tcom.sap.cds\n\t\t\tcds-starter-spring-boot\n\t\t\n\n\t\t\n\t\t\tcom.sap.cds\n\t\t\tcds-adapter-odata-v4\n\t\t\truntime\n\t\t\n\n\t\t\n\t\t\tcom.sap.cds\n\t\t\tcds-starter-cloudfoundry\n\t\t\truntime\n\t\t\n\n```\n", + " Building Applications > Generating Projects with Maven\nMaven, archetype, project generation, cds-services-archetype, setup, command-line\nGenerates a new CAP Java project from scratch using the cds-services-archetype with Maven. This command runs on Mac/Linux; similar commands are provided for Windows and Powershell.\n\n```shell\nmvn archetype:generate -DarchetypeArtifactId=cds-services-archetype -DarchetypeGroupId=com.sap.cds -DarchetypeVersion=RELEASE\n```\n", + " Building Applications > Building Projects with Maven\nMaven, build, run, spring-boot:run, local development\nBuilds and runs a CAP Java application using Maven's spring-boot:run goal. This starts the local development server using configured dependencies.\n\n```shell\nmvn spring-boot:run\n```\n", + " Building Applications > Building Projects with Maven > Using a Local cds-dk\npackage.json, cds-dk, npm, devDependency, build tool\nConfigures @sap/cds-dk as a devDependency in package.json for a CAP Java project. Starting with version 3.6.0 of the cds-services-archetype, the cds-dk version is maintained here and installed using 'npm ci' during the Maven build.\n\n```json\n{\n \"devDependencies\" : {\n \"@sap/cds-dk\" : \"^8.5.1\"\n }\n}\n```\n", + " Building Applications > Building Projects with Maven > Migrate From Goal install-cdsdk to npm ci\npom.xml, migration, cds-maven-plugin, npm ci, build, cds-dk\nConfigures the cds-maven-plugin in pom.xml to execute 'npm ci' as part of the build lifecycle, ensuring that Node.js dependencies in package.json, including @sap/cds-dk, are installed as part of the build. Used as part of the migration from the deprecated install-cdsdk goal.\n\n```xml\n\n\tcds.npm-ci\n\t\n\t\tnpm\n\t\n\t\n\t\tci\n\t\n\n```\n", + " Building Applications > Building Projects with Maven > Migrate From Goal install-cdsdk to npm ci\nnpm, install, package-lock.json, dependencies, Node.js\nInstalls Node.js dependencies and generates/updates package-lock.json, required for reproducible builds using npm ci in CAP Java projects using local cds-dk setup.\n\n```shell\nnpm install\n```\n", + " Building Applications > Building Projects with Maven > Maintaining cds-dk\nMaven, spring-boot:run, cds.install-cdsdk.force, cds-dk, update\nForcibly reinstalls @sap/cds-dk in the configured version using the install-cdsdk goal. Useful in older CAP Java projects that rely on this mechanism, to ensure the latest version is used.\n\n```shell\nmvn spring-boot:run -Dcds.install-cdsdk.force=true\n```\n", + " Building Applications > Building Projects with Maven > Using a Global cds-dk\nMaven, profile, cdsdk-global, global cds-dk, build\nRuns the Maven build using the cdsdk-global profile, which tells the build to use a globally installed Node.js and @sap/cds-dk rather than downloading/installing them locally. Allows for faster builds if prerequisites are met.\n\n```shell\nmvn spring-boot:run -P cdsdk-global\n```\n", + " Running Applications > Spring Boot Devtools\nSpring Boot, Devtools, Java, pom.xml, dependency, hot reload, development\nThis XML snippet shows how to add the Spring Boot Devtools dependency into the pom.xml file of the 'srv' module in a CAP Java application. Adding this enables automatic application context reloads upon file changes, which helps with faster development turnaround.\n\n```xml\n\n org.springframework.boot\n spring-boot-devtools\n\n```\n", + " Running Applications > Local Development Support > Use `cds` Prefix Everywhere\nMaven, plugin group, cds-maven-plugin, configuration, settings.xml, local development, cds prefix\nAdd this snippet to your ~/.m2/settings.xml to register 'com.sap.cds' as a plugin group. This enables you to use the 'cds' prefix for cds-maven-plugin goals everywhere, reducing the need to type the full plugin coordinates.\n\n```xml\n\n com.sap.cds\n\n```\n", + " Running Applications > Local Development Support > CDS Watch\nlocal development, cds-maven-plugin, Maven, watch, automation, hot reload, command line\nRuns the 'watch' goal of the cds-maven-plugin using Maven, enabling an automated workflow for local development. It rebuilds the CAP Java application whenever changes in the CDS model are detected, streamlining the edit-build-test cycle.\n\n```shell\nmvn cds:watch\n```\n", + " from your root directory\nwatch, cds-maven-plugin, development, hot reload, Maven, shell\nRuns the CDS Maven plugin in 'watch' mode from the project root directory, enabling hot reload during development for CAP Java projects. Automatically recompiles and restarts services on code changes.\n\n```shell\nmvn com.sap.cds:cds-maven-plugin:watch\n```\n", + " or your srv/ folder\nwatch, maven, cds build, Spring Boot, hot reload, project setup, devtools\nRuns the 'mvn cds:watch' command from the service module folder (srv/), which builds and starts a CAP Java Spring Boot application. The watcher monitors CDS model changes and restarts the application automatically. Spring Boot Devtools support enables fast context reloads instead of full restarts for improved developer productivity.\n\n```shell\ncd srv\nmvn cds:watch\n```\n", + " or your srv/ folder\nwatch, devtools, Spring Boot, hot reload\nExample Maven dependency for Spring Boot Devtools, which should be added to the CAP Java project's pom.xml file to enable application context hot reloads with the 'watch' goal. On Windows, this is required for the watcher to work.\n\n```xml\n\n org.springframework.boot\n spring-boot-devtools\n runtime\n\n```\n", + " CDS Auto-Build\nauto-build, cds build, Maven, IDE, automation\nExecutes the 'auto-build' goal, which continuously rebuilds the CDS model on any .cds file changes. Does not start or restart the CAP Java application, allowing control from the IDE. Can optionally touch the Spring Boot Devtools trigger file for integration with hot reload.\n\n```shell\nmvn cds:auto-build\n```\n", + " Testing Applications > Sample Tests\nJava, samples, service implementation, event handler\nThis is a sample event handler (CatalogServiceHandler) for CAP Java applications. It provides custom business logic for handling the SubmitOrder event (updating book stock or throwing an error if not enough stock) and for discounting books with stock above a threshold in the read event. Used as a base for testing examples.\n\n```java\n@Component\n@ServiceName(CatalogService_.CDS_NAME)\npublic class CatalogServiceHandler implements EventHandler {\n\n private final PersistenceService db;\n\n public CatalogServiceHandler(PersistenceService db) {\n this.db = db;\n }\n\n @On\n public void onSubmitOrder(SubmitOrderContext context) {\n Integer quantity = context.getQuantity();\n String bookId = context.getBook();\n\n Optional book = db.run(Select.from(BOOKS).columns(Books_::stock).byId(bookId)).first(Books.class);\n\n book.orElseThrow(() -> new ServiceException(ErrorStatuses.NOT_FOUND, MessageKeys.BOOK_MISSING)\n .messageTarget(Books_.class, b -> b.ID()));\n\n int stock = book.map(Books::getStock).get();\n\n if (stock >= quantity) {\n db.run(Update.entity(BOOKS).byId(bookId).data(Books.STOCK, stock -= quantity));\n SubmitOrderContext.ReturnType result = SubmitOrderContext.ReturnType.create();\n result.setStock(stock);\n context.setResult(result);\n } else {\n throw new ServiceException(ErrorStatuses.CONFLICT, MessageKeys.ORDER_EXCEEDS_STOCK, quantity);\n }\n }\n\n @After(event = CqnService.EVENT_READ)\n public void discountBooks(Stream books) {\n books.filter(b -> b.getTitle() != null).forEach(b -> {\n loadStockIfNotSet(b);\n discountBooksWithMoreThan111Stock(b);\n });\n }\n\n private void discountBooksWithMoreThan111Stock(Books b) {\n if (b.getStock() != null && b.getStock() > 111) {\n b.setTitle(String.format(\"%s -- 11%% discount\", b.getTitle()));\n }\n }\n\n private void loadStockIfNotSet(Books b) {\n if (b.getId() != null && b.getStock() == null) {\n b.setStock(db.run(Select.from(BOOKS).byId(b.getId()).columns(Books_::stock)).single(Books.class).getStock());\n }\n }\n}\n```\n", + " Testing Applications > Event Handler Layer Testing\nJava, unit test, event handler, testing, samples\nJUnit test for the discountBooks method of the CatalogServiceHandler using Mockito for mocking dependencies. It verifies that books with high stock get their titles updated to reflect the discount, while others remain unchanged. Demonstrates unit testing of an event handler with mocked PersistenceService.\n\n```java\n@ExtendWith(MockitoExtension.class)\npublic class CatalogServiceHandlerTest {\n\n @Mock\n private PersistenceService db;\n\n @Test\n public void discountBooks() {\n Books book1 = Books.create();\n book1.setTitle(\"Book 1\");\n book1.setStock(10);\n\n Books book2 = Books.create();\n book2.setTitle(\"Book 2\");\n book2.setStock(200);\n\n CatalogServiceHandler handler = new CatalogServiceHandler(db);\n handler.discountBooks(Stream.of(book1, book2));\n\n assertEquals(\"Book 1\", book1.getTitle(), \"Book 1 was discounted\");\n assertEquals(\"Book 2 -- 11% discount\", book2.getTitle(), \"Book 2 was not discounted\");\n }\n}\n```\n", + " Testing Applications > Service Layer Testing\nJava, service layer, integration test, samples, testing\nDemonstrates a service layer integration test by running a CQN select statement through the CqnService and asserting that the title of a high-stock book has the discount applied. Uses Spring Boot and dependency injection for testing actual service logic.\n\n```java\n@ExtendWith(SpringExtension.class)\n@SpringBootTest\npublic class CatalogServiceTest {\n\n @Autowired\n @Qualifier(CatalogService_.CDS_NAME)\n private CqnService catalogService;\n\n @Test\n public void discountApplied() {\n Result result = catalogService.run(Select.from(Books_.class).byId(\"51061ce3-ddde-4d70-a2dc-6314afbcc73e\"));\n\n // book with title \"The Raven\" and a stock quantity of > 111\n Books book = result.single(Books.class);\n\n assertEquals(\"The Raven -- 11% discount\", book.getTitle(), \"Book was not discounted\");\n }\n}\n```\n", + " Testing Applications > Service Layer Testing\nJava, service layer, samples, testing, event handler\nTest for service event handler logic using the emit method. This test simulates a SubmitOrder event, verifies stock reduction, and asserts the result using a known dataset/book. Good for coverage of custom event logic.\n\n```java\n@SpringBootTest\npublic class CatalogServiceTest {\n\n @Autowired\n @Qualifier(CatalogService_.CDS_NAME)\n private CqnService catalogService;\n\n @Test\n public void submitOrder() {\n SubmitOrderContext context = SubmitOrderContext.create();\n\n // ID of a book known to have a stock quantity of 22\n context.setBook(\"4a519e61-3c3a-4bd9-ab12-d7e0c5329933\");\n context.setQuantity(2);\n catalogService.emit(context);\n\n assertEquals(22 - context.getQuantity(), context.getResult().getStock());\n }\n}\n```\n", + " Testing Applications > Service Layer Testing\nJava, samples, service layer, testing, exception\nA test that verifies service logic throws a ServiceException if the ordered quantity exceeds the available stock. Uses Spring's testing annotations and context creation. Includes assertThrows validation for exception paths.\n\n```java\n@SpringBootTest\npublic class CatalogServiceTest {\n\n @Autowired\n @Qualifier(CatalogService_.CDS_NAME)\n private CqnService catalogService;\n\n @Test\n public void submitOrderExceedingStock() {\n SubmitOrderContext context = SubmitOrderContext.create();\n\n // ID of a book known to have a stock quantity of 22\n context.setBook(\"4a519e61-3c3a-4bd9-ab12-d7e0c5329933\");\n context.setQuantity(30);\n catalogService.emit(context);\n\n assertThrows(ServiceException.class, () -> catalogService.emit(context), context.getQuantity() + \" exceeds stock for book\");\n }\n}\n```\n", + " Testing Applications > Integration Testing\nJava, integration test, samples, OData, MockMvc, testing\nIntegration test using Spring Boot and MockMvc to simulate HTTP (OData) requests against a CAP Java application. Verifies the application of book discounts in the service's OData endpoint responses under different conditions, achieving end-to-end coverage through the protocol stack.\n\n```java\n@SpringBootTest\n@AutoConfigureMockMvc\npublic class CatalogServiceITest {\n\n private static final String booksURI = \"/api/browse/Books\";\n\n @Autowired\n private MockMvc mockMvc;\n\n @Test\n public void discountApplied() throws Exception {\n mockMvc.perform(get(booksURI + \"?$filter=stock gt 200&top=1\"))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.value[0].title\").value(containsString(\"11% discount\")));\n }\n\n @Test\n public void discountNotApplied() throws Exception {\n mockMvc.perform(get(booksURI + \"?$filter=stock lt 100&top=1\"))\n .andExpect(status().isOk())\n .andExpect(jsonPath(\"$.value[0].title\").value(not(containsString(\"11% discount\"))));\n }\n}\n```\n", + " Configuring Applications > Profiles and Properties > Production Profile\nconfiguration, Spring Boot, profile, production, property, deployment, cds.environment.production.profile\nSpecifies a custom production profile to use for CAP Java production deployments. This should be a Spring profile configured elsewhere in your deployment setup (e.g., in deployment descriptors like mta.yaml or Helm charts). By default, the profile 'cloud' is used, and you can override it for your specific production scenario.\n\n```yaml\ncds.environment.production.profile: my-production-profile\n```\n", + " Configuring Applications > Profiles and Properties > Production Profile\nindex page, production, cds.index-page.enabled, profile, disable\nDisables the index page when running your CAP Java application in production. This property is set to false by default when using the production profile, but you can override it explicitly. Disabling the index page is recommended for security reasons.\n\n```yaml\ncds.index-page.enabled: false\n```\n", + " Configuring Applications > Profiles and Properties > Production Profile\nmock users, production, cds.security.mock.enabled, profile, disable\nStrictly disables mock users for your CAP Java application in a production environment. This is the default in the production profile. You can override it in your application's configuration. Disabling mock users helps enforce real authentication and security.\n\n```yaml\ncds.security.mock.enabled: false\n```\n", + " Configuring Applications > Using SAP Java Buildpack\ndeployment, Java Buildpack, SAP BTP, Cloud Foundry, mta.yaml, Java 21, SapMachine JRE, buildpack\nConfigures your CAP Java application's mta.yaml to use SAP Java Buildpack for deployment on SAP BTP Cloud Foundry. This sets SapMachine JRE version 21+ using the sap_java_buildpack_jakarta buildpack. Place these lines under your Java module definition to ensure correct runtime settings in the cloud.\n\n```yaml\nparameters:\n buildpack: sap_java_buildpack_jakarta\nproperties:\n JBP_CONFIG_COMPONENTS: \"jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']\"\n JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 21.+ }'\n```\n", + " CDS Properties\nconfiguration, application.yaml, Spring, CAP Java\nExample of how to specify CAP Java properties in a project's application.yaml file. CAP Java uses the YAML file to define configuration properties, which control aspects of the CAP Java runtime.\n\n```yaml\ncds:\n some-property: some-value\n # Example showing how to set a CAP Java property in YAML\n```\n", + " CDS Properties\nconfiguration, application.properties, Spring, CAP Java\nExample of how to define a CAP Java configuration property in a Java .properties file. Use the dot-notation for hierarchy in property files.\n\n```properties\ncds.some-property=some-value\n# Example showing how to set a CAP Java property in a .properties file\n```\n", + " CDS Properties\nconfiguration, indexed property, YAML, Spring, CAP Java\nDemonstrates how to define a list of datasource properties in CAP Java using YAML list structures, which is more idiomatic in YAML than using indexed keys.\n\n```yaml\ncds:\n datasources:\n - name: 'db1'\n url: 'jdbc:h2:mem:test1'\n - name: 'db2'\n url: 'jdbc:h2:mem:test2'\n```\n", + " CDS Properties\nconfiguration, indexed property, properties, Spring, CAP Java\nIllustrates how to define indexed property arrays in Java .properties files for CAP Java, replacing with actual numbers as described in the tip.\n\n```properties\ncds.datasources[0].name=db1\ncds.datasources[0].url=jdbc:h2:mem:test1\ncds.datasources[1].name=db2\ncds.datasources[1].url=jdbc:h2:mem:test2\n```\n", + " CDS Properties\nconfiguration, map property, YAML, Spring, CAP Java\nShows how to define a map structure in a CAP Java configuration YAML file, using YAML syntax for key-value pairs rather than property file syntax.\n\n```yaml\ncds:\n myMap:\n key1: value1\n key2: value2\n```\n", + " Optimizing Applications > Profiling > Remote JMX-Based Tools\nprofiling, diagnostics, JVM, Spring Boot, JMX, configuration, application.properties\nThis property enables JMX support in a Spring Boot application, allowing management and monitoring via Java Management Extensions (JMX). It is typically set in the application's configuration file (e.g., application.properties or application.yaml) when you want to allow JMX clients to introspect or control aspects of your running service.\n\n```properties\nspring.jmx.enabled: true\n```\n", + " Optimizing Applications > Profiling > Remote JMX-Based Tools\nprofiling, diagnostics, JVM, JMX, remote access, JVM parameters\nThese JVM options enable and configure remote JMX access on a specific port, without authentication or SSL. This setup is suitable for development or trusted operator-only environments (e.g. via SSH tunnel), and should not be exposed to the public due to security risks.\n\n```shell\n-Djava.rmi.server.hostname=localhost\n-Dcom.sun.management.jmxremote\n-Dcom.sun.management.jmxremote.port=\n-Dcom.sun.management.jmxremote.rmi.port=\n-Dcom.sun.management.jmxremote.authenticate=false\n-Dcom.sun.management.jmxremote.ssl=false\n```\n", + " Optimizing Applications > Profiling > Remote JMX-Based Tools\nprofiling, ssh, cf CLI, secure tunneling, remote diagnostics\nThis Cloud Foundry CLI command creates a secure SSH tunnel from your local machine to a remote application container, forwarding a local port to the remote JMX port. This allows you to safely connect JMX clients to JVMs running in the cloud without exposing public endpoints.\n\n```shell\ncf ssh -N -T -L :localhost: \n```\n", + " Optimizing Applications > GraalVM Native Image Support \nnative image, GraalVM, Spring Boot, service bindings, configuration, native-build-env.json\nThis is an example native-build-env.json file. It supplies metadata for GraalVM Native Image build about required SAP HANA and XSUAA service bindings. Such metadata is required at build time for native image compatibility (CAP Java and dynamic Spring Boot bean/service definitions).\n\n```json\n{\n \"hana\": [ { \"name\": \"\" } ],\n \"xsuaa\": [ { \"name\": \"\" } ]\n}\n```\n", + " Optimizing Applications > GraalVM Native Image Support \nnative image, GraalVM, Spring Boot, Maven, profile, pom.xml\nThis Maven profile snippet configures the Spring Boot Maven Plugin to build a native image using GraalVM, with custom JVM arguments to provide a path to the native-build-env.json file and to set the active Spring profile. This is crucial for ensuring all required service bindings and profiles are available at native build time.\n\n```xml\n\n native\n \n \n \n \n org.springframework.boot\n spring-boot-maven-plugin\n \n \n process-aot\n \n cloud\n -Dcds.environment.local.defaultEnvPath=../native-build-env.json\n \n \n \n \n \n \n \n\n```\n", + " Optimizing Applications > GraalVM Native Image Support \nnative image, GraalVM, Spring Boot, Maven, Docker\nThis command builds a Docker image for your Spring Boot application as a GraalVM native executable using the defined 'native' Maven profile. It leverages Cloud Native Buildpacks for optimized containerization.\n\n```shell\nmvn spring-boot:build-image -Pnative\n```\n", + " Optimizing Applications > GraalVM Native Image Support \nnative image, GraalVM, Docker, runtime, execution\nThis Docker command runs the previously built native image Docker container, exposing port 8080. The image tag : refers to the CAP Java native executable container.\n\n```shell\ndocker run --rm -p 8080:8080 :\n```\n", + " Using SAP Event Mesh in Cloud Foundry > Use `enterprise-messaging`\nenterprise-messaging, cds.env, SAP Event Mesh, configuration, production, package.json\nConfigure CAP to use SAP Event Mesh as the messaging service in production. Add this block to your package.json to set the kind to 'enterprise-messaging' for the 'production' profile.\n\n```json\n{\n \"cds\": {\n \"requires\": {\n \"messaging\": {\n \"[production]\": { \"kind\": \"enterprise-messaging\" }\n }\n }\n }\n}\n```\n", + " Using SAP Event Mesh in Cloud Foundry > Optional: Add `namespace` Prefixing Rules\nSAP Event Mesh, namespace, prefix, configuration, package.json\nConfigure CAP to automatically prefix all published and subscribed event names with the SAP Event Mesh service instance's namespace. Add this to your package.json to enforce naming conventions as recommended by SAP.\n\n```json\n{\n \"cds\": {\n \"requires\": {\n \"messaging\": {\n \"publishPrefix\": \"$namespace/\",\n \"subscribePrefix\": \"$namespace/\"\n }\n }\n }\n}\n```\n", + " Using SAP Event Mesh in Cloud Foundry > Run Tests in `hybrid` Setup\nhybrid, enterprise-messaging-shared, cds.env, configuration, package.json, local testing\nConfigure CAP to use the 'enterprise-messaging-shared' variant for hybrid profile testing. Suitable for local development while connecting to a cloud Event Mesh instance in a single-tenant setup.\n\n```json\n{\n \"cds\": {\n \"requires\": {\n \"messaging\": {\n \"[hybrid]\": { \"kind\": \"enterprise-messaging-shared\" }\n }\n }\n }\n}\n```\n", + " Using SAP Event Mesh in Cloud Foundry > Run Tests in `hybrid` Setup\ndependencies, npm, SAP Event Mesh, hybrid, local testing\nInstall the AMQP library required for hybrid testing with SAP Event Mesh. Run this command to add the necessary dependency for local test setups utilizing the 'enterprise-messaging-shared' kind.\n\n```shell\nnpm add @sap/xb-msg-amqp-v100\n```\n", + " Using SAP Event Mesh in Cloud Foundry > Run Tests in `hybrid` Setup\nservice binding, Event Mesh, cds bind, hybrid, local testing\nBind CAP services to an Event Mesh instance using a service key in a hybrid test setup. Replace and with the appropriate names for your SAP Event Mesh instance and its service key.\n\n```shell\ncds bind -2 :\n```\n", + " Using SAP Event Mesh in Cloud Foundry > Run Tests in `hybrid` Setup\nrun server, cds watch, hybrid, profiles, local testing\nStart the 'reviews' and 'bookstore' CAP services in watch mode using the hybrid profile for local testing with SAP Event Mesh.\n\n```shell\ncds watch reviews --profile hybrid\ncds watch bookstore --profile hybrid\n```\n", + " Using SAP Event Mesh in Cloud Foundry > Optional: Configure Queue Names\nqueue, configuration, queue name, SAP Event Mesh, package.json\nExplicitly configure the queue name for SAP Event Mesh messaging in CAP. Set the desired queue name, including the namespace, in your package.json if you need to manage queues yourself.\n\n```json\n{\n \"cds\": {\n \"requires\": {\n \"messaging\": {\n \"queue\": { \"name\": \"$namespace/my/own/queue\" }\n }\n }\n }\n}\n```\n", + " Using SAP Event Mesh in Cloud Foundry > Deploy to the Cloud (with MTA) > 1. Specify Binding to SAP Event Mesh Instance\ndeployment, MTA, Cloud Foundry, SAP Event Mesh, binding, yaml\nExample MTA deployment configuration snippet to bind a CAP application module to an SAP Event Mesh service instance. Update and accordingly.\n\n```yaml\nmodules:\n - name: bookstore-srv\n requires:\n - name: \n\nresources:\n # SAP Event Mesh\n - name: \n type: org.cloudfoundry.managed-service\n parameters:\n service: enterprise-messaging\n service-plan: \n```\n", + " Using SAP Event Mesh in Cloud Foundry > Deploy to the Cloud (with MTA) > 2. Optional: Auto-Create SAP Event Mesh Instances\ndeployment, MTA, Cloud Foundry, SAP Event Mesh, service descriptor, yaml\nExtend the MTA deployment configuration to automatically create an SAP Event Mesh instance using a service descriptor JSON file. Reference the path to your descriptor in the 'parameters' section.\n\n```yaml\nresources:\n # SAP Event Mesh as above...\n parameters:\n path: ./\n```\n", + " Observability > Logging > Logging Façade > Logger API\nlogging, Java, SLF4J, Logger API, logging-facade\nThis Java snippet demonstrates how to use the SLF4J logging façade in a CAP service handler. Logger instances are retrieved via LoggerFactory and used for structured log output at different log levels. It also highlights usage within an '@After' handler for the READ event on Orders.\n\n```java\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nLogger logger = LoggerFactory.getLogger(\"my.loggers.order.consolidation\");\n\n@After(event = CqnService.EVENT_READ)\npublic void readAuthors(List orders) {\n\torders.forEach(order -> {\n\t\tlogger.debug(\"Consolidating order {}\", order);\n\t\tconsolidate(order);\n\t});\n\tlogger.info(\"Consolidated {} orders\", orders.size());\n}\n```\n", + " Set new default level\nlogging, log level, configuration, application.properties\nThis snippet sets the default log level for all loggers to WARN in a Spring Boot application's application.properties file. This suppresses INFO and DEBUG logs, only showing WARN, ERROR, and FATAL logs. Use this configuration to reduce log verbosity in production environments.\n\n```properties\nlogging.level.root: WARN\n```\n", + " Adjust custom logger\nlogging, custom logger, order, configuration, application.properties\nConfigures the log level for a specific custom logger (my.loggers.order.Consolidation) to INFO in the application's logging configuration. This line would typically be placed in application.properties when using Spring Boot or a similar Java framework.\n\n```properties\nlogging.level.my.loggers.order.Consolidation: INFO\n```\n", + "Turn off all loggers matching org.springframework.*\nlogging, configuration, properties, Spring Boot\nDisables all Spring loggers under the org.springframework.* namespace using the application.properties configuration in a Spring Boot application.\n\n```properties\nlogging.level.org.springframework: OFF\n```\n", + " At Runtime with Restart\nlogging, environment variable, Spring Boot, runtime, overrule\nSets the logger level for package my.loggers.order to DEBUG using an environment variable. Must restart the application for change to take effect. Note that Spring normalizes the environment variable name to match the package.\n\n```shell\nLOGGING_LEVEL_MY_LOGGERS_ORDER=DEBUG\n```\n", + " At Runtime with Restart\nlogging, environment variable, SAP BTP, Cloud Foundry, runtime\nHow to set the logging level for a custom logger on SAP BTP, Cloud Foundry using cf CLI. After setting, restart is needed. Note: config endures restart but may not persist across redeployments.\n\n```shell\ncf set-env LOGGING_LEVEL_MY_LOGGERS_ORDER DEBUG\ncf restart \n```\n", + " retrieve state of all loggers:\nlogging, logger usage, diagnostics, logger API, monitoring, health check, logs, Spring Boot, CAP Java SDK, API\nThis shell command uses curl to retrieve the state of all configured loggers from a running CAP Java application that exposes Spring Boot's actuator endpoints. The response contains details such as logger names and their current log levels, useful for diagnostics and runtime log level management.\n\n```shell\ncurl https:///actuator/loggers\n```\n", + "retrieve state of single logger\nlogger usage, devtools, logging, diagnostics, application, health check\nThis curl command queries the state of a single logger (my.loggers.oder.consolidation) via the Spring Boot Actuator endpoint. The response will include the logger's configured and effective logging levels. Useful for runtime diagnostics and on-the-fly troubleshooting in CAP Java applications using Spring Boot.\n\n```shell\ncurl https:///actuator/loggers/my.loggers.oder.consolidation\n```\n", + " Change logging level\nCLI, log level, Spring Boot Actuator, logging\nThis shell command uses curl to send a POST request to a Spring Boot Actuator endpoint, changing the log level of a specific logger to DEBUG at runtime. Replace and logger name as appropriate for your setup.\n\n```shell\ncurl -X POST -H 'Content-Type: application/json' -d '{\"configuredLevel\": \"DEBUG\"}' \\\n https:///actuator/loggers/my.loggers.oder.consolidation\n```\n", + " Logging Service\nlogging, logback, SAP Cloud Logging, dependency, SAP BTP\nAdd this Maven dependency to enable cf-java-logging-support for logback, preparing CAP Java logs for SAP Cloud Logging or SAP Application Logging service integration in SAP BTP Cloud Foundry.\n\n```xml\n\n\tcom.sap.hcp.cf.logging\n\tcf-java-logging-support-logback\n\t${logging.support.version}\n\n```\n", + " Logging Service\nlogging, logback, Spring profile, cloud profile\nSample logback-spring.xml configuration to use a custom logging encoder in profile 'cloud' (e.g., for SAP BTP cloud environments), and fall back to standard logback output for all other profiles during local development.\n\n```xml\n\n\n\n\t\n\t\t\n\t\t...\n\t\n\t\n\t\t\n\t\n\n```\n", + " JDBC Tracing in SAP Hana > Using datasource properties\nJDBC, SAP HANA, datasource properties, tracing, application.yaml\nConfiguration snippet for application.yaml to enable JDBC tracing with the SAP HANA JDBC driver, specifying trace file location and trace options via datasource properties. Useful for CAP Java apps needing JDBC debug logs.\n\n```yaml\ncds:\n dataSource:\n service-manager: # name of service binding\n hikari:\n data-source-properties:\n traceFile: \"/home/user/jdbctraces/trace_.log\" # use a path that is write accessible\n traceOptions: \"CONNECTIONS,API,PACKET\"\n```\n", + " JDBC Tracing in SAP Hana > Using datasource properties\nJDBC, environment variable, SAP HANA, tracing\nEnvironment variable to overwrite the traceFile path for JDBC tracing in the SAP HANA JDBC driver, matching application.yaml configuration. SERVICE_MANAGER is the name of your service binding.\n\n```yaml\nCDS_DATASOURCE_SERVICE_MANAGER_HIKARI_DATA_SOURCE_PROPERTIES_TRACEFILE: \"/home/cnb/jdbctraces/sm/trace_.log\"\n```\n", + " JDBC Tracing in SAP Hana > Using datasource properties\nJDBC, environment variable, SAP HANA, tracing\nEnvironment variable to overwrite the traceOptions for JDBC tracing in the SAP HANA JDBC driver, allowing dynamic trace configuration without redeploying.\n\n```yaml\nCDS_DATASOURCE_SERVICE_MANAGER_HIKARI_DATA_SOURCE_PROPERTIES_TRACEOPTIONS: \"DISTRIBUTIONS\"\n```\n", + " JDBC Tracing in SAP Hana > Using the command line > On Kyma\nJDBC, SAP HANA, command line, kubectl, Linux\nCommands to access a bash shell in a running Kyma pod, so you can perform JDBC tracing directly inside the container (e.g., set trace options or retrieve trace files).\n\n```shell\nkubectl get pods\nkubectl exec -it pod/ -- bash\n```\n", + " JDBC Tracing in SAP Hana > Using the command line > On Kyma\nJDBC, SAP HANA, command line, driver, Java\nPreparation and usage for running the SAP HANA JDBC driver in tracing mode inside a container with the paths for java executable and ngdbc.jar. Replace and