docs: @Override
      public ResourceFactory createResourceFactory(Map<String, Object> props) throws Exception {
          final boolean trace = TraceComponent.isAnyTracingEnabled();
          if (trace && tc.isEntryEnabled())
              Tr.entry(tc, "createResourceFactory", props);
  
          Hashtable<String, Object> adminObjectSvcProps = new Hashtable<String, Object>();
  
          Map<String, Object> annotationProps = new HashMap<String, Object>();
  
          // Initially copy everything into vendor properties and expand any variables
          VariableRegistry variableRegistry = variableRegistryRef.getServiceWithException();
          for (Map.Entry<String, Object> prop : props.entrySet()) {
              Object value = prop.getValue();
              if (value instanceof String)
                  value = variableRegistry.resolveRawString((String) value);
              annotationProps.put(prop.getKey(), value);
          }
  
          String application = (String) annotationProps.remove(AppDefinedResource.APPLICATION);
          String declaringApplication = (String) annotationProps.remove(DECLARING_APPLICATION);
  
          if (trace && tc.isDebugEnabled())
              Tr.debug(tc, "application : " + application + "  declaringApplication : " + declaringApplication);
  
          String module = (String) annotationProps.remove(AppDefinedResource.MODULE);
          String component = (String) annotationProps.remove(AppDefinedResource.COMPONENT);
          String jndiName = (String) annotationProps.remove(AdminObjectService.JNDI_NAME);
          annotationProps.remove(DESCRIPTION);
          annotationProps.remove(NAME);
  
          String adminObjectID = getadminObjectID(application, module, component, jndiName);
  
          StringBuilder filter = new StringBuilder(FilterUtils.createPropertyFilter(ID, adminObjectID));
          filter.insert(filter.length() - 1, '*');
          // Fail if server.xml is already using the id
          if (!removeExistingConfigurations(filter.toString()))
              throw new IllegalArgumentException(adminObjectID); // internal error, shouldn't ever have been permitted in server.xml
  
          adminObjectSvcProps.put(ID, adminObjectID);
          adminObjectSvcProps.put(CONFIG_DISPLAY_ID, adminObjectID);
          // Use the unique identifier because jndiName is not always unique for app-defined data sources
          adminObjectSvcProps.put(UNIQUE_JNDI_NAME, adminObjectID);
  
          adminObjectSvcProps.put(ResourceFactory.JNDI_NAME, jndiName);
          if (application != null) {
              adminObjectSvcProps.put(AppDefinedResource.APPLICATION, application);
              if (module != null) {
                  adminObjectSvcProps.put(AppDefinedResource.MODULE, module);
                  if (component != null)
                      adminObjectSvcProps.put(AppDefinedResource.COMPONENT, component);
              }
          }
          String resourceAdapter = (String) annotationProps.remove(RESOURCE_ADAPTER);
          String interfaceName = (String) annotationProps.remove(INTERFACE_NAME);
          String className = (String) annotationProps.remove(CLASS_NAME);
  
          //Handle embedded RA as in 18.9
          if (resourceAdapter.startsWith(EMBEDDED_RA_PREFIX)) {
              resourceAdapter = declaringApplication + "." + resourceAdapter.substring(resourceAdapter.indexOf(EMBEDDED_RA_PREFIX) + 1, resourceAdapter.length());
              if (trace && tc.isDebugEnabled())
                  Tr.debug(tc, "Embedded resourceAdapter name : " + resourceAdapter);
          }
          Dictionary<String, Object> adminObjectDefaultProps = getDefaultProperties(resourceAdapter, interfaceName, className);
  
          for (Enumeration<String> keys = adminObjectDefaultProps.keys(); keys.hasMoreElements();) {
              String key = keys.nextElement();
              Object value = adminObjectDefaultProps.get(key);
  
              //Override the administered object default property values with values provided annotation
              if (annotationProps.containsKey(key))
                  value = annotationProps.remove(key);
  
              if (value instanceof String)
                  value = variableRegistry.resolveString((String) value);
  
              adminObjectSvcProps.put(BASE_PROPERTIES_KEY + key, value);
          }
  
          adminObjectSvcProps.put(BOOTSTRAP_CONTEXT, "(id=" + resourceAdapter + ")");
  
          for (Map.Entry<String, Object> prop : annotationProps.entrySet())
              adminObjectSvcProps.put(BASE_PROPERTIES_KEY + prop.getKey(), prop.getValue());
  
          BundleContext bundleContext = priv.getBundleContext(FrameworkUtil.getBundle(AdminObjectService.class));
  
          StringBuilder adminObjectFilter = new StringBuilder(200);
          adminObjectFilter.append("(&").append(FilterUtils.createPropertyFilter(ID, adminObjectID));
          adminObjectFilter.append(FilterUtils.createPropertyFilter(Constants.OBJECTCLASS, AdminObjectService.class.getName())).append(")");
  
          ResourceFactory factory = new AppDefinedResourceFactory(this, bundleContext, adminObjectID, adminObjectFilter.toString(), declaringApplication);
          try {
  
              String bundleLocation = bundleContext.getBundle().getLocation();
              ConfigurationAdmin configAdmin = configAdminRef.getService();
  
              Configuration adminObjectSvcConfig = configAdmin.createFactoryConfiguration(AdminObjectService.ADMIN_OBJECT_PID, bundleLocation);
              adminObjectSvcConfig.update(adminObjectSvcProps);
          } catch (Exception x) {
              factory.destroy();
              throw x;
          } catch (Error x) {
              factory.destroy();
              throw x;
          }
  
          if (trace && tc.isEntryEnabled())
              Tr.exit(tc, "createResourceFactory", factory);
          return factory;
      }