Apache Axis2 OpenAPI Advanced Enterprise User Guide
Enterprise-Grade OpenAPI Integration - This advanced guide covers the OpenAPI capabilities introduced in Axis2 2.0.1: configuration through properties files and system properties, security schemes in the generated specification, Swagger UI customization, the OpenApiCustomizer post-processing interface, and resource filtering.
Anything not covered by the configuration properties listed below (OAuth2 and API key security schemes, extra servers, tags, examples and extensions) is done programmatically with an OpenApiCustomizer. The OpenAPI module does not read environment variables.
This guide focuses on modern enterprise patterns including Bearer token authentication, OAuth2 integration, microservices architectures, cloud-native deployments, and developer-first API design principles. All examples use contemporary security and architectural patterns.
For legacy system integration patterns, see the Basic OpenAPI User Guide.
Introduction - Enterprise OpenAPI Architecture
Axis2's OpenAPI integration represents a complete enterprise-grade solution for REST API development, documentation, and management. Unlike basic API documentation tools, this system provides:
- Configuration:
openapi.*properties loaded from classpath properties files and system properties - Security Schemes: a JWT Bearer scheme by default; OAuth2, API keys and others added with a customizer
- Developer Experience: Swagger UI with display options set through
SwaggerUiConfig - Extensibility: OpenAPI customizer interface for post-processing and enhancements
- Filtering: include or exclude resource packages, services, operations and routes
- Container-ready: configuration through a mounted properties file or JVM system properties
This guide assumes familiarity with modern REST API design, OAuth2/JWT authentication, and enterprise development patterns. All examples follow contemporary security and architectural practices.
Enterprise Configuration System
The Axis2 OpenAPI module reads its configuration from several sources, designed for enterprise deployment scenarios.
Configuration Sources and Precedence
Configuration is loaded from the following sources; a later source overrides an earlier one (lowest precedence first):
- Default Values - Built-in defaults
- Module Parameters -
title,version,description,prettyPrint,supportSwaggerUiandpropertiesFilein the module's module.xml - Properties Files -
openapi.propertieson the classpath, the file named by thepropertiesFilemodule parameter, andMETA-INF/openapi.properties,WEB-INF/openapi.propertiesoropenapi-config.propertiesif present - System Properties - JVM system properties with the same
openapi.*keys (highest precedence)
Properties File Configuration
Create openapi.properties in your classpath. These are all the supported keys:
# API Information openapi.title=Financial Services API openapi.description=Enterprise financial services with comprehensive security openapi.version=2.1.0 openapi.contact.name=API Team openapi.contact.email=api-team@company.com openapi.contact.url=https://company.com/api-docs openapi.license.name=Commercial License openapi.license.url=https://company.com/license openapi.termsOfServiceUrl=https://company.com/terms # Absolute URL for servers[].url (a relative URL is published by default) openapi.serverBaseUrl=https://api.company.com/axis2 # Resource Filtering openapi.readAllResources=false openapi.resourcePackages=com.company.api.v2,com.company.services openapi.ignoredRoutes=/internal/.*,/health,/metrics openapi.ignoredServices=AdminService,InternalService openapi.ignoredOperations=TradeService/debugDump,ping # Swagger UI openapi.swaggerUi.enabled=true openapi.swaggerUi.version=5.32.13 # Only needed when openapi.swaggerUi.version is not the default: # openapi.swaggerUi.integrity.bundle=sha384-... # openapi.swaggerUi.integrity.standalonePreset=sha384-... # Output openapi.prettyPrint=false openapi.useContextBasedConfig=false
Swagger UI is loaded from a CDN. For the default version the page pins Subresource Integrity hashes; if you choose another version, supply its hashes with the two openapi.swaggerUi.integrity.* keys, otherwise the page still renders but logs a warning that integrity is not enforced.
System Properties Configuration
Override any setting with JVM system properties:
java -Dopenapi.title="Development API" \
-Dopenapi.swaggerUi.enabled=true \
-jar your-application.jar
Modern Authentication Patterns
The generated specification can describe modern authentication patterns including OAuth2, JWT Bearer tokens and API keys. Axis2 documents these schemes; validating tokens remains the job of your service or of a security layer in front of it.
Bearer Token Authentication (JWT)
Modern REST APIs use Bearer token authentication. The generated specification declares an HTTP bearer security scheme named bearerAuth by default, so operations can reference it directly. To set bearerFormat or change the description, use a customizer (see Programmatic Security Configuration).
Service implementation with Bearer authentication:
@Path("/api/v2")
@Tag(name = "Financial Services API v2", description = "Financial Services API v2")
public class FinancialServicesController {
@POST
@Path("/trades")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Create new trade",
description = "Create a new trade with Bearer token authentication",
security = @SecurityRequirement(name = "bearerAuth")
)
@ApiResponses({
@ApiResponse(responseCode = "201", description = "Trade created successfully"),
@ApiResponse(responseCode = "401", description = "Unauthorized - invalid token"),
@ApiResponse(responseCode = "403", description = "Forbidden - insufficient permissions")
})
public TradeResponse createTrade(
@HeaderParam("Authorization") String bearerToken,
@Parameter(description = "Trade details") @Valid TradeRequest request) {
// Extract JWT token from Bearer header
String jwt = extractJwtFromBearerHeader(bearerToken);
// Validate JWT and extract user claims
JwtClaims claims = jwtValidator.validateToken(jwt);
UserContext userContext = UserContext.fromJwtClaims(claims);
// Business logic with authenticated user context
Trade trade = tradeService.createTrade(request, userContext);
return TradeResponse.from(trade);
}
private String extractJwtFromBearerHeader(String bearerToken) {
if (bearerToken == null || !bearerToken.startsWith("Bearer ")) {
throw new UnauthorizedException("Invalid Bearer token format");
}
return bearerToken.substring(7);
}
}
Client usage with Bearer tokens:
# Login to get JWT token
curl -X POST https://api.company.com/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"user@company.com","password":"secure123"}'
# Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "read:trades write:trades"
}
# Use JWT token for API calls
curl -X POST https://api.company.com/api/v2/trades \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"symbol": "AAPL",
"quantity": 100,
"side": "BUY",
"orderType": "MARKET"
}'
OAuth2 Integration
An OAuth2 security scheme, with its authorization and token URLs and scopes, is added to the specification programmatically; see Programmatic Security Configuration for a complete oauth2 scheme.
OAuth2 service implementation:
@Path("/api/v2/reports")
@Tag(name = "Financial Reports API", description = "Financial Reports API")
public class ReportsController {
@GET
@Path("/portfolio/{portfolioId}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Get portfolio report",
description = "Requires 'read:reports' scope",
security = @SecurityRequirement(name = "oauth2", scopes = {"read:reports"})
)
public PortfolioReport getPortfolioReport(
@HeaderParam("Authorization") String bearerToken,
@PathParam("portfolioId") @Parameter(description = "Portfolio identifier") String portfolioId) {
// Validate OAuth2 token and scopes
OAuth2TokenInfo tokenInfo = oauth2Validator.validateToken(bearerToken);
if (!tokenInfo.hasScope("read:reports")) {
throw new ForbiddenException("Insufficient scope for reports access");
}
return reportsService.generatePortfolioReport(portfolioId, tokenInfo.getUserId());
}
}
API Key Authentication
API key schemes (for example an X-API-Key header) are likewise declared with a customizer; the apiKeyAuth scheme in Programmatic Security Configuration shows one.
Service with API key authentication:
@Path("/api/v2/market-data")
@Tag(name = "Market Data API", description = "Market Data API")
public class MarketDataController {
@GET
@Path("/quotes/{symbol}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Get real-time quote",
description = "Requires valid API key",
security = @SecurityRequirement(name = "apiKeyAuth")
)
public QuoteResponse getQuote(
@HeaderParam("X-API-Key") @Parameter(description = "API Key") String apiKey,
@PathParam("symbol") @Parameter(description = "Stock symbol") String symbol) {
// Validate API key and get associated permissions
ApiKeyInfo keyInfo = apiKeyService.validateKey(apiKey);
if (!keyInfo.hasMarketDataAccess()) {
throw new ForbiddenException("API key does not have market data access");
}
Quote quote = marketDataService.getRealTimeQuote(symbol);
return QuoteResponse.from(quote);
}
}
Advanced Security Scheme Configuration
The specification can declare multiple simultaneous security schemes. Apart from the default bearerAuth scheme, they are configured in code.
Programmatic Security Configuration
Security setup using the OpenApiCustomizer interface:
public class SecuritySchemeCustomizer implements OpenApiCustomizer {
@Override
public void customize(OpenAPI openAPI) {
// Add OAuth2 security scheme with detailed flow configuration
SecurityScheme oauth2 = new SecurityScheme()
.type(SecurityScheme.Type.OAUTH2)
.description("OAuth2 authentication with PKCE support")
.flows(new OAuthFlows()
.authorizationCode(new OAuthFlow()
.authorizationUrl("https://auth.company.com/oauth2/authorize")
.tokenUrl("https://auth.company.com/oauth2/token")
.refreshUrl("https://auth.company.com/oauth2/refresh")
.scopes(createOAuth2Scopes())
)
);
// Add JWT Bearer token scheme
SecurityScheme bearerAuth = new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.description("JWT Bearer token authentication");
// Add enterprise API key scheme
SecurityScheme apiKeyAuth = new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.name("X-API-Key")
.in(SecurityScheme.In.HEADER)
.description("Enterprise API key for service authentication");
// Register all security schemes
openAPI.getComponents()
.addSecuritySchemes("oauth2", oauth2)
.addSecuritySchemes("bearerAuth", bearerAuth)
.addSecuritySchemes("apiKeyAuth", apiKeyAuth);
// Add global security requirements
openAPI.addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
.addSecurityItem(new SecurityRequirement().addList("apiKeyAuth"))
.addSecurityItem(new SecurityRequirement().addList("oauth2"));
}
private Scopes createOAuth2Scopes() {
return new Scopes()
.addString("read:markets", "Read access to market data")
.addString("write:trades", "Execute trades and orders")
.addString("read:portfolio", "Read portfolio information")
.addString("write:portfolio", "Modify portfolio settings")
.addString("admin:users", "Administrative access to user management")
.addString("admin:system", "System administration privileges");
}
@Override
public int getPriority() {
return 100; // High priority for security configuration
}
}
Register the customizer on the module's configuration once the OpenAPI module has been initialized, for example from your application's startup code:
OpenApiConfiguration config = OpenApiModule.getConfiguration(configContext); config.setCustomizer(new SecuritySchemeCustomizer());
Only one customizer is active at a time; to apply several, call them from a single customizer.
Advanced SwaggerUI Customization
The OpenAPI module provides SwaggerUI customization capabilities for enterprise branding and functionality.
Complete SwaggerUI Configuration
Only openapi.swaggerUi.enabled, openapi.swaggerUi.version and the two openapi.swaggerUi.integrity.* keys are read from properties (see Properties File Configuration). The display options are set in code on the module's SwaggerUiConfig:
SwaggerUiConfig ui = OpenApiModule.getConfiguration(configContext).getSwaggerUiConfig();
// UI behavior
ui.setDeepLinking(true);
ui.setDocExpansion("none"); // none, list, full
ui.setFilter(true);
ui.setDisplayOperationId(true);
ui.setDisplayRequestDuration(true);
ui.setDefaultModelsExpandDepth(2);
ui.setDefaultModelExpandDepth(2);
ui.setMaxDisplayedTags(20);
// Request/response
ui.setShowRequestHeaders(true);
ui.setShowResponseHeaders(true);
ui.setSupportedSubmitMethods(new String[] {"get", "post", "put", "delete", "patch"});
ui.setOauth2RedirectUrl("https://api.company.com/swagger-ui/oauth2-redirect.html");
// Custom styling
ui.setCustomCss("/assets/corporate-swagger-theme.css");
ui.setCustomJs("/assets/swagger-enhancements.js");
Corporate Branding with Custom CSS
Create corporate-themed SwaggerUI with custom CSS (/assets/corporate-swagger-theme.css):
/* Corporate theme for SwaggerUI */
.swagger-ui .topbar {
background-color: #1e3a8a;
border-bottom: 3px solid #3b82f6;
}
.swagger-ui .topbar .download-url-wrapper .select-label {
color: #ffffff;
}
.swagger-ui .info .title {
color: #1e3a8a;
font-size: 2.5em;
font-weight: 600;
}
.swagger-ui .info .description {
font-size: 1.1em;
line-height: 1.6;
color: #4b5563;
}
/* Corporate header styling */
.corporate-header {
background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%);
color: white;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
}
.corporate-header h1 {
margin: 0;
font-size: 2em;
font-weight: 600;
}
.corporate-header p {
margin: 10px 0 0 0;
opacity: 0.9;
font-size: 1.1em;
}
/* Enhanced operation styling */
.swagger-ui .opblock.opblock-post {
border-color: #059669;
background: rgba(5, 150, 105, 0.1);
}
.swagger-ui .opblock.opblock-get {
border-color: #0284c7;
background: rgba(2, 132, 199, 0.1);
}
.swagger-ui .opblock.opblock-put {
border-color: #ea580c;
background: rgba(234, 88, 12, 0.1);
}
.swagger-ui .opblock.opblock-delete {
border-color: #dc2626;
background: rgba(220, 38, 38, 0.1);
}
/* Security badge styling */
.swagger-ui .auth-wrapper .authorize {
background: #059669;
border-color: #059669;
}
.swagger-ui .auth-wrapper .authorize:hover {
background: #047857;
border-color: #047857;
}
/* Enhanced model styling */
.swagger-ui .model-box {
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 6px;
}
.swagger-ui .model .model-title {
color: #1e3a8a;
font-weight: 600;
}
Custom JavaScript Enhancements
Add advanced functionality with custom JavaScript (/assets/swagger-enhancements.js):
// Corporate SwaggerUI enhancements
window.addEventListener('load', function() {
// Add corporate header
const infoSection = document.querySelector('.swagger-ui .info');
if (infoSection) {
const corporateHeader = document.createElement('div');
corporateHeader.className = 'corporate-header';
corporateHeader.innerHTML = `
Financial Services API
Enterprise-grade financial services with comprehensive security and monitoring
Please authenticate using the Authorize button above
OpenAPI Customizer Interface
The OpenApiCustomizer interface provides powerful post-processing capabilities for advanced OpenAPI specification enhancement.
Advanced Customizer Implementation
Register it with OpenApiModule.getConfiguration(configContext).setCustomizer(...), as shown in Programmatic Security Configuration.
public class EnterpriseOpenApiCustomizer implements OpenApiCustomizer {
private final ApiDocumentationService documentationService;
private final SecurityConfigurationService securityService;
@Override
public void customize(OpenAPI openAPI) {
// Enhanced API information
enhanceApiInformation(openAPI);
// Add enterprise security schemes
configureEnterpriseSecuritySchemes(openAPI);
// Add custom extensions
addCustomExtensions(openAPI);
// Configure advanced servers
configureServers(openAPI);
// Add comprehensive examples
addComprehensiveExamples(openAPI);
// Configure enterprise tags
configureEnterpriseTags(openAPI);
}
private void enhanceApiInformation(OpenAPI openAPI) {
Info info = openAPI.getInfo();
// Add comprehensive contact information
info.contact(new Contact()
.name("API Development Team")
.email("api-team@company.com")
.url("https://company.com/api-support")
.extensions(Map.of("x-team-slack", "#api-support"))
);
// Add detailed license information
info.license(new License()
.name("Commercial License")
.url("https://company.com/api-license")
.extensions(Map.of(
"x-license-type", "commercial",
"x-support-level", "enterprise"
))
);
// Add enterprise extensions
info.addExtension("x-api-category", "financial-services");
info.addExtension("x-compliance", Arrays.asList("SOC2", "PCI-DSS", "ISO27001"));
info.addExtension("x-rate-limits", Map.of(
"requests-per-minute", 1000,
"burst-requests", 100
));
}
private void configureEnterpriseSecuritySchemes(OpenAPI openAPI) {
Components components = openAPI.getComponents();
// OAuth2 with multiple flows
SecurityScheme oauth2 = new SecurityScheme()
.type(SecurityScheme.Type.OAUTH2)
.description("OAuth2 with PKCE support")
.flows(new OAuthFlows()
.authorizationCode(createAuthorizationCodeFlow())
.clientCredentials(createClientCredentialsFlow())
);
// JWT Bearer with detailed configuration
SecurityScheme jwtBearer = new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.description("JWT Bearer tokens with RS256 signing")
.addExtension("x-token-issuer", "https://auth.company.com")
.addExtension("x-token-audience", "financial-api")
.addExtension("x-token-expiry", "1h");
// Enterprise API key
SecurityScheme enterpriseApiKey = new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.name("X-API-Key")
.in(SecurityScheme.In.HEADER)
.description("Enterprise API key with role-based permissions")
.addExtension("x-key-rotation", "monthly")
.addExtension("x-permissions-model", "rbac");
components.addSecuritySchemes("oauth2", oauth2)
.addSecuritySchemes("jwtBearer", jwtBearer)
.addSecuritySchemes("enterpriseApiKey", enterpriseApiKey);
}
private OAuthFlow createAuthorizationCodeFlow() {
return new OAuthFlow()
.authorizationUrl("https://auth.company.com/oauth2/authorize")
.tokenUrl("https://auth.company.com/oauth2/token")
.refreshUrl("https://auth.company.com/oauth2/refresh")
.scopes(createDetailedScopes())
.addExtension("x-pkce-required", true)
.addExtension("x-token-lifetime", "1h")
.addExtension("x-refresh-token-lifetime", "30d");
}
private OAuthFlow createClientCredentialsFlow() {
return new OAuthFlow()
.tokenUrl("https://auth.company.com/oauth2/token")
.scopes(createServiceScopes())
.addExtension("x-client-authentication", "client_secret_jwt")
.addExtension("x-token-lifetime", "1h");
}
private Scopes createDetailedScopes() {
return new Scopes()
.addString("read:profile", "Read user profile information")
.addString("read:accounts", "Read account information and balances")
.addString("read:transactions", "Read transaction history")
.addString("write:trades", "Execute trades and manage orders")
.addString("read:market-data", "Access real-time market data")
.addString("write:portfolio", "Modify portfolio allocations")
.addString("admin:users", "Manage user accounts and permissions")
.addString("admin:system", "System administration privileges");
}
private void addCustomExtensions(OpenAPI openAPI) {
// Add enterprise-specific extensions
openAPI.addExtension("x-api-governance", Map.of(
"owner", "financial-services-team",
"lifecycle-stage", "production",
"sla-tier", "gold"
));
openAPI.addExtension("x-monitoring", Map.of(
"health-check", "/health",
"metrics", "/metrics",
"traces", "distributed-tracing-enabled"
));
openAPI.addExtension("x-documentation", Map.of(
"guides", "https://docs.company.com/api/guides",
"tutorials", "https://docs.company.com/api/tutorials",
"changelog", "https://docs.company.com/api/changelog"
));
}
private void configureServers(OpenAPI openAPI) {
openAPI.servers(Arrays.asList(
new Server()
.url("https://api.company.com")
.description("Production environment")
.addExtension("x-environment", "production")
.addExtension("x-region", "us-east-1"),
new Server()
.url("https://staging-api.company.com")
.description("Staging environment")
.addExtension("x-environment", "staging")
.addExtension("x-region", "us-east-1"),
new Server()
.url("https://dev-api.company.com")
.description("Development environment")
.addExtension("x-environment", "development")
.addExtension("x-region", "us-west-2")
));
}
@Override
public int getPriority() {
return 100;
}
@Override
public boolean shouldApply(OpenAPI openAPI) {
// Only apply to production and staging environments
String environment = System.getProperty("deployment.environment", "development");
return Arrays.asList("production", "staging").contains(environment);
}
}
Resource Management and Filtering
Resource filtering capabilities for large-scale enterprise APIs.
Intelligent Resource Discovery
# Resource filtering configuration openapi.readAllResources=false # Package-based filtering openapi.resourcePackages=com.company.api.v2,com.company.services.financial,com.company.auth # Route exclusion patterns openapi.ignoredRoutes=/internal/.*,/admin/.*,/health,/metrics,/actuator/.* # Service and operation exclusion openapi.ignoredServices=AdminService,MonitoringService openapi.ignoredOperations=TradeService/debugDump,ping
System services (such as Version and any service whose name contains AdminService) are excluded automatically.
Enterprise Integration Examples
Complete examples demonstrating modern enterprise patterns with comprehensive security and functionality.
Financial Trading API with Bearer Authentication
@Path("/api/v2/trading")
@Tag(name = "Trading API", description = "Enterprise trading services with comprehensive security")
@Component
public class TradingController {
@Autowired
private TradingService tradingService;
@Autowired
private JwtTokenValidator tokenValidator;
@POST
@Path("/orders")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Place trading order",
description = "Execute trading order with comprehensive validation and risk checks",
security = @SecurityRequirement(name = "jwtBearer")
)
@ApiResponses({
@ApiResponse(responseCode = "201", description = "Order placed successfully",
content = @Content(schema = @Schema(implementation = OrderResponse.class))),
@ApiResponse(responseCode = "400", description = "Invalid order parameters",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "401", description = "Authentication required",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "403", description = "Insufficient trading permissions",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "429", description = "Rate limit exceeded",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
public Response placeOrder(
@HeaderParam("Authorization") @Parameter(description = "Bearer JWT token") String bearerToken,
@Parameter(description = "Order details") @Valid OrderRequest orderRequest,
@Context HttpServletRequest request) {
try {
// Extract and validate JWT token
String jwt = extractJwtToken(bearerToken);
JwtClaims claims = tokenValidator.validateToken(jwt);
// Create user context with permissions
UserContext userContext = UserContext.builder()
.userId(claims.getSubject())
.email(claims.getStringClaim("email"))
.permissions(extractPermissions(claims))
.sessionId(claims.getJwtId())
.build();
// Validate trading permissions
validateTradingPermissions(userContext, orderRequest);
// Execute order with risk management
OrderResult result = tradingService.placeOrder(orderRequest, userContext);
// Build comprehensive response
OrderResponse response = OrderResponse.builder()
.orderId(result.getOrderId())
.status(result.getStatus())
.executionPrice(result.getExecutionPrice())
.executionTime(result.getExecutionTime())
.commission(result.getCommission())
.estimatedSettlement(result.getEstimatedSettlement())
.riskMetrics(result.getRiskMetrics())
.build();
return Response
.status(Response.Status.CREATED)
.entity(response)
.header("X-Order-Id", result.getOrderId())
.header("X-Request-Id", generateRequestId())
.build();
} catch (InvalidTokenException e) {
return createErrorResponse(Response.Status.UNAUTHORIZED, "INVALID_TOKEN", e.getMessage());
} catch (InsufficientPermissionsException e) {
return createErrorResponse(Response.Status.FORBIDDEN, "INSUFFICIENT_PERMISSIONS", e.getMessage());
} catch (OrderValidationException e) {
return createErrorResponse(Response.Status.BAD_REQUEST, "INVALID_ORDER", e.getMessage());
} catch (RiskLimitExceededException e) {
return createErrorResponse(Response.Status.BAD_REQUEST, "RISK_LIMIT_EXCEEDED", e.getMessage());
}
}
@GET
@Path("/orders/{orderId}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Get order status",
description = "Retrieve detailed order information and execution status",
security = @SecurityRequirement(name = "jwtBearer")
)
public Response getOrderStatus(
@HeaderParam("Authorization") String bearerToken,
@PathParam("orderId") @Parameter(description = "Order identifier") String orderId) {
String jwt = extractJwtToken(bearerToken);
JwtClaims claims = tokenValidator.validateToken(jwt);
UserContext userContext = createUserContext(claims);
OrderStatus status = tradingService.getOrderStatus(orderId, userContext);
OrderStatusResponse response = OrderStatusResponse.from(status);
return Response.ok(response)
.header("Cache-Control", "no-cache")
.header("X-Request-Id", generateRequestId())
.build();
}
private String extractJwtToken(String bearerToken) {
if (bearerToken == null || !bearerToken.startsWith("Bearer ")) {
throw new InvalidTokenException("Invalid Bearer token format");
}
return bearerToken.substring(7);
}
private Set<String> extractPermissions(JwtClaims claims) {
try {
return new HashSet<>(claims.getStringListClaim("permissions"));
} catch (Exception e) {
return Collections.emptySet();
}
}
private void validateTradingPermissions(UserContext userContext, OrderRequest orderRequest) {
if (!userContext.hasPermission("trade:execute")) {
throw new InsufficientPermissionsException("Trading permission required");
}
if (orderRequest.getOrderValue() > 100000 && !userContext.hasPermission("trade:large_orders")) {
throw new InsufficientPermissionsException("Large order permission required");
}
}
private Response createErrorResponse(Response.Status status, String errorCode, String message) {
ErrorResponse error = ErrorResponse.builder()
.errorCode(errorCode)
.message(message)
.timestamp(Instant.now())
.requestId(generateRequestId())
.build();
return Response.status(status)
.entity(error)
.header("X-Request-Id", error.getRequestId())
.build();
}
private String generateRequestId() {
return UUID.randomUUID().toString();
}
}
Modern Request/Response Models
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(description = "Trading order request with comprehensive validation")
public class OrderRequest {
@NotNull(message = "Symbol is required")
@Pattern(regexp = "[A-Z]{1,5}", message = "Invalid symbol format")
@Schema(description = "Stock symbol", required = true, example = "AAPL")
private String symbol;
@NotNull(message = "Order side is required")
@Schema(description = "Order side", required = true, allowableValues = {"BUY", "SELL"})
private OrderSide side;
@NotNull(message = "Quantity is required")
@DecimalMin(value = "0.01", message = "Quantity must be positive")
@Schema(description = "Order quantity", required = true, example = "100")
private BigDecimal quantity;
@NotNull(message = "Order type is required")
@Schema(description = "Order type", required = true, allowableValues = {"MARKET", "LIMIT", "STOP", "STOP_LIMIT"})
private OrderType orderType;
@Schema(description = "Limit price (required for LIMIT and STOP_LIMIT orders)", example = "150.50")
private BigDecimal limitPrice;
@Schema(description = "Stop price (required for STOP and STOP_LIMIT orders)", example = "145.00")
private BigDecimal stopPrice;
@NotNull(message = "Time in force is required")
@Schema(description = "Time in force", required = true, allowableValues = {"DAY", "GTC", "IOC", "FOK"})
private TimeInForce timeInForce;
@Schema(description = "Client order ID for tracking", example = "CLIENT-ORDER-123")
private String clientOrderId;
@Valid
@Schema(description = "Additional order parameters")
private OrderParameters parameters;
// Constructors, getters, setters, builder pattern
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(description = "Trading order response with execution details")
public class OrderResponse {
@Schema(description = "Unique order identifier", example = "ORD-12345678")
private String orderId;
@Schema(description = "Current order status", allowableValues = {"PENDING", "FILLED", "PARTIALLY_FILLED", "CANCELLED", "REJECTED"})
private OrderStatus status;
@Schema(description = "Order submission timestamp", example = "2023-12-21T15:30:00Z")
private Instant submissionTime;
@Schema(description = "Execution price (if filled)", example = "150.25")
private BigDecimal executionPrice;
@Schema(description = "Filled quantity", example = "100")
private BigDecimal filledQuantity;
@Schema(description = "Remaining quantity", example = "0")
private BigDecimal remainingQuantity;
@Schema(description = "Commission charged", example = "0.99")
private BigDecimal commission;
@Schema(description = "Estimated settlement date", example = "2023-12-23")
private LocalDate estimatedSettlement;
@Valid
@Schema(description = "Risk metrics for this order")
private RiskMetrics riskMetrics;
@Schema(description = "Execution venue", example = "NASDAQ")
private String venue;
// Constructors, getters, setters, builder pattern
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(description = "Risk metrics and compliance information")
public class RiskMetrics {
@Schema(description = "Position delta after execution", example = "0.15")
private BigDecimal positionDelta;
@Schema(description = "Portfolio value at risk", example = "25000.00")
private BigDecimal valueAtRisk;
@Schema(description = "Regulatory compliance status")
private ComplianceStatus complianceStatus;
@Schema(description = "Risk limit utilization percentage", example = "45.5")
private BigDecimal riskUtilization;
// Additional risk metrics...
}
Performance and Monitoring
Enterprise-grade performance optimization and monitoring capabilities for production deployments.
Performance Configuration
The OpenAPI module has no performance properties of its own. The specification responses carry a Cache-Control max-age of five minutes and static Swagger UI resources one of 24 hours, so a reverse proxy or CDN can cache them. Response compression, connection pooling and timeouts are configured in the servlet container or proxy.
Monitoring and Observability
@Component
public class OpenApiMetricsCollector {
private final MeterRegistry meterRegistry;
private final Timer specGenerationTimer;
private final Counter apiCallCounter;
private final Gauge activeConnectionsGauge;
public OpenApiMetricsCollector(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.specGenerationTimer = Timer.builder("openapi.spec.generation.time")
.description("Time taken to generate OpenAPI specification")
.register(meterRegistry);
this.apiCallCounter = Counter.builder("openapi.api.calls")
.description("Total API calls processed")
.register(meterRegistry);
this.activeConnectionsGauge = Gauge.builder("openapi.connections.active")
.description("Active connections to OpenAPI endpoints")
.register(meterRegistry, this, OpenApiMetricsCollector::getActiveConnections);
}
public void recordSpecGeneration(Duration duration) {
specGenerationTimer.record(duration);
}
public void recordApiCall(String endpoint, String method, int statusCode) {
apiCallCounter.increment(
Tags.of(
"endpoint", endpoint,
"method", method,
"status", String.valueOf(statusCode)
)
);
}
private double getActiveConnections() {
// Implementation to get active connections
return 0.0;
}
}
@Component
public class OpenApiHealthIndicator implements HealthIndicator {
private final OpenApiSpecGenerator specGenerator;
private final SwaggerUIHandler uiHandler;
@Override
public Health health() {
try {
// Check OpenAPI spec generation
long startTime = System.currentTimeMillis();
specGenerator.generateOpenApiSpec(null);
long specGenTime = System.currentTimeMillis() - startTime;
// Check SwaggerUI availability
boolean uiAvailable = uiHandler.getConfiguration().isSupportSwaggerUi();
return Health.up()
.withDetail("specGenerationTime", specGenTime + "ms")
.withDetail("swaggerUiEnabled", uiAvailable)
.withDetail("configurationSource", getConfigurationSource())
.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.withException(e)
.build();
}
}
private String getConfigurationSource() {
// Determine primary configuration source
return "properties-file";
}
}
Cloud-Native Deployment
Configuration and deployment patterns for cloud-native and containerized environments.
Docker Configuration
# Dockerfile FROM tomcat:11.0-jdk21 # OpenAPI settings are read from system properties (not environment variables) ENV JAVA_OPTS="-Dopenapi.swaggerUi.enabled=false -Dopenapi.resourcePackages=com.company.api.v2" # Copy application; openapi.properties in Tomcat's lib directory is on the classpath COPY target/financial-api.war /usr/local/tomcat/webapps/ COPY config/openapi-production.properties /usr/local/tomcat/lib/openapi.properties EXPOSE 8080 CMD ["catalina.sh", "run"]
Kubernetes Configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: openapi-config
data:
openapi.properties: |
openapi.title=Financial Services API
openapi.version=2.1.0
openapi.serverBaseUrl=https://api.company.com/axis2
openapi.swaggerUi.enabled=false
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: financial-api
spec:
replicas: 3
selector:
matchLabels:
app: financial-api
template:
metadata:
labels:
app: financial-api
spec:
containers:
- name: api
image: company/financial-api:2.1.0
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-Dopenapi.title=Production-Financial-API"
volumeMounts:
- name: openapi-config
mountPath: /usr/local/tomcat/lib/openapi.properties
subPath: openapi.properties
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /openapi.json
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: openapi-config
configMap:
name: openapi-config
Enterprise Security Best Practices
Comprehensive security guidelines for production OpenAPI deployments.
Production Security Checklist
- ✓ JWT Token Validation: Implement proper JWT signature verification and expiration checking
- ✓ OAuth2 PKCE: Enforce PKCE for public clients and authorization code flows
- ✓ CORS Configuration: The specification endpoints send
Access-Control-Allow-Origin: *; restrict origins at the proxy or container if you need to - ✓ Rate Limiting: Implement rate limiting per API key/user to prevent abuse
- ✓ Input Validation: Validate all request parameters against OpenAPI schemas
- ✓ HTTPS Only: Enforce HTTPS for all API endpoints and disable HTTP
- ✓ Security Headers: Include security headers (HSTS, CSP, X-Frame-Options)
- ✓ API Key Rotation: Implement regular API key rotation policies
- ✓ Audit Logging: Log all API access and authentication events
- ✓ SwaggerUI Security: Disable SwaggerUI in production or restrict access
Security Configuration Example
The OpenAPI module's own security-relevant settings are few:
# Disable SwaggerUI in production openapi.swaggerUi.enabled=false # Publish a fixed absolute server URL instead of a relative one openapi.serverBaseUrl=https://api.company.com/axis2
HTTPS enforcement, HSTS, CORS restrictions, rate limiting and audit logging are not OpenAPI module settings; configure them in the servlet container, a servlet filter or the reverse proxy. The Swagger UI page sets its own Content-Security-Policy with a per-request nonce, and loads the default Swagger UI version with Subresource Integrity.
Troubleshooting and Advanced Topics
Common issues and advanced configuration scenarios for enterprise deployments.
Common Configuration Issues
- Configuration Precedence: System properties override properties files, which override module.xml parameters; environment variables are not read
- Security Scheme Validation: Ensure OAuth2 endpoints are accessible and properly configured
- Resource Filtering: Verify package names and class paths are correct
- Memory Usage: Monitor memory usage with large OpenAPI specifications
- Performance: Let a proxy or CDN cache the specification responses, which carry a Cache-Control max-age
Advanced Debugging
# Enable debug logging for the OpenAPI module (log4j2 example) <Logger name="org.apache.axis2.openapi" level="debug"/>
At startup the module logs the configuration sources it loaded (for example "Loaded OpenAPI configuration from: openapi.properties") and the resulting configuration.
For comprehensive support and advanced enterprise deployment scenarios, contact the Apache Axis2 development team or consult the Basic OpenAPI User Guide for fundamental concepts.
This advanced guide demonstrates the full enterprise capabilities of Axis2's OpenAPI integration. The system provides the flexibility and power needed for modern enterprise API development while maintaining the reliability and performance expected in production environments.
Apache Axis2
