Package org.hsqldb

Source Code of org.hsqldb.ClientConnection

/* Copyright (c) 2001-2010, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


package org.hsqldb;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.DataOutputStream;
import org.hsqldb.navigator.RowSetNavigatorClient;
import org.hsqldb.persist.HsqlProperties;
import org.hsqldb.result.Result;
import org.hsqldb.result.ResultConstants;
import org.hsqldb.result.ResultLob;
import org.hsqldb.rowio.RowInputBinary;
import org.hsqldb.rowio.RowOutputBinary;
import org.hsqldb.rowio.RowOutputInterface;
import org.hsqldb.server.HsqlSocketFactory;
import org.hsqldb.store.ValuePool;
import org.hsqldb.types.BlobDataID;
import org.hsqldb.types.ClobDataID;
import org.hsqldb.types.TimestampData;

/**
* Base remote session proxy implementation. Uses instances of Result to
* transmit and recieve data. This implementation utilises the updated HSQL
* protocol.
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 1.9.0
* @since 1.7.2
*/
public class ClientConnection implements SessionInterface {

    /**
     * Specifies the Compatibility version required for both Servers and
     * network JDBC Clients built with this baseline.  Must remain public
     * for Server to have visibility to it.
     *
     * Update this value only when the current version of HSQLDB does not
     * have inter-compatibility with Server and network JDBC Driver of
     * the previous HSQLDB version.
     *
     * Must specify all 4 version segments (any segment may be the value 0,
     * however). The string elements at (position p from right counted from 0)
     * are multiplied by 100 to power p and added up, then negated, to form the
     * integer representation of version string.
     */
    public static final String NETWORK_COMPATIBILITY_VERSION     = "1.9.0.0";
    public static final int    NETWORK_COMPATIBILITY_VERSION_INT = -1090000;

    //
    static final int             BUFFER_SIZE = 0x1000;
    final byte[]                 mainBuffer  = new byte[BUFFER_SIZE];
    private boolean              isClosed;
    private Socket               socket;
    protected DataOutputStream   dataOutput;
    protected DataInputStream    dataInput;
    protected RowOutputInterface rowOut;
    protected RowInputBinary     rowIn;
    private Result               resultOut;
    private long                 sessionID;
    private long                 lobIDSequence;

    //
    private boolean  isReadOnlyDefault = false;
    private boolean  isAutoCommit      = true;
    private int      zoneSeconds;
    private Scanner  scanner;
    private String   zoneString;
    private Calendar calendar;

    //
    String         host;
    int            port;
    String         path;
    String         database;
    boolean        isTLS;
    int            databaseID;
    String         clientPropertiesString;
    HsqlProperties clientProperties;

    /**
     * Establishes a connection to the server.
     */
    public ClientConnection(String host, int port, String path,
                            String database, boolean isTLS, String user,
                            String password, int timeZoneSeconds) {

        this.host        = host;
        this.port        = port;
        this.path        = path;
        this.database    = database;
        this.isTLS       = isTLS;
        this.zoneSeconds = timeZoneSeconds;
        this.zoneString  = TimeZone.getDefault().getID();

        initStructures();

        Result login = Result.newConnectionAttemptRequest(user, password,
            database, zoneString, timeZoneSeconds);

        initConnection(host, port, isTLS);

        Result resultIn = execute(login);

        if (resultIn.isError()) {
            throw Error.error(resultIn);
        }

        sessionID              = resultIn.getSessionId();
        databaseID             = resultIn.getDatabaseId();
        clientPropertiesString = resultIn.getMainString();
    }

    /**
     * resultOut is reused to trasmit all remote calls for session management.
     * Here the structure is preset for sending attributes.
     */
    private void initStructures() {

        RowOutputBinary rowOutTemp = new RowOutputBinary(mainBuffer);

        rowOut    = rowOutTemp;
        rowIn     = new RowInputBinary(rowOutTemp);
        resultOut = Result.newSessionAttributesResult();
    }

    protected void initConnection(String host, int port, boolean isTLS) {
        openConnection(host, port, isTLS);
    }

    protected void openConnection(String host, int port, boolean isTLS) {

        try {
            socket = HsqlSocketFactory.getInstance(isTLS).createSocket(host,
                                                   port);

            socket.setTcpNoDelay(true);

            dataOutput = new DataOutputStream(socket.getOutputStream());
            dataInput = new DataInputStream(
                new BufferedInputStream(socket.getInputStream()));

            handshake();
        } catch (Exception e) {

            // The details from "e" should not be thrown away here.  This is
            // very useful info for end users to diagnose the runtime problem.
            throw new HsqlException(e, Error.getStateString(ErrorCode.X_08001),
                                    -ErrorCode.X_08001);
        }
    }

    protected void closeConnection() {

        try {
            if (socket != null) {
                socket.close();
            }
        } catch (Exception e) {}

        socket = null;
    }

    public synchronized Result execute(Result r) {

        try {
            r.setSessionId(sessionID);
            r.setDatabaseId(databaseID);
            write(r);

            return read();
        } catch (Throwable e) {
            throw Error.error(ErrorCode.X_08006, e.toString());
        }
    }

    public synchronized RowSetNavigatorClient getRows(long navigatorId,
            int offset, int size) {

        try {
            resultOut.setResultType(ResultConstants.REQUESTDATA);
            resultOut.setResultId(navigatorId);
            resultOut.setUpdateCount(offset);
            resultOut.setFetchSize(size);

            Result result = execute(resultOut);

            return (RowSetNavigatorClient) result.getNavigator();
        } catch (Throwable e) {
            throw Error.error(ErrorCode.X_08006, e.toString());
        }
    }

    public synchronized void closeNavigator(long navigatorId) {

        try {
            resultOut.setResultType(ResultConstants.CLOSE_RESULT);
            resultOut.setResultId(navigatorId);
            execute(resultOut);
        } catch (Throwable e) {}
    }

    public synchronized void close() {

        if (isClosed) {
            return;
        }

        isClosed = true;

        try {
            resultOut.setResultType(ResultConstants.DISCONNECT);
            execute(resultOut);
        } catch (Exception e) {}

        try {
            closeConnection();
        } catch (Exception e) {}
    }

    public synchronized Object getAttribute(int id) {

        resultOut.setResultType(ResultConstants.GETSESSIONATTR);
        resultOut.setStatementType(id);

        Result in = execute(resultOut);

        if (in.isError()) {
            throw Error.error(in);
        }

        Object[] data = in.getSingleRowData();

        switch (id) {

            case SessionInterface.INFO_AUTOCOMMIT :
                return data[SessionInterface.INFO_BOOLEAN];

            case SessionInterface.INFO_CONNECTION_READONLY :
                return data[SessionInterface.INFO_BOOLEAN];

            case SessionInterface.INFO_ISOLATION :
                return data[SessionInterface.INFO_INTEGER];

            case SessionInterface.INFO_CATALOG :
                return data[SessionInterface.INFO_VARCHAR];
        }

        return null;
    }

    public synchronized void setAttribute(int id, Object value) {

        resultOut.setResultType(ResultConstants.SETSESSIONATTR);

        Object[] data = resultOut.getSingleRowData();

        data[SessionInterface.INFO_ID] = ValuePool.getInt(id);

        switch (id) {

            case SessionInterface.INFO_AUTOCOMMIT :
            case SessionInterface.INFO_CONNECTION_READONLY :
                data[SessionInterface.INFO_BOOLEAN] = value;
                break;

            case SessionInterface.INFO_ISOLATION :
                data[SessionInterface.INFO_INTEGER] = value;
                break;

            case SessionInterface.INFO_CATALOG :
                data[SessionInterface.INFO_VARCHAR] = value;
                break;
        }

        Result resultIn = execute(resultOut);

        if (resultIn.isError()) {
            throw Error.error(resultIn);
        }
    }

    public synchronized boolean isReadOnlyDefault() {

        Object info = getAttribute(SessionInterface.INFO_CONNECTION_READONLY);

        isReadOnlyDefault = ((Boolean) info).booleanValue();

        return isReadOnlyDefault;
    }

    public synchronized void setReadOnlyDefault(boolean mode) {

        if (mode != isReadOnlyDefault) {
            setAttribute(SessionInterface.INFO_CONNECTION_READONLY,
                         mode ? Boolean.TRUE
                              : Boolean.FALSE);

            isReadOnlyDefault = mode;
        }
    }

    public synchronized boolean isAutoCommit() {

        Object info = getAttribute(SessionInterface.INFO_AUTOCOMMIT);

        isAutoCommit = ((Boolean) info).booleanValue();

        return isAutoCommit;
    }

    public synchronized void setAutoCommit(boolean mode) {

        if (mode != isAutoCommit) {
            setAttribute(SessionInterface.INFO_AUTOCOMMIT, mode ? Boolean.TRUE
                                                                : Boolean
                                                                .FALSE);

            isAutoCommit = mode;
        }
    }

    public synchronized void setIsolationDefault(int level) {
        setAttribute(SessionInterface.INFO_ISOLATION, ValuePool.getInt(level));
    }

    public synchronized int getIsolation() {

        Object info = getAttribute(SessionInterface.INFO_ISOLATION);

        return ((Integer) info).intValue();
    }

    public synchronized boolean isClosed() {
        return isClosed;
    }

    public Session getSession() {
        return null;
    }

    public synchronized void startPhasedTransaction() {}

    public synchronized void prepareCommit() {

        resultOut.setAsTransactionEndRequest(ResultConstants.PREPARECOMMIT,
                                             null);

        Result in = execute(resultOut);

        if (in.isError()) {
            throw Error.error(in);
        }
    }

    public synchronized void commit(boolean chain) {

        resultOut.setAsTransactionEndRequest(ResultConstants.TX_COMMIT, null);

        Result in = execute(resultOut);

        if (in.isError()) {
            throw Error.error(in);
        }
    }

    public synchronized void rollback(boolean chain) {

        resultOut.setAsTransactionEndRequest(ResultConstants.TX_ROLLBACK,
                                             null);

        Result in = execute(resultOut);

        if (in.isError()) {
            throw Error.error(in);
        }
    }

    public synchronized void rollbackToSavepoint(String name) {

        resultOut.setAsTransactionEndRequest(
            ResultConstants.TX_SAVEPOINT_NAME_ROLLBACK, name);

        Result in = execute(resultOut);

        if (in.isError()) {
            throw Error.error(in);
        }
    }

    public synchronized void savepoint(String name) {

        Result result = Result.newSetSavepointRequest(name);
        Result in     = execute(result);

        if (in.isError()) {
            throw Error.error(in);
        }
    }

    public synchronized void releaseSavepoint(String name) {

        resultOut.setAsTransactionEndRequest(
            ResultConstants.TX_SAVEPOINT_NAME_RELEASE, name);

        Result in = execute(resultOut);

        if (in.isError()) {
            throw Error.error(in);
        }
    }

    public void addWarning(HsqlException warning) {}

    public synchronized long getId() {
        return sessionID;
    }

    /**
     * Used by pooled connections to reset the server-side session to a new
     * one. In case of failure, the connection is closed.
     *
     * When the Connection.close() method is called, a pooled connection calls
     * this method instead of HSQLClientConnection.close(). It can then
     * reuse the HSQLClientConnection object with no further initialisation.
     *
     */
    public synchronized void resetSession() {

        Result login    = Result.newResetSessionRequest();
        Result resultIn = execute(login);

        if (resultIn.isError()) {
            isClosed = true;

            closeConnection();

            throw Error.error(resultIn);
        }

        sessionID  = resultIn.getSessionId();
        databaseID = resultIn.getDatabaseId();
    }

    protected void write(Result r) throws IOException, HsqlException {
        r.write(dataOutput, rowOut);
    }

    protected Result read() throws IOException, HsqlException {

        Result result = Result.newResult(dataInput, rowIn);

        result.readAdditionalResults(this, dataInput, rowIn);
        rowOut.setBuffer(mainBuffer);
        rowIn.resetRow(mainBuffer.length);

        return result;
    }

    /**
     * Never called on this class
     */
    public synchronized String getInternalConnectionURL() {
        return null;
    }

    public synchronized long getLobId() {
        return lobIDSequence++;
    }

    public BlobDataID createBlob(long length) {

        BlobDataID blob = new BlobDataID(getLobId());

        return blob;
    }

    public ClobDataID createClob(long length) {

        ClobDataID clob = new ClobDataID(getLobId());

        return clob;
    }

    /**
     * Does nothing here
     */
    public void allocateResultLob(ResultLob resultLob,
                                  InputStream dataInput) {}

    public Scanner getScanner() {

        if (scanner == null) {
            scanner = new Scanner();
        }

        return scanner;
    }

    public Calendar getCalendar() {

        if (calendar == null) {
            TimeZone zone = TimeZone.getTimeZone(zoneString);

            calendar = new GregorianCalendar(zone);
        }

        return calendar;
    }

    public TimestampData getCurrentDate() {

        long currentMillis = System.currentTimeMillis();
        long seconds = HsqlDateTime.getCurrentDateMillis(currentMillis) / 1000;

        return new TimestampData(seconds);
    }

    public int getZoneSeconds() {
        return zoneSeconds;
    }

    public int getStreamBlockSize() {
        return 512 * 1024;
    }

    public HsqlProperties getClientProperties() {

        if (clientProperties == null) {
            if (clientPropertiesString.length() > 0) {
                HsqlProperties.delimitedArgPairsToProps(clientPropertiesString,
                        "=", ";", null);
            } else {
                clientProperties = new HsqlProperties();
            }
        }

        return clientProperties;
    }

    /**
     * Converts specified encoded integer to a Network Compatibility Version
     * String. The tranmitted integer is negative to distinguish it from
     * 7 bit ASCII characters.
     */
    static public String toNetCompVersionString(int i) {

        StringBuffer sb = new StringBuffer();

        i *= -1;

        sb.append(i / 1000000);

        i %= 1000000;

        sb.append('.');
        sb.append(i / 10000);

        i %= 10000;

        sb.append('.');
        sb.append(i / 100);

        i %= 100;

        sb.append('.');
        sb.append(i);

        return sb.toString();
    }

    protected void handshake() throws IOException {
        dataOutput.writeInt(NETWORK_COMPATIBILITY_VERSION_INT);
        dataOutput.flush();
    }
}
TOP

Related Classes of org.hsqldb.ClientConnection

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.