Clean up H2 SQL interactions 47/101747/8
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 5 Jul 2022 20:27:09 +0000 (22:27 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 6 Jul 2022 11:02:55 +0000 (13:02 +0200)
We have a rather ugly mess around consistency of various queries. Clean
them up, so we can comfortably change things around in future. Also make
sure the tests are mocking things they should be mocking.

JIRA: AAA-221
Change-Id: Ide9ad6fb7028ba996ed8c1ed60df9cae17318999
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
12 files changed:
aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/AbstractStore.java
aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/ConnectionProvider.java
aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/DomainStore.java
aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/GrantStore.java
aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/IdmLightSimpleConnectionProvider.java
aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/RoleStore.java
aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/SQLTable.java [new file with mode: 0644]
aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/UserStore.java
aaa-idm-store-h2/src/test/java/org/opendaylight/aaa/datastore/h2/DomainStoreTest.java
aaa-idm-store-h2/src/test/java/org/opendaylight/aaa/datastore/h2/GrantStoreTest.java
aaa-idm-store-h2/src/test/java/org/opendaylight/aaa/datastore/h2/RoleStoreTest.java
aaa-idm-store-h2/src/test/java/org/opendaylight/aaa/datastore/h2/UserStoreTest.java

index 6f2eca6f4016cafba19ca05951b567788d60968a..9b9aa3130b1e1002f1bebe8759389c4052dc75bb 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2016 Red Hat, Inc. and others.
+ * Copyright (c) 2022 PANTHEON.tech, s.r.o.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -7,43 +8,40 @@
  */
 package org.opendaylight.aaa.datastore.h2;
 
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.VisibleForTesting;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.sql.Connection;
-import java.sql.DatabaseMetaData;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * Base class for H2 stores.
  */
-// "Nonconstant string passed to execute or addBatch method on an SQL statement...Consider using a prepared statement
-// instead. It is more efficient and less vulnerable to SQL injection attacks.". Possible TODO - is it worth it here to
-// use prepared statements?
-@SuppressFBWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
 abstract class AbstractStore<T> {
-
     private static final Logger LOG = LoggerFactory.getLogger(AbstractStore.class);
 
     /**
      * The name of the table used to represent this store.
      */
-    private final String tableName;
-
+    private final @NonNull String tableName;
     /**
      * Database connection factory.
      */
-    private final ConnectionProvider dbConnectionFactory;
-
+    private final @NonNull ConnectionProvider dbConnectionFactory;
     /**
      * Table types we're interested in (when checking tables' existence).
      */
-    public static final String[] TABLE_TYPES = new String[] { "TABLE" };
+    @VisibleForTesting
+    static final String[] TABLE_TYPES = new String[] { "TABLE" };
 
     /**
      * Creates an instance.
@@ -51,9 +49,9 @@ abstract class AbstractStore<T> {
      * @param dbConnectionFactory factory to obtain JDBC Connections from
      * @param tableName The name of the table being managed.
      */
-    protected AbstractStore(ConnectionProvider dbConnectionFactory, String tableName) {
-        this.dbConnectionFactory = dbConnectionFactory;
-        this.tableName = tableName;
+    AbstractStore(final ConnectionProvider dbConnectionFactory, final String tableName) {
+        this.dbConnectionFactory = requireNonNull(dbConnectionFactory);
+        this.tableName = requireNonNull(tableName);
     }
 
     /**
@@ -61,71 +59,74 @@ abstract class AbstractStore<T> {
      * exist, it will be created (using {@link #getTableCreationStatement()}).
      *
      * @return A database connection.
-     *
      * @throws StoreException if an error occurs.
      */
-    protected Connection dbConnect() throws StoreException {
-        Connection conn = dbConnectionFactory.getConnection();
-        try {
-            // Ensure table check/creation is atomic
-            synchronized (this) {
-                DatabaseMetaData dbm = conn.getMetaData();
-                try (ResultSet rs = dbm.getTables(null, null, tableName, TABLE_TYPES)) {
-                    if (rs.next()) {
-                        LOG.debug("Table {} already exists", tableName);
-                    } else {
+    final Connection dbConnect() throws StoreException {
+        final var conn = dbConnectionFactory.getConnection();
+        // Ensure table check/creation is atomic
+        synchronized (this) {
+            try {
+                final var dbm = conn.getMetaData();
+                try (var rs = dbm.getTables(null, null, tableName, TABLE_TYPES)) {
+                    if (!rs.next()) {
                         LOG.info("Table {} does not exist, creating it", tableName);
-                        try (Statement stmt = conn.createStatement()) {
-                            stmt.executeUpdate(getTableCreationStatement());
+                        try (var stmt = conn.createStatement()) {
+                            createTable(stmt);
                         }
+                    } else {
+                        LOG.debug("Table {} already exists", tableName);
                     }
                 }
+            } catch (SQLException e) {
+                LOG.error("Error connecting to the H2 database", e);
+                throw new StoreException("Cannot connect to database server", e);
             }
-        } catch (SQLException e) {
-            LOG.error("Error connecting to the H2 database", e);
-            throw new StoreException("Cannot connect to database server", e);
         }
         return conn;
     }
 
+    /**
+     * Create a managed table for on a particular connection..
+     *
+     * @param stmt A pre-allocated SQL statement
+     * @throws SQLException If table creation fails
+     */
+    abstract void createTable(Statement stmt) throws SQLException;
+
     /**
      * Empties the store.
      *
      * @throws StoreException if a connection error occurs.
      */
-    public void dbClean() throws StoreException {
-        try (Connection c = dbConnect()) {
-            // The table name can't be a parameter in a prepared statement
-            String sql = "DELETE FROM " + tableName;
-            try (Statement statement = c.createStatement()) {
-                statement.execute(sql);
-            }
+    @VisibleForTesting
+    @SuppressFBWarnings(value = "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE",
+        justification = "table name cannot be a parameter in a prepared statement")
+    final void dbClean() throws StoreException {
+        try (var c = dbConnect();
+             var statement = c.createStatement()) {
+            // FIXME: can we somehow make this a constant?
+            statement.execute("DELETE FROM " + tableName);
         } catch (SQLException e) {
             LOG.error("Error clearing table {}", tableName, e);
             throw new StoreException("Error clearing table " + tableName, e);
         }
     }
 
-    /**
-     * Returns the SQL code required to create the managed table.
-     *
-     * @return The SQL table creation statement.
-     */
-    protected abstract String getTableCreationStatement();
+    abstract void cleanTable(Statement stmt) throws SQLException;
 
     /**
      * Lists all the stored items.
      *
      * @return The stored item.
-     *
      * @throws StoreException if an error occurs.
      */
-    protected List<T> listAll() throws StoreException {
+    @SuppressFBWarnings(value = "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE",
+        justification = "table name cannot be a parameter in a prepared statement")
+    final List<T> listAll() throws StoreException {
         List<T> result = new ArrayList<>();
-        String query = "SELECT * FROM " + tableName;
-        try (Connection conn = dbConnect();
-             Statement stmt = conn.createStatement();
-             ResultSet rs = stmt.executeQuery(query)) {
+        try (var conn = dbConnect();
+             var stmt = conn.createStatement();
+             var rs = stmt.executeQuery("SELECT * FROM " + tableName)) {
             while (rs.next()) {
                 result.add(fromResultSet(rs));
             }
@@ -140,14 +141,12 @@ abstract class AbstractStore<T> {
      * Lists the stored items returned by the given statement.
      *
      * @param ps The statement (which must be ready for execution). It is the caller's responsibility to close this.
-     *
      * @return The stored items.
-     *
      * @throws StoreException if an error occurs.
      */
-    protected List<T> listFromStatement(PreparedStatement ps) throws StoreException {
-        List<T> result = new ArrayList<>();
-        try (ResultSet rs = ps.executeQuery()) {
+    final List<T> listFromStatement(final PreparedStatement ps) throws StoreException {
+        final var result = new ArrayList<T>();
+        try (var rs = ps.executeQuery()) {
             while (rs.next()) {
                 result.add(fromResultSet(rs));
             }
@@ -162,18 +161,12 @@ abstract class AbstractStore<T> {
      * Extracts the first item returned by the given statement, if any.
      *
      * @param ps The statement (which must be ready for execution). It is the caller's responsibility to close this.
-     *
      * @return The first item, or {@code null} if none.
-     *
      * @throws StoreException if an error occurs.
      */
-    protected T firstFromStatement(PreparedStatement ps) throws StoreException {
-        try (ResultSet rs = ps.executeQuery()) {
-            if (rs.next()) {
-                return fromResultSet(rs);
-            } else {
-                return null;
-            }
+    final T firstFromStatement(final PreparedStatement ps) throws StoreException {
+        try (var rs = ps.executeQuery()) {
+            return rs.next() ? fromResultSet(rs) : null;
         } catch (SQLException e) {
             LOG.error("Error listing first matching item from {}", tableName, e);
             throw new StoreException(e);
@@ -184,10 +177,8 @@ abstract class AbstractStore<T> {
      * Converts a single row in a result set to an instance of the managed type.
      *
      * @param rs The result set (which is ready for extraction; {@link ResultSet#next()} must <b>not</b> be called).
-     *
      * @return The corresponding instance.
-     *
      * @throws SQLException if an error occurs.
      */
-    protected abstract T fromResultSet(ResultSet rs) throws SQLException;
+    abstract T fromResultSet(ResultSet rs) throws SQLException;
 }
index 990a20695a8d9c4727135098c4fcebc8c65b4746..a992ccdc9cf187069c8c86ef93bb1895a28f482c 100644 (file)
@@ -8,25 +8,23 @@
 package org.opendaylight.aaa.datastore.h2;
 
 import java.sql.Connection;
+import javax.sql.CommonDataSource;
 import javax.sql.DataSource;
 
 /**
- * Provider of JDBC Connections.
- * Essentially a much simplified {@link DataSource}.
+ * Provider of JDBC Connections. Essentially a much simplified {@link DataSource} -- sans the {@link CommonDataSource}
+ * bits, which are a hassle.
  *
  * @author Michael Vorburger
  */
 public interface ConnectionProvider {
-
     /**
-     * Get a Connection.
+     * Get an SQL {@link Connection}.
      *
-     * @return a connection from this Factory; it may be a brand new one
-     *         obtained from the JDBC Driver, or an existing open one, if it
-     *         hasn't previously been closed
-     * @throws StoreException
-     *             if no Connection could be obtained
+     * @return a connection from this Factory; it may be a brand new one obtained from the JDBC Driver, or an existing
+     *         open one, if it has not previously been closed
+     * @throws StoreException if no Connection could be obtained
      */
+    // FIXME: what is the blocking behaviour?
     Connection getConnection() throws StoreException;
-
 }
index d6e7debc49041691e2d5978f645701ae321d1334..a7e810260bfa3b4be15b37c2e4db38a1ecb0359d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014, 2017 Hewlett-Packard Development Company, L.P. and others.  All rights reserved.
+ * Copyright (c) 2022 PANTHEON.tech, s.r.o.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -9,13 +10,13 @@ package org.opendaylight.aaa.datastore.h2;
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.annotations.VisibleForTesting;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import org.apache.commons.text.StringEscapeUtils;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.aaa.api.model.Domain;
 import org.opendaylight.aaa.api.model.Domains;
 import org.slf4j.Logger;
@@ -23,56 +24,89 @@ import org.slf4j.LoggerFactory;
 
 /**
  * Domain store.
- *
- * @author peter.mellquist@hp.com
- *
  */
-public class DomainStore extends AbstractStore<Domain> {
+final class DomainStore extends AbstractStore<Domain> {
     private static final Logger LOG = LoggerFactory.getLogger(DomainStore.class);
 
-    public static final String SQL_ID = "domainid";
-    public static final String SQL_NAME = "name";
-    public static final String SQL_DESCR = "description";
-    public static final String SQL_ENABLED = "enabled";
-    private static final String TABLE_NAME = "DOMAINS";
+    /**
+     * Name of our SQL table. This constant lives here rather than in {@link SQLTable} for brevity.
+     */
+    // FIXME: AAA-221: this is a system table
+    static final @NonNull String TABLE = "DOMAINS";
+
+    static {
+        SQLTable.DOMAIN.verifyTable(TABLE);
+    }
 
-    public DomainStore(final ConnectionProvider dbConnectionFactory) {
-        super(dbConnectionFactory, TABLE_NAME);
+    /**
+     * Column storing {@link Domain#getDomainid()}, which is a flat namespace.
+     */
+    // FIXME: rename to "id"
+    @VisibleForTesting
+    static final String COL_ID = "domainid";
+    /**
+     * Column storing {@link Domain#getName()}, which is a short name.
+     */
+    @VisibleForTesting
+    static final String COL_NAME = "name";
+    /**
+     * Column storing {@link Domain#getDescription()}, which is a detailed description.
+     */
+    @VisibleForTesting
+    static final String COL_DESC = "description";
+    /**
+     * Column storing {@link Domain#isEnabled()}, which is ... not used anywhere.
+     */
+    // FIXME: remove or audit for potential callers of isEnabled()
+    @VisibleForTesting
+    static final String COL_ENABLED = "enabled";
+
+    DomainStore(final ConnectionProvider dbConnectionFactory) {
+        super(dbConnectionFactory, TABLE);
+    }
+
+    @Override
+    void createTable(final Statement stmt) throws SQLException {
+        stmt.executeUpdate("CREATE TABLE " + TABLE + " ("
+            // FIXME: on delete cascade? RoleStore.COL_DOMAIN_ID seems to reference this
+            + COL_ID      + " VARCHAR(128) PRIMARY KEY, "
+            + COL_NAME    + " VARCHAR(128) UNIQUE NOT NULL, "
+            + COL_DESC    + " VARCHAR(128), "
+            // FIXME: change boolean
+            + COL_ENABLED + " INTEGER      NOT NULL)");
     }
 
     @Override
-    protected String getTableCreationStatement() {
-        return "CREATE TABLE DOMAINS "
-                + "(domainid   VARCHAR(128)      PRIMARY KEY,"
-                + "name        VARCHAR(128)      UNIQUE NOT NULL, "
-                + "description VARCHAR(128)      , "
-                + "enabled     INTEGER           NOT NULL)";
+    void cleanTable(final Statement stmt) throws SQLException {
+        stmt.execute("DELETE FROM " + TABLE);
     }
 
     @Override
     protected Domain fromResultSet(final ResultSet rs) throws SQLException {
         Domain domain = new Domain();
-        domain.setDomainid(rs.getString(SQL_ID));
-        domain.setName(rs.getString(SQL_NAME));
-        domain.setDescription(rs.getString(SQL_DESCR));
-        domain.setEnabled(rs.getInt(SQL_ENABLED) == 1);
+        domain.setDomainid(rs.getString(COL_ID));
+        domain.setName(rs.getString(COL_NAME));
+        domain.setDescription(rs.getString(COL_DESC));
+        domain.setEnabled(rs.getInt(COL_ENABLED) == 1);
         return domain;
     }
 
-    public Domains getDomains() throws StoreException {
+    Domains getDomains() throws StoreException {
         Domains domains = new Domains();
         domains.setDomains(listAll());
         return domains;
     }
 
-    protected Domains getDomains(final String domainName) throws StoreException {
-        LOG.debug("getDomains for: {}", domainName);
-        Domains domains = new Domains();
-        try (Connection conn = dbConnect();
-             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM DOMAINS WHERE name = ?")) {
-            pstmt.setString(1, domainName);
-            LOG.debug("query string: {}", pstmt);
-            domains.setDomains(listFromStatement(pstmt));
+    // FIXME: seems to be unused
+    Domains getDomains(final String domainName) throws StoreException {
+        final Domains domains;
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE + " WHERE " + COL_NAME + " = ?")) {
+            stmt.setString(1, domainName);
+
+            domains = new Domains();
+            LOG.debug("getDomains() request: {}", stmt);
+            domains.setDomains(listFromStatement(stmt));
         } catch (SQLException e) {
             LOG.error("Error listing domains matching {}", domainName, e);
             throw new StoreException("Error listing domains", e);
@@ -80,31 +114,33 @@ public class DomainStore extends AbstractStore<Domain> {
         return domains;
     }
 
-    protected Domain getDomain(final String id) throws StoreException {
-        try (Connection conn = dbConnect();
-             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM DOMAINS WHERE domainid = ? ")) {
-            pstmt.setString(1, id);
-            LOG.debug("query string: {}", pstmt);
-            return firstFromStatement(pstmt);
+    Domain getDomain(final String id) throws StoreException {
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE + " WHERE " + COL_ID + " = ?")) {
+            stmt.setString(1, id);
+
+            LOG.debug("getDomain() request: {}", stmt);
+            return firstFromStatement(stmt);
         } catch (SQLException e) {
             LOG.error("Error retrieving domain {}", id, e);
             throw new StoreException("Error loading domain", e);
         }
     }
 
-    public Domain createDomain(final Domain domain) throws StoreException {
+    Domain createDomain(final Domain domain) throws StoreException {
         requireNonNull(domain);
         requireNonNull(domain.getName());
         requireNonNull(domain.isEnabled());
-        String query = "insert into DOMAINS (domainid,name,description,enabled) values(?, ?, ?, ?)";
-        try (Connection conn = dbConnect();
-             PreparedStatement statement = conn.prepareStatement(query)) {
-            statement.setString(1, domain.getName());
-            statement.setString(2, domain.getName());
-            statement.setString(3, domain.getDescription());
-            statement.setInt(4, domain.isEnabled() ? 1 : 0);
-            int affectedRows = statement.executeUpdate();
-            if (affectedRows == 0) {
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("INSERT INTO " + TABLE + " ("
+                 + COL_ID + ", " + COL_NAME + ", " + COL_DESC + ", " + COL_ENABLED + ") VALUES (?, ?, ?, ?)")) {
+            stmt.setString(1, domain.getName());
+            stmt.setString(2, domain.getName());
+            stmt.setString(3, domain.getDescription());
+            stmt.setInt(4, domain.isEnabled() ? 1 : 0);
+
+            LOG.debug("createDomain() request: {}", stmt);
+            if (stmt.executeUpdate() == 0) {
                 throw new StoreException("Creating domain failed, no rows affected.");
             }
             domain.setDomainid(domain.getName());
@@ -115,12 +151,11 @@ public class DomainStore extends AbstractStore<Domain> {
         }
     }
 
-    protected Domain putDomain(final Domain domain) throws StoreException {
-        Domain savedDomain = this.getDomain(domain.getDomainid());
+    Domain putDomain(final Domain domain) throws StoreException {
+        final var savedDomain = getDomain(domain.getDomainid());
         if (savedDomain == null) {
             return null;
         }
-
         if (domain.getDescription() != null) {
             savedDomain.setDescription(domain.getDescription());
         }
@@ -131,14 +166,16 @@ public class DomainStore extends AbstractStore<Domain> {
             savedDomain.setEnabled(domain.isEnabled());
         }
 
-        String query = "UPDATE domains SET description = ?, enabled = ?, name = ? WHERE domainid = ?";
-        try (Connection conn = dbConnect();
-             PreparedStatement statement = conn.prepareStatement(query)) {
-            statement.setString(1, savedDomain.getDescription());
-            statement.setInt(2, savedDomain.isEnabled() ? 1 : 0);
-            statement.setString(3, savedDomain.getName());
-            statement.setString(4, savedDomain.getDomainid());
-            statement.executeUpdate();
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("UPDATE " + TABLE + " SET "
+                 + COL_NAME + " = ?, " + COL_DESC + " = ?, " + COL_ENABLED + " = ? WHERE " + COL_ID + " = ?")) {
+            stmt.setString(1, savedDomain.getName());
+            stmt.setString(2, savedDomain.getDescription());
+            stmt.setInt(3, savedDomain.isEnabled() ? 1 : 0);
+            stmt.setString(4, savedDomain.getDomainid());
+
+            LOG.debug("putDomain() request: {}", stmt);
+            stmt.executeUpdate();
         } catch (SQLException e) {
             LOG.error("Error updating domain {}", domain.getDomainid(), e);
             throw new StoreException("Error updating domain", e);
@@ -147,17 +184,22 @@ public class DomainStore extends AbstractStore<Domain> {
         return savedDomain;
     }
 
-    @SuppressFBWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
-    protected Domain deleteDomain(String domainid) throws StoreException {
-        domainid = StringEscapeUtils.escapeHtml4(domainid);
-        Domain deletedDomain = this.getDomain(domainid);
+    @SuppressFBWarnings(value = "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE", justification = "Weird original code")
+    Domain deleteDomain(final String domainid) throws StoreException {
+        // FIXME: remove this once we have a more modern H2
+        final String escaped = StringEscapeUtils.escapeHtml4(domainid);
+        final var deletedDomain = getDomain(escaped);
         if (deletedDomain == null) {
             return null;
         }
-        String query = String.format("DELETE FROM DOMAINS WHERE domainid = '%s'", domainid);
-        try (Connection conn = dbConnect();
-             Statement statement = conn.createStatement()) {
-            int deleteCount = statement.executeUpdate(query);
+
+        try (var conn = dbConnect();
+             var stmt = conn.createStatement()) {
+            // FIXME: prepare statement instead
+            final String query = String.format("DELETE FROM " + TABLE + " WHERE " + COL_ID + " = '%s'", escaped);
+            LOG.debug("deleteDomain() request: {}", query);
+
+            int deleteCount = stmt.executeUpdate(query);
             LOG.debug("deleted {} records", deleteCount);
             return deletedDomain;
         } catch (SQLException e) {
index a4b7bac7a33ecde6abd56660f598ab5bddcbf384..981b359f922857dccdbc7b74a674cf5974e9ca58 100644 (file)
@@ -8,9 +8,8 @@
 
 package org.opendaylight.aaa.datastore.h2;
 
+import com.google.common.annotations.VisibleForTesting;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
@@ -25,38 +24,60 @@ import org.slf4j.LoggerFactory;
  * Grant store.
  *
  * @author peter.mellquist@hp.com
- *
  */
-public class GrantStore extends AbstractStore<Grant> {
+final class GrantStore extends AbstractStore<Grant> {
     private static final Logger LOG = LoggerFactory.getLogger(GrantStore.class);
 
-    public static final String SQL_ID = "grantid";
-    public static final String SQL_TENANTID = "domainid";
-    public static final String SQL_USERID = "userid";
-    public static final String SQL_ROLEID = "roleid";
-    private static final String TABLE_NAME = "GRANTS";
+    static final String TABLE = "GRANTS";
+
+    static {
+        SQLTable.GRANT.verifyTable(TABLE);
+    }
+
+    // FIXME: javadoc
+    static final String COL_ID = "grantid";
 
-    public GrantStore(ConnectionProvider dbConnectionFactory) {
-        super(dbConnectionFactory, TABLE_NAME);
+    // FIXME: javadoc
+    // FIXME: 'tenant' vs 'domain' ?
+    @VisibleForTesting
+    static final String COL_TENANTID = "domainid";
+
+    // FIXME: javadoc
+    @VisibleForTesting
+    static final String COL_USERID = "userid";
+    // FIXME: javadoc
+    @VisibleForTesting
+    static final String COL_ROLEID = "roleid";
+
+    GrantStore(final ConnectionProvider dbConnectionFactory) {
+        super(dbConnectionFactory, TABLE);
     }
 
     @Override
-    protected String getTableCreationStatement() {
-        return "CREATE TABLE GRANTS "
-                + "(grantid    VARCHAR(128) PRIMARY KEY,"
-                + "domainid    VARCHAR(128)         NOT NULL, "
-                + "userid      VARCHAR(128)         NOT NULL, "
-                + "roleid      VARCHAR(128)         NOT NULL)";
+    void createTable(final Statement stmt) throws SQLException {
+        stmt.executeUpdate("CREATE TABLE " + TABLE + " ("
+            + COL_ID       + " VARCHAR(128) PRIMARY KEY, "
+            // FIXME: foreign key to DomainStore.COL_ID?
+            + COL_TENANTID + " VARCHAR(128) NOT NULL, "
+            // FIXME: foreign key to UserStore.COL_ID?
+            + COL_USERID   + " VARCHAR(128) NOT NULL, "
+            // FIXME: foreign key to RoleStore.COL_ID?
+            + COL_ROLEID   + " VARCHAR(128) NOT NULL)");
     }
 
     @Override
-    protected Grant fromResultSet(ResultSet rs) throws SQLException {
+    void cleanTable(final Statement stmt) throws SQLException {
+        stmt.execute("DELETE FROM " + TABLE);
+    }
+
+    @Override
+    protected Grant fromResultSet(final ResultSet rs) throws SQLException {
         Grant grant = new Grant();
         try {
-            grant.setGrantid(rs.getString(SQL_ID));
-            grant.setDomainid(rs.getString(SQL_TENANTID));
-            grant.setUserid(rs.getString(SQL_USERID));
-            grant.setRoleid(rs.getString(SQL_ROLEID));
+            grant.setGrantid(rs.getString(COL_ID));
+            grant.setDomainid(rs.getString(COL_TENANTID));
+            grant.setUserid(rs.getString(COL_USERID));
+            grant.setRoleid(rs.getString(COL_ROLEID));
         } catch (SQLException sqle) {
             LOG.error("SQL Exception: ", sqle);
             throw sqle;
@@ -64,94 +85,101 @@ public class GrantStore extends AbstractStore<Grant> {
         return grant;
     }
 
-    public Grants getGrants(String did, String uid) throws StoreException {
-        Grants grants = new Grants();
-        try (Connection conn = dbConnect();
-             PreparedStatement pstmt = conn
-                     .prepareStatement("SELECT * FROM grants WHERE domainid = ? AND userid = ?")) {
-            pstmt.setString(1, did);
-            pstmt.setString(2, uid);
-            LOG.debug("query string: {}", pstmt);
-            grants.setGrants(listFromStatement(pstmt));
+    Grants getGrants(final String domainId, final String userId) throws StoreException {
+        final Grants grants;
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE
+                 + " WHERE " + COL_TENANTID + " = ? AND " + COL_USERID + " = ?")) {
+            stmt.setString(1, domainId);
+            stmt.setString(2, userId);
+            LOG.debug("getGrants() request: {}", stmt);
+
+            grants = new Grants();
+            grants.setGrants(listFromStatement(stmt));
         } catch (SQLException e) {
             throw new StoreException("SQL Exception", e);
         }
         return grants;
     }
 
-    protected Grants getGrants(String userid) throws StoreException {
-        Grants grants = new Grants();
-        try (Connection conn = dbConnect();
-             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM GRANTS WHERE userid = ? ")) {
-            pstmt.setString(1, userid);
-            LOG.debug("query string: {}", pstmt);
-            grants.setGrants(listFromStatement(pstmt));
+    Grants getGrants(final String userid) throws StoreException {
+        final Grants grants;
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE + " WHERE " + COL_USERID + " = ?")) {
+            stmt.setString(1, userid);
+            LOG.debug("getGrants() request: {}", stmt);
+
+            grants = new Grants();
+            grants.setGrants(listFromStatement(stmt));
         } catch (SQLException e) {
             throw new StoreException("SQL Exception", e);
         }
         return grants;
     }
 
-    protected Grant getGrant(String id) throws StoreException {
-        try (Connection conn = dbConnect();
-             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM GRANTS WHERE grantid = ? ")) {
-            pstmt.setString(1, id);
-            LOG.debug("query string: {}", pstmt);
-            return firstFromStatement(pstmt);
+    Grant getGrant(final String id) throws StoreException {
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE + " WHERE " + COL_ID + " = ?")) {
+            stmt.setString(1, id);
+            LOG.debug("getGrant() request: {}", stmt);
+
+            return firstFromStatement(stmt);
         } catch (SQLException e) {
             throw new StoreException("SQL Exception", e);
         }
     }
 
-    protected Grant getGrant(String did, String uid, String rid) throws StoreException {
-        try (Connection conn = dbConnect();
-             PreparedStatement pstmt = conn
-                     .prepareStatement("SELECT * FROM GRANTS WHERE domainid = ? AND userid = ? AND roleid = ? ")) {
-            pstmt.setString(1, did);
-            pstmt.setString(2, uid);
-            pstmt.setString(3, rid);
-            LOG.debug("query string: {}", pstmt);
-            return firstFromStatement(pstmt);
+    // FIXME: seems to be unused
+    Grant getGrant(final String did, final String uid, final String rid) throws StoreException {
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE
+                 + " WHERE " + COL_TENANTID + " = ? AND " + COL_USERID + " = ? AND " + COL_ROLEID + " = ?")) {
+            stmt.setString(1, did);
+            stmt.setString(2, uid);
+            stmt.setString(3, rid);
+            LOG.debug("getGrant() request: {}", stmt);
+
+            return firstFromStatement(stmt);
         } catch (SQLException e) {
             throw new StoreException("SQL Exception", e);
         }
     }
 
-    protected Grant createGrant(Grant grant) throws StoreException {
-        String query = "insert into grants  (grantid,domainid,userid,roleid) values(?,?,?,?)";
-        try (Connection conn = dbConnect();
-             PreparedStatement statement = conn.prepareStatement(query)) {
-            statement.setString(
-                    1,
-                    IDMStoreUtil.createGrantid(grant.getUserid(), grant.getDomainid(),
-                            grant.getRoleid()));
-            statement.setString(2, grant.getDomainid());
-            statement.setString(3, grant.getUserid());
-            statement.setString(4, grant.getRoleid());
-            int affectedRows = statement.executeUpdate();
-            if (affectedRows == 0) {
+    Grant createGrant(final Grant grant) throws StoreException {
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("INSERT INTO " + TABLE + " ("
+                 + COL_ID + ", " + COL_TENANTID + ", " + COL_USERID + ", " + COL_ROLEID + ") VALUES (?, ?, ?, ?)")) {
+            stmt.setString(1, IDMStoreUtil.createGrantid(grant.getUserid(), grant.getDomainid(), grant.getRoleid()));
+            stmt.setString(2, grant.getDomainid());
+            stmt.setString(3, grant.getUserid());
+            stmt.setString(4, grant.getRoleid());
+            LOG.debug("createGrant() request: {}", stmt);
+
+            if (stmt.executeUpdate() == 0) {
                 throw new StoreException("Creating grant failed, no rows affected.");
             }
-            grant.setGrantid(IDMStoreUtil.createGrantid(grant.getUserid(), grant.getDomainid(),
-                    grant.getRoleid()));
+            grant.setGrantid(IDMStoreUtil.createGrantid(grant.getUserid(), grant.getDomainid(), grant.getRoleid()));
             return grant;
         } catch (SQLException e) {
             throw new StoreException("SQL Exception", e);
         }
     }
 
-    @SuppressFBWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
-    protected Grant deleteGrant(String grantid) throws StoreException {
-        grantid = StringEscapeUtils.escapeHtml4(grantid);
-        Grant savedGrant = this.getGrant(grantid);
+    @SuppressFBWarnings(value = "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE", justification = "Weird original code")
+    Grant deleteGrant(final String grantid) throws StoreException {
+        final String escaped = StringEscapeUtils.escapeHtml4(grantid);
+        final var savedGrant = getGrant(escaped);
         if (savedGrant == null) {
             return null;
         }
 
-        String query = String.format("DELETE FROM GRANTS WHERE grantid = '%s'", grantid);
-        try (Connection conn = dbConnect();
-             Statement statement = conn.createStatement()) {
-            int deleteCount = statement.executeUpdate(query);
+        try (var conn = dbConnect();
+             var stmt = conn.createStatement()) {
+            // FIXME: prepare statement instead
+            final String query = String.format("DELETE FROM " + TABLE +  " WHERE " + COL_ID + " = '%s'", escaped);
+            LOG.debug("deleteGrant() request: {}", query);
+
+            int deleteCount = stmt.executeUpdate(query);
             LOG.debug("deleted {} records", deleteCount);
             return savedGrant;
         } catch (SQLException e) {
index 51d190e12a2046a6d9bc963a1321b84e63fe6117..6b71591b819828b066a9c2e0fe84e40b68c07396 100644 (file)
@@ -10,10 +10,10 @@ package org.opendaylight.aaa.datastore.h2;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
+import org.h2.jdbcx.JdbcConnectionPool;
 
 /**
- * Simple Provider of JDBC Connections, based on an {@link IdmLightConfig} and
- * {@link DriverManager}.
+ * Simple Provider of JDBC Connections, based on an {@link IdmLightConfig} and {@link DriverManager}.
  *
  * @author Michael Vorburger
  */
@@ -25,6 +25,15 @@ public class IdmLightSimpleConnectionProvider implements ConnectionProvider {
         this.config = config;
     }
 
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec This implemenation always opens a new connection.
+     *
+     *     FIXME: Integrate a {@link JdbcConnectionPool}, as {@link #config} is guaranteed to be constant. This is
+     *            needlessly heavy, as we are locating the driver.
+     */
     @Override
     public Connection getConnection() throws StoreException {
         try {
index 3a911dd1824c6f74ffda30bd3151852138c0fdb3..1b68088ee73632ce359e31323435bb8aa2e611ec 100644 (file)
@@ -9,13 +9,13 @@ package org.opendaylight.aaa.datastore.h2;
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.annotations.VisibleForTesting;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import org.apache.commons.text.StringEscapeUtils;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.aaa.api.IDMStoreUtil;
 import org.opendaylight.aaa.api.model.Role;
 import org.opendaylight.aaa.api.model.Roles;
@@ -23,39 +23,73 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Store for roles.
+ * An {@link AbstractStore} of {@link Role}s.
  *
  * @author peter.mellquist@hp.com
- *
  */
-public class RoleStore extends AbstractStore<Role> {
+final class RoleStore extends AbstractStore<Role> {
     private static final Logger LOG = LoggerFactory.getLogger(RoleStore.class);
 
-    public static final String SQL_ID = "roleid";
-    protected static final String SQL_DOMAIN_ID = "domainid";
-    public static final String SQL_NAME = "name";
-    public static final String SQL_DESCR = "description";
-    private static final String TABLE_NAME = "ROLES";
+    /**
+     * Name of our SQL table. This constant lives here rather than in {@link SQLTable} for brevity.
+     */
+    // FIXME: AAA-221: this is a system table
+    static final @NonNull String TABLE = "ROLES";
+
+    static {
+        SQLTable.ROLE.verifyTable(TABLE);
+    }
+
+    /**
+     * Column storing {@link Role#getRoleid()}, which is a flat namespace.
+     */
+    // FIXME: rename to "id"
+    @VisibleForTesting
+    static final String COL_ID = "roleid";
+    /**
+     * Column storing {@link Role#getName()}, which is a short name.
+     */
+    @VisibleForTesting
+    static final String COL_NAME = "name";
+    // FIXME: document this column
+    // FIXME: rename to "domain_id"
+    // FIXME: cross-reference DomainStore?
+    @VisibleForTesting
+    static final String COL_DOMAIN_ID = "domainid";
+    /**
+     * Column storing {@link Role#getDescription()}, which is a detailed description.
+     * FIXME: this should be optional, justlike {@link DomainStore#COL_DESC}
+     */
+    @VisibleForTesting
+    static final String COL_DESC = "description";
+
+    RoleStore(final ConnectionProvider dbConnectionFactory) {
+        super(dbConnectionFactory, TABLE);
+    }
 
-    public RoleStore(final ConnectionProvider dbConnectionFactory) {
-        super(dbConnectionFactory, TABLE_NAME);
+    @Override
+    void createTable(final Statement stmt) throws SQLException {
+        stmt.executeUpdate("CREATE TABLE " + TABLE + " ("
+            + COL_ID        + " VARCHAR(128) PRIMARY KEY, "
+            + COL_NAME      + " VARCHAR(128) NOT NULL, "
+            // FIXME: FOREIGN_KEY to DomainStore?
+            + COL_DOMAIN_ID + " VARCHAR(128) NOT NULL, "
+            + COL_DESC      + " VARCHAR(128) NOT NULL)");
     }
 
     @Override
-    protected String getTableCreationStatement() {
-        return "CREATE TABLE ROLES " + "(roleid     VARCHAR(128)   PRIMARY KEY,"
-                + "name        VARCHAR(128)   NOT NULL, " + "domainid    VARCHAR(128)   NOT NULL, "
-                + "description VARCHAR(128)      NOT NULL)";
+    void cleanTable(final Statement stmt) throws SQLException {
+        stmt.execute("DELETE FROM " + TABLE);
     }
 
     @Override
     protected Role fromResultSet(final ResultSet rs) throws SQLException {
         Role role = new Role();
         try {
-            role.setRoleid(rs.getString(SQL_ID));
-            role.setDomainid(rs.getString(SQL_DOMAIN_ID));
-            role.setName(rs.getString(SQL_NAME));
-            role.setDescription(rs.getString(SQL_DESCR));
+            role.setRoleid(rs.getString(COL_ID));
+            role.setDomainid(rs.getString(COL_DOMAIN_ID));
+            role.setName(rs.getString(COL_NAME));
+            role.setDescription(rs.getString(COL_DESC));
         } catch (SQLException sqle) {
             LOG.error("SQL Exception: ", sqle);
             throw sqle;
@@ -63,36 +97,40 @@ public class RoleStore extends AbstractStore<Role> {
         return role;
     }
 
-    public Roles getRoles() throws StoreException {
+    Roles getRoles() throws StoreException {
         Roles roles = new Roles();
         roles.setRoles(listAll());
         return roles;
     }
 
-    protected Role getRole(final String id) throws StoreException {
-        try (Connection conn = dbConnect();
-                PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM ROLES WHERE roleid = ? ")) {
-            pstmt.setString(1, id);
-            LOG.debug("query string: {}", pstmt);
-            return firstFromStatement(pstmt);
+    Role getRole(final String id) throws StoreException {
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE + " WHERE " + COL_ID + " = ?")) {
+            stmt.setString(1, id);
+
+            LOG.debug("getRole() request: {}", stmt);
+            return firstFromStatement(stmt);
         } catch (SQLException s) {
             throw new StoreException("SQL Exception: " + s);
         }
     }
 
-    protected Role createRole(final Role role) throws StoreException {
+    Role createRole(final Role role) throws StoreException {
         requireNonNull(role);
         requireNonNull(role.getName());
         requireNonNull(role.getDomainid());
-        String query = "insert into roles (roleid,domainid,name,description) values(?,?,?,?)";
-        try (Connection conn = dbConnect(); PreparedStatement statement = conn.prepareStatement(query)) {
+
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("INSERT INTO " + TABLE + " ("
+                + COL_ID + ", " + COL_DOMAIN_ID + ", " + COL_NAME + ", " + COL_DESC + ") VALUES (?, ?, ?, ?)")) {
             role.setRoleid(IDMStoreUtil.createRoleid(role.getName(), role.getDomainid()));
-            statement.setString(1, role.getRoleid());
-            statement.setString(2, role.getDomainid());
-            statement.setString(3, role.getName());
-            statement.setString(4, role.getDescription());
-            int affectedRows = statement.executeUpdate();
-            if (affectedRows == 0) {
+            stmt.setString(1, role.getRoleid());
+            stmt.setString(2, role.getDomainid());
+            stmt.setString(3, role.getName());
+            stmt.setString(4, role.getDescription());
+
+            LOG.debug("createRole() request: {}", stmt);
+            if (stmt.executeUpdate() == 0) {
                 throw new StoreException("Creating role failed, no rows affected.");
             }
             return role;
@@ -101,9 +139,8 @@ public class RoleStore extends AbstractStore<Role> {
         }
     }
 
-    protected Role putRole(final Role role) throws StoreException {
-
-        Role savedRole = this.getRole(role.getRoleid());
+    Role putRole(final Role role) throws StoreException {
+        Role savedRole = getRole(role.getRoleid());
         if (savedRole == null) {
             return null;
         }
@@ -115,11 +152,14 @@ public class RoleStore extends AbstractStore<Role> {
             savedRole.setName(role.getName());
         }
 
-        String query = "UPDATE roles SET description = ? WHERE roleid = ?";
-        try (Connection conn = dbConnect(); PreparedStatement statement = conn.prepareStatement(query)) {
-            statement.setString(1, savedRole.getDescription());
-            statement.setString(2, savedRole.getRoleid());
-            statement.executeUpdate();
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement(
+                 "UPDATE " + TABLE + " SET " + COL_DESC + " = ? WHERE " + COL_ID + " = ?")) {
+            stmt.setString(1, savedRole.getDescription());
+            stmt.setString(2, savedRole.getRoleid());
+
+            LOG.debug("putRole() request: {}", stmt);
+            stmt.executeUpdate();
         } catch (SQLException s) {
             throw new StoreException("SQL Exception : " + s);
         }
@@ -128,16 +168,21 @@ public class RoleStore extends AbstractStore<Role> {
     }
 
     @SuppressFBWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
-    protected Role deleteRole(String roleid) throws StoreException {
-        roleid = StringEscapeUtils.escapeHtml4(roleid);
-        Role savedRole = this.getRole(roleid);
+    Role deleteRole(final String roleid) throws StoreException {
+        // FIXME: remove this once we have a more modern H2
+        final String escaped = StringEscapeUtils.escapeHtml4(roleid);
+        Role savedRole = getRole(escaped);
         if (savedRole == null) {
             return null;
         }
 
-        String query = String.format("DELETE FROM ROLES WHERE roleid = '%s'", roleid);
-        try (Connection conn = dbConnect(); Statement statement = conn.createStatement()) {
-            int deleteCount = statement.executeUpdate(query);
+        try (var conn = dbConnect();
+             var stmt = conn.createStatement()) {
+            // FIXME: prepare statement instead
+            final String query = String.format("DELETE FROM " + TABLE + " WHERE " + COL_ID + " = '%s'", escaped);
+            LOG.debug("deleteRole() request: {}", query);
+
+            int deleteCount = stmt.executeUpdate(query);
             LOG.debug("deleted {} records", deleteCount);
             return savedRole;
         } catch (SQLException s) {
diff --git a/aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/SQLTable.java b/aaa-idm-store-h2/src/main/java/org/opendaylight/aaa/datastore/h2/SQLTable.java
new file mode 100644 (file)
index 0000000..64eed45
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.datastore.h2;
+
+import static com.google.common.base.Verify.verify;
+
+import com.google.common.base.MoreObjects;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Enumeration of tables in our schema.
+ */
+@NonNullByDefault
+enum SQLTable {
+    /**
+     * Domains.
+     */
+    // FIXME: Yeah, say more in documentation:
+    //        - what is a domain?
+    //        - how does it relate to others?
+    DOMAIN(DomainStore.TABLE),
+    /**
+     * Users.
+     */
+    // FIXME: Yeah, say more in documentation
+    USER(UserStore.TABLE),
+    /**
+     * Roles.
+     */
+    // FIXME: Yeah, say more in documentation
+    ROLE(RoleStore.TABLE),
+    /**
+     * Grants. Probably just a (domain, user, role) tuple, but do not take my word for it.
+     */
+    // FIXME: Yeah, say more in documentation
+    GRANT(GrantStore.TABLE);
+
+    private final String tableName;
+
+    SQLTable(final String name) {
+        tableName = name;
+    }
+
+    void verifyTable(final String storeTableName) {
+        verify(tableName.equals(storeTableName), "Mismatched table name '%s' with allocation %s", storeTableName, this);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(name()).add("tableName", tableName).toString();
+    }
+}
index e434d17a66540ee493d7914b690559dcf2a3a7e7..1d539d51d0e5227f7adf5a10198e65011dedb4dd 100644 (file)
@@ -9,18 +9,15 @@ package org.opendaylight.aaa.datastore.h2;
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.annotations.VisibleForTesting;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
-import java.util.Objects;
 import org.apache.commons.text.StringEscapeUtils;
 import org.opendaylight.aaa.api.IDMStoreUtil;
 import org.opendaylight.aaa.api.model.User;
 import org.opendaylight.aaa.api.model.Users;
-import org.opendaylight.aaa.api.password.service.PasswordHash;
 import org.opendaylight.aaa.api.password.service.PasswordHashService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -29,110 +26,147 @@ import org.slf4j.LoggerFactory;
  * Store for users.
  *
  * @author peter.mellquist@hp.com
- *
  */
-public class UserStore extends AbstractStore<User> {
+final class UserStore extends AbstractStore<User> {
     private static final Logger LOG = LoggerFactory.getLogger(UserStore.class);
 
-    public static final String SQL_ID = "userid";
-    public static final String SQL_DOMAIN_ID = "domainid";
-    public static final String SQL_NAME = "name";
-    public static final String SQL_EMAIL = "email";
-    public static final String SQL_PASSWORD = "password";
-    public static final String SQL_DESCR = "description";
-    public static final String SQL_ENABLED = "enabled";
-    public static final String SQL_SALT = "salt";
-    private static final String TABLE_NAME = "USERS";
+    static final String TABLE = "USERS";
+
+    static {
+        SQLTable.USER.verifyTable(TABLE);
+    }
+
+    /**
+     * Column storing {@link User#getUserid()}, which is a flat namespace.
+     */
+    // FIXME: rename to "id"
+    @VisibleForTesting
+    static final String COL_ID = "userid";
+    // FIXME: javadoc
+    @VisibleForTesting
+    static final String COL_DOMAIN_ID = "domainid";
+    // FIXME: javadoc
+    @VisibleForTesting
+    static final String COL_NAME = "name";
+    // FIXME: javadoc
+    @VisibleForTesting
+    static final String COL_EMAIL = "email";
+    // FIXME: javadoc
+    @VisibleForTesting
+    static final String COL_PASSWORD = "password";
+    // FIXME: javadoc
+    @VisibleForTesting
+    static final String COL_DESC = "description";
+    // FIXME: javadoc
+    @VisibleForTesting
+    static final String COL_ENABLED = "enabled";
+    // FIXME: javadoc
+    private static final String COL_SALT = "salt";
 
     private final PasswordHashService passwordService;
 
-    public UserStore(final ConnectionProvider dbConnectionFactory, final PasswordHashService passwordService) {
-        super(dbConnectionFactory, TABLE_NAME);
-        this.passwordService = Objects.requireNonNull(passwordService);
+    UserStore(final ConnectionProvider dbConnectionFactory, final PasswordHashService passwordService) {
+        super(dbConnectionFactory, TABLE);
+        this.passwordService = requireNonNull(passwordService);
+    }
+
+    @Override
+    void createTable(final Statement stmt) throws SQLException {
+        stmt.executeUpdate("CREATE TABLE " + TABLE + " ("
+            + COL_ID        + " VARCHAR(128) PRIMARY KEY, "
+            + COL_NAME      + " VARCHAR(128) NOT NULL, "
+            // FIXME: foreign key to DomainStore.COL_ID?
+            + COL_DOMAIN_ID + " VARCHAR(128) NOT NULL, "
+            + COL_EMAIL     + " VARCHAR(128) NOT NULL, "
+            + COL_DESC      + " VARCHAR(128) NOT NULL, "
+            // FIXME: is 'salt' even used? Some comparators are not storing hashes, either
+            + COL_PASSWORD  + " VARCHAR(128) NOT NULL, "
+            + COL_SALT      + " VARCHAR(128) NOT NULL, "
+            // FIXME: boolean
+            + COL_ENABLED   + " INTEGER      NOT NULL)");
     }
 
     @Override
-    protected String getTableCreationStatement() {
-        return "CREATE TABLE users " + "(userid    VARCHAR(128) PRIMARY KEY,"
-                + "name       VARCHAR(128)      NOT NULL, " + "domainid   VARCHAR(128)      NOT NULL, "
-                + "email      VARCHAR(128)      NOT NULL, " + "password   VARCHAR(128)      NOT NULL, "
-                + "description VARCHAR(128)     NOT NULL, " + "salt        VARCHAR(128)      NOT NULL, "
-                + "enabled     INTEGER          NOT NULL)";
+    void cleanTable(final Statement stmt) throws SQLException {
+        stmt.execute("DELETE FROM " + TABLE);
     }
 
     @Override
     protected User fromResultSet(final ResultSet rs) throws SQLException {
         User user = new User();
         try {
-            user.setUserid(rs.getString(SQL_ID));
-            user.setDomainid(rs.getString(SQL_DOMAIN_ID));
-            user.setName(rs.getString(SQL_NAME));
-            user.setEmail(rs.getString(SQL_EMAIL));
-            user.setPassword(rs.getString(SQL_PASSWORD));
-            user.setDescription(rs.getString(SQL_DESCR));
-            user.setEnabled(rs.getInt(SQL_ENABLED) == 1);
-            user.setSalt(rs.getString(SQL_SALT));
-        } catch (SQLException sqle) {
-            LOG.error("SQL Exception: ", sqle);
-            throw sqle;
+            user.setUserid(rs.getString(COL_ID));
+            user.setDomainid(rs.getString(COL_DOMAIN_ID));
+            user.setName(rs.getString(COL_NAME));
+            user.setEmail(rs.getString(COL_EMAIL));
+            user.setPassword(rs.getString(COL_PASSWORD));
+            user.setDescription(rs.getString(COL_DESC));
+            user.setEnabled(rs.getInt(COL_ENABLED) == 1);
+            user.setSalt(rs.getString(COL_SALT));
+        } catch (SQLException e) {
+            LOG.error("SQL Exception: ", e);
+            throw e;
         }
         return user;
     }
 
-    public Users getUsers() throws StoreException {
+    Users getUsers() throws StoreException {
         Users users = new Users();
         users.setUsers(listAll());
         return users;
     }
 
-    protected Users getUsers(final String username, final String domain) throws StoreException {
-        LOG.debug("getUsers for: {} in domain {}", username, domain);
+    Users getUsers(final String username, final String domain) throws StoreException {
+        final Users users;
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE + " USERS WHERE " + COL_ID + " = ?")) {
+            stmt.setString(1, IDMStoreUtil.createUserid(username, domain));
+            LOG.debug("getUsers() request: {}", stmt);
 
-        Users users = new Users();
-        try (Connection conn = dbConnect();
-                PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM USERS WHERE userid = ? ")) {
-            pstmt.setString(1, IDMStoreUtil.createUserid(username, domain));
-            LOG.debug("query string: {}", pstmt);
-            users.setUsers(listFromStatement(pstmt));
+            users = new Users();
+            users.setUsers(listFromStatement(stmt));
         } catch (SQLException s) {
             throw new StoreException("SQL Exception : " + s);
         }
         return users;
     }
 
-    public User getUser(final String id) throws StoreException {
-        try (Connection conn = dbConnect();
-                PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM USERS WHERE userid = ? ")) {
-            pstmt.setString(1, id);
-            LOG.debug("query string: {}", pstmt);
-            return firstFromStatement(pstmt);
+    User getUser(final String id) throws StoreException {
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("SELECT * FROM " + TABLE + " WHERE " + COL_ID + " = ? ")) {
+            stmt.setString(1, id);
+            LOG.debug("getUser() request: {}", stmt);
+
+            return firstFromStatement(stmt);
         } catch (SQLException s) {
             throw new StoreException("SQL Exception : " + s);
         }
     }
 
-    protected User createUser(final User user) throws StoreException {
+    User createUser(final User user) throws StoreException {
         requireNonNull(user);
         requireNonNull(user.getName());
         requireNonNull(user.getDomainid());
 
-        final PasswordHash passwordHash = passwordService.getPasswordHash(user.getPassword());
+        final var passwordHash = passwordService.getPasswordHash(user.getPassword());
         user.setSalt(passwordHash.getSalt());
-        String query =
-                "insert into users"
-                + " (userid,domainid,name,email,password,description,enabled,salt) values(?,?,?,?,?,?,?,?)";
-        try (Connection conn = dbConnect(); PreparedStatement statement = conn.prepareStatement(query)) {
+
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("INSERT INTO " + TABLE + " ("
+                 + COL_ID + ", " + COL_DOMAIN_ID + ", " + COL_NAME + ", " + COL_EMAIL + ", " + COL_PASSWORD + ", "
+                 + COL_DESC + ", " + COL_ENABLED + ", " + COL_SALT + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?)")) {
             user.setUserid(IDMStoreUtil.createUserid(user.getName(), user.getDomainid()));
-            statement.setString(1, user.getUserid());
-            statement.setString(2, user.getDomainid());
-            statement.setString(3, user.getName());
-            statement.setString(4, user.getEmail());
-            statement.setString(5, passwordHash.getHashedPassword());
-            statement.setString(6, user.getDescription());
-            statement.setInt(7, user.isEnabled() ? 1 : 0);
-            statement.setString(8, user.getSalt());
-            int affectedRows = statement.executeUpdate();
-            if (affectedRows == 0) {
+            stmt.setString(1, user.getUserid());
+            stmt.setString(2, user.getDomainid());
+            stmt.setString(3, user.getName());
+            stmt.setString(4, user.getEmail());
+            stmt.setString(5, passwordHash.getHashedPassword());
+            stmt.setString(6, user.getDescription());
+            stmt.setInt(7, user.isEnabled() ? 1 : 0);
+            stmt.setString(8, user.getSalt());
+            LOG.debug("createUser() request: {}", stmt);
+
+            if (stmt.executeUpdate() == 0) {
                 throw new StoreException("Creating user failed, no rows affected.");
             }
             return user;
@@ -141,9 +175,8 @@ public class UserStore extends AbstractStore<User> {
         }
     }
 
-    public User putUser(final User user) throws StoreException {
-
-        User savedUser = this.getUser(user.getUserid());
+    User putUser(final User user) throws StoreException {
+        final var savedUser = getUser(user.getUserid());
         if (savedUser == null) {
             return null;
         }
@@ -161,24 +194,26 @@ public class UserStore extends AbstractStore<User> {
             savedUser.setEmail(user.getEmail());
         }
         if (user.getPassword() != null) {
-            // If a new salt is provided, use it. Otherwise, derive salt from
-            // existing.
+            // If a new salt is provided, use it. Otherwise, derive salt from existing.
             String salt = user.getSalt();
             if (salt == null) {
                 salt = savedUser.getSalt();
             }
-            final PasswordHash passwordHash = passwordService.getPasswordHash(user.getPassword(), salt);
+            final var passwordHash = passwordService.getPasswordHash(user.getPassword(), salt);
             savedUser.setPassword(passwordHash.getHashedPassword());
         }
 
-        String query = "UPDATE users SET email = ?, password = ?, description = ?, enabled = ? WHERE userid = ?";
-        try (Connection conn = dbConnect(); PreparedStatement statement = conn.prepareStatement(query)) {
-            statement.setString(1, savedUser.getEmail());
-            statement.setString(2, savedUser.getPassword());
-            statement.setString(3, savedUser.getDescription());
-            statement.setInt(4, savedUser.isEnabled() ? 1 : 0);
-            statement.setString(5, savedUser.getUserid());
-            statement.executeUpdate();
+        try (var conn = dbConnect();
+             var stmt = conn.prepareStatement("UPDATE " + TABLE + " SET " + COL_EMAIL + " = ?, "
+                 + COL_PASSWORD + " = ?," + COL_DESC + " = ?, " + COL_ENABLED + "= ? WHERE " + COL_ID + " = ?")) {
+            stmt.setString(1, savedUser.getEmail());
+            stmt.setString(2, savedUser.getPassword());
+            stmt.setString(3, savedUser.getDescription());
+            stmt.setInt(4, savedUser.isEnabled() ? 1 : 0);
+            stmt.setString(5, savedUser.getUserid());
+            LOG.debug("putUser() request: {}", stmt);
+
+            stmt.executeUpdate();
         } catch (SQLException s) {
             throw new StoreException("SQL Exception : " + s);
         }
@@ -186,17 +221,22 @@ public class UserStore extends AbstractStore<User> {
         return savedUser;
     }
 
-    @SuppressFBWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
-    protected User deleteUser(String userid) throws StoreException {
-        userid = StringEscapeUtils.escapeHtml4(userid);
-        User savedUser = this.getUser(userid);
+    @SuppressFBWarnings(value = "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE", justification = "Weird original code")
+    User deleteUser(final String userid) throws StoreException {
+        // FIXME: remove this once we have a more modern H2
+        final var escaped = StringEscapeUtils.escapeHtml4(userid);
+        final var savedUser = getUser(escaped);
         if (savedUser == null) {
             return null;
         }
 
-        String query = String.format("DELETE FROM USERS WHERE userid = '%s'", userid);
-        try (Connection conn = dbConnect(); Statement statement = conn.createStatement()) {
-            int deleteCount = statement.executeUpdate(query);
+        try (var conn = dbConnect();
+             var stmt = conn.createStatement()) {
+            // FIXME: prepare statement instead
+            final var query = String.format("DELETE FROM " + TABLE + " WHERE " + COL_ID + " = '%s'", escaped);
+            LOG.debug("deleteUser() request: {}", query);
+
+            int deleteCount = stmt.executeUpdate(query);
             LOG.debug("deleted {} records", deleteCount);
             return savedUser;
         } catch (SQLException s) {
index 3ce190491559f4e411d7b64fe02ecb70d5133e6f..6448264a4dcf190f71c67278234dc0cc2184e419 100644 (file)
@@ -20,26 +20,23 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.aaa.api.model.Domain;
 import org.opendaylight.aaa.api.model.Domains;
 
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
 public class DomainStoreTest {
-
     private final Connection connectionMock = mock(Connection.class);
-
-    private final ConnectionProvider connectionFactoryMock = () -> connectionMock;
-
-    private final DomainStore domainStoreUnderTest = new DomainStore(connectionFactoryMock);
+    private final DomainStore domainStoreUnderTest = new DomainStore(() -> connectionMock);
 
     @Test
-    public void getDomainsTest() throws SQLException, Exception {
+    public void getDomainsTest() throws Exception {
         // Setup Mock Behavior
-        String[] tableTypes = { "TABLE" };
-        when(connectionMock.isClosed()).thenReturn(false);
         DatabaseMetaData dbmMock = mock(DatabaseMetaData.class);
         when(connectionMock.getMetaData()).thenReturn(dbmMock);
         ResultSet rsUserMock = mock(ResultSet.class);
-        when(dbmMock.getTables(null, null, "DOMAINS", tableTypes)).thenReturn(rsUserMock);
+        when(dbmMock.getTables(null, null, DomainStore.TABLE, AbstractStore.TABLE_TYPES)).thenReturn(rsUserMock);
         when(rsUserMock.next()).thenReturn(true);
 
         Statement stmtMock = mock(Statement.class);
@@ -75,13 +72,13 @@ public class DomainStoreTest {
         assertNull(ds.getDomain(domainId));
     }
 
-    public ResultSet getMockedResultSet() throws SQLException {
+    private static ResultSet getMockedResultSet() throws SQLException {
         ResultSet rsMock = mock(ResultSet.class);
         when(rsMock.next()).thenReturn(true).thenReturn(false);
-        when(rsMock.getInt(DomainStore.SQL_ID)).thenReturn(1);
-        when(rsMock.getString(DomainStore.SQL_NAME)).thenReturn("DomainName_1");
-        when(rsMock.getString(DomainStore.SQL_DESCR)).thenReturn("Desc_1");
-        when(rsMock.getInt(DomainStore.SQL_ENABLED)).thenReturn(1);
+        when(rsMock.getString(DomainStore.COL_ID)).thenReturn("1");
+        when(rsMock.getString(DomainStore.COL_NAME)).thenReturn("DomainName_1");
+        when(rsMock.getString(DomainStore.COL_DESC)).thenReturn("Desc_1");
+        when(rsMock.getInt(DomainStore.COL_ENABLED)).thenReturn(1);
         return rsMock;
     }
 }
index a0409060fde85c471e940bd326944ccaef67d8d9..e3a5701957a18af0e852311d13eabda22b658ae5 100644 (file)
@@ -19,28 +19,25 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.aaa.api.model.Grants;
 
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
 public class GrantStoreTest {
+    private static final String DOMAIN_ID = "5";
+    private static final String USER_ID = "5";
 
     private final Connection connectionMock = mock(Connection.class);
-
-    private final ConnectionProvider connectionFactoryMock = () -> connectionMock;
-
-    private final GrantStore grantStoreUnderTest = new GrantStore(connectionFactoryMock);
-
-    private final String did = "5";
-    private final String uid = "5";
+    private final GrantStore grantStoreUnderTest = new GrantStore(() -> connectionMock);
 
     @Test
     public void getGrantsTest() throws Exception {
         // Setup Mock Behavior
-        String[] tableTypes = { "TABLE" };
-        when(connectionMock.isClosed()).thenReturn(false);
         DatabaseMetaData dbmMock = mock(DatabaseMetaData.class);
         when(connectionMock.getMetaData()).thenReturn(dbmMock);
         ResultSet rsUserMock = mock(ResultSet.class);
-        when(dbmMock.getTables(null, null, "GRANTS", tableTypes)).thenReturn(rsUserMock);
+        when(dbmMock.getTables(null, null, GrantStore.TABLE, AbstractStore.TABLE_TYPES)).thenReturn(rsUserMock);
         when(rsUserMock.next()).thenReturn(true);
 
         PreparedStatement pstmtMock = mock(PreparedStatement.class);
@@ -50,22 +47,20 @@ public class GrantStoreTest {
         when(pstmtMock.executeQuery()).thenReturn(rsMock);
 
         // Run Test
-        Grants grants = grantStoreUnderTest.getGrants(did, uid);
+        Grants grants = grantStoreUnderTest.getGrants(DOMAIN_ID, USER_ID);
 
         // Verify
         assertEquals(1, grants.getGrants().size());
         verify(pstmtMock).close();
     }
 
-    public ResultSet getMockedResultSet() throws SQLException {
+    private static ResultSet getMockedResultSet() throws SQLException {
         ResultSet rsMock = mock(ResultSet.class);
         when(rsMock.next()).thenReturn(true).thenReturn(false);
-        when(rsMock.getInt(GrantStore.SQL_ID)).thenReturn(1);
-        when(rsMock.getString(GrantStore.SQL_TENANTID)).thenReturn(did);
-        when(rsMock.getString(GrantStore.SQL_USERID)).thenReturn(uid);
-        when(rsMock.getString(GrantStore.SQL_ROLEID)).thenReturn("Role_1");
-
+        when(rsMock.getString(GrantStore.COL_ID)).thenReturn("1");
+        when(rsMock.getString(GrantStore.COL_TENANTID)).thenReturn(DOMAIN_ID);
+        when(rsMock.getString(GrantStore.COL_USERID)).thenReturn(USER_ID);
+        when(rsMock.getString(GrantStore.COL_ROLEID)).thenReturn("Role_1");
         return rsMock;
     }
-
 }
index 45997c462739a4b32e5993ff114313ade5ef7046..29d567b41a3564bea0813cf8bb646ee645b13832 100644 (file)
@@ -19,25 +19,22 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.aaa.api.model.Roles;
 
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
 public class RoleStoreTest {
-
     private final Connection connectionMock = mock(Connection.class);
-
-    private final ConnectionProvider connectionFactoryMock = () -> connectionMock;
-
-    private final RoleStore roleStoreUnderTest = new RoleStore(connectionFactoryMock);
+    private final RoleStore roleStoreUnderTest = new RoleStore(() -> connectionMock);
 
     @Test
-    public void getRolesTest() throws SQLException, Exception {
+    public void getRolesTest() throws Exception {
         // Setup Mock Behavior
-        String[] tableTypes = { "TABLE" };
-        when(connectionMock.isClosed()).thenReturn(false);
         DatabaseMetaData dbmMock = mock(DatabaseMetaData.class);
         when(connectionMock.getMetaData()).thenReturn(dbmMock);
         ResultSet rsUserMock = mock(ResultSet.class);
-        when(dbmMock.getTables(null, null, "ROLES", tableTypes)).thenReturn(rsUserMock);
+        when(dbmMock.getTables(null, null, RoleStore.TABLE, AbstractStore.TABLE_TYPES)).thenReturn(rsUserMock);
         when(rsUserMock.next()).thenReturn(true);
 
         Statement stmtMock = mock(Statement.class);
@@ -54,12 +51,13 @@ public class RoleStoreTest {
         verify(stmtMock).close();
     }
 
-    public ResultSet getMockedResultSet() throws SQLException {
+    private static ResultSet getMockedResultSet() throws SQLException {
         ResultSet rsMock = mock(ResultSet.class);
         when(rsMock.next()).thenReturn(true).thenReturn(false);
-        when(rsMock.getInt(RoleStore.SQL_ID)).thenReturn(1);
-        when(rsMock.getString(RoleStore.SQL_NAME)).thenReturn("RoleName_1");
-        when(rsMock.getString(RoleStore.SQL_DESCR)).thenReturn("Desc_1");
+        when(rsMock.getString(RoleStore.COL_ID)).thenReturn("1");
+        when(rsMock.getString(RoleStore.COL_NAME)).thenReturn("RoleName_1");
+        when(rsMock.getString(RoleStore.COL_DOMAIN_ID)).thenReturn("Domain_1");
+        when(rsMock.getString(RoleStore.COL_DESC)).thenReturn("Desc_1");
         return rsMock;
     }
 }
index 086a549cff1d28e974e8ed144056d923b09c1e1a..3105a75a65f3c357ed6afba55e8c7efdd08c5965 100644 (file)
@@ -19,27 +19,24 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.aaa.api.model.Users;
 import org.opendaylight.aaa.impl.password.service.DefaultPasswordHashService;
 
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
 public class UserStoreTest {
-
     private final Connection connectionMock = mock(Connection.class);
-
-    private final ConnectionProvider connectionFactoryMock = () -> connectionMock;
-
-    private final UserStore userStoreUnderTest = new UserStore(connectionFactoryMock,
+    private final UserStore userStoreUnderTest = new UserStore(() -> connectionMock,
             new DefaultPasswordHashService());
 
     @Test
-    public void getUsersTest() throws SQLException, Exception {
+    public void getUsersTest() throws Exception {
         // Setup Mock Behavior
-        String[] tableTypes = { "TABLE" };
-        when(connectionMock.isClosed()).thenReturn(false);
         DatabaseMetaData dbmMock = mock(DatabaseMetaData.class);
         when(connectionMock.getMetaData()).thenReturn(dbmMock);
         ResultSet rsUserMock = mock(ResultSet.class);
-        when(dbmMock.getTables(null, null, "USERS", tableTypes)).thenReturn(rsUserMock);
+        when(dbmMock.getTables(null, null, UserStore.TABLE, AbstractStore.TABLE_TYPES)).thenReturn(rsUserMock);
         when(rsUserMock.next()).thenReturn(true);
 
         Statement stmtMock = mock(Statement.class);
@@ -56,15 +53,16 @@ public class UserStoreTest {
         verify(stmtMock).close();
     }
 
-    public ResultSet getMockedResultSet() throws SQLException {
+    private static ResultSet getMockedResultSet() throws SQLException {
         ResultSet rsMock = mock(ResultSet.class);
         when(rsMock.next()).thenReturn(true).thenReturn(false);
-        when(rsMock.getInt(UserStore.SQL_ID)).thenReturn(1);
-        when(rsMock.getString(UserStore.SQL_NAME)).thenReturn("Name_1");
-        when(rsMock.getString(UserStore.SQL_EMAIL)).thenReturn("Name_1@company.com");
-        when(rsMock.getString(UserStore.SQL_PASSWORD)).thenReturn("Pswd_1");
-        when(rsMock.getString(UserStore.SQL_DESCR)).thenReturn("Desc_1");
-        when(rsMock.getInt(UserStore.SQL_ENABLED)).thenReturn(1);
+        when(rsMock.getString(UserStore.COL_ID)).thenReturn("1");
+        when(rsMock.getString(UserStore.COL_NAME)).thenReturn("Name_1");
+        when(rsMock.getString(UserStore.COL_EMAIL)).thenReturn("Name_1@company.com");
+        when(rsMock.getString(UserStore.COL_PASSWORD)).thenReturn("Pswd_1");
+        when(rsMock.getString(UserStore.COL_DESC)).thenReturn("Desc_1");
+        when(rsMock.getString(UserStore.COL_DOMAIN_ID)).thenReturn("Domain_1");
+        when(rsMock.getInt(UserStore.COL_ENABLED)).thenReturn(1);
         return rsMock;
     }
 }