docs: public static DataSource getDataSource(final ConnectionProperties poolSpec)
              throws FactoryException {
  
          Validate.notNull(poolSpec, "The validated object 'poolSpec' is null");
          Validate.notBlank(poolSpec.getDriver(),
                  "The validated character sequence 'poolSpec.getDriver()' is null or empty");
          Validate.notBlank(poolSpec.getUrl(), "The validated character sequence 'poolSpec.getUrl()' is null or empty");
  
          // no need for defensive copies of Strings
  
          final String driver = poolSpec.getDriver();
          final String url = poolSpec.getUrl();
          // CHECKSTYLE:OFF
          // this particular set of inline conditions is easy to read :-)
          final String username = poolSpec.getUsername() == null ? "" : poolSpec.getUsername();
          final String password = poolSpec.getPassword() == null ? "" : poolSpec.getPassword();
          // CHECKSTYLE:OFF
  
          // Load the database driver (if not already done)
          loadDriver(driver);
  
          // create the hash map required for the connection pool username + password
          final ConcurrentMap<String, String> properties = new ConcurrentHashMap<>();
          properties.put("user", username);
          properties.put("password", password);
  
          // we keep a separate pool per connection
          // a connection is identified by the URL, the username, and the password
          final String key = String.format("%s:%s", url, username);
  
          // avoid if possible to create the pool multiple times, and store the data source pool for later use
          if (!DS_POOLS.containsKey(key)) {
              synchronized (DataSourceFactory.class) {
                  if (!DS_POOLS.containsKey(key)) {
  
                      // this call is thread safe even without the double if check and extra synchronization. However, it
                      // might happen that the pool is created multiple times. While additional copies would be simply
                      // thrown away, we might run into problems in case that, for instance, the number of connections
                      // from the same user / machine are restricted on the DB server.
                      // While this does not happen a lot (it only happens if there is not already an entry and multiple
                      // threads race this block and lose), it could still lead to a failure, and we must take this double
                      // sync workaround. There is a solution for Java 8 - see below.
                      DS_POOLS.putIfAbsent(key, getPoolingDataSource(url, properties, poolSpec));
                  }
              }
          }
          // This would solve the problem of multiple pools being created and all but one being throws away, but it
          // does not work before Java 8 because the "computeIfAbsent()" method with the lambda function is not
          // available before Java 8:
          // TODO: add the pooled data source with the "computeIfAbsent()" method to improve performance in Java 8
          //DS_POOLS.computeIfAbsent(key, k -> getPoolingDataSource(url, properties, poolSpec));
  
          return DS_POOLS.get(key);
      }