From 4b8d255727e32aabe34e5e98ca9d5485d6e06c49 Mon Sep 17 00:00:00 2001 From: Sandeep Belgavi Date: Tue, 17 Feb 2026 13:19:28 +0530 Subject: [PATCH 1/7] docs: add feature parity tracking (JSON + Markdown generator) --- PARITY_STATUS.md | 21 +++++++++++++ generate_parity_report.py | 36 +++++++++++++++++++++ parity.json | 66 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 PARITY_STATUS.md create mode 100644 generate_parity_report.py create mode 100644 parity.json diff --git a/PARITY_STATUS.md b/PARITY_STATUS.md new file mode 100644 index 000000000..ca3edc0c1 --- /dev/null +++ b/PARITY_STATUS.md @@ -0,0 +1,21 @@ +# A2A Java Parity Status + +**Last Updated:** 2026-02-17 +**Python Reference:** [dc1fedd](https://github.com/a2aproject/a2a-python/commit/dc1fedd2c9d3d8e8e016826a49fbfff278d87d13) +**Java Version:** 1.0.0.Alpha3-SNAPSHOT + +## Feature Implementation Matrix + +| Feature | Status | Python Reference | Java Implementation | Notes | +| :--- | :---: | :--- | :--- | :--- | +| **Client Initialization** | ✅ DONE | `client/client.py:Client.__init__` | `client/src/main/java/io/a2a/client/Client.java` | Java uses Builder pattern. | +| **Server gRPC Transport** | ✅ DONE | `server/request_handlers/grpc_handler.py` | `transport/grpc/` | Implemented via spec-grpc. | +| **Server JSON-RPC Transport** | ✅ DONE | `server/request_handlers/jsonrpc_handler.py` | `jsonrpc-common/` | Common handlers available. | +| **Agent Executor** | ✅ DONE | `server/agent_execution/agent_executor.py` | `server-common/src/main/java/io/a2a/server/agentexecution/AgentExecutor.java` | Supports AgentEmitter. | +| **OpenTelemetry** | ✅ DONE | `utils/telemetry.py` | `server-common/src/main/java/io/a2a/server/telemetry/A2ATelemetry.java` | Full OpenTelemetry integration. | +| **JWS Signing** | ✅ DONE | `utils/signing.py` | `server-common/src/main/java/io/a2a/server/security/SigningService.java` | Supports ES256/ES384. | +| **ID Generation** | ✅ DONE | `utils/ids.py` | `server-common/src/main/java/io/a2a/server/util/IdGenerator.java` | Pluggable interface (UUID default). | + + +--- +*Generated automatically by `generate_parity_report.py`* \ No newline at end of file diff --git a/generate_parity_report.py b/generate_parity_report.py new file mode 100644 index 000000000..496c0e0b0 --- /dev/null +++ b/generate_parity_report.py @@ -0,0 +1,36 @@ +import json +import sys +from datetime import datetime + +def generate_markdown(json_file, output_file): + with open(json_file, 'r') as f: + data = json.load(f) + + meta = data.get('meta', {}) + features = data.get('features', []) + + with open(output_file, 'w') as f: + f.write("# A2A Java Parity Status\n\n") + f.write(f"**Last Updated:** {meta.get('last_updated', datetime.now().isoformat())}\n") + f.write(f"**Python Reference:** [{meta.get('python_reference_commit')[:7]}](https://github.com/a2aproject/{meta.get('python_reference_repo')}/commit/{meta.get('python_reference_commit')})\n") + f.write(f"**Java Version:** {meta.get('java_version')}\n\n") + + f.write("## Feature Implementation Matrix\n\n") + f.write("| Feature | Status | Python Reference | Java Implementation | Notes |\n") + f.write("| :--- | :---: | :--- | :--- | :--- |\n") + + for feature in features: + status_symbol = { + 'DONE': '✅', + 'PARTIAL': '⚠️', + 'MISSING': '❌', + 'N/A': '➖' + }.get(feature['status'], feature['status']) + + f.write(f"| **{feature['name']}** | {status_symbol} {feature['status']} | `{feature['python_ref']}` | `{feature['java_impl']}` | {feature.get('notes', '')} |\n") + + f.write("\n\n---\n*Generated automatically by `generate_parity_report.py`*") + +if __name__ == "__main__": + generate_markdown('parity.json', 'PARITY_STATUS.md') + print("Generated PARITY_STATUS.md from parity.json") diff --git a/parity.json b/parity.json new file mode 100644 index 000000000..abd068906 --- /dev/null +++ b/parity.json @@ -0,0 +1,66 @@ +{ + "meta": { + "last_updated": "2026-02-17", + "python_reference_repo": "a2a-python", + "python_reference_commit": "dc1fedd2c9d3d8e8e016826a49fbfff278d87d13", + "java_version": "1.0.0.Alpha3-SNAPSHOT" + }, + "features": [ + { + "id": "client_instantiation", + "name": "Client Initialization", + "status": "DONE", + "python_ref": "client/client.py:Client.__init__", + "java_impl": "client/src/main/java/io/a2a/client/Client.java", + "notes": "Java uses Builder pattern." + }, + { + "id": "transport_grpc_server", + "name": "Server gRPC Transport", + "status": "DONE", + "python_ref": "server/request_handlers/grpc_handler.py", + "java_impl": "transport/grpc/", + "notes": "Implemented via spec-grpc." + }, + { + "id": "transport_jsonrpc_server", + "name": "Server JSON-RPC Transport", + "status": "DONE", + "python_ref": "server/request_handlers/jsonrpc_handler.py", + "java_impl": "jsonrpc-common/", + "notes": "Common handlers available." + }, + { + "id": "core_agent_execution", + "name": "Agent Executor", + "status": "DONE", + "python_ref": "server/agent_execution/agent_executor.py", + "java_impl": "server-common/src/main/java/io/a2a/server/agentexecution/AgentExecutor.java", + "notes": "Supports AgentEmitter." + }, + { + "id": "telemetry", + "name": "OpenTelemetry", + "status": "DONE", + "python_ref": "utils/telemetry.py", + "java_impl": "server-common/src/main/java/io/a2a/server/telemetry/A2ATelemetry.java", + "notes": "Full OpenTelemetry integration." + }, + { + "id": "signing_jws", + "name": "JWS Signing", + "status": "DONE", + "python_ref": "utils/signing.py", + "java_impl": "server-common/src/main/java/io/a2a/server/security/SigningService.java", + "notes": "Supports ES256/ES384." + }, + { + "id": "id_generation", + "name": "ID Generation", + "status": "DONE", + "python_ref": "utils/ids.py", + "java_impl": "server-common/src/main/java/io/a2a/server/util/IdGenerator.java", + "notes": "Pluggable interface (UUID default)." + } + ] +} From 68d9c7203452cd205e4c5367b06dc3bcbc1ee200 Mon Sep 17 00:00:00 2001 From: Sandeep Belgavi Date: Tue, 17 Feb 2026 16:17:09 +0530 Subject: [PATCH 2/7] feat: add postgres docker setup for task store --- docker-compose.yml | 17 +++++++++++++++++ scripts/db/init.sql | 4 ++++ scripts/start-db.sh | 13 +++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 docker-compose.yml create mode 100644 scripts/db/init.sql create mode 100755 scripts/start-db.sh diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..a7bb81579 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +version: '3.8' + +services: + db: + image: postgres:15 + environment: + POSTGRES_USER: a2a + POSTGRES_PASSWORD: a2a + POSTGRES_DB: a2a_db + ports: + - "5432:5432" + volumes: + - pgdata:/var/lib/postgresql/data + - ./scripts/db/init.sql:/docker-entrypoint-initdb.d/init.sql + +volumes: + pgdata: diff --git a/scripts/db/init.sql b/scripts/db/init.sql new file mode 100644 index 000000000..b9b26ccd9 --- /dev/null +++ b/scripts/db/init.sql @@ -0,0 +1,4 @@ +CREATE TABLE IF NOT EXISTS a2a_tasks ( + task_id VARCHAR(255) PRIMARY KEY, + task_data TEXT NOT NULL +); diff --git a/scripts/start-db.sh b/scripts/start-db.sh new file mode 100755 index 000000000..ef166722e --- /dev/null +++ b/scripts/start-db.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e + +# Navigate to the a2a-java root directory +cd "$(dirname "$0")/.." + +echo "Starting database container..." +docker-compose up -d + +echo "Waiting for database to be ready..." +sleep 5 + +echo "Database started successfully." From 2ed5c7ce2a60e7f6d709cfd5b9b31e140f6ecb10 Mon Sep 17 00:00:00 2001 From: Sandeep Belgavi Date: Tue, 17 Feb 2026 16:33:36 +0530 Subject: [PATCH 3/7] refactor: replace python/sql scripts with pure Java DB initialization --- docker-compose.yml | 1 - extras/task-store-database-jpa/pom.xml | 16 ++++ .../database/jpa/DatabaseInitializer.java | 78 +++++++++++++++++++ generate_parity_report.py | 36 --------- scripts/db/init.sql | 4 - scripts/start-db.sh | 3 + 6 files changed, 97 insertions(+), 41 deletions(-) create mode 100644 extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java delete mode 100644 generate_parity_report.py delete mode 100644 scripts/db/init.sql diff --git a/docker-compose.yml b/docker-compose.yml index a7bb81579..7d6cc133c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,6 @@ services: - "5432:5432" volumes: - pgdata:/var/lib/postgresql/data - - ./scripts/db/init.sql:/docker-entrypoint-initdb.d/init.sql volumes: pgdata: diff --git a/extras/task-store-database-jpa/pom.xml b/extras/task-store-database-jpa/pom.xml index 34a214ed4..503f66d48 100644 --- a/extras/task-store-database-jpa/pom.xml +++ b/extras/task-store-database-jpa/pom.xml @@ -107,5 +107,21 @@ quarkus-reactive-routes test + + io.quarkus + quarkus-jdbc-postgresql + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + io.a2a.extras.taskstore.database.jpa.DatabaseInitializer + + + + \ No newline at end of file diff --git a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java new file mode 100644 index 000000000..382af2030 --- /dev/null +++ b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java @@ -0,0 +1,78 @@ +package io.a2a.extras.taskstore.database.jpa; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.util.UUID; +import java.time.Instant; + +/** + * Utility class to initialize the database schema and insert sample data. + * This class handles: + * 1. Creation of 'a2a_tasks' table if it does not exist. + * 2. Insertion of a sample task record. + * + * IMPORTANT: No deletion logic is implemented here to ensure data safety. + */ +public class DatabaseInitializer { + + private static final String JDBC_URL = "jdbc:postgresql://localhost:5432/a2a_db"; + private static final String USER = "a2a"; + private static final String PASS = "a2a"; + + public static void main(String[] args) { + System.out.println("Starting Database Initialization..."); + try { + // Load PostgreSQL driver explicitly + Class.forName("org.postgresql.Driver"); + + try (Connection conn = DriverManager.getConnection(JDBC_URL, USER, PASS)) { + // 1. Create Table + createTable(conn); + + // 2. Insert Sample Data + insertSampleTask(conn); + } + + System.out.println("Database Initialization Completed Successfully."); + + } catch (ClassNotFoundException e) { + System.err.println("PostgreSQL Driver not found. Ensure 'org.postgresql:postgresql' is on the classpath."); + e.printStackTrace(); + } catch (Exception e) { + System.err.println("Database Initialization Failed."); + e.printStackTrace(); + } + } + + private static void createTable(Connection conn) throws Exception { + String sql = "CREATE TABLE IF NOT EXISTS a2a_tasks (" + + "task_id VARCHAR(255) PRIMARY KEY, " + + "task_data TEXT NOT NULL" + + ")"; + try (Statement stmt = conn.createStatement()) { + stmt.execute(sql); + System.out.println("Verified table 'a2a_tasks'. Created if missing."); + } + } + + private static void insertSampleTask(Connection conn) throws Exception { + String taskId = UUID.randomUUID().toString(); + // Sample JSON structure for task data + String taskData = String.format("{\"status\": \"SUBMITTED\", \"created_at\": \"%s\", \"description\": \"Sample initialization task\"}", Instant.now()); + + String sql = "INSERT INTO a2a_tasks (task_id, task_data) VALUES (?, ?) ON CONFLICT (task_id) DO NOTHING"; + + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, taskId); + stmt.setString(2, taskData); + int rows = stmt.executeUpdate(); + if (rows > 0) { + System.out.println("Inserted sample task: " + taskId); + } else { + System.out.println("Sample task insertion skipped (conflict or no-op)."); + } + } + } +} diff --git a/generate_parity_report.py b/generate_parity_report.py deleted file mode 100644 index 496c0e0b0..000000000 --- a/generate_parity_report.py +++ /dev/null @@ -1,36 +0,0 @@ -import json -import sys -from datetime import datetime - -def generate_markdown(json_file, output_file): - with open(json_file, 'r') as f: - data = json.load(f) - - meta = data.get('meta', {}) - features = data.get('features', []) - - with open(output_file, 'w') as f: - f.write("# A2A Java Parity Status\n\n") - f.write(f"**Last Updated:** {meta.get('last_updated', datetime.now().isoformat())}\n") - f.write(f"**Python Reference:** [{meta.get('python_reference_commit')[:7]}](https://github.com/a2aproject/{meta.get('python_reference_repo')}/commit/{meta.get('python_reference_commit')})\n") - f.write(f"**Java Version:** {meta.get('java_version')}\n\n") - - f.write("## Feature Implementation Matrix\n\n") - f.write("| Feature | Status | Python Reference | Java Implementation | Notes |\n") - f.write("| :--- | :---: | :--- | :--- | :--- |\n") - - for feature in features: - status_symbol = { - 'DONE': '✅', - 'PARTIAL': '⚠️', - 'MISSING': '❌', - 'N/A': '➖' - }.get(feature['status'], feature['status']) - - f.write(f"| **{feature['name']}** | {status_symbol} {feature['status']} | `{feature['python_ref']}` | `{feature['java_impl']}` | {feature.get('notes', '')} |\n") - - f.write("\n\n---\n*Generated automatically by `generate_parity_report.py`*") - -if __name__ == "__main__": - generate_markdown('parity.json', 'PARITY_STATUS.md') - print("Generated PARITY_STATUS.md from parity.json") diff --git a/scripts/db/init.sql b/scripts/db/init.sql deleted file mode 100644 index b9b26ccd9..000000000 --- a/scripts/db/init.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE IF NOT EXISTS a2a_tasks ( - task_id VARCHAR(255) PRIMARY KEY, - task_data TEXT NOT NULL -); diff --git a/scripts/start-db.sh b/scripts/start-db.sh index ef166722e..a453194d7 100755 --- a/scripts/start-db.sh +++ b/scripts/start-db.sh @@ -11,3 +11,6 @@ echo "Waiting for database to be ready..." sleep 5 echo "Database started successfully." + +echo "To initialize the database schema and insert sample data, run:" +echo " mvn exec:java -pl extras/task-store-database-jpa" From af2dbebc28ccf466b3e9c6ece3d11d7b3cbe29d0 Mon Sep 17 00:00:00 2001 From: Sandeep Belgavi Date: Tue, 17 Feb 2026 16:41:10 +0530 Subject: [PATCH 4/7] refactor: remove parity tracking and docker, configure DB via env vars --- PARITY_STATUS.md | 21 ------ docker-compose.yml | 16 ----- .../database/jpa/DatabaseInitializer.java | 16 ++++- parity.json | 66 ------------------- scripts/start-db.sh | 16 ----- 5 files changed, 13 insertions(+), 122 deletions(-) delete mode 100644 PARITY_STATUS.md delete mode 100644 docker-compose.yml delete mode 100644 parity.json delete mode 100755 scripts/start-db.sh diff --git a/PARITY_STATUS.md b/PARITY_STATUS.md deleted file mode 100644 index ca3edc0c1..000000000 --- a/PARITY_STATUS.md +++ /dev/null @@ -1,21 +0,0 @@ -# A2A Java Parity Status - -**Last Updated:** 2026-02-17 -**Python Reference:** [dc1fedd](https://github.com/a2aproject/a2a-python/commit/dc1fedd2c9d3d8e8e016826a49fbfff278d87d13) -**Java Version:** 1.0.0.Alpha3-SNAPSHOT - -## Feature Implementation Matrix - -| Feature | Status | Python Reference | Java Implementation | Notes | -| :--- | :---: | :--- | :--- | :--- | -| **Client Initialization** | ✅ DONE | `client/client.py:Client.__init__` | `client/src/main/java/io/a2a/client/Client.java` | Java uses Builder pattern. | -| **Server gRPC Transport** | ✅ DONE | `server/request_handlers/grpc_handler.py` | `transport/grpc/` | Implemented via spec-grpc. | -| **Server JSON-RPC Transport** | ✅ DONE | `server/request_handlers/jsonrpc_handler.py` | `jsonrpc-common/` | Common handlers available. | -| **Agent Executor** | ✅ DONE | `server/agent_execution/agent_executor.py` | `server-common/src/main/java/io/a2a/server/agentexecution/AgentExecutor.java` | Supports AgentEmitter. | -| **OpenTelemetry** | ✅ DONE | `utils/telemetry.py` | `server-common/src/main/java/io/a2a/server/telemetry/A2ATelemetry.java` | Full OpenTelemetry integration. | -| **JWS Signing** | ✅ DONE | `utils/signing.py` | `server-common/src/main/java/io/a2a/server/security/SigningService.java` | Supports ES256/ES384. | -| **ID Generation** | ✅ DONE | `utils/ids.py` | `server-common/src/main/java/io/a2a/server/util/IdGenerator.java` | Pluggable interface (UUID default). | - - ---- -*Generated automatically by `generate_parity_report.py`* \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 7d6cc133c..000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: '3.8' - -services: - db: - image: postgres:15 - environment: - POSTGRES_USER: a2a - POSTGRES_PASSWORD: a2a - POSTGRES_DB: a2a_db - ports: - - "5432:5432" - volumes: - - pgdata:/var/lib/postgresql/data - -volumes: - pgdata: diff --git a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java index 382af2030..7c45cf137 100644 --- a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java +++ b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java @@ -12,14 +12,24 @@ * This class handles: * 1. Creation of 'a2a_tasks' table if it does not exist. * 2. Insertion of a sample task record. + * + *

Configuration via Environment Variables: + *

    + *
  • {@code DB_URL}: JDBC URL (default: {@code jdbc:postgresql://localhost:5432/a2a_db})
  • + *
  • {@code DB_USER}: Database User (default: {@code a2a})
  • + *
  • {@code DB_PASSWORD}: Database Password (default: {@code a2a})
  • + *
* * IMPORTANT: No deletion logic is implemented here to ensure data safety. + * + * @author Sandeep Belgavi + * @since 2026-02-17 */ public class DatabaseInitializer { - private static final String JDBC_URL = "jdbc:postgresql://localhost:5432/a2a_db"; - private static final String USER = "a2a"; - private static final String PASS = "a2a"; + private static final String JDBC_URL = System.getenv().getOrDefault("DB_URL", "jdbc:postgresql://localhost:5432/a2a_db"); + private static final String USER = System.getenv().getOrDefault("DB_USER", "a2a"); + private static final String PASS = System.getenv().getOrDefault("DB_PASSWORD", "a2a"); public static void main(String[] args) { System.out.println("Starting Database Initialization..."); diff --git a/parity.json b/parity.json deleted file mode 100644 index abd068906..000000000 --- a/parity.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "meta": { - "last_updated": "2026-02-17", - "python_reference_repo": "a2a-python", - "python_reference_commit": "dc1fedd2c9d3d8e8e016826a49fbfff278d87d13", - "java_version": "1.0.0.Alpha3-SNAPSHOT" - }, - "features": [ - { - "id": "client_instantiation", - "name": "Client Initialization", - "status": "DONE", - "python_ref": "client/client.py:Client.__init__", - "java_impl": "client/src/main/java/io/a2a/client/Client.java", - "notes": "Java uses Builder pattern." - }, - { - "id": "transport_grpc_server", - "name": "Server gRPC Transport", - "status": "DONE", - "python_ref": "server/request_handlers/grpc_handler.py", - "java_impl": "transport/grpc/", - "notes": "Implemented via spec-grpc." - }, - { - "id": "transport_jsonrpc_server", - "name": "Server JSON-RPC Transport", - "status": "DONE", - "python_ref": "server/request_handlers/jsonrpc_handler.py", - "java_impl": "jsonrpc-common/", - "notes": "Common handlers available." - }, - { - "id": "core_agent_execution", - "name": "Agent Executor", - "status": "DONE", - "python_ref": "server/agent_execution/agent_executor.py", - "java_impl": "server-common/src/main/java/io/a2a/server/agentexecution/AgentExecutor.java", - "notes": "Supports AgentEmitter." - }, - { - "id": "telemetry", - "name": "OpenTelemetry", - "status": "DONE", - "python_ref": "utils/telemetry.py", - "java_impl": "server-common/src/main/java/io/a2a/server/telemetry/A2ATelemetry.java", - "notes": "Full OpenTelemetry integration." - }, - { - "id": "signing_jws", - "name": "JWS Signing", - "status": "DONE", - "python_ref": "utils/signing.py", - "java_impl": "server-common/src/main/java/io/a2a/server/security/SigningService.java", - "notes": "Supports ES256/ES384." - }, - { - "id": "id_generation", - "name": "ID Generation", - "status": "DONE", - "python_ref": "utils/ids.py", - "java_impl": "server-common/src/main/java/io/a2a/server/util/IdGenerator.java", - "notes": "Pluggable interface (UUID default)." - } - ] -} diff --git a/scripts/start-db.sh b/scripts/start-db.sh deleted file mode 100755 index a453194d7..000000000 --- a/scripts/start-db.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -set -e - -# Navigate to the a2a-java root directory -cd "$(dirname "$0")/.." - -echo "Starting database container..." -docker-compose up -d - -echo "Waiting for database to be ready..." -sleep 5 - -echo "Database started successfully." - -echo "To initialize the database schema and insert sample data, run:" -echo " mvn exec:java -pl extras/task-store-database-jpa" From 075ba49627771a83f955e260e2b03409ca8dfb2f Mon Sep 17 00:00:00 2001 From: Sandeep Belgavi Date: Tue, 17 Feb 2026 16:50:37 +0530 Subject: [PATCH 5/7] feat: add schema.sql and remove sample data insertion for professional setup --- .../database/jpa/DatabaseInitializer.java | 30 +------------------ .../src/main/resources/schema.sql | 8 +++++ 2 files changed, 9 insertions(+), 29 deletions(-) create mode 100644 extras/task-store-database-jpa/src/main/resources/schema.sql diff --git a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java index 7c45cf137..8b8267930 100644 --- a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java +++ b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java @@ -2,16 +2,12 @@ import java.sql.Connection; import java.sql.DriverManager; -import java.sql.PreparedStatement; import java.sql.Statement; -import java.util.UUID; -import java.time.Instant; /** - * Utility class to initialize the database schema and insert sample data. + * Utility class to initialize the database schema. * This class handles: * 1. Creation of 'a2a_tasks' table if it does not exist. - * 2. Insertion of a sample task record. * *

Configuration via Environment Variables: *

    @@ -20,8 +16,6 @@ *
  • {@code DB_PASSWORD}: Database Password (default: {@code a2a})
  • *
* - * IMPORTANT: No deletion logic is implemented here to ensure data safety. - * * @author Sandeep Belgavi * @since 2026-02-17 */ @@ -40,9 +34,6 @@ public static void main(String[] args) { try (Connection conn = DriverManager.getConnection(JDBC_URL, USER, PASS)) { // 1. Create Table createTable(conn); - - // 2. Insert Sample Data - insertSampleTask(conn); } System.out.println("Database Initialization Completed Successfully."); @@ -66,23 +57,4 @@ private static void createTable(Connection conn) throws Exception { System.out.println("Verified table 'a2a_tasks'. Created if missing."); } } - - private static void insertSampleTask(Connection conn) throws Exception { - String taskId = UUID.randomUUID().toString(); - // Sample JSON structure for task data - String taskData = String.format("{\"status\": \"SUBMITTED\", \"created_at\": \"%s\", \"description\": \"Sample initialization task\"}", Instant.now()); - - String sql = "INSERT INTO a2a_tasks (task_id, task_data) VALUES (?, ?) ON CONFLICT (task_id) DO NOTHING"; - - try (PreparedStatement stmt = conn.prepareStatement(sql)) { - stmt.setString(1, taskId); - stmt.setString(2, taskData); - int rows = stmt.executeUpdate(); - if (rows > 0) { - System.out.println("Inserted sample task: " + taskId); - } else { - System.out.println("Sample task insertion skipped (conflict or no-op)."); - } - } - } } diff --git a/extras/task-store-database-jpa/src/main/resources/schema.sql b/extras/task-store-database-jpa/src/main/resources/schema.sql new file mode 100644 index 000000000..f4e330e15 --- /dev/null +++ b/extras/task-store-database-jpa/src/main/resources/schema.sql @@ -0,0 +1,8 @@ +-- Table Schema for A2A Task Store +-- Author: Sandeep Belgavi +-- Date: 2026-02-17 + +CREATE TABLE IF NOT EXISTS a2a_tasks ( + task_id VARCHAR(255) PRIMARY KEY, + task_data TEXT NOT NULL +); From 3cc8859d87899d4dda0a07339699d5082e7d87e7 Mon Sep 17 00:00:00 2001 From: Sandeep Belgavi Date: Tue, 17 Feb 2026 16:56:07 +0530 Subject: [PATCH 6/7] Update schema.sql and DatabaseInitializer.java to match JpaTask schema --- .../taskstore/database/jpa/DatabaseInitializer.java | 11 +++++++++++ .../src/main/resources/schema.sql | 10 +++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java index 8b8267930..5354fcf0c 100644 --- a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java +++ b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/DatabaseInitializer.java @@ -50,11 +50,22 @@ public static void main(String[] args) { private static void createTable(Connection conn) throws Exception { String sql = "CREATE TABLE IF NOT EXISTS a2a_tasks (" + "task_id VARCHAR(255) PRIMARY KEY, " + + "context_id VARCHAR(255), " + + "state VARCHAR(50), " + + "status_timestamp TIMESTAMP, " + + "finalized_at TIMESTAMP, " + "task_data TEXT NOT NULL" + ")"; try (Statement stmt = conn.createStatement()) { stmt.execute(sql); System.out.println("Verified table 'a2a_tasks'. Created if missing."); } + + // Also add index creation + String indexSql = "CREATE INDEX IF NOT EXISTS idx_a2a_tasks_context_id ON a2a_tasks(context_id)"; + try (Statement stmt = conn.createStatement()) { + stmt.execute(indexSql); + System.out.println("Verified index 'idx_a2a_tasks_context_id'."); + } } } diff --git a/extras/task-store-database-jpa/src/main/resources/schema.sql b/extras/task-store-database-jpa/src/main/resources/schema.sql index f4e330e15..6adc5855b 100644 --- a/extras/task-store-database-jpa/src/main/resources/schema.sql +++ b/extras/task-store-database-jpa/src/main/resources/schema.sql @@ -1,8 +1,16 @@ --- Table Schema for A2A Task Store +-- Table Schema for A2A Task Store (Java Implementation) +-- Matches io.a2a.extras.taskstore.database.jpa.JpaTask -- Author: Sandeep Belgavi -- Date: 2026-02-17 CREATE TABLE IF NOT EXISTS a2a_tasks ( task_id VARCHAR(255) PRIMARY KEY, + context_id VARCHAR(255), + state VARCHAR(50), + status_timestamp TIMESTAMP, + finalized_at TIMESTAMP, task_data TEXT NOT NULL ); + +-- Optional: Create index on context_id for faster lookups +CREATE INDEX IF NOT EXISTS idx_a2a_tasks_context_id ON a2a_tasks(context_id); From e44fb60c9311835f617381c40fe37dc420c2544e Mon Sep 17 00:00:00 2001 From: Sandeep Belgavi Date: Tue, 17 Feb 2026 16:59:55 +0530 Subject: [PATCH 7/7] refactor: align JpaTask schema with database table definition --- .../java/io/a2a/extras/taskstore/database/jpa/JpaTask.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaTask.java b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaTask.java index 021a693e3..58de27046 100644 --- a/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaTask.java +++ b/extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaTask.java @@ -13,7 +13,9 @@ import io.a2a.spec.Task; @Entity -@Table(name = "a2a_tasks") +@Table(name = "a2a_tasks", indexes = { + @jakarta.persistence.Index(name = "idx_a2a_tasks_context_id", columnList = "context_id") +}) public class JpaTask { @Id @Column(name = "task_id") @@ -22,7 +24,7 @@ public class JpaTask { @Column(name = "context_id") private String contextId; - @Column(name = "state") + @Column(name = "state", length = 50) private String state; @Column(name = "status_timestamp")