/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.karaf.main.lock; import java.sql.ResultSet; import java.sql.SQLException; /** * <p>This class is used to create the sql statements for the Karaf lock tables that are used * for clustering of Karaf instances.</p> * * <p>It will generate sql statement to create two separate tables, a lock table and a lock id table:</p> * * <code> * CREATE TABLE LOCK ( ID INTEGER DEFAULT 0, STATE INTEGER DEFAULT 0, LOCK_DELAY INTEGER DEFAULT 0 ) * * CREATE TABLE LOCK_ID ( ID INTEGER DEFAULT 0 ) * </code> * */ public class GenericStatements { private final String lockTableName; private final String lockIdTableName; private final String clusterName; /** * This constructor is used to determine the name of the Karaf lock table, the Karaf lock id * table and the name of the clustered instances. * * @param lockTableName The name of the karaf lock table. * @param lockIdTableName The name of the karaf lock id table. * @param clusterName the name of the cluster being used. */ public GenericStatements(String lockTableName, String lockIdTableName, String clusterName) { this.lockTableName = lockTableName; this.lockIdTableName = lockIdTableName; this.clusterName = clusterName; } /** * This method will return the name of the cluster that the instances are using to compete for the * master lock. * * @return The cluster node name. */ public final String getNodeName() { return this.clusterName; } /** * This method will return the name of the Karaf lock table. * * @return The name of the Karaf lock table. */ public final String getLockTableName() { return lockTableName; } /** * This method will return the insert statement used to create a row in the Lock table and will * generate the following sql statement. * * <code> * INSERT INTO KARAF_LOCK (ID, STATE, LOCK_DELAY) VALUES (0, 0, 0) * </code> * * @return The SQL insert statement. */ private String getLockTableInitialInsertStatement() { return "INSERT INTO " + this.getLockTableName() + "(ID, STATE, LOCK_DELAY) VALUES (0, 0, 0)"; } /** * This will be called when trying to acquire the lock and will generate the following sql statement. * * <code> * UPDATE KARAF_LOCK SET ID = ?, STATE = ?, LOCK_DELAY = ? WHERE ID = 0 OR ID = ? * </code> * * You are then expected to assign the values associated with the sql statement. * * @param id The new ID. * @param state The new lock state. * @param lock_delay The new lock delay. * @param curId The current ID. * @return The SQL update statement. */ public String getLockUpdateIdStatement(int id, int state, int lock_delay, int curId) { return String.format("UPDATE %s SET ID = %d, STATE = %d, LOCK_DELAY = %d WHERE ID = 0 OR ID = %d", this.getLockTableName(), id, state, lock_delay, curId); } /** * This will be called when trying to steal the lock and will generate the following sql statement. * * <code> * UPDATE KARAF_LOCK SET ID = ?, STATE = ?, LOCK_DELAY = ? WHERE ( ID = 0 OR ID = ? ) AND STATE = ? * </code> * * You are then responsible to assign the values of the different fields using standard JDBC statement * calls. * * @param id The new ID. * @param state The new lock state. * @param lock_delay The new lock delay. * @param curId The current ID. * @param curState The current state. * @return The SQL update statement. */ public String getLockUpdateIdStatementToStealLock(int id, int state, int lock_delay, int curId, int curState) { return String.format("UPDATE %s SET ID = %d, STATE = %d, LOCK_DELAY = %d WHERE ( ID = 0 OR ID = %d ) AND STATE = %d", this.getLockTableName(), id, state, lock_delay, curId, curState) ; } /** * This method is called only when we are releasing the lock and will generate the following sql * statement. * * UPDATE KARAF_LOCK SET ID = 0 WHERE ID = ? * * @param id The current ID. * @return sql update statement */ public String getLockResetIdStatement(int id) { return String.format("UPDATE %s SET ID = 0 WHERE ID = %d", this.getLockTableName(), id); } /** * This will be called to determine the current master instance for the lock table and will * generate the following sql statement. * * <code> * SELECT ID, STATE, LOCK_DELAY FROM KARAF_LOCK * </code> * * @return sql select statement */ public String getLockSelectStatement() { return "SELECT ID, STATE, LOCK_DELAY FROM " + this.getLockTableName(); } public int getIdFromLockSelectStatement(ResultSet rs) throws SQLException { return rs.getInt(1); } public int getStateFromLockSelectStatement(ResultSet rs) throws SQLException { return rs.getInt(2); } public int getLockDelayFromLockSelectStatement(ResultSet rs) throws SQLException { return rs.getInt(3); } /** * This method should only be called during the creation of the KARAF_LOCK table and will * generate the following sql statement. * * <code> * CREATE TABLE KARAF_LOCK (ID INTEGER DEFAULT 0, STATE INTEGER DEFAULT 0, LOCK_DELAY INTEGER DEFAULT 0) * </code> * * @return The SQL create table statement. */ private String getLockTableCreateStatement() { return "CREATE TABLE " + this.getLockTableName() + " ( ID INTEGER DEFAULT 0, STATE INTEGER DEFAULT 0 , LOCK_DELAY INTEGER DEFAULT 0 )"; } /** * This method will generate the create table sql statement to create the karaf id table and will * generate the following sql statement. * * <code> * CREATE TABLE KARAF_ID ( ID INTEGER DEFAULT 0 ) * </code> * * @return The SQL create table statement. */ private String getLockIdTableCreateStatement() { return "CREATE TABLE " + this.getLockIdTableName() + " ( ID INTEGER DEFAULT 0 )"; } /** * This method will return the sql statement to retreive the id of the lock id table and will * generate the following sql statement. * * <code> * SELECT ID FROM KARAF_ID * </code> * * @return The SQL select statement. */ public String getLockIdSelectStatement() { return "SELECT ID FROM " + this.getLockIdTableName(); } public int getIdFromLockIdSelectStatement(ResultSet rs) throws SQLException { return rs.getInt(1); } /** * This method will return the update statement for the lock id table and will generate the * following sql statement. * * <code> * UPDATE KARAF_ID SET ID = ? WHERE ID = ? * </code> * * @param id The new ID. * @param curId The current ID. * @return The SQL update statement. */ public String getLockIdUpdateIdStatement(int id, int curId) { return String.format("UPDATE %s SET ID = %d WHERE ID = %d", this.getLockIdTableName(), id, curId); } /** * This method will return the name of the Karaf lock id table. * * @return The name of the Karaf lock id table. */ public final String getLockIdTableName() { return lockIdTableName; } /** * This method will return the required sql statements to initialize the lock database. * * @param moment The moment. * @return The array of SQL statements. */ public String[] getLockCreateSchemaStatements(long moment) { return new String[] { getLockTableCreateStatement(), getLockIdTableCreateStatement(), getLockTableInitialInsertStatement(), getLockIdTableInitialInsertStatement(), }; } /** * This method will return the insert statement to insert a row in the lock id table and will * generate the following sql statement. * * <code> * INSERT INTO KARAF_ID (ID) VALUES (0) * </code> * * @return The SQL insert statement. */ private String getLockIdTableInitialInsertStatement() { return "INSERT INTO " + this.getLockIdTableName() + "(ID) VALUES (0)"; } }