| /* |
| * 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.felix.karaf.main; |
| |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.PreparedStatement; |
| import java.sql.SQLException; |
| import java.util.Properties; |
| import java.util.logging.Logger; |
| |
| /** |
| * Represents an exclusive lock on a database, |
| * used to avoid multiple Karaf instances attempting |
| * to become master. |
| * |
| * @version $Revision: $ |
| */ |
| public class DefaultJDBCLock implements Lock { |
| |
| private static final Logger LOG = Logger.getLogger(DefaultJDBCLock.class.getName()); |
| private static final String PROPERTY_LOCK_URL = "karaf.lock.jdbc.url"; |
| private static final String PROPERTY_LOCK_JDBC_DRIVER = "karaf.lock.jdbc.driver"; |
| private static final String PROPERTY_LOCK_JDBC_USER = "karaf.lock.jdbc.user"; |
| private static final String PROPERTY_LOCK_JDBC_PASSWORD = "karaf.lock.jdbc.password"; |
| private static final String PROPERTY_LOCK_JDBC_TABLE = "karaf.lock.jdbc.table"; |
| private static final String PROPERTY_LOCK_JDBC_CLUSTERNAME = "karaf.lock.jdbc.clustername"; |
| private static final String PROPERTY_LOCK_JDBC_TIMEOUT = "karaf.lock.jdbc.timeout"; |
| |
| private final Statements statements; |
| private Connection lockConnection; |
| private String url; |
| private String driver; |
| private String user; |
| private String password; |
| private String table; |
| private String clusterName; |
| private int timeout; |
| |
| public DefaultJDBCLock(Properties props) { |
| LOG.addHandler(BootstrapLogManager.getDefaultHandler()); |
| this.url = props.getProperty(PROPERTY_LOCK_URL); |
| this.driver = props.getProperty(PROPERTY_LOCK_JDBC_DRIVER); |
| this.user = props.getProperty(PROPERTY_LOCK_JDBC_USER); |
| this.password = props.getProperty(PROPERTY_LOCK_JDBC_PASSWORD); |
| this.table = props.getProperty(PROPERTY_LOCK_JDBC_TABLE); |
| this.clusterName = props.getProperty(PROPERTY_LOCK_JDBC_CLUSTERNAME); |
| String time = props.getProperty(PROPERTY_LOCK_JDBC_TIMEOUT); |
| this.lockConnection = null; |
| if (table == null) { table = "KARAF_LOCK"; } |
| if ( clusterName == null) { clusterName = "karaf"; } |
| this.statements = new Statements(table, clusterName); |
| if (time != null) { |
| this.timeout = Integer.parseInt(time) * 1000; |
| } else { |
| this.timeout = 10000; // 10 seconds |
| } |
| if (user == null) { user = ""; } |
| if (password == null) { password = ""; } |
| } |
| |
| /** |
| * setUpdateCursor - Send Update directive to data base server. |
| * |
| * @throws Exception |
| */ |
| private boolean setUpdateCursor() throws Exception { |
| PreparedStatement statement = null; |
| boolean result = false; |
| try { |
| if ((lockConnection == null) || (lockConnection.isClosed())) { |
| lockConnection = getConnection(driver, url, user, password); |
| lockConnection.setAutoCommit(false); |
| statements.init(lockConnection); |
| } |
| //statements.init(lockConnection); |
| String sql = statements.setUpdateCursor(); |
| statement = lockConnection.prepareStatement(sql); |
| result = statement.execute(); |
| } catch (Exception e) { |
| LOG.warning("Could not obtain connection: " + e.getMessage()); |
| } finally { |
| if (null != statement) { |
| try { |
| LOG.severe("Cleaning up DB connection."); |
| statement.close(); |
| } catch (SQLException e1) { |
| LOG.severe("Caught while closing statement: " + e1.getMessage()); |
| } |
| statement = null; |
| } |
| } |
| LOG.info("Connected to data source: " + url); |
| return result; |
| } |
| |
| /** |
| * lock - a KeepAlive function to maintain lock. |
| * |
| * @return true if connection lock retained, false otherwise. |
| */ |
| public boolean lock() { |
| PreparedStatement statement = null; |
| boolean result = false; |
| try { |
| if (!setUpdateCursor()) { |
| LOG.severe("Could not set DB update cursor"); |
| return result; |
| } |
| long time = System.currentTimeMillis(); |
| statement = lockConnection.prepareStatement(statements.getLockUpdateStatement(time)); |
| int rows = statement.executeUpdate(); |
| if (rows == 1) { |
| result=true; |
| } |
| } catch (Exception e) { |
| LOG.warning("Failed to acquire database lock: " + e.getMessage()); |
| }finally { |
| if (statement != null) { |
| try { |
| statement.close(); |
| } catch (SQLException e) { |
| LOG.severe("Failed to close statement" + e); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * release - terminate the lock connection safely. |
| */ |
| public void release() throws Exception { |
| if (lockConnection != null && !lockConnection.isClosed()) { |
| lockConnection.rollback(); |
| lockConnection.close(); |
| lockConnection = null; |
| } |
| } |
| |
| /** |
| * isAlive - test if lock still exists. |
| */ |
| public boolean isAlive() throws Exception { |
| if ((lockConnection == null) || (lockConnection.isClosed())) { |
| LOG.severe("Lost lock!"); |
| return false; |
| } |
| PreparedStatement statement = null; |
| boolean result = true; |
| try { |
| long time = System.currentTimeMillis(); |
| statement = lockConnection.prepareStatement(statements.getLockUpdateStatement(time)); |
| int rows = statement.executeUpdate(); |
| if (rows != 1) { |
| result = false; |
| } |
| } catch (Exception ex) { |
| LOG.severe("Error occured while testing lock: " + ex + " " + ex.getMessage()); |
| return false; |
| } finally { |
| if (statement != null) { |
| try { |
| statement.close(); |
| } catch (Exception ex1) { |
| LOG.severe("Error occured after testing lock: " + ex1.getMessage()); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * getConnection - Obtain connection to database via jdbc driver. |
| * |
| * @throws Exception |
| * @param driver, the JDBC driver class. |
| * @param url, url to data source. |
| * @param username, user to access data source. |
| * @param password, password for specified user. |
| * @return connection, null returned if conenction fails. |
| */ |
| private Connection getConnection(String driver, String url, |
| String username, String password) throws Exception { |
| Connection conn = null; |
| try { |
| Class.forName(driver); |
| if (url.startsWith("jdbc:derby:")) { |
| conn = DriverManager.getConnection(url + ";create=true", username, password); |
| } else { |
| conn = DriverManager.getConnection(url, username, password); |
| } |
| } catch (Exception e) { |
| LOG.severe("Error occured while setting up JDBC connection: " + e); |
| throw e; |
| } |
| return conn; |
| } |
| |
| } |