Federico Mariani created CAMEL-24757:
----------------------------------------

             Summary: camel-spring-boot: Spring Cache-backed KeyValueRepository 
adapter for the State Store component
                 Key: CAMEL-24757
                 URL: https://issues.apache.org/jira/browse/CAMEL-24757
             Project: Camel
          Issue Type: New Feature
          Components: camel-spring-boot
            Reporter: Federico Mariani


h2. Background

The State Store component (camel-state-store, since 4.23) provides a unified 
key-value API (put/get/putIfAbsent/delete/contains/keys/size/clear) backed by 
the pluggable {{KeyValueRepository}} SPI from camel-api. When no backend bean 
is configured, it falls back to the in-memory {{MemoryKeyValueRepository}}; for 
anything persistent/distributed, camel-api already ships implementations for 
Caffeine, Cassandra, Ehcache, Hazelcast, Infinispan, JCache, JDBC, JPA, Kafka 
and Redis.

h2. Problem

Those implementations don't line up with what Spring Boot users already have 
auto-configured:

* {{RedisKeyValueRepository}} (camel-redis) is built on *Redisson* 
({{RedissonClient}}), not Spring Data Redis (Lettuce/{{RedisTemplate}}), which 
is what {{spring-boot-starter-data-redis}} actually auto-configures. A Spring 
Boot user has to add Redisson separately and hand-wire a {{RedissonClient}} 
bean just to get a {{KeyValueRepository}}.
* The same friction applies to Caffeine/Ehcache/Hazelcast: Camel's 
implementations expect Camel-flavored construction, not the {{CacheManager}} 
bean that {{spring-boot-starter-cache}} already auto-configures from 
{{spring.cache.type}}.

So in a Spring Boot application, using the State Store component with a real 
backend currently means adding a second, Camel-specific client/dependency and 
manually wiring a bean, even when Spring Boot already manages an equivalent 
cache/client for you.

h2. Proposal

Add a {{KeyValueRepository}} implementation in *camel-spring-boot* (core 
auto-configuration module, not the generated starter) backed by Spring's cache 
abstraction ({{org.springframework.cache.Cache}} / {{CacheManager}}). 
Auto-configure it with {{@ConditionalOnBean(CacheManager.class)}} and 
{{@ConditionalOnMissingBean(KeyValueRepository.class)}}, so it only kicks in 
when the application already has a Spring-managed {{CacheManager}} and no 
explicit Camel {{KeyValueRepository}} bean.

One adapter then covers every backend Spring Boot's cache abstraction already 
supports (Caffeine, Redis via Lettuce, Ehcache, Hazelcast, JCache, Couchbase, 
etc.) via the standard {{spring.cache.*}} properties, with no extra 
Camel-specific dependency or bean.

The State Store endpoint's {{storeName}} would map 1:1 to the Spring {{Cache}} 
name looked up via {{CacheManager.getCache(storeName)}}.

h2. Example usage

Caffeine, using only spring-boot-starter-cache (no camel-caffeine dependency 
needed):
{code:yaml}
spring:
  cache:
    type: caffeine
    cache-names: myStore
    caffeine:
      spec: maximumSize=10000,expireAfterWrite=600s
{code}
{code:java}
from("direct:store")
    .setHeader("CamelStateStoreKey", constant("myKey"))
    .to("state-store:myStore?operation=put");

from("direct:retrieve")
    .setHeader("CamelStateStoreKey", constant("myKey"))
    .to("state-store:myStore?operation=get");
{code}

Redis via Spring Data Redis/Lettuce (no camel-redis/Redisson dependency needed):
{code:yaml}
spring:
  cache:
    type: redis
    cache-names: myStore
  data:
    redis:
      host: localhost
      port: 6379
{code}
Same route code as above - only the Spring Boot configuration changes to switch 
backend.

h2. Limitations

* *No {{keys()}} support* - Spring's {{Cache}} SPI has no portable key 
enumeration across backends, so the adapter would throw 
{{UnsupportedOperationException}} for the {{keys}} operation.
* *No {{size()}} support* - same reason as above; {{size}} would also throw 
{{UnsupportedOperationException}}.
* *No per-entry TTL* - Spring's {{Cache.put}} has no TTL parameter; TTL is 
fixed per cache/CacheManager configuration (e.g. the Caffeine spec or Redis 
entry-ttl config), not per message. The State Store {{ttl}} endpoint option and 
{{CamelStateStoreTtl}} header would have no effect against this backend; the 
adapter should log a WARN if a TTL is supplied so the mismatch isn't silent.
* *Spring Boot only* - this lives in camel-spring-boot, not camel-api/core, so 
it is not available to other runtimes (Quarkus, camel-main, etc.); those keep 
using the existing backend-specific KeyValueRepository implementations.
* *Cache pre-declaration* - some {{CacheManager}} implementations require cache 
names to be pre-declared (e.g. via {{spring.cache.cache-names}}); a 
{{storeName}} without a matching configured cache would fail to resolve, unlike 
the always-available in-memory default.

_Claude Code on behalf of Federico Mariani_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to