public static void mapPlatformRolesToMondrianRolesHelper(Util.PropertyList properties)
      throws PentahoAccessControlException {
    if (properties.get(RolapConnectionProperties.Role.name(), null) == null) {
      // Only if the action sequence/requester hasn't already injected a role in here do this.

      if (PentahoSystem.getObjectFactory().objectDefined(MDXConnection.MDX_CONNECTION_MAPPER_KEY)) {
        IConnectionUserRoleMapper mondrianUserRoleMapper =
            PentahoSystem.get(
                IConnectionUserRoleMapper.class, MDXConnection.MDX_CONNECTION_MAPPER_KEY, null);
        if (mondrianUserRoleMapper != null) {
          // Do role mapping
          String[] validMondrianRolesForUser =
              mondrianUserRoleMapper.mapConnectionRoles(
                  PentahoSessionHolder.getSession(),
                  properties.get(RolapConnectionProperties.Catalog.name()));
          if ((validMondrianRolesForUser != null) && (validMondrianRolesForUser.length > 0)) {
            StringBuffer buff = new StringBuffer();
            String aRole = null;
            for (int i = 0; i < validMondrianRolesForUser.length; i++) {
              aRole = validMondrianRolesForUser[i];
              // According to http://mondrian.pentaho.org/documentation/configuration.php
              // double-comma escapes a comma
              if (i > 0) {
                buff.append(","); // $NON-NLS-1$
              }
              buff.append(aRole.replaceAll(",", ",,")); // $NON-NLS-1$//$NON-NLS-2$
            }
            properties.put(RolapConnectionProperties.Role.name(), buff.toString());
          }
        }
      }
    }
  }
  public String filter(String schemaUrl, Util.PropertyList connectInfo, InputStream stream)
      throws Exception {
    setLocale(
        connectInfo.get("Locale") == null
            ? Locale.getDefault().toString()
            : connectInfo.get("Locale"));

    loadProperties();

    String schema = super.filter(schemaUrl, connectInfo, stream);
    if (bundle != null) {
      schema = doRegExReplacements(schema);
    }
    LOGGER.debug(schema);
    return schema;
  }
  public void testPooledConnectionWithProperties() throws SQLException {
    Util.PropertyList properties = TestContext.instance().getConnectionProperties().clone();

    // Only the JDBC-ODBC bridge gives the error necessary for this
    // test to succeed. So trivially succeed for all other JDBC
    // drivers.
    final String jdbc = properties.get("Jdbc");
    if (jdbc != null && !jdbc.startsWith("jdbc:odbc:")) {
      return;
    }

    // JDBC-ODBC driver does not support UTF-16, so this test succeeds
    // because creating the connection from the DataSource will fail.
    properties.put("jdbc.charSet", "UTF-16");

    final StringBuilder buf = new StringBuilder();
    DataSource dataSource = RolapConnection.createDataSource(null, properties, buf);
    final String desc = buf.toString();
    assertTrue(desc.startsWith("Jdbc="));

    Connection connection;
    try {
      connection = dataSource.getConnection();
      connection.close();
      fail("Expected exception");
    } catch (SQLException e) {
      if (e.getClass().getName().equals("org.apache.commons.dbcp.DbcpException")) {
        // This is expected. (We use string-comparison so that the
        // compiler doesn't warn about using a deprecated class.)
      } else if (e.getClass() == SQLException.class
          && e.getCause() == null
          && e.getMessage() != null
          && e.getMessage().equals("")) {
        // This is expected, from a later version of Dbcp.
      } else {
        fail("Expected exception, but got a different one: " + e);
      }
    } catch (IllegalArgumentException e) {
      handleIllegalArgumentException(properties, e);
    } finally {
      RolapConnectionPool.instance().clearPool();
    }
  }
  public void testNonPooledConnectionWithProperties() {
    Util.PropertyList properties = TestContext.instance().getConnectionProperties().clone();

    // Only the JDBC-ODBC bridge gives the error necessary for this
    // test to succeed. So trivially succeed for all other JDBC
    // drivers.
    final String jdbc = properties.get("Jdbc");
    if (jdbc != null && !jdbc.startsWith("jdbc:odbc:")) {
      return;
    }

    // This test is just like the test testPooledConnectionWithProperties
    // except with non-pooled connections.
    properties.put("jdbc.charSet", "UTF-16");
    properties.put(RolapConnectionProperties.PoolNeeded.name(), "false");

    final StringBuilder buf = new StringBuilder();
    DataSource dataSource = RolapConnection.createDataSource(null, properties, buf);
    final String desc = buf.toString();
    assertTrue(desc.startsWith("Jdbc="));

    Connection connection = null;
    try {
      connection = dataSource.getConnection();
      fail("Expected exception");
    } catch (SQLException se) {
      // this is expected
    } catch (IllegalArgumentException e) {
      handleIllegalArgumentException(properties, e);
    } finally {
      if (connection != null) {
        try {
          connection.close();
        } catch (SQLException e) {
          // ignore
        }
      }
    }
  }
  protected void init(Util.PropertyList properties) {
    try {
      if (nativeConnection != null) { // Assume we're open
        close();
      }

      // Set a locale for this connection if specified in the platform's mondrian metadata
      // This is required if mondrian.i18n.LocalizingDynamicSchemaProcessor is being used
      if (properties.get(RolapConnectionProperties.Locale.name()) == null) {
        properties.put(
            RolapConnectionProperties.Locale.name(), LocaleHelper.getLocale().toString());
      }

      String dataSourceName = properties.get(RolapConnectionProperties.DataSource.name());

      mapPlatformRolesToMondrianRoles(properties);

      if (dataSourceName != null) {
        IDBDatasourceService datasourceService =
            PentahoSystem.getObjectFactory().get(IDBDatasourceService.class, null);
        DataSource dataSourceImpl = datasourceService.getDataSource(dataSourceName);
        if (dataSourceImpl != null) {
          properties.remove(RolapConnectionProperties.DataSource.name());
          nativeConnection = DriverManager.getConnection(properties, null, dataSourceImpl);
        } else {
          nativeConnection = DriverManager.getConnection(properties, null);
        }
      } else {
        nativeConnection = DriverManager.getConnection(properties, null);
      }

      if (nativeConnection != null) {
        if (role != null) {
          nativeConnection.setRole(role);
        }
      }

      if (nativeConnection == null) {
        logger.error(
            Messages.getInstance()
                .getErrorString(
                    "MDXConnection.ERROR_0002_INVALID_CONNECTION",
                    properties != null
                        ? properties.toString()
                        : "null")); //$NON-NLS-1$ //$NON-NLS-2$
      }
    } catch (Throwable t) {
      if (logger != null) {
        logger.error(
            Messages.getInstance()
                .getErrorString(
                    "MDXConnection.ERROR_0002_INVALID_CONNECTION",
                    properties != null ? properties.toString() : "null"),
            t); //$NON-NLS-1$ //$NON-NLS-2$
      } else {
        Logger.error(
            this.getClass().getName(),
            Messages.getInstance()
                .getErrorString(
                    "MDXConnection.ERROR_0002_INVALID_CONNECTION",
                    properties != null ? properties.toString() : "null"),
            t); //$NON-NLS-1$ //$NON-NLS-2$
      }
    }
  }
  public void testDataSourceOverrideUserPass() throws SQLException, NamingException {
    // use the datasource property to connect to the database
    Util.PropertyList properties = TestContext.instance().getConnectionProperties().clone();
    final Dialect dialect = TestContext.instance().getDialect();
    if (dialect.getDatabaseProduct() == Dialect.DatabaseProduct.ACCESS) {
      // Access doesn't accept user/password, so this test is pointless.
      return;
    }

    final String jdbcUser = properties.get(RolapConnectionProperties.JdbcUser.name());
    final String jdbcPassword = properties.get(RolapConnectionProperties.JdbcPassword.name());
    if (jdbcUser == null || jdbcPassword == null) {
      // Can only run this test if username and password are explicit.
      return;
    }

    // Define a data source with bogus user and password.
    properties.put(RolapConnectionProperties.JdbcUser.name(), "bogususer");
    properties.put(RolapConnectionProperties.JdbcPassword.name(), "boguspassword");
    properties.put(RolapConnectionProperties.PoolNeeded.name(), "false");
    final StringBuilder buf = new StringBuilder();
    final DataSource dataSource = RolapConnection.createDataSource(null, properties, buf);
    final String desc = buf.toString();
    assertTrue(desc, desc.startsWith("Jdbc="));
    assertTrue(desc, desc.indexOf("JdbcUser=bogususer; JdbcPassword=boguspassword") >= 0);
    final String jndiName = "jndiDataSource";
    THREAD_INITIAL_CONTEXT.set(
        new InitialContext() {
          public Object lookup(String str) {
            return str.equals(jndiName) ? dataSource : null;
          }
        });

    // Create a property list that we will use for the actual mondrian
    // connection. Replace the original JDBC info with the data source we
    // just created.
    final Util.PropertyList properties2 = new Util.PropertyList();
    for (Pair<String, String> entry : properties) {
      properties2.put(entry.getKey(), entry.getValue());
    }
    properties2.remove(RolapConnectionProperties.Jdbc.name());
    properties2.put(RolapConnectionProperties.DataSource.name(), jndiName);

    // With JdbcUser and JdbcPassword credentials in the mondrian connect
    // string, the data source's "user" and "password" properties are
    // overridden and the connection succeeds.
    properties2.put(RolapConnectionProperties.JdbcUser.name(), jdbcUser);
    properties2.put(RolapConnectionProperties.JdbcPassword.name(), jdbcPassword);
    mondrian.olap.Connection connection = null;
    try {
      connection = DriverManager.getConnection(properties2, null);
      Query query = connection.parseQuery("select from [Sales]");
      final Result result = connection.execute(query);
      assertNotNull(result);
    } finally {
      if (connection != null) {
        connection.close();
        connection = null;
      }
    }

    // If we don't specify JdbcUser and JdbcPassword in the mondrian
    // connection properties, mondrian uses the data source's
    // bogus credentials, and the connection fails.
    properties2.remove(RolapConnectionProperties.JdbcUser.name());
    properties2.remove(RolapConnectionProperties.JdbcPassword.name());
    for (String poolNeeded : Arrays.asList("false", "true")) {
      // Important to test with & without pooling. Connection pools
      // typically do not let you change user, so it's important that
      // mondrian handles these right.
      properties2.put(RolapConnectionProperties.PoolNeeded.name(), poolNeeded);
      try {
        connection = DriverManager.getConnection(properties2, null);
        fail("Expected exception");
      } catch (MondrianException e) {
        final String s = TestContext.getStackTrace(e);
        assertTrue(
            s,
            s.indexOf("Error while creating SQL connection: " + "DataSource=jndiDataSource") >= 0);
        switch (dialect.getDatabaseProduct()) {
          case DERBY:
            assertTrue(
                s,
                s.indexOf(
                        "Caused by: java.sql.SQLException: " + "Schema 'BOGUSUSER' does not exist")
                    >= 0);
            break;
          case ORACLE:
            assertTrue(
                s,
                s.indexOf(
                        "Caused by: java.sql.SQLException: ORA-01017: "
                            + "invalid username/password; logon denied")
                    >= 0);
            break;
          case MYSQL:
            assertTrue(
                s,
                s.indexOf(
                        "Caused by: java.sql.SQLException: Access denied " + "for user 'bogususer'")
                    >= 0);
            break;
          case POSTGRESQL:
            assertTrue(
                s,
                s.indexOf(
                        "Caused by: org.postgresql.util.PSQLException: "
                            + "FATAL: password authentication failed for "
                            + "user \"bogususer\"")
                    >= 0);
            break;
        }
      } finally {
        if (connection != null) {
          connection.close();
          connection = null;
        }
      }
    }
  }