Skip to content

Implement CDI Interceptors for @CloseDBIfOpened and @WrapInTransaction #34482

@spbolton

Description

@spbolton

Description

Implement CDI interceptor bindings for all 6 ByteBuddy Advice annotations to make them work correctly on CDI beans.

Background

ByteBuddy annotations currently fail silently on @ApplicationScoped CDI beans because Weld proxies do not copy method annotations. ByteBuddy's class matcher uses declaresMethod(isAnnotatedWith(...)) which cannot see annotations on proxy classes. This was the root cause of the connection leak fixed in #34134.

Current ByteBuddy Annotations (from ByteBuddyFactory):

  1. @CloseDB → CloseDBAdvice - Closes and commits DB connection at method exit
  2. @CloseDBIfOpened → CloseDBIfOpenedAdvice - Closes DB connection only if opened during method
  3. @WrapInTransaction → WrapInTransactionAdvice - Wraps method in database transaction
  4. @ExternalTransaction → ExternalTransactionAdvice - Creates separate transaction context
  5. @logtime → LogTimeAdvice - Logs method execution time with configurable level
  6. @EnterpriseFeature → EnterpriseFeatureAdvice - Validates enterprise license level before execution

Implementation Approach

For each annotation, implement CDI interceptor:

1. Database Connection/Transaction Annotations (@CloseDB, @CloseDBIfOpened, @WrapInTransaction, @ExternalTransaction):

  • Add @InterceptorBinding meta-annotation to each
  • Create corresponding interceptor classes with @AroundInvoke
  • Replicate ByteBuddy advice logic in interceptor methods
  • Handle connection lifecycle, transaction boundaries, and cleanup

2. Performance/Observability Annotations (@logtime):

  • Add @InterceptorBinding meta-annotation
  • Create LogTimeInterceptor with @AroundInvoke
  • Use StopWatch to measure execution time
  • Support configurable logging level (INFO/DEBUG)

3. Security/License Annotations (@EnterpriseFeature):

  • Add @InterceptorBinding meta-annotation
  • Create EnterpriseFeatureInterceptor with @AroundInvoke
  • Validate license level before method execution
  • Throw DotInvalidLicenseException if requirements not met

4. Enable interceptors in beans.xml:

<interceptors>
    <class>com.dotcms.business.interceptor.CloseDBInterceptor</class>
    <class>com.dotcms.business.interceptor.CloseDBIfOpenedInterceptor</class>
    <class>com.dotcms.business.interceptor.WrapInTransactionInterceptor</class>
    <class>com.dotcms.business.interceptor.ExternalTransactionInterceptor</class>
    <class>com.dotcms.business.interceptor.LogTimeInterceptor</class>
    <class>com.dotcms.business.interceptor.EnterpriseFeatureInterceptor</class>
</interceptors>

Technical Details

Why Both ByteBuddy and CDI Interceptors Can Coexist:

  • ByteBuddy: Fires on non-CDI classes (instrumented at class load time)
  • CDI Interceptors: Fire on CDI beans at proxy boundary (runtime)
  • Both use same lifecycle guards (e.g., isNewConnection) to prevent double-processing
  • Result: Annotations work correctly everywhere with backward compatibility

Priority Order (Critical → Nice-to-Have):

  1. @CloseDBIfOpened - Connection leak prevention (showstopper bug)
  2. @WrapInTransaction - Data integrity (high priority)
  3. @CloseDB - Resource management (high priority)
  4. @ExternalTransaction - Transaction isolation (medium priority)
  5. @EnterpriseFeature - License enforcement (medium priority)
  6. @logtime - Observability (low priority)

Benefits

  • Fixes 7+ known legacy violations in UniqueFieldDataBaseUtil, JobQueueManagerAPIImpl, MetricsAPIImpl, CustomAttributeAPIImpl, HostWebAPIImpl, DBUniqueFieldValidationStrategy
  • Eliminates manual wrapping - No more LocalTransaction.wrapReturn() boilerplate
  • Prevents future leaks - Annotations work correctly on CDI beans
  • Backward compatible - Non-CDI code continues to use ByteBuddy
  • Consistent behavior - Same semantics across CDI and non-CDI classes

Acceptance Criteria

  • All 6 annotations converted to @InterceptorBinding (backward compatible)
  • CDI interceptor classes implemented for each annotation
  • Interceptors enabled in beans.xml
  • Unit tests verify interceptors fire correctly on CDI beans
  • Integration tests verify no double-processing (ByteBuddy + CDI)
  • ArchUnit test updated to allow annotations on CDI beans after interceptors enabled
  • Known legacy violations migrated or documented
  • Performance impact measured (interceptor overhead vs ByteBuddy)

Testing Strategy

  1. Unit Tests: Mock CDI context, verify interceptor invocation
  2. Integration Tests: Real CDI beans with annotations, verify behavior
  3. Compatibility Tests: Ensure ByteBuddy still works on non-CDI classes
  4. Performance Tests: Measure overhead of CDI interceptors vs ByteBuddy
  5. Leak Tests: Run MetricsStatsCollector repeatedly, verify no connection leaks

References

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Status

    New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions