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);
  
          //Holds ConnectionManagerService properties
          Hashtable<String, Object> cmSvcProps = new Hashtable<String, Object>();
          //Holds Connection Factory service properties
          Hashtable<String, Object> connectionFactorySvcProps = new Hashtable<String, Object>();
          //Store all the props from annotation as well as from deployment descriptor
          Map<String, Object> annotationDDProps = new HashMap<String, Object>();
  
          //Just move all the properties from props to annotationProps after resolving strings.
          VariableRegistry variableRegistry = variableRegistryRef.getServiceWithException();
          for (Map.Entry<String, Object> prop : props.entrySet()) {
              Object value = prop.getValue();
              if (value instanceof String)
                  value = variableRegistry.resolveString((String) value);
              annotationDDProps.put(prop.getKey(), value);
          }
  
          String application = (String) annotationDDProps.remove(AppDefinedResource.APPLICATION);
          String declaringApplication = (String) annotationDDProps.remove(DECLARING_APPLICATION);
          String module = (String) annotationDDProps.remove(AppDefinedResource.MODULE);
          String component = (String) annotationDDProps.remove(AppDefinedResource.COMPONENT);
          String jndiName = (String) annotationDDProps.remove(ResourceFactory.JNDI_NAME);
  
          String connectionFactoryID = getConnectionFactoryID(application, module, component, jndiName);
          String conManagerID = connectionFactoryID + '/' + ConnectionManagerService.CONNECTION_MANAGER;
  
          String conManagerFilter = FilterUtils.createPropertyFilter(ID, conManagerID);
  
          StringBuilder filter = new StringBuilder(FilterUtils.createPropertyFilter(ID, connectionFactoryID));
          filter.insert(filter.length() - 1, '*');
          // Fail if server.xml is already using the id
          if (!removeExistingConfigurations(filter.toString()))
              throw new IllegalArgumentException(connectionFactoryID); // internal error, shouldn't ever have been permitted in server.xml
  
          cmSvcProps.put(ID, conManagerID);
          cmSvcProps.put(CONFIG_DISPLAY_ID, conManagerID);
  
          connectionFactorySvcProps.put(ID, connectionFactoryID);
          connectionFactorySvcProps.put(CONFIG_DISPLAY_ID, connectionFactoryID);
          connectionFactorySvcProps.put(ResourceFactory.JNDI_NAME, jndiName);
          // Use the unique identifier(like connectionFactoryID) because jndiName is not always unique for app-defined resources
          connectionFactorySvcProps.put(UNIQUE_JNDI_NAME, connectionFactoryID);
          connectionFactorySvcProps.put(TARGET_CONNECTION_MANAGER, conManagerFilter);
  
          // There will always be a connection manager, so set the minimum cardinality to 1 so that the connection factory doesn't
          // activate before the connection manager
          connectionFactorySvcProps.put(CARDINALITY_MINIMUM_CONNECTION_MANAGER, 1);
  
          if (application != null) {
              connectionFactorySvcProps.put(AppDefinedResource.APPLICATION, application);
              if (module != null) {
                  connectionFactorySvcProps.put(AppDefinedResource.MODULE, module);
                  if (component != null)
                      connectionFactorySvcProps.put(AppDefinedResource.COMPONENT, component);
              }
          }
          String resourceAdapter = (String) annotationDDProps.remove(RESOURCE_ADAPTER);
          String interfaceName = (String) annotationDDProps.remove(INTERFACE_NAME);
  
          connectionFactorySvcProps.put(BOOTSTRAP_CONTEXT, "(id=" + resourceAdapter + ")");
          connectionFactorySvcProps.put(CREATES_OBJECTCLASS, interfaceName);
  
          //Get props with default values only and see if the same is specified by the user in annotation/dd, then use that value otherwise set the default value.
          //Note: Its not necessary for the user to specify the props which has default value, so we set them in here.
          Dictionary<String, Object> connectionFactoryDefaultProps = getDefaultProperties(resourceAdapter, interfaceName);
  
          for (Enumeration<String> keys = connectionFactoryDefaultProps.keys(); keys.hasMoreElements();) {
              String key = keys.nextElement();
              Object value = connectionFactoryDefaultProps.get(key);
  
              //Override the managed connection factory class default property values with values provided annotation
              if (annotationDDProps.containsKey(key))
                  value = annotationDDProps.remove(key);
  
              if (value instanceof String)
                  value = variableRegistry.resolveString((String) value);
  
              connectionFactorySvcProps.put(JMSResourceDefinitionConstants.PROPERTIES_REF_KEY + key, value);
          }
  
          //Additional property handling due to naming inconsistency between JEE specification and wasJms & wmqJms resource adapter
          //For instance, "user" is the key of the property to specify user name in annotation/dd but the wasJms/wmqJms resource adapter expects the key to be "userName"
          //The key "password" do not have any inconsistency, so not handled here
          //TODO: There may some third party resource adapters which may have naming inconsistency with different properties, to handle that in future we can keep the mapping(inProp = outProp) in a collection
          //so that it can be handled dynamically.
          annotationDDProps.put(USER_NAME_PORP, annotationDDProps.get(USER_PROP));
  
          //Get all the properties for a given resource(get the resource by the interfaceName) from the corresponding resource adapter,
          //then see if user specified any of these props in annotation/dd, if yes set that value otherwise ignore.
          //Note: The above section for handling default values can be eliminated by handling the same here in this section since we get all the properties. Will be taken care in future.
          AttributeDefinition[] attributeDefinitions = getAttributeDefinitions(resourceAdapter, interfaceName);
          for (AttributeDefinition attributeDefinition : attributeDefinitions) {
              Object value = annotationDDProps.remove(attributeDefinition.getID());
              if (value != null) {
  
                  if (value instanceof String)
                      value = variableRegistry.resolveString((String) value);
  
                  connectionFactorySvcProps.put(JMSResourceDefinitionConstants.PROPERTIES_REF_KEY + attributeDefinition.getID(), value);
              }
          }
  
          Object value;
          for (String name : ConnectionManagerService.CONNECTION_MANAGER_PROPS)
              if ((value = annotationDDProps.remove(name)) != null)
                  cmSvcProps.put(name, value);
  
          BundleContext bundleContext = FrameworkUtil.getBundle(ConnectionFactoryService.class).getBundleContext();
  
          StringBuilder connectionFactoryFilter = new StringBuilder(200);
          connectionFactoryFilter.append("(&").append(FilterUtils.createPropertyFilter(ID, connectionFactoryID));
          connectionFactoryFilter.append(FilterUtils.createPropertyFilter(Constants.OBJECTCLASS, ConnectionFactoryService.class.getName())).append(")");
  
          //Create AppDefinedResourceFactory based on props specified in the annotation/DD
          ResourceFactory factory = new AppDefinedResourceFactory(this, bundleContext, connectionFactoryID, connectionFactoryFilter.toString(), declaringApplication);
          try {
              String bundleLocation = bundleContext.getBundle().getLocation();
              String jcaBundleLocation = FrameworkUtil.getBundle(ConnectorService.class).getBundleContext().getBundle().getLocation();
              ConfigurationAdmin configAdmin = configAdminRef.getService();
  
              Configuration conMgrConfig = configAdmin.createFactoryConfiguration(ConnectionManagerService.FACTORY_PID, jcaBundleLocation);
              conMgrConfig.update(cmSvcProps);
              connectionFactorySvcProps.put(CONNECTION_MANAGER_REF, new String[] { conMgrConfig.getPid() });
  
              Configuration connectionFactorySvcConfig = configAdmin.createFactoryConfiguration(ConnectionFactoryService.FACTORY_PID, bundleLocation);
              connectionFactorySvcConfig.update(connectionFactorySvcProps);
          } 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;
      }