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:
- HTTP/2 Protocol Detection: Checks
request->protocolfor "HTTP/2" or "HTTP/2.0" strings - JSON Content-Type Detection: Analyzes Content-Type header for:
application/jsontext/jsonapplication/hal+jsonapplication/vnd.api+json
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:
- HTTP/2 + JSON Content-Type → JSON Processor (thread-safe)
- HTTP/2 + Any Content-Type → JSON Processor (assume modern client)
- HTTP/1.1 + SOAP Content-Type → SOAP Processor (legacy compatibility)
- HTTP/1.1 + JSON Content-Type → SOAP Processor (safe fallback)
- Default/Unknown → SOAP Processor (maximum compatibility)
Usage Example¶
Simply send an HTTP/2 request with the appropriate Content-Type header:
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¶
<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¶
JSONBasedDefaultDispatcherJSONMessageHandler
4. HTTP/2 Transport Sender¶
<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¶
- Zero Configuration: No axis2.xml modifications required
- Runtime Flexibility: Dynamic processor selection based on actual request characteristics
- Backward Compatibility: Existing SOAP services continue working unchanged
- Intelligent Routing: HTTP/2 requests automatically get optimized processing
- Thread Safety: HTTP/2 requests automatically use thread-safe processors
Axis2/Java Advantages¶
- Explicit Control: Developers can precisely control message processing pipeline
- Performance Optimization: Pre-configured processors avoid runtime decision overhead
- Enterprise Features: Rich configuration options for big data processing (50MB+ payloads)
- Monitoring: Built-in performance metrics and optimization indicators
Implementation Details¶
Axis2/C Request Flow¶
- Request Reception: Apache HTTP server receives request
- Header Analysis: Factory analyzes HTTP protocol version and Content-Type header
- Processor Selection: Factory selects appropriate processor (JSON vs SOAP)
- Processing: Selected processor handles the request with appropriate optimizations
- Response Generation: Response format matches request expectations
Axis2/Java Request Flow¶
- Configuration Loading: axis2.xml defines processing pipeline at startup
- Request Reception: Pre-configured message receivers handle requests
- Format Detection: Content-Type header routes to appropriate formatter
- Processing: Fixed pipeline processes the request
- Response Generation: Pre-configured formatters generate response
Best Practices¶
For Axis2/C Development¶
- No Configuration Changes: Simply use HTTP/2 with appropriate Content-Type headers
- Test Both Protocols: Verify services work with both HTTP/1.1 and HTTP/2
- Monitor Logs: Check processor selection in debug logs
- Content-Type Headers: Ensure clients send
Content-Type: application/json
For Axis2/Java Migration to Axis2/C¶
- Remove axis2.xml HTTP/2 Configuration: Not needed in Axis2/C
- Simplify Deployment: No message formatter/receiver configuration required
- Test Runtime Detection: Verify automatic processor selection works as expected
- 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:
- Move
finbench_extract_fields_param()andfinbench_filter_json_response()into anaxutilshared utility (e.g.,axutil_json_field_filter.c). - 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. - 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 - Axis2/Java FieldFilteringMessageFormatter - Axis2/Java Streaming JSON Formatter