blob: c235bb2e66310ce5fc2f5366c2f04cd24f82fad9 [file] [view]
# HTTP/2 and axis2.xml Configuration: Axis2/C vs Axis2/Java
## Executive Summary
**No axis2.xml changes are required for HTTP/2 and JSON support in Axis2/C.** This document explains why Axis2/C differs from Axis2/Java in this regard and provides a comprehensive comparison of the architectural approaches.
## Key Difference: No Configuration Changes Required
Unlike Axis2/Java, **Axis2/C automatically detects and handles HTTP/2 with JSON content without requiring any axis2.xml configuration changes**. The request processing is determined at runtime through intelligent header analysis rather than static configuration.
## Axis2/C: Runtime Detection Approach
### Automatic Protocol and Content-Type Detection
Axis2/C uses the `axis2_apache2_request_processor_is_json_http2_request()` function in `src/core/transport/http/server/apache2/axis2_apache2_request_processor_factory.c` to automatically detect:
1. **HTTP/2 Protocol Detection**: Checks `request->protocol` for "HTTP/2" or "HTTP/2.0" strings
2. **JSON Content-Type Detection**: Analyzes Content-Type header for:
- `application/json`
- `text/json`
- `application/hal+json`
- `application/vnd.api+json`
```c
AXIS2_EXTERN axis2_bool_t AXIS2_CALL
axis2_apache2_request_processor_is_json_http2_request(request_rec* request)
{
const axis2_char_t* content_type = NULL;
const axis2_char_t* protocol = NULL;
if (!request) return AXIS2_FALSE;
/* Check protocol version */
protocol = request->protocol;
if (!protocol || (!strstr(protocol, "HTTP/2") && !strstr(protocol, "HTTP/2.0")))
{
return AXIS2_FALSE;
}
/* Check content type */
content_type = apr_table_get(request->headers_in, "Content-Type");
if (!content_type)
{
content_type = apr_table_get(request->headers_in, "content-type");
}
if (!content_type) return AXIS2_FALSE;
/* JSON content type detection */
return (strstr(content_type, "application/json") != NULL ||
strstr(content_type, "text/json") != NULL ||
strstr(content_type, "application/hal+json") != NULL ||
strstr(content_type, "application/vnd.api+json") != NULL) ?
AXIS2_TRUE : AXIS2_FALSE;
}
```
### Intelligent Processor Selection
The factory method at `axis2_apache2_request_processor_factory.c:66-135` implements a decision matrix:
1. **HTTP/2 + JSON Content-Type** → JSON Processor (thread-safe)
2. **HTTP/2 + Any Content-Type** → JSON Processor (assume modern client)
3. **HTTP/1.1 + SOAP Content-Type** → SOAP Processor (legacy compatibility)
4. **HTTP/1.1 + JSON Content-Type** → SOAP Processor (safe fallback)
5. **Default/Unknown** → SOAP Processor (maximum compatibility)
### Usage Example
Simply send an HTTP/2 request with the appropriate Content-Type header:
```bash
curl -k --http2 -H "Content-Type: application/json" \
-X POST -d '{"getCameraStatus":[]}' \
https://localhost:8443/axis2/services/CameraControlService
```
No axis2.xml configuration is needed - the system automatically routes to the appropriate processor.
## Axis2/Java: Static Configuration Approach
### Why Axis2/Java Requires axis2.xml Changes
Based on the Spring Boot user guide (`src/site/xdoc/docs/json-springboot-userguide.xml` in axis-axis2-java-core), Axis2/Java requires explicit axis2.xml configuration because it uses a **static configuration model** where message processors are pre-configured rather than dynamically selected.
### Required Axis2/Java Configuration Components
#### 1. Message Formatters
```xml
<message name="requestMessage">
<messageFormatter contentType="application/json"
class="org.apache.axis2.json.moshi.JsonFormatter"/>
</message>
```
#### 2. Message Receivers
Required classes mentioned in the Java documentation:
- `JsonRpcMessageReceiver`
- `JsonInOnlyRPCMessageReceiver`
#### 3. Message Builders
- `JsonBuilder`
#### 4. Dispatchers and Handlers
- `JSONBasedDefaultDispatcher`
- `JSONMessageHandler`
#### 4. HTTP/2 Transport Sender
```xml
<transportSender name="h2"
class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender">
<parameter name="PROTOCOL">HTTP/2.0</parameter>
<parameter name="maxConcurrentStreams">100</parameter>
<parameter name="initialWindowSize">65536</parameter>
<parameter name="serverPushEnabled">false</parameter>
<parameter name="connectionTimeout">30000</parameter>
<parameter name="responseTimeout">300000</parameter>
<parameter name="streamingBufferSize">65536</parameter>
<parameter name="memoryPressureThreshold">0.8</parameter>
<!-- Enterprise Big Data Configuration -->
<parameter name="enableStreamingOptimization">true</parameter>
<parameter name="enableMemoryOptimization">true</parameter>
<parameter name="largePayloadThreshold">52428800</parameter> <!-- 50MB -->
</transportSender>
```
**Note on Buffer Sizes**: The 64KB values shown above (`initialWindowSize`, `streamingBufferSize`) are Axis2/Java defaults. Axis2/C uses an **incremental buffer growth** approach:
- **Initial allocation**: 64KB (efficient for IoT/camera payloads ~24 bytes)
- **Growth strategy**: Doubles on demand (64KB → 128KB → 256KB → ... → 10MB max)
- **Maximum limit**: 10MB (supports 500+ asset financial portfolios at ~5MB)
- **Service-level limit**: Configurable via `maxJSONPayloadSize` in services.xml (default 10MB)
- **Implementation note**: Uses standard C `malloc/realloc` since `AXIS2_REALLOC` is unreliable
**Memory Efficiency Comparison**:
| Payload | Axis2/C (incremental) | Static 10MB | Savings |
|---------|----------------------|-------------|---------|
| IoT/Camera (~24B) | 64KB | 10MB | 160x |
| Medium JSON (~50KB) | 64KB | 10MB | 160x |
| Large portfolio (~235KB) | 256KB | 10MB | 40x |
## Architectural Comparison
### Axis2/C Advantages
1. **Zero Configuration**: No axis2.xml modifications required
2. **Runtime Flexibility**: Dynamic processor selection based on actual request characteristics
3. **Backward Compatibility**: Existing SOAP services continue working unchanged
4. **Intelligent Routing**: HTTP/2 requests automatically get optimized processing
5. **Thread Safety**: HTTP/2 requests automatically use thread-safe processors
### Axis2/Java Advantages
1. **Explicit Control**: Developers can precisely control message processing pipeline
2. **Performance Optimization**: Pre-configured processors avoid runtime decision overhead
3. **Enterprise Features**: Rich configuration options for big data processing (50MB+ payloads)
4. **Monitoring**: Built-in performance metrics and optimization indicators
## Implementation Details
### Axis2/C Request Flow
1. **Request Reception**: Apache HTTP server receives request
2. **Header Analysis**: Factory analyzes HTTP protocol version and Content-Type header
3. **Processor Selection**: Factory selects appropriate processor (JSON vs SOAP)
4. **Processing**: Selected processor handles the request with appropriate optimizations
5. **Response Generation**: Response format matches request expectations
### Axis2/Java Request Flow
1. **Configuration Loading**: axis2.xml defines processing pipeline at startup
2. **Request Reception**: Pre-configured message receivers handle requests
3. **Format Detection**: Content-Type header routes to appropriate formatter
4. **Processing**: Fixed pipeline processes the request
5. **Response Generation**: Pre-configured formatters generate response
## Best Practices
### For Axis2/C Development
1. **No Configuration Changes**: Simply use HTTP/2 with appropriate Content-Type headers
2. **Test Both Protocols**: Verify services work with both HTTP/1.1 and HTTP/2
3. **Monitor Logs**: Check processor selection in debug logs
4. **Content-Type Headers**: Ensure clients send `Content-Type: application/json`
### For Axis2/Java Migration to Axis2/C
1. **Remove axis2.xml HTTP/2 Configuration**: Not needed in Axis2/C
2. **Simplify Deployment**: No message formatter/receiver configuration required
3. **Test Runtime Detection**: Verify automatic processor selection works as expected
4. **Update Documentation**: Inform clients that configuration is not needed
## Conclusion
The fundamental difference between Axis2/C and Axis2/Java lies in their architectural philosophy:
- **Axis2/Java**: Static configuration with explicit control through axis2.xml
- **Axis2/C**: Dynamic runtime detection with zero configuration
This makes Axis2/C significantly easier to deploy for HTTP/2 and JSON scenarios while maintaining full backward compatibility with existing SOAP services. The intelligent request processor factory ensures that each request type gets appropriate handling without any manual configuration.
For HTTP/2 and JSON support, developers can focus on service implementation rather than configuration management, as the framework handles protocol and content-type detection transparently.
## Streaming and Field Filtering: Java vs C Architecture
### JSON Serialization Model
| | Axis2/Java | Axis2/C |
|---|---|---|
| **Serialization** | Streaming — Moshi/GSON writes fields directly to a `JsonWriter` backed by an `OutputStream`. No intermediate tree. | Tree — json-c builds a `json_object*` in memory, then `json_object_to_json_string()` serializes the whole tree at once. |
| **Memory profile** | Only the current field's value is in memory during serialization. A 50 MB response never exists as a 50 MB buffer. | The full json-c tree is in memory before serialization. For typical responses (1-10 KB) this is negligible; for large responses Java is more memory-efficient. |
### HTTP/2 Streaming
| | Axis2/Java | Axis2/C |
|---|---|---|
| **Mechanism** | `FlushingOutputStream` wraps the transport `OutputStream` and flushes every 64 KB. The flush happens DURING Moshi/GSON serialization — each field written eventually triggers a flush, converting one buffered response into a stream of HTTP/2 DATA frames. | `ap_rflush(r)` called periodically during response generation via Apache httpd `mod_h2`. Achieves similar chunked delivery but is manual — each service must call `ap_rflush()` at the right points in its serialization code. |
| **Scope** | Framework-level — configure `MoshiStreamingMessageFormatter` in `axis2.xml` and ALL services get 64 KB streaming automatically. | Service-level — each service decides when to flush. The financial benchmark service uses the same 64 KB interval as Java. |
### Field Filtering (`?fields=`)
| | Axis2/Java | Axis2/C |
|---|---|---|
| **Approach** | True streaming (Option C): reflection-based selective serialization inside `MoshiStreamingMessageFormatter.writeFilteredObject()`. Non-selected fields are NEVER serialized, never buffered, never written to the wire. | Post-build tree filtering: json-c builds the full `json_object*` tree, then `finbench_filter_json_response()` deletes unwanted keys via `json_object_object_del()`, then re-serializes. The full tree is briefly in memory. |
| **Scope** | Framework-level — `FieldFilteringMessageFormatter` wraps any `MessageFormatter`. Configure once in `axis2.xml`, all services get `?fields=` for free. | Service-level — implemented in the financial benchmark service handler. Other C services would need their own filter call. |
| **Code** | ~320 lines (`FieldFilteringMessageFormatter.java`) + ~100 lines added to `MoshiStreamingMessageFormatter.java`) | ~60 lines in `financial_benchmark_service_handler.c` (`finbench_extract_fields_param` + `finbench_filter_json_response`) |
### Why the Difference
Axis2/Java has a **pluggable message formatter pipeline** in the kernel.
`MessageFormatter` is an interface that the engine calls to serialize
every outbound message. `FlushingOutputStream`, `FieldFilteringMessageFormatter`,
and `MoshiStreamingMessageFormatter` all live in this pipeline. Any
service deployed to any Axis2/Java instance gets these features by
changing one line in `axis2.xml`.
Axis2/C has **no equivalent pluggable JSON formatter pipeline**. The C
architecture was designed for SOAP (Axiom / libxml2). JSON services
bypass the SOAP pipeline entirely by handling serialization themselves
— each service builds its own json-c tree and calls
`json_object_to_json_string()`. This is simpler per-service but means
streaming and field filtering must be implemented in each service's
handler rather than once in the framework.
### Reusability Path for C
The `finbench_filter_json_response()` function is already generic —
it operates on any JSON string using json-c and `axutil_strdup`. To
make field filtering available to all Axis2/C JSON services:
1. Move `finbench_extract_fields_param()` and
`finbench_filter_json_response()` into an `axutil` shared utility
(e.g., `axutil_json_field_filter.c`).
2. In the JSON message receiver (`axis2_json_rpc_msg_recv`), check for
`?fields=` on the request URI and apply the filter to the outbound
JSON string before sending.
3. This would give all Axis2/C JSON services field filtering without
per-service code — matching the Axis2/Java architecture.
For now, the per-service approach in the financial benchmark handler is
correct and KISS — it is ~60 lines of self-contained C that achieves
feature parity with the Axis2/Java deployment.
### Parity Reference
| Feature | Axis2/Java | Axis2/C | Parity |
|---------|-----------|---------|--------|
| HTTP/2 transport | `modules/transport-h2` | `mod_h2` via Apache httpd | ✅ |
| 64 KB streaming flush | `FlushingOutputStream` | `ap_rflush(r)` | ✅ |
| `?fields=` response filtering | `FieldFilteringMessageFormatter` | `finbench_filter_json_response()` | ✅ |
| Pluggable for all services | Yes (axis2.xml config) | No (per-service) | ⚠️ Java ahead |
| Streaming during serialization | Yes (Moshi → Okio → flush) | No (json-c tree → serialize) | ⚠️ Java ahead |
| MCP tool catalog | `openapi-mcp.json` auto-generated | `mcp_catalog_handler.c` | ✅ |
| Financial benchmark parity | portfolioVariance, monteCarlo, scenarioAnalysis | Same three services | ✅ |
See also:
- [Axis2/Java HTTP/2 Integration Guide](https://github.com/apache/axis-axis2-java-core/blob/master/src/site/xdoc/docs/http2-integration-guide.xml)
- [Axis2/Java FieldFilteringMessageFormatter](https://github.com/apache/axis-axis2-java-core/blob/master/modules/json/src/org/apache/axis2/json/streaming/FieldFilteringMessageFormatter.java)
- [Axis2/Java Streaming JSON Formatter](https://github.com/apache/axis-axis2-java-core/blob/master/src/site/xdoc/docs/json-streaming-formatter.xml)