docs: synchronized void activateLazily() {
          if (cacheManager != null)
              return; // lazy initialization has already completed
  
          final boolean trace = TraceComponent.isAnyTracingEnabled();
          
          Properties vendorProperties = new Properties();
          
          String uriValue = (String) configurationProperties.get("uri");
          final URI uri;
          if (uriValue != null)
              try {
                  uri = new URI(uriValue);
              } catch (URISyntaxException e) {
                  throw new IllegalArgumentException(Tr.formatMessage(tc, "INCORRECT_URI_SYNTAX", e), e);
              }
          else
              uri = null;
          
          for (Map.Entry<String, Object> entry : configurationProperties.entrySet()) {
              String key = entry.getKey();
              Object value = entry.getValue();
  
              //properties start with properties.0.
              if (key.length () > TOTAL_PREFIX_LENGTH && key.charAt(BASE_PREFIX_LENGTH) == '.' && key.startsWith(BASE_PREFIX)) {
                  key = key.substring(TOTAL_PREFIX_LENGTH);
                  if (!key.equals("config.referenceType")) 
                      vendorProperties.setProperty(key, (String) value);
              }
          }
  
          // load JCache provider from configured library, which is either specified as a libraryRef or via a bell
          final ClassLoader cl = library.getClassLoader();
  
          try {
              AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
                  ClassLoader loader = new CachingProviderClassLoader(cl);
  
                  if (trace && tc.isDebugEnabled())
                      CacheHashMap.tcInvoke("Caching", "getCachingProvider", loader);
  
                  cachingProvider = Caching.getCachingProvider(loader);
  
                  tcCachingProvider = "CachingProvider" + Integer.toHexString(System.identityHashCode(cachingProvider));
  
                  if (trace && tc.isDebugEnabled()) {
                      CacheHashMap.tcReturn("Caching", "getCachingProvider", tcCachingProvider, cachingProvider);
                      Tr.debug(this, tc, "caching provider class is " + cachingProvider.getClass().getName());
                      CacheHashMap.tcInvoke(tcCachingProvider, "getCacheManager", uri, null, vendorProperties);
                  }
  
                  cacheManager = cachingProvider.getCacheManager(uri, null, vendorProperties);
  
                  return null;
              });
  
              tcCacheManager = "CacheManager" + Integer.toHexString(System.identityHashCode(cacheManager));
  
              if (trace && tc.isDebugEnabled()) {
                  CacheHashMap.tcReturn(tcCachingProvider, "getCacheManager", tcCacheManager, cacheManager);
                  CacheHashMap.tcInvoke(tcCachingProvider, "isSupported", "STORE_BY_REFERENCE");
              }
  
              supportsStoreByReference = cachingProvider.isSupported(OptionalFeature.STORE_BY_REFERENCE);
  
              if (trace && tc.isDebugEnabled())
                  CacheHashMap.tcReturn(tcCachingProvider, "isSupported", supportsStoreByReference);
          } catch (CacheException x) {
              if (library.getFiles().isEmpty()) {
                  Tr.error(tc, "ERROR_CONFIG_EMPTY_LIBRARY", library.id(), Tr.formatMessage(tc, "SESSION_CACHE_CONFIG_MESSAGE", RuntimeUpdateListenerImpl.sampleConfig));
              }
              throw x;
          } catch (Error | RuntimeException x) {
              // deactivate will not be invoked if activate fails, so ensure CachingProvider is closed on error paths
              if (cachingProvider != null) {
                  CacheHashMap.tcInvoke(tcCachingProvider, "close");
                  cachingProvider.close();
                  CacheHashMap.tcReturn(tcCachingProvider, "close");
              }
              throw x;
          }
      }