/** {@inheritDoc} */
 @Override
 public void undeployResource(Object resource, String applicationName, String moduleName)
     throws Exception {
   JdbcConnectionPool jdbcConnPool = (JdbcConnectionPool) resource;
   PoolInfo poolInfo = new PoolInfo(jdbcConnPool.getName(), applicationName, moduleName);
   if (_logger.isLoggable(Level.FINE)) {
     _logger.fine(
         " JdbcConnectionPoolDeployer - unDeployResource : "
             + "calling actualUndeploy of "
             + poolInfo);
   }
   actualUndeployResource(poolInfo);
 }
  /** {@inheritDoc} */
  @Override
  public void deployResource(Object resource, String applicationName, String moduleName)
      throws Exception {
    // deployResource is not synchronized as there is only one caller
    // ResourceProxy which is synchronized

    // intentional no-op
    // From 8.1 PE/SE/EE, JDBC connection pools are no more resources and
    // they would be available only to server instances that have a resoruce-ref
    // that maps to a pool. So deploy resource would not be called during
    // JDBC connection pool creation. The actualDeployResource method
    // below is invoked by JdbcResourceDeployer when a resource-ref for a
    // resource that is pointed to this pool is added to a server instance
    JdbcConnectionPool jcp = (JdbcConnectionPool) resource;
    PoolInfo poolInfo = new PoolInfo(jcp.getName(), applicationName, moduleName);
    if (_logger.isLoggable(Level.FINE)) {
      _logger.fine(
          " JdbcConnectionPoolDeployer - deployResource : " + poolInfo + " calling actualDeploy");
    }
    actualDeployResource(resource, poolInfo);
  }
  private void setConnectorConnectionPoolAttributes(
      ConnectorConnectionPool ccp, JdbcConnectionPool adminPool) {
    String poolName = ccp.getName();
    ccp.setMaxPoolSize(adminPool.getMaxPoolSize());
    ccp.setSteadyPoolSize(adminPool.getSteadyPoolSize());
    ccp.setMaxWaitTimeInMillis(adminPool.getMaxWaitTimeInMillis());

    ccp.setPoolResizeQuantity(adminPool.getPoolResizeQuantity());

    ccp.setIdleTimeoutInSeconds(adminPool.getIdleTimeoutInSeconds());

    ccp.setFailAllConnections(Boolean.valueOf(adminPool.getFailAllConnections()));

    ccp.setConnectionValidationRequired(
        Boolean.valueOf(adminPool.getIsConnectionValidationRequired()));

    ccp.setNonTransactional(Boolean.valueOf(adminPool.getNonTransactionalConnections()));
    ccp.setNonComponent(Boolean.valueOf(adminPool.getAllowNonComponentCallers()));

    ccp.setPingDuringPoolCreation(Boolean.valueOf(adminPool.getPing()));
    // These are default properties of all Jdbc pools
    // So set them here first and then figure out from the parsing routine
    // if they need to be reset
    ccp.setMatchConnections(Boolean.valueOf(adminPool.getMatchConnections()));
    ccp.setAssociateWithThread(Boolean.valueOf(adminPool.getAssociateWithThread()));
    ccp.setConnectionLeakTracingTimeout(adminPool.getConnectionLeakTimeoutInSeconds());
    ccp.setConnectionReclaim(Boolean.valueOf(adminPool.getConnectionLeakReclaim()));

    boolean lazyConnectionEnlistment = Boolean.valueOf(adminPool.getLazyConnectionEnlistment());
    boolean lazyConnectionAssociation = Boolean.valueOf(adminPool.getLazyConnectionAssociation());

    // lazy-connection-enlistment need to be ON for lazy-connection-association to work.
    if (lazyConnectionAssociation) {
      if (lazyConnectionEnlistment) {
        ccp.setLazyConnectionAssoc(true);
        ccp.setLazyConnectionEnlist(true);
      } else {
        _logger.log(
            Level.SEVERE,
            "conn_pool_obj_utils.lazy_enlist-lazy_assoc-invalid-combination",
            poolName);
        String i18nMsg = sm.getString("cpou.lazy_enlist-lazy_assoc-invalid-combination", poolName);
        throw new RuntimeException(i18nMsg);
      }
    } else {
      ccp.setLazyConnectionAssoc(lazyConnectionAssociation);
      ccp.setLazyConnectionEnlist(lazyConnectionEnlistment);
    }

    boolean pooling = Boolean.valueOf(adminPool.getPooling());

    if (!pooling) {
      // Throw exception if assoc with thread is set to true.
      if (Boolean.valueOf(adminPool.getAssociateWithThread())) {
        _logger.log(
            Level.SEVERE,
            "conn_pool_obj_utils.pooling_disabled_assocwiththread_invalid_combination",
            poolName);
        String i18nMsg =
            sm.getString("cpou.pooling_disabled_assocwiththread_invalid_combination", poolName);
        throw new RuntimeException(i18nMsg);
      }

      // Below are useful in pooled environment only.
      // Throw warning for connection validation/validate-atmost-once/
      // match-connections/max-connection-usage-count/idele-timeout
      if (Boolean.valueOf(adminPool.getIsConnectionValidationRequired())) {
        _logger.log(
            Level.WARNING,
            "conn_pool_obj_utils.pooling_disabled_conn_validation_invalid_combination",
            poolName);
      }
      if (Integer.parseInt(adminPool.getValidateAtmostOncePeriodInSeconds()) > 0) {
        _logger.log(
            Level.WARNING,
            "conn_pool_obj_utils.pooling_disabled_validate_atmost_once_invalid_combination",
            poolName);
      }
      if (Boolean.valueOf(adminPool.getMatchConnections())) {
        _logger.log(
            Level.WARNING,
            "conn_pool_obj_utils.pooling_disabled_match_connections_invalid_combination",
            poolName);
      }
      if (Integer.parseInt(adminPool.getMaxConnectionUsageCount()) > 0) {
        _logger.log(
            Level.WARNING,
            "conn_pool_obj_utils.pooling_disabled_max_conn_usage_invalid_combination",
            poolName);
      }
      if (Integer.parseInt(adminPool.getIdleTimeoutInSeconds()) > 0) {
        _logger.log(
            Level.WARNING,
            "conn_pool_obj_utils.pooling_disabled_idle_timeout_invalid_combination",
            poolName);
      }
    }
    ccp.setPooling(pooling);
    ccp.setMaxConnectionUsage(adminPool.getMaxConnectionUsageCount());

    ccp.setConCreationRetryAttempts(adminPool.getConnectionCreationRetryAttempts());
    ccp.setConCreationRetryInterval(adminPool.getConnectionCreationRetryIntervalInSeconds());

    ccp.setValidateAtmostOncePeriod(adminPool.getValidateAtmostOncePeriodInSeconds());
  }
  /**
   * Pull out the MCF configuration properties and return them as an array of
   * ConnectorConfigProperty
   *
   * @param adminPool - The JdbcConnectionPool to pull out properties from
   * @param conConnPool - ConnectorConnectionPool which will be used by Resource Pool
   * @param connDesc - The ConnectorDescriptor for this JDBC RA
   * @return ConnectorConfigProperty [] array of MCF Config properties specified in this JDBC RA
   */
  private ConnectorConfigProperty[] getMCFConfigProperties(
      JdbcConnectionPool adminPool,
      ConnectorConnectionPool conConnPool,
      ConnectorDescriptor connDesc) {

    ArrayList propList = new ArrayList();

    if (adminPool.getResType() != null) {
      if (ConnectorConstants.JAVA_SQL_DRIVER.equals(adminPool.getResType())) {
        propList.add(
            new ConnectorConfigProperty(
                "ClassName",
                adminPool.getDriverClassname() == null ? "" : adminPool.getDriverClassname(),
                "The driver class name",
                "java.lang.String"));
      } else {
        propList.add(
            new ConnectorConfigProperty(
                "ClassName",
                adminPool.getDatasourceClassname() == null
                    ? ""
                    : adminPool.getDatasourceClassname(),
                "The datasource class name",
                "java.lang.String"));
      }
    } else {
      // When resType is null, one of these classnames would be specified
      if (adminPool.getDriverClassname() != null) {
        propList.add(
            new ConnectorConfigProperty(
                "ClassName",
                adminPool.getDriverClassname() == null ? "" : adminPool.getDriverClassname(),
                "The driver class name",
                "java.lang.String"));
      } else if (adminPool.getDatasourceClassname() != null) {
        propList.add(
            new ConnectorConfigProperty(
                "ClassName",
                adminPool.getDatasourceClassname() == null
                    ? ""
                    : adminPool.getDatasourceClassname(),
                "The datasource class name",
                "java.lang.String"));
      }
    }
    propList.add(
        new ConnectorConfigProperty(
            "ConnectionValidationRequired",
            adminPool.getIsConnectionValidationRequired() + "",
            "Is connection validation required",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "ValidationMethod",
            adminPool.getConnectionValidationMethod() == null
                ? ""
                : adminPool.getConnectionValidationMethod(),
            "How the connection is validated",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "ValidationTableName",
            adminPool.getValidationTableName() == null ? "" : adminPool.getValidationTableName(),
            "Validation Table name",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "ValidationClassName",
            adminPool.getValidationClassname() == null ? "" : adminPool.getValidationClassname(),
            "Validation Class name",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "TransactionIsolation",
            adminPool.getTransactionIsolationLevel() == null
                ? ""
                : adminPool.getTransactionIsolationLevel(),
            "Transaction Isolatin Level",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "GuaranteeIsolationLevel",
            adminPool.getIsIsolationLevelGuaranteed() + "",
            "Transaction Isolation Guarantee",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "StatementWrapping",
            adminPool.getWrapJdbcObjects() + "",
            "Statement Wrapping",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "LogJdbcCalls",
            adminPool.getLogJdbcCalls() + "",
            "Log JDBC Calls",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "SlowQueryThresholdInSeconds",
            adminPool.getSlowQueryThresholdInSeconds() + "",
            "Slow Query Threshold In Seconds",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "StatementTimeout",
            adminPool.getStatementTimeoutInSeconds() + "",
            "Statement Timeout",
            "java.lang.String"));

    PoolInfo poolInfo = conConnPool.getPoolInfo();

    propList.add(
        new ConnectorConfigProperty(
            "PoolMonitoringSubTreeRoot",
            ConnectorsUtil.getPoolMonitoringSubTreeRoot(poolInfo, true) + "",
            "Pool Monitoring Sub Tree Root",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "PoolName", poolInfo.getName() + "", "Pool Name", "java.lang.String"));

    if (poolInfo.getApplicationName() != null) {
      propList.add(
          new ConnectorConfigProperty(
              "ApplicationName",
              poolInfo.getApplicationName() + "",
              "Application Name",
              "java.lang.String"));
    }

    if (poolInfo.getModuleName() != null) {
      propList.add(
          new ConnectorConfigProperty(
              "ModuleName", poolInfo.getModuleName() + "", "Module name", "java.lang.String"));
    }

    propList.add(
        new ConnectorConfigProperty(
            "StatementCacheSize",
            adminPool.getStatementCacheSize() + "",
            "Statement Cache Size",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "StatementCacheType",
            adminPool.getStatementCacheType() + "",
            "Statement Cache Type",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "InitSql", adminPool.getInitSql() + "", "InitSql", "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "SqlTraceListeners",
            adminPool.getSqlTraceListeners() + "",
            "Sql Trace Listeners",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "StatementLeakTimeoutInSeconds",
            adminPool.getStatementLeakTimeoutInSeconds() + "",
            "Statement Leak Timeout in seconds",
            "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "StatementLeakReclaim",
            adminPool.getStatementLeakReclaim() + "",
            "Statement Leak Reclaim",
            "java.lang.String"));

    // dump user defined poperties into the list
    Set connDefDescSet = connDesc.getOutboundResourceAdapter().getConnectionDefs();
    // since this a 1.0 RAR, we will have only 1 connDefDesc
    if (connDefDescSet.size() != 1) {
      throw new MissingResourceException("Only one connDefDesc present", null, null);
    }

    Iterator iter = connDefDescSet.iterator();

    // Now get the set of MCF config properties associated with each
    // connection-definition . Each element here is an EnviromnentProperty
    Set mcfConfigProps = null;
    while (iter.hasNext()) {
      mcfConfigProps = ((ConnectionDefDescriptor) iter.next()).getConfigProperties();
    }
    if (mcfConfigProps != null) {

      Map mcfConPropKeys = new HashMap();
      Iterator mcfConfigPropsIter = mcfConfigProps.iterator();
      while (mcfConfigPropsIter.hasNext()) {
        String key = ((ConnectorConfigProperty) mcfConfigPropsIter.next()).getName();
        mcfConPropKeys.put(key.toUpperCase(locale), key);
      }

      String driverProperties = "";
      for (Property rp : adminPool.getProperty()) {
        if (rp == null) {
          continue;
        }
        String name = rp.getName();

        // The idea here is to convert the Environment Properties coming from
        // the admin connection pool to standard pool properties thereby
        // making it easy to compare in the event of a reconfig
        if ("MATCHCONNECTIONS".equals(name.toUpperCase(locale))) {
          // JDBC - matchConnections if not set is decided by the ConnectionManager
          // so default is false
          conConnPool.setMatchConnections(toBoolean(rp.getValue(), false));
          logFine("MATCHCONNECTIONS");

        } else if ("ASSOCIATEWITHTHREAD".equals(name.toUpperCase(locale))) {
          conConnPool.setAssociateWithThread(toBoolean(rp.getValue(), false));
          logFine("ASSOCIATEWITHTHREAD");

        } else if ("LAZYCONNECTIONASSOCIATION".equals(name.toUpperCase(locale))) {
          ConnectionPoolObjectsUtils.setLazyEnlistAndLazyAssocProperties(
              rp.getValue(), adminPool.getProperty(), conConnPool);
          logFine("LAZYCONNECTIONASSOCIATION");

        } else if ("LAZYCONNECTIONENLISTMENT".equals(name.toUpperCase(Locale.getDefault()))) {
          conConnPool.setLazyConnectionEnlist(toBoolean(rp.getValue(), false));
          logFine("LAZYCONNECTIONENLISTMENT");

        } else if ("POOLDATASTRUCTURE".equals(name.toUpperCase(Locale.getDefault()))) {
          conConnPool.setPoolDataStructureType(rp.getValue());
          logFine("POOLDATASTRUCTURE");

        } else if (ConnectorConstants.DYNAMIC_RECONFIGURATION_FLAG.equals(
            name.toLowerCase(locale))) {
          String value = rp.getValue();
          try {
            conConnPool.setDynamicReconfigWaitTimeout(Long.parseLong(rp.getValue()) * 1000L);
            logFine(ConnectorConstants.DYNAMIC_RECONFIGURATION_FLAG);
          } catch (NumberFormatException nfe) {
            _logger.log(
                Level.WARNING,
                "Invalid value for "
                    + "'"
                    + ConnectorConstants.DYNAMIC_RECONFIGURATION_FLAG
                    + "' : "
                    + value);
          }
        } else if ("POOLWAITQUEUE".equals(name.toUpperCase(locale))) {
          conConnPool.setPoolWaitQueue(rp.getValue());
          logFine("POOLWAITQUEUE");

        } else if ("DATASTRUCTUREPARAMETERS".equals(name.toUpperCase(locale))) {
          conConnPool.setDataStructureParameters(rp.getValue());
          logFine("DATASTRUCTUREPARAMETERS");

        } else if ("USERNAME".equals(name.toUpperCase(Locale.getDefault()))
            || "USER".equals(name.toUpperCase(locale))) {

          propList.add(
              new ConnectorConfigProperty("User", rp.getValue(), "user name", "java.lang.String"));

        } else if ("PASSWORD".equals(name.toUpperCase(locale))) {

          propList.add(
              new ConnectorConfigProperty(
                  "Password", rp.getValue(), "Password", "java.lang.String"));

        } else if ("JDBC30DATASOURCE".equals(name.toUpperCase(locale))) {

          propList.add(
              new ConnectorConfigProperty(
                  "JDBC30DataSource", rp.getValue(), "JDBC30DataSource", "java.lang.String"));

        } else if ("PREFER-VALIDATE-OVER-RECREATE".equals(name.toUpperCase(Locale.getDefault()))) {
          String value = rp.getValue();
          conConnPool.setPreferValidateOverRecreate(toBoolean(value, false));
          logFine("PREFER-VALIDATE-OVER-RECREATE : " + value);

        } else if ("STATEMENT-CACHE-TYPE".equals(name.toUpperCase(Locale.getDefault()))) {

          if (adminPool.getStatementCacheType() != null) {
            propList.add(
                new ConnectorConfigProperty(
                    "StatementCacheType", rp.getValue(), "StatementCacheType", "java.lang.String"));
          }

        } else if ("NUMBER-OF-TOP-QUERIES-TO-REPORT"
            .equals(name.toUpperCase(Locale.getDefault()))) {

          propList.add(
              new ConnectorConfigProperty(
                  "NumberOfTopQueriesToReport",
                  rp.getValue(),
                  "NumberOfTopQueriesToReport",
                  "java.lang.String"));

        } else if ("TIME-TO-KEEP-QUERIES-IN-MINUTES"
            .equals(name.toUpperCase(Locale.getDefault()))) {

          propList.add(
              new ConnectorConfigProperty(
                  "TimeToKeepQueriesInMinutes",
                  rp.getValue(),
                  "TimeToKeepQueriesInMinutes",
                  "java.lang.String"));

        } else if (mcfConPropKeys.containsKey(name.toUpperCase(Locale.getDefault()))) {

          propList.add(
              new ConnectorConfigProperty(
                  (String) mcfConPropKeys.get(name.toUpperCase(Locale.getDefault())),
                  rp.getValue() == null ? "" : rp.getValue(),
                  "Some property",
                  "java.lang.String"));
        } else {
          driverProperties =
              driverProperties + "set" + escape(name) + "#" + escape(rp.getValue()) + "##";
        }
      }

      if (!driverProperties.equals("")) {
        propList.add(
            new ConnectorConfigProperty(
                "DriverProperties",
                driverProperties,
                "some proprietarty properties",
                "java.lang.String"));
      }
    }

    propList.add(new ConnectorConfigProperty("Delimiter", "#", "delim", "java.lang.String"));

    propList.add(
        new ConnectorConfigProperty(
            "EscapeCharacter", "\\", "escapeCharacter", "java.lang.String"));

    // create an array of EnvironmentProperties from above list
    ConnectorConfigProperty[] eProps = new ConnectorConfigProperty[propList.size()];
    ListIterator propListIter = propList.listIterator();

    for (int i = 0; propListIter.hasNext(); i++) {
      eProps[i] = (ConnectorConfigProperty) propListIter.next();
    }

    return eProps;
  }