Skip to main content

persistence-hana

Invoke this skill to configure HANA Cloud database connectivity. Detects javax.sql.DataSource or jakarta.sql.DataSource resource-ref in web.xml, or @Resource DataSource in Java. Replaces Neo JNDI with CF HANA schema binding.

Informações da origem

Repositório
SAP-samples/btp-neo-java-app-migration
Última atividade na origem
29 de julho de 2026 às 13:03
Idioma detectado do SKILL.md
inglês
Estrelas
6
Forks
0

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
3 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
persistence-hana
description
Invoke this skill to configure HANA Cloud database connectivity. Detects javax.sql.DataSource or jakarta.sql.DataSource resource-ref in web.xml, or @Resource DataSource in Java. Replaces Neo JNDI with CF HANA schema binding.
disable-model-invocation
false
allowed-tools
Read, Edit, Write, Bash, Grep, Glob
# Persistence (Database) Configure HANA Cloud database connectivity for Cloud Foundry. ## Purpose Replace Neo's `javax.sql.DataSource` JNDI resource reference with Cloud Foundry's HANA schema binding using the SAP Java Buildpack's `TomcatDataSourceFactory`. ## Detection This skill applies if any of these patterns are found: ### In web.xml ```xml <resource-ref> <res-ref-name>jdbc/DefaultDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> </resource-ref> ``` ### In Java source files ```java import javax.sql.DataSource; import javax.annotation.Resource; @Resource(name = "jdbc/DefaultDB") private DataSource dataSource; // OR JNDI lookup Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/DefaultDB"); ``` ## Prerequisites > **Working directory:** This skill must run inside the `-cf-migration` copy of your app, created by `jakarta-java25-migration` or `neo-to-cf-migration-orchestrator`. If your current directory does not end in `-cf-migration`, switch to it before proceeding. Before invoking this skill, ensure you have invoked: 1. **sdk-replacement** - `Use the sdk-replacement skill` - Sets up SAP Cloud SDK - REQUIRED before this skill Also required: - HANA Cloud instance available in your subaccount ## Transformation Steps ### Step 0: Detect existing JSON conventions Before generating any code, scan for existing JSON library usage: ```bash # JSON libraries grep -E "fasterxml\.jackson|com\.google\.code\.gson|org\.json|jakarta\.json" pom.xml grep -rl "ObjectMapper\|new Gson()\|new JSONObject\|Json\.create" --include="*.java" src/main/java/ 2>/dev/null | head -5 ``` **Rule:** Reuse what is found. Default if nothing found: `jakarta.json` (JSON-P) — already in `cf-tomcat-bom`, no extra dependency needed. ### Step 1: Remove Resource Reference from web.xml **Remove this from web.xml:** ```xml <resource-ref> <res-ref-name>jdbc/DefaultDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> </resource-ref> ``` ### Step 2: Create context.xml Create `src/main/webapp/META-INF/context.xml` - see [assets/context.xml](assets/context.xml): ```xml <?xml version='1.0' encoding='utf-8'?> <Context> <Resource name="jdbc/DefaultDB" auth="Container" type="javax.sql.DataSource" factory="com.sap.xs.jdbc.datasource.tomcat.TomcatDataSourceFactory" service="${service_name_for_DefaultDB}"/> </Context> ``` > **Note:** The `${service_name_for_DefaultDB}` placeholder is replaced at runtime via the `JBP_CONFIG_RESOURCE_CONFIGURATION` environment variable. ### Step 3: Create resource_configuration.yml Create `src/main/webapp/META-INF/sap_java_buildpack/config/resource_configuration.yml` - see [assets/resource_configuration.yml](assets/resource_configuration.yml): ```yaml --- tomcat/webapps/ROOT/META-INF/context.xml: service_name_for_DefaultDB: ${app-name}-hana ``` > **Note:** Replace `${app-name}-hana` with your actual HANA service instance name defined in mtad.yaml. ### Step 4: Update MTA Descriptor Add HANA schema resource and configuration to `mtad.yaml`: ```yaml _schema-version: "3.2" ID: ${app-name} version: 0.0.1 modules: - name: ${app-name} type: java.tomcat path: target/<artifactId>.war parameters: buildpack: sap_java_buildpack_jakarta disk-quota: 1024M memory: 1024M properties: ENABLE_SECURITY_JAVA_API_V2: true SET_LOGGING_LEVEL: 'ROOT: INFO' # Resource configuration - MUST use YAML list format JBP_CONFIG_RESOURCE_CONFIGURATION: - tomcat/webapps/ROOT/META-INF/context.xml: service_name_for_DefaultDB: ${app-name}-hana requires: - name: ${app-name}-hana resources: - name: ${app-name}-hana type: com.sap.xs.hana-schema ``` > **CRITICAL — do NOT add `service: hana` or `service-plan: hdi-shared` > under a `com.sap.xs.hana-schema` resource.** > > ❌ Anti-pattern subagents sometimes emit (it breaks deploy): > ```yaml > - name: ${app-name}-hana > type: com.sap.xs.hana-schema > parameters: > service: hana # ← WRONG for hana-schema > service-plan: hdi-shared # ← WRONG for hana-schema > ``` > Those two keys belong on the GENERIC > `type: org.cloudfoundry.managed-service` (xsuaa, destination, credstore, > sdm, …). The dedicated `com.sap.xs.hana-schema` type already implies the > service and the plan — adding them makes the controller reject the > request at deploy time with: > > > `CF-UnprocessableEntity(10008): Invalid service plan. ... Ensure that > > the service plan is visible in your current space ...` > > ✅ Correct form: > ```yaml > - name: ${app-name}-hana > type: com.sap.xs.hana-schema > ``` ### Step 5: Java Code (No Changes Required) The Java code using DataSource via JNDI lookup continues to work: ```java import javax.sql.DataSource; import javax.naming.Context; import javax.naming.InitialContext; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; public class PersistenceServlet extends HttpServlet { private DataSource getDataSource() throws Exception { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/DefaultDB"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try (Connection conn = getDataSource().getConnection()) { // Create table if not exists String createTable = "CREATE TABLE IF NOT EXISTS PERSONS " + "(ID INTEGER PRIMARY KEY, NAME VARCHAR(255))"; try (PreparedStatement stmt = conn.prepareStatement(createTable)) { stmt.execute(); } // Query data String query = "SELECT * FROM PERSONS"; try (PreparedStatement stmt = conn.prepareStatement(query); ResultSet rs = stmt.executeQuery()) { response.setContentType("application/json"); response.getWriter().println("["); boolean first = true; while (rs.next()) { if (!first) response.getWriter().println(","); response.getWriter().printf("{\"id\": %d, \"name\": \"%s\"}", rs.getInt("ID"), rs.getString("NAME")); first = false; } response.getWriter().println("]"); } } catch (Exception e) { throw new ServletException("Database error: " + e.getMessage(), e); } } } ``` ### Step 6: Alternative - Using @Resource Annotation If using `@Resource` annotation, it continues to work: ```java import javax.annotation.Resource; import javax.sql.DataSource; public class PersistenceServlet extends HttpServlet { @Resource(name = "jdbc/DefaultDB") private DataSource dataSource; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try (Connection conn = dataSource.getConnection()) { // ... use connection } catch (SQLException e) { throw new ServletException(e); } } } ``` ## Directory Structure After applying this skill, your project should have: ``` src/main/webapp/ ├── META-INF/ │ ├── context.xml # DataSource configuration │ └── sap_java_buildpack/ │ └── config/ │ └── resource_configuration.yml # Service name mapping └── WEB-INF/ └── web.xml # (resource-ref removed) ``` ## Configuration Files | File | Location | Purpose | |------|----------|---------| | `context.xml` | src/main/webapp/META-INF/ | Defines JNDI DataSource | | `resource_configuration.yml` | src/main/webapp/META-INF/sap_java_buildpack/config/ | Maps service name placeholder | ## CF Services | Service | Type | Purpose | |---------|------|---------| | `${app-name}-hana` | com.sap.xs.hana-schema | HANA Cloud schema binding | ## Creating HANA Cloud Instance If you don't have a HANA Cloud instance: ### Option 1: Via BTP Cockpit 1. Navigate to your subaccount 2. Go to Service Marketplace 3. Find "SAP HANA Cloud" 4. Create an instance 5. Create a schema service key ### Option 2: Via CF CLI ```bash # List available plans cf marketplace -s hana # Create HANA schema cf create-service hana schema ${app-name}-hana ``` ## Verification ### 1. Verify Directory Structure ```bash ls -la src/main/webapp/META-INF/ # Should show: context.xml ls -la src/main/webapp/META-INF/sap_java_buildpack/config/ # Should show: resource_configuration.yml ``` ### 2. Build and Deploy ```bash mvn clean package cf deploy . -f ``` ### 3. Verify Service Binding ```bash cf services # Should show ${app-name}-hana bound to ${app-name} cf env ${app-name} | grep -A 20 "hana" # Should show HANA credentials ``` ### 4. Test Database Connectivity ```bash curl "https://${app-url}/persistence" # Should return database query results ``` ### 5. Check Logs ```bash cf logs ${app-name} --recent | grep -i "datasource\|hana\|jdbc" ``` ## Common Issues ### Issue: "Cannot create JDBC driver" error **Cause:** HANA JDBC driver not available. **Solution:** The SAP Java Buildpack includes HANA drivers. Ensure you're using `sap_java_buildpack_jakarta`. ### Issue: "Service not found" during deployment **Cause:** HANA schema service doesn't exist. **Solution:** 1. Check HANA Cloud entitlement in subaccount 2. Create the hana-schema service manually first: ```bash cf create-service hana schema ${app-name}-hana ``` ### Issue: Connection refused **Cause:** HANA Cloud instance not running or IP allowlist. **Solution:** 1. Check HANA Cloud instance is started 2. Verify IP allowlist includes CF runtime IPs ### Issue: "Invalid object name" SQL error **Cause:** Schema not set correctly or table doesn't exist. **Solution:** HANA schema services automatically set the current schema. Verify table names are correct. ### Issue: JBP_CONFIG_RESOURCE_CONFIGURATION not working **Cause:** YAML syntax error or wrong path. **Solution:** 1. Validate YAML syntax 2. Ensure path matches: `tomcat/webapps/ROOT/META-INF/context.xml` 3. Check indentation in mtad.yaml ## Using JPA (Optional) If your application uses JPA, update `persistence.xml`: ```xml <?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd" version="3.0"> <persistence-unit name="default" transaction-type="RESOURCE_LOCAL"> <non-jta-data-source>java:comp/env/jdbc/DefaultDB</non-jta-data-source> <properties> <property name="jakarta.persistence.schema-generation.database.action" value="create"/> <property name="eclipselink.logging.level" value="INFO"/> </properties> </persistence-unit> </persistence> ``` ## Next Steps After completing this skill, proceed to other applicable skills: - [../document-management-sdm/SKILL.md](../document-management-sdm/SKILL.md) - Document storage - [../keystore-credstore/SKILL.md](../keystore-credstore/SKILL.md) - Credential storage
Ver no GitHub