io.dirigible.mongodb.jdbc.MongodbConnection.java Source code

Java tutorial

Introduction

Here is the source code for io.dirigible.mongodb.jdbc.MongodbConnection.java

Source

/**
 *    Copyright 2015 Georgi Pavlov
 *
 *   Licensed 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 io.dirigible.mongodb.jdbc;

import io.dirigible.mongodb.jdbc.util.SingleColumnMongoIteratorResultSet;
import io.dirigible.mongodb.jdbc.util.SingleColumnStaticResultSet;

import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

import org.bson.BsonDocument;
import org.bson.BsonInt32;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

public class MongodbConnection implements Connection {

    private static final Logger LOG = LoggerFactory.getLogger(MongodbConnection.class);

    private Properties info;
    private MongoClientURI uri;

    private String dbName;
    private String collectionName;
    private boolean isClosed = true;
    private boolean isReadonly = false;

    private MongoClient client;
    private MongoClientOptions clientOptions;
    MongoDatabase db;
    MongoCollection<Document> collection;

    private MongodbDatabaseMetadata metadata;

    public MongodbConnection(String url, Properties info) {
        String dbUrl = url.replace("jdbc:", "");
        MongoClientURI uri = new MongoClientURI(dbUrl);
        this.uri = uri;
        this.dbName = this.uri.getDatabase();
        this.collectionName = this.uri.getCollection();

        this.client = new MongoClient(this.uri);
        this.isClosed = false;

        this.info = info;
        if (this.info == null)
            this.info = new Properties();
        this.clientOptions = this.client.getMongoClientOptions();
        this.info.putAll(this.mongoClientOptionsAsProperties(this.clientOptions, this.info));

        //retrieve these from connected client
        this.dbName = this.uri.getDatabase();
        if (this.dbName != null)
            this.db = this.client.getDatabase(this.dbName);
        if (this.collectionName != null)
            this.collection = this.db.getCollection(this.collectionName);

        LOG.debug("Connected with client properties: " + this.info.toString());
    }

    MongoDatabase getMongoDb() {
        return this.db;
    }

    String getCollectionName() {
        return this.collectionName;
    }

    private Properties mongoClientOptionsAsProperties(MongoClientOptions ops, Properties props) {
        //TODO: write complex object properties too?
        if (ops.getDescription() != null)
            props.setProperty("description", ops.getDescription());
        if (ops.getRequiredReplicaSetName() != null)
            props.setProperty("requiredReplicaSetName", ops.getRequiredReplicaSetName());
        props.setProperty("connectionsPerHost", "" + ops.getConnectionsPerHost());
        props.setProperty("connectTimeout", "" + ops.getConnectTimeout());
        props.setProperty("heartbeatConnectTimeout", "" + ops.getHeartbeatConnectTimeout());
        props.setProperty("heartbeatFrequency", "" + ops.getHeartbeatFrequency());
        props.setProperty("heartbeatSocketTimeout", "" + ops.getHeartbeatSocketTimeout());
        props.setProperty("localThreshold", "" + ops.getLocalThreshold());
        props.setProperty("maxConnectionIdleTime", "" + ops.getMaxConnectionIdleTime());
        props.setProperty("maxConnectionLifeTime", "" + ops.getMaxConnectionLifeTime());
        props.setProperty("maxWaitTime", "" + ops.getMaxWaitTime());
        props.setProperty("minConnectionsPerHost", "" + ops.getMinConnectionsPerHost());
        props.setProperty("minHeartbeatFrequency", "" + ops.getMinHeartbeatFrequency());
        props.setProperty("serverSelectionTimeout", "" + ops.getServerSelectionTimeout());
        props.setProperty("socketTimeout", "" + ops.getSocketTimeout());
        return props;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        if (isWrapperFor(iface)) {
            return (T) this;
        }
        throw new SQLException("No wrapper for " + iface);
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return iface != null && iface.isAssignableFrom(getClass());
    }

    @Override
    public Statement createStatement() throws SQLException {
        return new MongodbStatement(this);
    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
            throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return new MongodbPreparedStatement(this, sql);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
            throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
            int resultSetHoldability) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
            int resultSetHoldability) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
            throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public String nativeSQL(String sql) throws SQLException {
        //TODO: currently works only ofr queries
        BsonDocument filterDocument = null;
        if (sql == null || sql.length() < 1)//that is a call to find() in terms of mongodb queries
            filterDocument = new BsonDocument();
        else
            filterDocument = BsonDocument.parse(sql);
        return filterDocument.toJson();
    }

    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
        //silently ignore
    }

    @Override
    public boolean getAutoCommit() throws SQLException {
        return false;
    }

    @Override
    public void commit() throws SQLException {
        //silently ignore
    }

    @Override
    public void rollback() throws SQLException {
        //silently ignore
    }

    @Override
    public void close() throws SQLException {
        this.client.close();
        this.isClosed = true;
    }

    @Override
    public boolean isClosed() throws SQLException {
        return this.isClosed;
    }

    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        if (metadata == null) {
            metadata = new MongodbDatabaseMetadata();
            Document response = db.runCommand(BsonDocument.parse("{ buildInfo: 1 }"));
            metadata.setDatabaseProductName("MongoDB");
            metadata.setDatabaseProductVersion(response.getString("version"));
            metadata.setDriverName("Java Driver");
            metadata.setURL(this.uri.getURI());
        }
        metadata.setIsReadOnly(client.isLocked());
        ResultSet schemasRS = new SingleColumnStaticResultSet(Arrays.asList(new String[] { "default" }).iterator());
        metadata.setSchemas(schemasRS);
        metadata.setTables(new SingleColumnMongoIteratorResultSet(this.db.listCollectionNames()));

        return metadata;
    }

    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {
        this.isReadonly = readOnly;
    }

    @Override
    public boolean isReadOnly() throws SQLException {
        return this.isReadonly;
    }

    @Override
    public void setCatalog(String catalog) throws SQLException {
        //silently ignore
    }

    @Override
    public String getCatalog() throws SQLException {
        return null;
    }

    @Override
    public void setTransactionIsolation(int level) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public int getTransactionIsolation() throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void clearWarnings() throws SQLException {
        //silently ignore
    }

    @Override
    public Map<String, Class<?>> getTypeMap() throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
        // TODO Auto-generated method stub

    }

    @Override
    public void setHoldability(int holdability) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public int getHoldability() throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public Savepoint setSavepoint() throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void rollback(Savepoint savepoint) throws SQLException {
        //silenty ignore
    }

    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public Clob createClob() throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public Blob createBlob() throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public NClob createNClob() throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public SQLXML createSQLXML() throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public boolean isValid(int timeout) throws SQLException {
        Document response = this.db.runCommand(new BsonDocument("ping", new BsonInt32(1)));
        response.getDouble("ok");
        return response != null && response.getDouble("ok") == 1.0;
    }

    @Override
    public void setClientInfo(String name, String value) throws SQLClientInfoException {
        //silently ingore
    }

    @Override
    public void setClientInfo(Properties properties) throws SQLClientInfoException {
        // silently ingore
    }

    @Override
    public String getClientInfo(String name) throws SQLException {
        return this.info.getProperty(name);
    }

    @Override
    public Properties getClientInfo() throws SQLException {
        return this.info;
    }

    @Override
    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setSchema(String schema) throws SQLException {
        if (schema == null || schema.length() < 1)
            throw new IllegalArgumentException();
        this.collection = this.db.getCollection(schema);
    }

    @Override
    public String getSchema() throws SQLException {
        return this.collectionName;
    }

    @Override
    public void abort(Executor executor) throws SQLException {
        executor.execute(new AsyncAbort(this));
    }

    private class AsyncAbort implements Runnable {
        MongodbConnection mongodbJdbcConnection;

        public AsyncAbort(MongodbConnection mongodbJdbcConnection) {
            this.mongodbJdbcConnection = mongodbJdbcConnection;
        }

        @Override
        public void run() {
            try {
                if (!this.mongodbJdbcConnection.isClosed()) {
                    this.mongodbJdbcConnection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public int getNetworkTimeout() throws SQLException {
        return this.clientOptions.getConnectTimeout();
    }

}