Skip to main content

Local gRPC Server

This playbook provides instructions for running the ArchitecturalPlanServer locally for development and testing.

Prerequisites

  • Java 23 (as specified in pom.xml)
  • Maven
  • Google Cloud authentication (if using GCP services)
  • grpcurl (for testing)

Environment Setup

Load the development environment variables:

source env/dev/setvars.sh

Starting the Server

Fastest method for development - no need to build JAR each time:

mvn exec:java -Dexec.mainClass="org.codetricks.construction.code.assistant.service.ArchitecturalPlanServer"

With custom port:

mvn exec:java -Dexec.mainClass="org.codetricks.construction.code.assistant.service.ArchitecturalPlanServer" -Dexec.args="8081"

Build the executable JAR with dependencies:

mvn clean package -DskipTests

Run the JAR file:

java -jar target/construction-code-expert-1.0-SNAPSHOT-jar-with-dependencies.jar

With custom port:

java -jar target/construction-code-expert-1.0-SNAPSHOT-jar-with-dependencies.jar 8081

Method 3: Using Java Classpath with Explicit Main Class Override

Get the latest built JAR file:

LATEST_JAR_FILE=$(ls target/construction-code-expert-*-jar-with-dependencies.jar | sort -V | tail -n 1)

Run with explicit main class:

java -cp "$LATEST_JAR_FILE" org.codetricks.construction.code.assistant.service.ArchitecturalPlanServer

With custom port:

java -cp "$LATEST_JAR_FILE" org.codetricks.construction.code.assistant.service.ArchitecturalPlanServer 8081

Overriding Filesystem Handler for Local Development

By default, the services use GcsFileSystemHandler which requires Google Cloud Storage. For local development, you can override this to use LocalFileSystemHandler instead.

Add this to your env/dev/setvars.sh or set it before starting the server:

export CODEPROOF_USE_LOCAL_FILESYSTEM=true

Then modify the getDefaultFilesystemHandler() method in each service to check for this environment variable:

private FileSystemHandler getDefaultFilesystemHandler() {
if(overrideFileSystemHandler != null) {
return overrideFileSystemHandler;
}

// Check for local filesystem override
String useLocalFs = Utils.getenv("CODEPROOF_USE_LOCAL_FILESYSTEM");
if ("true".equalsIgnoreCase(useLocalFs)) {
return new LocalFileSystemHandler();
}

return new GcsFileSystemHandler(Utils.getenv("GCP_GCS_BUCKET_NAME"));
}

Option 2: Programmatic Override

Create a custom server startup class that sets the override:

public class LocalArchitecturalPlanServer {
public static void main(String[] args) throws IOException, InterruptedException {
final ArchitecturalPlanServer server = new ArchitecturalPlanServer();

// Create service instances and set local filesystem handler
ArchitecturalPlanServiceImpl architecturalPlanService = new ArchitecturalPlanServiceImpl();
architecturalPlanService.setOverrideFileSystemHandler(new LocalFileSystemHandler());

ArchitecturalPlanReviewServiceImpl reviewService = new ArchitecturalPlanReviewServiceImpl();
reviewService.setOverrideFileSystemHandler(new LocalFileSystemHandler());

ComplianceCodeSearchServiceImpl searchService = new ComplianceCodeSearchServiceImpl();
searchService.setOverrideFileSystemHandler(new LocalFileSystemHandler());

// Start server with custom services
server.start(8080, architecturalPlanService, reviewService, searchService);
server.blockUntilShutdown();
}
}

Option 3: Using a Local Development Script

Create a script that sets up the local filesystem handler:

#!/bin/bash
# cli/start-local-server.sh

# Load environment variables
source env/dev/setvars.sh

# Set local filesystem flag
export CODEPROOF_USE_LOCAL_FILESYSTEM=true

# Start the server
mvn exec:java -Dexec.mainClass="org.codetricks.construction.code.assistant.service.ArchitecturalPlanServer"

Usage:

./cli/start-local-server.sh

Local Data Structure

When using LocalFileSystemHandler, ensure your local directory structure matches what the services expect:

your-project-root/
├── database/
│ └── icc-irc/
│ └── index.json
├── inputs/
│ └── architectural-plans/
│ └── R2024.0091-2024-10-14/
│ ├── page-1/
│ │ ├── page.pdf
│ │ └── page.md
│ └── page-2/
│ ├── page.pdf
│ └── page.md
└── api/
└── icc/
└── content.chapters.3757.json

Server Configuration

  • Default port: 8080
  • Services provided:
    • ArchitecturalPlanServiceImpl
    • ArchitecturalPlanReviewServiceImpl
    • ComplianceCodeSearchServiceImpl
    • AccessControlListServiceImpl

Testing the Server

Install grpcurl (if not already installed)

# macOS
brew install grpcurl

# Ubuntu/Debian
sudo apt-get install grpcurl

# Or download from: https://github.com/fullstorydev/grpcurl/releases

Basic Testing

List available services:

grpcurl -plaintext localhost:8080 list

Describe a specific service:

grpcurl -plaintext localhost:8080 describe org.codetricks.construction.code.assistant.service.ArchitecturalPlanService

Alternative: List services with explicit proto paths (if reflection doesn't work):

grpcurl -plaintext \
-import-path src/main/proto \
-import-path env/dependencies/googleapis \
-proto src/main/proto/api.proto \
localhost:8080 \
list

Example API Calls

Get Architectural Plan:

grpcurl -plaintext \
-import-path src/main/proto \
-import-path env/dependencies/googleapis \
-proto src/main/proto/api.proto \
-d '{"architectural_plan_id": "R2024.0091-2024-10-14"}' \
localhost:8080 \
org.codetricks.construction.code.assistant.service.ArchitecturalPlanService/GetArchitecturalPlan

Get Architectural Plan Page PDF (with increased message size):

grpcurl -plaintext \
-import-path src/main/proto \
-import-path env/dependencies/googleapis \
-proto src/main/proto/api.proto \
-d '{"architectural_plan_id": "R2024.0091-2024-10-14", "page_number": 1}' \
-max-msg-sz $((10 * 1024 * 1024)) \
localhost:8080 \
org.codetricks.construction.code.assistant.service.ArchitecturalPlanService/GetArchitecturalPlanPagePdf

Search ICC Code:

grpcurl -plaintext \
-import-path src/main/proto \
-import-path env/dependencies/googleapis \
-proto src/main/proto/api.proto \
-d '{"icc_book_id": "2217", "query": "Cooling towers located on a roof of a building shall be constructed of non-combustible materials when the base area of the cooling tower is greater than how many square feet?", "max_results": 3}' \
localhost:8080 \
org.codetricks.construction.code.assistant.service.ComplianceCodeSearchService/GetIccCodeSearchResults

Troubleshooting

Port Already in Use

If you get a "port already in use" error, either:

  • Kill the existing process using the port
  • Use a different port number as shown in the examples above

Memory Issues

The server may require significant memory for processing large PDF files. If you encounter memory issues:

  • Increase JVM heap size: java -Xmx4g -jar target/construction-code-expert-1.0-SNAPSHOT-jar-with-dependencies.jar
  • Or use Maven with increased memory: MAVEN_OPTS="-Xmx4g" mvn exec:java -Dexec.mainClass="org.codetricks.construction.code.assistant.service.ArchitecturalPlanServer"

Authentication Issues

If you encounter Google Cloud authentication issues:

  • Ensure you have proper GCP credentials set up
  • Check that the environment variables in env/dev/setvars.sh are correctly configured
  • Verify your GCP project has the necessary APIs enabled

Filesystem Handler Issues

If you encounter filesystem-related errors:

  • Ensure your local data structure matches the expected layout
  • Check that the CODEPROOF_USE_LOCAL_FILESYSTEM environment variable is set correctly
  • Verify that the local files and directories exist and are readable

Development Workflow

  1. For active development: Use Method 1 (Maven exec plugin)
  2. For testing production-like behavior: Use Method 2 (JAR execution)
  3. For running different main classes: Use Method 3 (classpath override)
  4. For local development without GCS: Use the filesystem override options
  • src/main/java/org/codetricks/construction/code/assistant/service/ArchitecturalPlanServer.java - Main server class
  • src/main/java/org/codetricks/construction/code/assistant/service/ArchitecturalPlanServiceImpl.java - Service implementation with filesystem handler
  • src/main/java/org/codetricks/construction/code/assistant/data/rag/corpus/LocalFileSystemHandler.java - Local filesystem implementation
  • env/dev/setvars.sh - Development environment variables
  • pom.xml - Maven configuration with main class specification
  • src/main/assembly/assembly.xml - JAR assembly configuration
  • cli/codeproof.sh - Example of classpath override approach

Running Local HTTP REST Service with ESPv2

For local development with HTTP REST transcoding (similar to Cloud Run ESPv2), you can run ESPv2 locally with Docker.

Prerequisites

  • Docker installed and running
  • protoc (Protocol Buffers compiler) installed
  • gRPC server running on port 8080

Start Local ESPv2

Step 1: Start the gRPC server first

./cli/start-local-server.sh

Step 2: Start ESPv2 proxy (in a new terminal)

./cli/start-local-espv2.sh

The ESPv2 script will:

  1. Check if gRPC server is running on port 8080
  2. Generate the API descriptor from your proto files
  3. Start ESPv2 Docker container on port 8081
  4. Provide HTTP REST API endpoints that proxy to your gRPC server

Local Environment Configuration

The local ESPv2 setup uses the environment structure at env/local/gcp/cloud-run/endpoints/:

  • api_config.yaml - ESPv2 service configuration
  • setvars.sh - Local environment variables
  • vars.yaml - Environment variables for ESPv2

Testing HTTP REST API

Once both services are running, you can test the HTTP REST endpoints:

# List architectural plans
curl http://localhost:8081/v1/architectural-plans

# Get specific architectural plan
curl http://localhost:8081/v1/architectural-plans/R2024.0091-2024-10-14

# Search ICC codes
curl -X POST http://localhost:8081/v1/icc-books/2217/search \
-H "Content-Type: application/json" \
-d '{"query": "Cooling towers", "max_results": 3}'

Port Configuration

  • gRPC Server: localhost:8080 (started with start-local-server.sh)
  • HTTP REST API: localhost:8081 (ESPv2 proxy)

Stopping Services

Stop ESPv2 only:

docker stop local-espv2
docker rm local-espv2

Stop gRPC server:

pkill -f "ArchitecturalPlanServer"

Or press Ctrl+C in the respective terminal windows.