From e63b03f3d7e4851e008e4bb4d184982c2c0bd229 Mon Sep 17 00:00:00 2001 From: WuKong Date: Tue, 24 May 2016 17:13:17 +0200 Subject: odl/aaa clone Change-Id: I2b72c16aa3245e02d985a2c6189aacee7caad36e Signed-off-by: WuKong --- .../aaa/h2/persistence/AbstractStore.java | 187 +++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 odl-aaa-moon/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java (limited to 'odl-aaa-moon/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java') diff --git a/odl-aaa-moon/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java b/odl-aaa-moon/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java new file mode 100644 index 00000000..ba00eb84 --- /dev/null +++ b/odl-aaa-moon/aaa-h2-store/src/main/java/org/opendaylight/aaa/h2/persistence/AbstractStore.java @@ -0,0 +1,187 @@ +/* + * Copyright © 2016 Red Hat, Inc. and others. + * + * 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.h2.persistence; + +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Base class for H2 stores. + */ +abstract class AbstractStore { + /** + * Logger. + */ + private static final Logger LOG = LoggerFactory.getLogger(AbstractStore.class); + + /** + * The name of the table used to represent this store. + */ + private final String tableName; + + /** + * Database connection, only used for tests. + */ + Connection dbConnection = null; + + /** + * Table types we're interested in (when checking tables' existence). + */ + public static final String[] TABLE_TYPES = new String[] { "TABLE" }; + + /** + * Creates an instance. + * + * @param tableName The name of the table being managed. + */ + protected AbstractStore(String tableName) { + this.tableName = tableName; + } + + /** + * Returns a database connection. It is the caller's responsibility to close it. If the managed table does not + * 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 = H2Store.getConnection(dbConnection); + 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 { + LOG.info("Table {} does not exist, creating it", tableName); + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate(getTableCreationStatement()); + } + } + } + } + } catch (SQLException e) { + LOG.error("Error connecting to the H2 database", e); + throw new StoreException("Cannot connect to database server", e); + } + return conn; + } + + /** + * Empties the store. + * + * @throws StoreException if a connection error occurs. + */ + protected 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; + c.createStatement().execute(sql); + } 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(); + + /** + * Lists all the stored items. + * + * @return The stored item. + * + * @throws StoreException if an error occurs. + */ + protected List listAll() throws StoreException { + List result = new ArrayList<>(); + String query = "SELECT * FROM " + tableName; + try (Connection conn = dbConnect(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(query)) { + while (rs.next()) { + result.add(fromResultSet(rs)); + } + } catch (SQLException e) { + LOG.error("Error listing all items from {}", tableName, e); + throw new StoreException(e); + } + return result; + } + + /** + * Lists the stored items returned by the given statement. + * + * @param ps The statement (which must be ready for execution). It is the caller's reponsibility to close this. + * + * @return The stored items. + * + * @throws StoreException if an error occurs. + */ + protected List listFromStatement(PreparedStatement ps) throws StoreException { + List result = new ArrayList<>(); + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + result.add(fromResultSet(rs)); + } + } catch (SQLException e) { + LOG.error("Error listing matching items from {}", tableName, e); + throw new StoreException(e); + } + return result; + } + + /** + * 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 reponsibility 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; + } + } catch (SQLException e) { + LOG.error("Error listing first matching item from {}", tableName, e); + throw new StoreException(e); + } + } + + /** + * 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 not be called). + * + * @return The corresponding instance. + * + * @throws SQLException if an error occurs. + */ + protected abstract T fromResultSet(ResultSet rs) throws SQLException; +} -- cgit 1.2.3-korg