Package com.sun.messaging.jmq.jmsserver.persist.jdbc

Source Code of com.sun.messaging.jmq.jmsserver.persist.jdbc.BrokerDAOImpl

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2000-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* @(#)BrokerDAOImpl.java  1.30 06/29/07
*/

package com.sun.messaging.jmq.jmsserver.persist.jdbc;

import com.sun.messaging.jmq.util.log.Logger;
import com.sun.messaging.jmq.jmsserver.util.*;
import com.sun.messaging.jmq.jmsserver.FaultInjection;
import com.sun.messaging.jmq.jmsserver.cluster.BrokerState;
import com.sun.messaging.jmq.jmsserver.persist.HABrokerInfo;
import com.sun.messaging.jmq.jmsserver.persist.TakeoverLockException;
import com.sun.messaging.jmq.jmsserver.resources.*;
import com.sun.messaging.jmq.jmsserver.Globals;
import com.sun.messaging.jmq.util.UID;
import com.sun.messaging.jmq.io.Status;

import java.util.*;
import java.sql.*;

/**
* BrokerDAOImpl defines/implements the generic DAO API for the Broker table.
*/
class BrokerDAOImpl extends BaseDAOImpl implements BrokerDAO {

    public static final String STORE_SESSION_ID_COLUMN = "STORE_SESSION_ID";

    protected String tableName;

    // SQLs
    protected String insertSQL;
    protected String updateVersionSQL;
    protected String updateURLSQL;
    protected String resetTakeoverBrokerSQL;
    protected String restoreOnTakeoverFailSQL;
    protected String restoreHeartbeatOnTakeoverFailSQL;
    protected String updateHeartbeatSQL;
    protected String updateHeartbeatAndCheckStateSQL;
    protected String updateStateThisBrokerSQL;
    protected String updateStateOtherBrokerSQL;
    protected String takeoverSQL;
    protected String deleteSQL;
    protected String selectSQL;
    protected String selectAllSQL;
    protected String selectAllByStateSQL;
    protected String selectHeartbeatSQL;
    protected String selectAllHeartbeatsSQL;
    protected String selectStateSQL;
    protected String selectAllStatesSQL;
    protected String selectIsBeingTakenOverSQL;

    private FaultInjection fi = null;

    /**
     * Constructor
     * @throws BrokerException
     */
    BrokerDAOImpl() throws BrokerException {

        fi = FaultInjection.getInjection();

        // Initialize all SQLs
        DBManager dbMgr = DBManager.getDBManager();

        tableName = dbMgr.getTableName( TABLE_NAME_PREFIX );

        insertSQL = new StringBuffer(128)
            .append( "INSERT INTO " ).append( tableName )
            .append( " ( " )
            .append( ID_COLUMN ).append( ", " )
            .append( URL_COLUMN ).append( ", " )
            .append( VERSION_COLUMN ).append( ", " )
            .append( STATE_COLUMN ).append( ", " )
            .append( TAKEOVER_BROKER_COLUMN ).append( ", " )
            .append( HEARTBEAT_TS_COLUMN )
            .append( ") VALUES ( ?, ?, ?, ?, ?, ? )" )
            .toString();

        updateVersionSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( VERSION_COLUMN ).append( " = ? " )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .toString();

        updateURLSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( URL_COLUMN ).append( " = ? " )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .toString();

        resetTakeoverBrokerSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " = NULL, " )
            .append( STATE_COLUMN ).append( " = ? " )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " IS NOT NULL")
            .append( " AND " )
            .append( STATE_COLUMN ).append( " = ")
            .append(BrokerState.I_FAILOVER_COMPLETE)
            .toString();

        restoreOnTakeoverFailSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " = NULL, " )
            .append( STATE_COLUMN ).append( " = ? " )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( STATE_COLUMN ).append( " = " )
            .append(BrokerState.I_FAILOVER_STARTED)
            .append( " AND " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " = ?" )
            .toString();

        restoreHeartbeatOnTakeoverFailSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( HEARTBEAT_TS_COLUMN ).append( " = ? " )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( STATE_COLUMN ).append( " = " )
            .append(BrokerState.I_FAILOVER_STARTED)
            .append( " AND " )
            .append( HEARTBEAT_TS_COLUMN ).append( " = ? " )
            .append( " AND " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " = ?" )
            .toString();

        updateHeartbeatSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( HEARTBEAT_TS_COLUMN ).append( " = ?" )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .toString();

        updateHeartbeatAndCheckStateSQL = new StringBuffer( updateHeartbeatSQL )
            .append( " AND " )
            .append( HEARTBEAT_TS_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( STATE_COLUMN ).append( " NOT IN (" )
            .append( BrokerState.I_FAILOVER_PENDING ).append( ", " )
            .append( BrokerState.I_FAILOVER_STARTED ).append( ", " )
            .append( BrokerState.I_FAILOVER_COMPLETE ).append( ", " )
            .append( BrokerState.I_FAILOVER_FAILED ).append( ")" )
            .toString();

        updateStateThisBrokerSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( STATE_COLUMN ).append( " = ?" )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( STATE_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " IS NULL " )
            .toString();

        updateStateOtherBrokerSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( STATE_COLUMN ).append( " = ?" )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( STATE_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " = ?" )
            .toString();

        takeoverSQL = new StringBuffer(128)
            .append( "UPDATE " ).append( tableName )
            .append( " SET " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " = ?, " )
            .append( STATE_COLUMN ).append( " = ?, " )
            .append( HEARTBEAT_TS_COLUMN ).append( " = ?" )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( STATE_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( HEARTBEAT_TS_COLUMN ).append( " = ?" )
            .append( " AND " )
            .append( TAKEOVER_BROKER_COLUMN ).append( " is NULL" )
            .toString();

        deleteSQL = new StringBuffer(128)
            .append( "DELETE FROM " ).append( tableName )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .toString();

        /*
         * All the supported store sessions for a broker is kept in the session
         * table but for convenience we will load the current store session
         * when load the broker info. If a broker doesn't have a current store
         * session, i.e. taken over by another broker, then its value will be 0.
         */

        selectAllSQL = new StringBuffer(128)
            .append( "SELECT bTbl." )
            .append( ID_COLUMN ).append( ", " )
            .append( URL_COLUMN ).append( ", " )
            .append( VERSION_COLUMN ).append( ", " )
            .append( STATE_COLUMN ).append( ", " )
            .append( TAKEOVER_BROKER_COLUMN ).append( ", " )
            .append( HEARTBEAT_TS_COLUMN ).append( ", sTbl." )
            .append( StoreSessionDAO.ID_COLUMN ).append( " AS " )
            .append( STORE_SESSION_ID_COLUMN )
            .append( " FROM " ).append( tableName )
            .append(   " bTbl LEFT JOIN " )
            .append(   dbMgr.getTableName( StoreSessionDAO.TABLE_NAME_PREFIX ) )
            .append(   " sTbl ON bTbl." ).append( ID_COLUMN ).append( " = sTbl." )
            .append(   StoreSessionDAO.BROKER_ID_COLUMN ).append( " AND sTbl." )
            .append(   StoreSessionDAO.IS_CURRENT_COLUMN ).append( " = 1" )
            .toString();

        selectAllByStateSQL = new StringBuffer(128)
            .append( selectAllSQL )
            .append( " WHERE bTbl." )
            .append( STATE_COLUMN ).append( " = ?" )
            .toString();

        selectSQL = new StringBuffer(128)
            .append( selectAllSQL )
            .append( " WHERE bTbl." )
            .append( ID_COLUMN ).append( " = ?" )
            .toString();

        selectHeartbeatSQL = new StringBuffer(128)
            .append( "SELECT " )
            .append( HEARTBEAT_TS_COLUMN )
            .append( " FROM " ).append( tableName )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .toString();

        selectAllHeartbeatsSQL = new StringBuffer(128)
            .append( "SELECT " )
            .append( ID_COLUMN ).append( ", " )
            .append( HEARTBEAT_TS_COLUMN )
            .append( " FROM " ).append( tableName )
            .toString();

        selectStateSQL = new StringBuffer(128)
            .append( "SELECT " )
            .append( STATE_COLUMN )
            .append( " FROM " ).append( tableName )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ?" )
            .toString();

        selectAllStatesSQL = new StringBuffer(128)
            .append( "SELECT " )
            .append( ID_COLUMN ).append( ", " )
            .append( STATE_COLUMN )
            .append( " FROM " ).append( tableName )
            .toString();

        // SQL that can be embedded in EXISTS clause to check if the specified
        // broker is being takenover (uses by other DAOs)
        selectIsBeingTakenOverSQL = new StringBuffer(128)
            .append( "SELECT 1 FROM " ).append( tableName )
            .append( " WHERE " )
            .append( ID_COLUMN ).append( " = ? AND " )
            .append( STATE_COLUMN ).append( " IN (" )
            .append( BrokerState.I_FAILOVER_PENDING ).append( ", " )
            .append( BrokerState.I_FAILOVER_STARTED ).append( ", " )
            .append( BrokerState.I_FAILOVER_COMPLETE ).append( ", " )
            .append( BrokerState.I_FAILOVER_FAILED ).append( ")" )
            .toString();
    }

    /**
     * Get the prefix name of the table.
     * @return table name
     */
    public final String getTableNamePrefix() {
        return TABLE_NAME_PREFIX;
    }

    /**
     * Get the name of the table.
     * @return table name
     */
    public final String getTableName() {
        return tableName;
    }

    /**
     * Insert a new entry.
     * @param conn database connection
     * @param id Broker ID
     * @param takeoverID Broker ID taken over the store
     * @param url the broker's URL
     * @param version the broker's version
     * @param state the broker's state
     * @param sessionID the broker's session ID
     * @param heartbeat the broker's heartbeat timestamp
     * @throws BrokerException
     */
    public void insert( Connection conn, String id, String takeoverID, String url,
        int version, int state, long sessionID, long heartbeat )
        throws BrokerException {

        Exception myex = null;
        boolean myConn = false;
        PreparedStatement pstmt = null;
        try {
            // Get a connection
            DBManager dbMgr = DBManager.getDBManager();
            if ( conn == null ) {
                conn = dbMgr.getConnection( false );
                myConn = true;
            }

            // First insert broker info
            pstmt = conn.prepareStatement( insertSQL );
            pstmt.setString( 1, id );
            pstmt.setString( 2, url );
            pstmt.setInt( 3, version );
            pstmt.setInt( 4, state );
            Util.setString( pstmt, 5, takeoverID );
            Util.setLong( pstmt, 6, heartbeat );

            pstmt.executeUpdate();
            pstmt.close();

            dbMgr.getDAOFactory().getStoreSessionDAO().insert( conn, id, sessionID, true);

            if ( myConn ) {
                conn.commit();
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + insertSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_PERSIST_BROKERINFO_FAILED,
                    id ), ex );
        } finally {
            if ( myConn ) {
                Util.close( null, pstmt, conn, myex );
            } else {
                Util.close( null, pstmt, null, myex );
            }
        }
    }

    /**
     * Update an existing entry.
     * @param conn database connection
     * @param id Broker ID
     * @param updateType (as defined in HABrokerInfo)
     * @param oldValue (depending on updateType)
     * @param newValue (depending on updateType)
     * @return current active store session UID only if reseted takeover broker
     * @throws BrokerException
     */
    public UID update( Connection conn, String id,
                        int updateType, Object oldValue, Object newValue )
                        throws BrokerException {

        String _updatesql = "";

        UID currentID = null;
        boolean myConn = false;
        PreparedStatement pstmt = null;
        Exception myex = null;
        try {
            // Get a connection
            DBManager dbMgr = DBManager.getDBManager();
            if ( conn == null ) {
                conn = dbMgr.getConnection( false );
                myConn = true;
            }

            switch (updateType) {
                case HABrokerInfo.UPDATE_VERSION:
                    _updatesql = updateVersionSQL;
                    pstmt = conn.prepareStatement( updateVersionSQL );
                    pstmt.setInt( 1, ((Integer)newValue).intValue() );
                    pstmt.setString( 2, id );
                    pstmt.executeUpdate();
                    pstmt.close();
                    break;
                case HABrokerInfo.UPDATE_URL:
                    _updatesql = updateURLSQL;
                    pstmt = conn.prepareStatement( updateURLSQL );
                    pstmt.setString( 1, (String)newValue );
                    pstmt.setString( 2, id );
                    pstmt.executeUpdate();
                    pstmt.close();
                    break;
                case HABrokerInfo.RESET_TAKEOVER_BROKER_READY_OPERATING:
                    _updatesql = resetTakeoverBrokerSQL;
                    pstmt = conn.prepareStatement( resetTakeoverBrokerSQL );
                    pstmt.setInt( 1, (BrokerState.OPERATING).intValue() );
                    pstmt.setString( 2, id );
                    int updateCnt = pstmt.executeUpdate();
                    pstmt.close();
                    if (updateCnt == 1) {
                        logger.log(logger.INFO,  br.getKString(
                            BrokerResources.I_THIS_BROKER_RESETED_TAKEOVER_BROKER, TAKEOVER_BROKER_COLUMN, id));
                        long ssid = dbMgr.getDAOFactory().getStoreSessionDAO().insert(
                                          conn, id, ((UID)newValue).longValue(), false);
                        logger.log(logger.INFO,  br.getKString(
                            BrokerResources.I_THIS_BROKER_CURRENT_STORE_SESSION, id, String.valueOf(ssid)));
                        currentID = new UID(ssid);
                        break;
                    } else if (updateCnt == 0) {
                        _updatesql = updateStateThisBrokerSQL;
                        if (!updateState( conn, id, BrokerState.OPERATING,
                                          (BrokerState)oldValue, true )) {
                            HABrokerInfo info = getBrokerInfo( conn, id);
                            throw new BrokerException(
                            "IllegalStateException for updating state "+oldValue+
                            " to "+BrokerState.OPERATING.toString()+": "+info);
                        }
                        break;
                    } else {
                        throw new BrokerException(
                        "Unexpected affected row count "+updateCnt+" for updating broker info "+id);
                    }
                case HABrokerInfo.RESTORE_ON_TAKEOVER_FAIL:
                   
                    if (fi.FAULT_INJECTION) {
                        fi.checkFaultAndThrowBrokerException(
                           FaultInjection.FAULT_HA_TAKEOVER_RESTORE_EXCEPTION, null);
                        fi.checkFaultAndExit(
                           FaultInjection.FAULT_HA_TAKEOVER_RESTORE_HALT, null, 2, false);
                    }

                    _updatesql = restoreOnTakeoverFailSQL;
                    pstmt = conn.prepareStatement( restoreOnTakeoverFailSQL );
                    pstmt.setInt( 1, ((HABrokerInfo)newValue).getState() );
                    pstmt.setString( 2, id );
                    pstmt.setString( 3, (String)oldValue );
                    updateCnt = pstmt.executeUpdate();
                    pstmt.close();
                    if (updateCnt != 1) {
                        throw new BrokerException(
                        "Unexpected affected row count "+updateCnt+" for restoring broker info "+id);
                    }
                    break;

                case HABrokerInfo.RESTORE_HEARTBEAT_ON_TAKEOVER_FAIL:
                    _updatesql = restoreHeartbeatOnTakeoverFailSQL;
                    pstmt = conn.prepareStatement( restoreHeartbeatOnTakeoverFailSQL );
                    pstmt.setLong( 1, ((HABrokerInfo)newValue).getHeartbeat() );
                    pstmt.setString( 2, id );
                    pstmt.setLong( 3, ((HABrokerInfo)newValue).getTakeoverTimestamp() );
                    pstmt.setString( 4, (String)oldValue );
                    pstmt.executeUpdate();
                    pstmt.close();
                    break;

                default:
                    throw new BrokerException(BrokerResources.E_INTERNAL_ERROR+
                    " Unknown update type "+updateType+" for updating broker info "+id);
            }
            if ( myConn ) {
                conn.commit();
            }
            return currentID;

        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + _updatesql + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_PERSIST_BROKERINFO_FAILED, id ), ex );
        } finally {
            if ( myConn ) {
                Util.close( null, pstmt, conn, myex );
            } else {
                Util.close( null, pstmt, null, myex );
            }
        }
    }

    /**
     * Update the broker heartbeat timestamp to the current time.
     * @param conn database connection
     * @param id Broker ID
     * @return new heartbeat timestamp if set else null
     * @throws BrokerException
     */
    public Long updateHeartbeat( Connection conn, String id)
        throws BrokerException {

        Long newheartbeat = null;

        boolean myConn = false;
        PreparedStatement pstmt = null;
        Exception myex = null;
        try {
            // Get a connection
            if ( conn == null ) {
                conn = DBManager.getDBManager().getConnection( true );
                myConn = true;
            }

            long heartbeat = System.currentTimeMillis();
            pstmt = conn.prepareStatement( updateHeartbeatSQL );
            pstmt.setLong( 1, heartbeat );
            pstmt.setString( 2, id );
            if ( pstmt.executeUpdate() == 1 ) {
                 newheartbeat = new Long( heartbeat );
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + updateHeartbeatSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_UPDATE_HEARTBEAT_TS_FAILED, id ), ex );
        } finally {
            if ( myConn ) {
                Util.close( null, pstmt, conn, myex );
            } else {
                Util.close( null, pstmt, null, myex );
            }
        }

        return newheartbeat;
    }

    /**
     * Update the broker heartbeat timestamp only if the specified lastHeartbeat
     * value match the value store in the DB.
     * @param conn database connection
     * @param id Broker ID
     * @param lastHeartbeat broker's last heartbeat
     * @return new heartbeat timestamp if set else null
     * @throws BrokerException
     */
    public Long updateHeartbeat( Connection conn, String id,
        long lastHeartbeat ) throws BrokerException {

        Long newheartbeat = null;
        boolean myConn = false;
        PreparedStatement pstmt = null;
        Exception myex = null;
        try {
            // Get a connection
            if ( conn == null ) {
                conn = DBManager.getDBManager().getConnection( true );
                myConn = true;
            }

            long heartbeat = System.currentTimeMillis();
            pstmt = conn.prepareStatement( updateHeartbeatAndCheckStateSQL );
            pstmt.setLong( 1, heartbeat );
            pstmt.setString( 2, id );
            pstmt.setLong( 3, lastHeartbeat );
            if ( pstmt.executeUpdate() == 0 ) {
                HABrokerInfo bkrInfo = getBrokerInfo( conn, id );
                if ( bkrInfo == null ) {
                    String errorMsg = br.getKString(
                        BrokerResources.E_BROKERINFO_NOT_FOUND_IN_STORE, id );
                    throw new BrokerException( br.getKString(
                        BrokerResources.X_UPDATE_HEARTBEAT_TS_2_FAILED, id, errorMsg ) );
                }

                // Verify if persistent store is being taken over
                String takeoverBroker = bkrInfo.getTakeoverBrokerID();
                int state = bkrInfo.getState();
                if ( takeoverBroker != null && takeoverBroker.length() > 0 &&
                     ( state == BrokerState.I_FAILOVER_PENDING ||
                       state == BrokerState.I_FAILOVER_STARTED ||
                       state == BrokerState.I_FAILOVER_COMPLETE ||
                       state == BrokerState.I_FAILOVER_FAILED ) ) {
                    BrokerException be = new StoreBeingTakenOverException(
                        br.getKString( BrokerResources.E_STORE_BEING_TAKEN_OVER ) );
                    logger.log( Logger.ERROR, br.getKString(
                        BrokerResources.X_UPDATE_HEARTBEAT_TS_2_FAILED, id,
                        bkrInfo.toString() ), be );
                    throw be;
                }
            } else {
                newheartbeat = new Long( heartbeat );
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + updateHeartbeatAndCheckStateSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            String arg = "Expected last heartbeat " + lastHeartbeat;
            throw new BrokerException(
                br.getKString( BrokerResources.X_UPDATE_HEARTBEAT_TS_2_FAILED, id, arg ), ex );
        } finally {
            if ( myConn ) {
                Util.close( null, pstmt, conn, myex );
            } else {
                Util.close( null, pstmt, null, myex );
            }
        }

        return newheartbeat;
    }

    /**
     * Update the state of a broker only if the current state matches the
     * expected state.
     * @param conn database connection
     * @param id Broker ID
     * @param newState the new state
     * @param expectedState the expected state
     * @return true if state is successfully updated.
     * @throws BrokerException
     */
    public boolean updateState( Connection conn, String id,
                                BrokerState newState,
                                BrokerState expectedState,
                                boolean local) throws BrokerException {

        String _updatesql = "";

        boolean updated = false;
        boolean myConn = false;
        PreparedStatement pstmt = null;
        Exception myex = null;
        try {
            // Get a connection
            if ( conn == null ) {
                conn = DBManager.getDBManager().getConnection( true );
                myConn = true;
            }

            if ( local ) {
                _updatesql = updateStateThisBrokerSQL;
                pstmt = conn.prepareStatement( updateStateThisBrokerSQL );
                pstmt.setInt( 1, newState.intValue() );
                pstmt.setString( 2, id );
                pstmt.setInt( 3, expectedState.intValue() );
                if (pstmt.executeUpdate() == 1) {
                    updated = true;
                }

            } else {
                _updatesql = updateStateOtherBrokerSQL;
                pstmt = conn.prepareStatement( updateStateOtherBrokerSQL );
                pstmt.setInt( 1, newState.intValue() );
                pstmt.setString( 2, id );
                pstmt.setInt( 3, expectedState.intValue() );
                pstmt.setString( 4, DBManager.getDBManager().getBrokerID() );
                if ( pstmt.executeUpdate() == 1 ) {
                    updated = true;
                }
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + _updatesql  + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_PERSIST_BROKERINFO_FAILED, id ), ex );
        } finally {
            if ( myConn ) {
                Util.close( null, pstmt, conn, myex );
            } else {
                Util.close( null, pstmt, null, myex );
            }
        }

        return updated;
    }

    /**
     * Update the state and other relevant attributes of a broker to signify
     * the store is being taken over by another broker. If the operation is
     * successful then this means that the current broker was able to acquire
     * the lock and it is now responsible for taken over the store of the
     * target broker.
     * @param conn database connection
     * @param id the current or local broker ID
     * @param targetBrokerID the broker ID of the store being taken over
     * @param lastHeartbeat broker's last heartbeat
     * @param expectedState the expected state
     * @param newHeartbeat the new timestamp
     * @param newState the new state
     * @throws TakeoverLockException if the current broker is unable to acquire
     *      the takeover lock
     * @throws BrokerException
     * @return previous broker's info associated with the broker
     */
    public HABrokerInfo takeover( Connection conn, String id,
        String targetBrokerID, long lastHeartbeat, BrokerState expectedState,
        long newHeartbeat, BrokerState newState) throws BrokerException {

        HABrokerInfo bkrInfo = null;

        PreparedStatement pstmt = null;
        Exception myex = null;
        try {
            // Save the broker's state before updating
            bkrInfo = getBrokerInfo( conn, targetBrokerID );
            if ( bkrInfo == null ) {
                String errorMsg = br.getKString(
                    BrokerResources.E_BROKERINFO_NOT_FOUND_IN_STORE, targetBrokerID );
                throw new BrokerException(
                    br.getKString( BrokerResources.E_INTERNAL_BROKER_ERROR, errorMsg ) );
            }

            pstmt = conn.prepareStatement( takeoverSQL );
            pstmt.setString( 1, id );
            pstmt.setInt( 2, newState.intValue() );
            pstmt.setLong( 3, newHeartbeat );
            pstmt.setString( 4, targetBrokerID );
            pstmt.setInt( 5, expectedState.intValue() );
            pstmt.setLong( 6, lastHeartbeat );

            if ( pstmt.executeUpdate() != 1 ) {
                String errorMsg = br.getKString(
                    BrokerResources.E_UNABLE_TO_ACQUIRE_TAKEOVER_LOCK, targetBrokerID );
                TakeoverLockException ex = new TakeoverLockException( errorMsg );
                ex.setBrokerInfo( bkrInfo ); // Store broker info
                throw ex;
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + takeoverSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.E_UNABLE_TO_TAKEOVER_BROKER, targetBrokerID ), ex );
        } finally {
            Util.close( null, pstmt, null, myex );
        }

        return bkrInfo;
    }

    /**
     * Delete an entry.
     * @param conn database connection
     * @param id Broker ID
     * @throws BrokerException
     */
    public void delete( Connection conn, String id )
        throws BrokerException {

        boolean myConn = false;
        PreparedStatement pstmt = null;
        Exception myex = null;
        try {
            // Get a connection
            if ( conn == null ) {
                conn = DBManager.getDBManager().getConnection( true );
                myConn = true;
            }

            pstmt = conn.prepareStatement( deleteSQL );
            pstmt.setString( 1, id );
            pstmt.executeUpdate();
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + deleteSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_REMOVE_BROKERINFO_FAILED, id ), ex );
        } finally {
            if ( myConn ) {
                Util.close( null, pstmt, conn, myex );
            } else {
                Util.close( null, pstmt, null, myex );
            }
        }
    }

    /**
     * Delete all entries.
     * @param conn database connection
     * @throws BrokerException
     */
    public void deleteAll( Connection conn )
        throws BrokerException {

        if ( Globals.getHAEnabled() ) {
            return; // // Broker table cannot be reset
        } else {
            super.deleteAll( conn );
        }
    }

    /**
     * Get the heartbeat timestamp for the specified brokerID.
     * @param conn database connection
     * @param id Broker ID
     * @return heartbeat timestamp
     * @throws BrokerException
     */
    public long getHeartbeat( Connection conn, String id )
        throws BrokerException {

        long heartBeat = -1;

        boolean myConn = false;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Exception myex = null;
        try {
            // Get a connection
            if ( conn == null ) {
                conn = DBManager.getDBManager().getConnection( true );
                myConn = true;
            }

            pstmt = conn.prepareStatement( selectHeartbeatSQL );
            pstmt.setString( 1, id );
            rs = pstmt.executeQuery();
            if ( rs.next() ) {
                heartBeat = rs.getLong( 1 );
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + selectHeartbeatSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_LOAD_BROKERINFO_FAILED, id ), ex );
        } finally {
            if ( myConn ) {
                Util.close( rs, pstmt, conn, myex );
            } else {
                Util.close( rs, pstmt, null, myex );
            }
        }

        return heartBeat;
    }

    /**
     * Get the heartbeat timestamp for all brokers in an HA cluster.
     * @param conn database connection
     * @return a HashMap object where the key is the broker ID and the entry
     * value is the broker's heartbeat timestamps
     * @throws BrokerException
     */
    public HashMap getAllHeartbeats( Connection conn )
        throws BrokerException {

        HashMap data = new HashMap();

        boolean myConn = false;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Exception myex = null;
        try {
            // Get a connection
            if ( conn == null ) {
                conn = DBManager.getDBManager().getConnection( true );
                myConn = true;
            }

            pstmt = conn.prepareStatement( selectAllHeartbeatsSQL );
            rs = pstmt.executeQuery();
            while ( rs.next() ) {
                String id = rs.getString( 1 );
                long timestamp = rs.getLong( 2 );
                data.put( id, new Long( timestamp ) );
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + selectAllHeartbeatsSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_LOAD_ALL_BROKERINFO_FAILED ), ex );
        } finally {
            if ( myConn ) {
                Util.close( rs, pstmt, conn, myex );
            } else {
                Util.close( rs, pstmt, null, myex );
            }
        }

        return data;
    }

    /**
     * Get the state for the specified brokerID.
     * @param conn database connection
     * @param id Broker ID
     * @return state of the broker
     * @throws BrokerException
     */
    public BrokerState getState( Connection conn, String id )
        throws BrokerException {

        BrokerState state = null;

        boolean myConn = false;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Exception myex = null;
        try {
            // Get a connection
            if ( conn == null ) {
                conn = DBManager.getDBManager().getConnection( true );
                myConn = true;
            }

            pstmt = conn.prepareStatement( selectStateSQL );
            pstmt.setString( 1, id );
            rs = pstmt.executeQuery();
            if ( rs.next() ) {
                state = BrokerState.getState( rs.getInt( 1 ) );
            } else {
                throw new BrokerException(
                    br.getKString( BrokerResources.E_BROKERINFO_NOT_FOUND_IN_STORE, id ),
                    Status.NOT_FOUND );
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + selectStateSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_LOAD_BROKERINFO_FAILED, id ), ex );
        } finally {
            if ( myConn ) {
                Util.close( rs, pstmt, conn, myex );
            } else {
                Util.close( rs, pstmt, null, myex );
            }
        }

        return state;
    }

    /**
     * Get the state for all brokers in an HA cluster.
     * @param conn database connection
     * @return an array of Object whose 1st element contains an ArrayList
     * of broker IDs and the 2nd element contains an ArrayList of BrokerState
     * @throws BrokerException
     */
    public Object[] getAllStates( Connection conn )
        throws BrokerException {

        ArrayList ids = new ArrayList();
        ArrayList states = new ArrayList();
        Object[] data = new Object[2];
        data[0] = ids;
        data[1] = states;

        boolean myConn = false;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Exception myex = null;
        try {
            // Get a connection
            if ( conn == null ) {
                conn = DBManager.getDBManager().getConnection( true );
                myConn = true;
            }

            pstmt = conn.prepareStatement( selectAllStatesSQL );
            rs = pstmt.executeQuery();
            while ( rs.next() ) {
                String id = rs.getString( 1 );
                int state = rs.getInt( 2 );
                ids.add( id );
                states.add( BrokerState.getState( state ) );
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED+"["+selectAllStatesSQL+"]", rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + selectAllStatesSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_LOAD_ALL_BROKERINFO_FAILED ), ex );
        } finally {
            if ( myConn ) {
                Util.close( rs, pstmt, conn, myex );
            } else {
                Util.close( rs, pstmt, null, myex );
            }
        }

        return data;
    }

    /**
     * Get broker information.
     * @param conn database connection
     * @param id the broker ID.
     * @return a HABrokerInfo object
     * @throws BrokerException
     */
    public HABrokerInfo getBrokerInfo( Connection conn, String id )
        throws BrokerException {

        HABrokerInfo bkrInfo = null;

        boolean myConn = false;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Exception myex = null;
        try {
            // Get a connection
            DBManager dbMgr = DBManager.getDBManager();
            if ( conn == null ) {
                conn = dbMgr.getConnection( true );
                myConn = true;
            }

            pstmt = conn.prepareStatement( selectSQL );
            pstmt.setString( 1, id );
            rs = pstmt.executeQuery();
            if ( rs.next() ) {
                bkrInfo = loadData( rs );
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED+"["+selectSQL+"]", rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + selectSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_LOAD_BROKERINFO_FAILED, id ), ex );
        } finally {
            if ( myConn ) {
                Util.close( rs, pstmt, conn, myex );
            } else {
                Util.close( rs, pstmt, null, myex );
            }
        }

        return bkrInfo;
    }

    /**
     * Get broker information for all brokers.
     * @param conn database connection
     * @param loadSession specify if store sessions should be loaded
     * @return a HashMap object containing HABrokerInfo for all brokers
     * @throws BrokerException
     */
    public HashMap getAllBrokerInfos( Connection conn, boolean loadSession )
        throws BrokerException {

        HashMap data = new HashMap();

        boolean myConn = false;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Exception myex = null;
        try {
            // Get a connection
            DBManager dbMgr = DBManager.getDBManager();
            if ( conn == null ) {
                conn = dbMgr.getConnection( true );
                myConn = true;
            }

            pstmt = conn.prepareStatement( selectAllSQL );
            rs = pstmt.executeQuery();
            while ( rs.next() ) {
                HABrokerInfo bkrInfo = loadData( rs );
                data.put( bkrInfo.getId(), bkrInfo );
            }

            if ( loadSession ) {
                rs.close();
                pstmt.close();
               
                Map sessionMap =
                    dbMgr.getDAOFactory().getStoreSessionDAO().getAllStoreSessions( conn );
                Iterator itr = sessionMap.entrySet().iterator();
                while ( itr.hasNext() ) {
                    Map.Entry entry = (Map.Entry)itr.next();
                    String brokerID = (String)entry.getKey();
                    HABrokerInfo bkrInfo = (HABrokerInfo)data.get( brokerID );
                    if ( bkrInfo != null ) {
                        bkrInfo.setSessionList( (List)entry.getValue() );
                    }
                }
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                        conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED, rbe );
            }

          Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + selectAllSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_LOAD_ALL_BROKERINFO_FAILED ), ex );
        } finally {
            if ( myConn ) {
                Util.close( rs, pstmt, conn, myex );
            } else {
                Util.close( rs, pstmt, null, myex );
            }
        }

        return data;
    }

    /**
     * Get broker information for all brokers in an HA cluster by state.
     * @param conn database connection
     * @param state the state of the broker
     * @return a HashMap object containing HABrokerInfo for all brokers
     * @throws BrokerException
     */
    public HashMap getAllBrokerInfosByState( Connection conn, BrokerState state )
        throws BrokerException {

        HashMap data = new HashMap();

        boolean myConn = false;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Exception myex = null;
        try {
            // Get a connection
            DBManager dbMgr = DBManager.getDBManager();
            if ( conn == null ) {
                conn = dbMgr.getConnection( true );
                myConn = true;
            }

            pstmt = conn.prepareStatement( selectAllByStateSQL );
            pstmt.setInt( 1, state.intValue() );
            rs = pstmt.executeQuery();
            while ( rs.next() ) {
                HABrokerInfo bkrInfo = loadData( rs );
                data.put( bkrInfo.getId(), bkrInfo );
            }
        } catch ( Exception e ) {
            myex = e;
            try {
                if ( (conn != null) && !conn.getAutoCommit() ) {
                    conn.rollback();
                }
            } catch ( SQLException rbe ) {
                logger.log( Logger.ERROR, BrokerResources.X_DB_ROLLBACK_FAILED+"["+selectAllByStateSQL+"]", rbe );
            }

            Exception ex;
            if ( e instanceof BrokerException ) {
                throw (BrokerException)e;
            } else if ( e instanceof SQLException ) {
                ex = DBManager.wrapSQLException("[" + selectAllByStateSQL + "]", (SQLException)e);
            } else {
                ex = e;
            }

            throw new BrokerException(
                br.getKString( BrokerResources.X_LOAD_ALL_BROKERINFO_FAILED ), ex );
        } finally {
            if ( myConn ) {
                Util.close( rs, pstmt, conn, myex );
            } else {
                Util.close( rs, pstmt, null, myex );
            }
        }

        return data;
    }

    /**
     * Get debug information about the store.
     * @param conn database connection
     * @return a HashMap of name value pair of information
     */
    public HashMap getDebugInfo( Connection conn ) {

        HashMap map = new HashMap();
        StringBuffer strBuf = new StringBuffer( 512 );

        try {
            // Get info for all brokers in the cluster
            Collection data = getAllBrokerInfos( conn, false ).values();
            Iterator itr = data.iterator();
            while ( itr.hasNext() ) {
                Object obj = itr.next();
                strBuf.append( obj.toString() ).append( BrokerResources.NL );
            }

        } catch ( Exception e ) {}

        map.put( "Broker(" + tableName + ")", strBuf.toString() );
        return map;
    }

    /**
     * Check whether the specified broker is being taken over by another broker.
     * @param conn database connection
     * @param id Broker ID
     * @return true if the specified broker is being taken over
     * @throws BrokerException
     */
    public boolean isBeingTakenOver( Connection conn, String id )
        throws BrokerException {

        BrokerState brokerState = getState( conn, id );
        int state = brokerState.intValue();
        return ( state == BrokerState.I_FAILOVER_PENDING ||
                 state == BrokerState.I_FAILOVER_STARTED ||
                 state == BrokerState.I_FAILOVER_COMPLETE ||
                 state == BrokerState.I_FAILOVER_FAILED );
    }

    /**
     * Load the broker info to a value object.
     */
    protected HABrokerInfo loadData( ResultSet rs )
        throws SQLException {

        HABrokerInfo brokerInfo = new HABrokerInfo(
            rs.getString( ID_COLUMN ),
            rs.getString( TAKEOVER_BROKER_COLUMN ),
            rs.getString( URL_COLUMN ),
            rs.getInt( VERSION_COLUMN ),
            rs.getInt( STATE_COLUMN ),
            rs.getLong( STORE_SESSION_ID_COLUMN ),
            rs.getLong( HEARTBEAT_TS_COLUMN )
        );

        return brokerInfo;
    }
}
TOP

Related Classes of com.sun.messaging.jmq.jmsserver.persist.jdbc.BrokerDAOImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.