jbonofre commented on code in PR #739:
URL: https://github.com/apache/camel-karaf/pull/739#discussion_r3851027127


##########
core/camel-core-osgi/src/main/java/org/apache/camel/karaf/core/OsgiTypeConverter.java:
##########
@@ -100,8 +100,17 @@ public void 
modifiedService(ServiceReference<TypeConverterLoader> serviceReferen
     }
 
     @Override
-    public void removedService(ServiceReference<TypeConverterLoader> 
serviceReference, Object o) {
+    public synchronized void 
removedService(ServiceReference<TypeConverterLoader> serviceReference, Object 
o) {
         LOG.trace("RemovedService: {}, Bundle: {}", serviceReference, 
serviceReference.getBundle());
+        if (this.delegate != null) {
+            // the rebuild in createRegistry replays the core converters and 
the loaders the tracker still

Review Comment:
   When `removedService()` stops the entire delegate and `createRegistry()` 
rebuilds it, only converters discovered via the `ServiceTracker` are replayed. 
Converters registered programmatically via `addTypeConverter()`, 
`addBulkTypeConverters()`, or `addFallbackTypeConverter()`, including Blueprint 
bean-registered converters, are silently dropped with the old delegate.
   
   Routes relying on those converters will fail with 
`NoTypeConversionAvailableException` after any bundle uninstalls a 
`TypeConverterLoader`, with no diagnostic pointing to the root cause. The log 
warning is insufficient. Either:
   - Maintain a separate replay list of programmatically registered converters 
and re-apply them in `createRegistry()`.
   - Abandon full-delegate teardown in favour of partial removal (unloading 
only the converters contributed by the departing loader).



##########
core/camel-core-osgi/src/main/java/org/apache/camel/karaf/core/OsgiTypeConverter.java:
##########
@@ -242,15 +251,26 @@ public void setTypeConverterExists(TypeConverterExists 
typeConverterExists) {
     }
 
     public DefaultTypeConverter getDelegate() {
-        if (delegate == null) {
-            // ensure the tracker is open so we can discover 
TypeConverterLoader services

Review Comment:
   The fast path reads `answer = delegate` (volatile) and, if non-null, skips 
the `synchronized` block and returns `answer` directly to the caller. However, 
a concurrent `removedService()` (holding `synchronized(this)`) can call 
`ServiceHelper.stopService(this.delegate)` and set `this.delegate = null` 
*after* Thread A's null-check but *before* Thread A uses the returned value. 
Thread A then calls conversion methods on a stopped converter, resulting in 
`IllegalStateException` or silent data loss.
   
   DCL is only safe when the published object is truly immutable after 
publication. A delegate that can be stopped and replaced does not meet that 
bar. Consider always going through the lock in `getDelegate()` — type 
conversion is not so hot that the lock overhead is measurable compared to 
actual conversion work.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to