All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.postgis.DriverWrapper Maven / Gradle / Ivy

Go to download

PostGIS adds support for geographic objects to the PostgreSQL object-relational database.

There is a newer version: 2024.1.0
Show newest version
/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * (C) 2005 Markus Schaber, [email protected]
 *
 * (C) 2015 Phillip Ross, [email protected]
 */

package org.postgis;


import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.postgresql.Driver;
import org.postgresql.PGConnection;


/**
 * DriverWrapper
 * 
 * Wraps the PostGreSQL Driver to transparently add the PostGIS Object Classes.
 * This avoids the need of explicit addDataType() calls from the driver users
 * side.
 * 
 * This method currently works with J2EE DataSource implementations, and with
 * DriverManager framework.
 * 
 * Simply replace the "jdbc:postgresql:" with a "jdbc:postgresql_postGIS:" in
 * the jdbc URL.
 * 
 * When using the drivermanager, you need to initialize DriverWrapper instead of
 * (or in addition to) org.postgresql.Driver. When using a J2EE DataSource
 * implementation, set the driver class property in the datasource config, the
 * following works for jboss:
 * 
 * 
 * <driver-class>org.postgis.DriverWrapper</driver-class>
 * 
 * If you don't like or want to use the DriverWrapper, you have two
 * alternatives, see the README file.
 * 
 * Also note that the addDataType() methods known from earlier pgjdbc versions
 * are deprecated in pgjdbc 8.0, see the commented code variants in the
 * addGisTypes() method.
 * 
 * This wrapper always uses EWKT as canonical text representation, and thus
 * works against PostGIS 1.x servers as well as 0.x (tested with 0.8, 0.9 and
 * 1.0).
 * 
 * @author {@literal Markus Schaber }
 * @see DriverWrapperLW
 * @see DriverWrapperAutoprobe
 */
public class DriverWrapper extends Driver {

    /** The static logger instance. */
    protected static final Logger logger = Logger.getLogger("org.postgis.DriverWrapper");
    
    public static final String POSTGRES_PROTOCOL = "jdbc:postgresql:";
    public static final String POSTGIS_PROTOCOL = "jdbc:postgresql_postGIS:";
    public static final String REVISION = "$Revision$";
    protected static TypesAdder ta72 = null;
    protected static TypesAdder ta74 = null;
    protected static TypesAdder ta80 = null;

    protected TypesAdder typesAdder;


    static {
        try {
            // Try to register ourself to the DriverManager
            java.sql.DriverManager.registerDriver(new DriverWrapper());
        } catch (SQLException e) {
            logger.log(Level.WARNING, "Error registering PostGIS Wrapper Driver", e);
        }
    }


    /**
     * Default constructor.
     * 
     * This also loads the appropriate TypesAdder for our SQL Driver instance.
     * 
     * @throws SQLException when a SQLException occurs
     */
    public DriverWrapper() throws SQLException {
        super();
        typesAdder = getTypesAdder(this);
        // The debug method is @since 7.2
        if (super.getMajorVersion() > 8 || super.getMinorVersion() > 1) {
            logger.fine(this.getClass().getName() + " loaded TypesAdder: "
                    + typesAdder.getClass().getName());
        }
    }


    protected static TypesAdder getTypesAdder(final Driver d) throws SQLException {
        if (d.getMajorVersion() == 7) {
            if (d.getMinorVersion() >= 3) {
                if (ta74 == null) {
                    ta74 = loadTypesAdder("74");
                }
                return ta74;
            } else {
                if (ta72 == null) {
                    ta72 = loadTypesAdder("72");
                }
                return ta72;
            }
        } else {
            if (ta80 == null) {
                ta80 = loadTypesAdder("80");
            }
            return ta80;
        }
    }


    private static TypesAdder loadTypesAdder(final String version) throws SQLException {
        try {
            Class klass = Class.forName("org.postgis.DriverWrapper$TypesAdder" + version);
            return (TypesAdder) klass.newInstance();
        } catch (Exception e) {
            throw new SQLException("Cannot create TypesAdder instance! " + e.getMessage());
        }
    }


    /**
     * Creates a postgresql connection, and then adds the PostGIS data types to it calling addpgtypes().
     *
     * A side-effect of this method is that the specified url parameter may be be changed
     * 
     * @param url the URL of the database to connect to (may be changed as a side-effect of this method)
     * @param info a list of arbitrary tag/value pairs as connection arguments
     * @return a connection to the URL or null if it isnt us
     * @exception SQLException if a database access error occurs
     * 
     * @see java.sql.Driver#connect
     * @see org.postgresql.Driver
     */
    public java.sql.Connection connect(String url, final Properties info) throws SQLException {
        url = mangleURL(url);
        Connection result = super.connect(url, info);
        typesAdder.addGT(result, useLW(result));
        return result;
    }


    /**
     * Do we have HexWKB as well known text representation - to be overridden by
     * subclasses.
     *
     * @param result Connection to check
     * @return true if using EWKB, false otherwise
     */
    protected boolean useLW(final Connection result) {
        if (result == null) {
            throw new IllegalArgumentException("null is no valid parameter");
        }
        return false;
    }


    /**
     * Check whether the driver thinks he can handle the given URL.
     *
     * A side-effect of this method is that the specified url parameter may be be changed
     * 
     * @see java.sql.Driver#acceptsURL
     * @param url the URL of the driver (may be changed as a side-effect of this method)
     * @return true if this driver accepts the given URL
     */
    public boolean acceptsURL(String url) {
        try {
            url = mangleURL(url);
        } catch (SQLException e) {
            return false;
        }
        return super.acceptsURL(url);
    }


    /**
     * Returns our own CVS version plus postgres Version
     *
     * @return String value reprenstation of the version
     */
    public static String getVersion() {
        return "PostGisWrapper " + REVISION + ", wrapping " + Driver.getVersion();
    }


    /*
     * Here follows the addGISTypes() stuff. This is a little tricky because the
     * pgjdbc people had several, partially incompatible API changes during 7.2
     * and 8.0. We still want to support all those releases, however.
     * 
     */
    /**
     * adds the JTS/PostGIS Data types to a PG 7.3+ Connection. If you use
     * PostgreSQL jdbc drivers V8.0 or newer, those methods are deprecated due
     * to some class loader problems (but still work for now), and you may want
     * to use the method below instead.
     *
     * @param pgconn The PGConnection object to add the types to
     * @throws SQLException when a SQLException occurs
     * 
     */
    public static void addGISTypes(final PGConnection pgconn) throws SQLException {
        loadTypesAdder("74").addGT((Connection) pgconn, false);
    }


    /**
     * adds the JTS/PostGIS Data types to a PG 8.0+ Connection.
     *
     * @param pgconn The PGConnection object to add the types to
     * @throws SQLException when a SQLException occurs
     */
    public static void addGISTypes80(final PGConnection pgconn) throws SQLException {
        loadTypesAdder("80").addGT((Connection) pgconn, false);
    }


    /**
     * adds the JTS/PostGIS Data types to a PG 7.2 Connection.
     *
     * @param pgconn The PGConnection object to add the types to
     * @throws SQLException when a SQLException occurs
     */
    public static void addGISTypes72(final org.postgresql.PGConnection pgconn) throws SQLException {
        loadTypesAdder("72").addGT((Connection) pgconn, false);
    }


    /**
     * Mangles the PostGIS URL to return the original PostGreSQL URL
     *
     * @param url String containing the url to be "mangled"
     * @return "mangled" string
     * @throws SQLException when a SQLException occurs
     */
    protected String mangleURL(final String url) throws SQLException {
        String myProgo = getProtoString();
        if (url.startsWith(myProgo)) {
            return POSTGRES_PROTOCOL + url.substring(myProgo.length());
        } else {
            throw new SQLException("Unknown protocol or subprotocol in url " + url);
        }
    }


    protected String getProtoString() {
        return POSTGIS_PROTOCOL;
    }


    /** Base class for the three typewrapper implementations */
    protected abstract static class TypesAdder {
        public final void addGT(final java.sql.Connection conn, final boolean lw) throws SQLException {
            if (lw) {
                addBinaryGeometries(conn);
            } else {
                addGeometries(conn);
            }
            addBoxen(conn);
        }

        public abstract void addGeometries(final Connection conn) throws SQLException;

        public abstract void addBoxen(final Connection conn) throws SQLException;

        public abstract void addBinaryGeometries(final Connection conn) throws SQLException;
    }


    /** addGISTypes for V7.3 and V7.4 pgjdbc */
    protected static final class TypesAdder74 extends TypesAdder {

        /** {@inheritDoc} */
        @Override
        public void addGeometries(final Connection conn) throws SQLException {
            PGConnection pgconn = (PGConnection) conn;
            pgconn.addDataType("geometry", org.postgis.PGgeometry.class);
            pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class);
            pgconn.addDataType("\"public\".\"geometry\"", org.postgis.PGgeometry.class);

            pgconn.addDataType("geography", org.postgis.PGgeography.class);
            pgconn.addDataType("public.geography", org.postgis.PGgeography.class);
            pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeography.class);
        }

        /** {@inheritDoc} */
        @Override
        public void addBoxen(final Connection conn) throws SQLException {
            PGConnection pgconn = (PGConnection) conn;
            pgconn.addDataType("box3d", org.postgis.PGbox3d.class);
            pgconn.addDataType("box2d", org.postgis.PGbox2d.class);
        }

        /** {@inheritDoc} */
        @Override
        public void addBinaryGeometries(final Connection conn) throws SQLException {
            PGConnection pgconn = (PGConnection) conn;
            pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class);
            pgconn.addDataType("geography", org.postgis.PGgeographyLW.class);
        }
    }


    /** addGISTypes for V7.2 pgjdbc */
    protected static class TypesAdder72 extends TypesAdder {

        /** {@inheritDoc} */
        @Override
        public void addGeometries(final Connection conn) throws SQLException {
            org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn;
            pgconn.addDataType("geometry", org.postgis.PGgeometry.class);
            pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class);
            pgconn.addDataType("\"public\".\"geometry\"", org.postgis.PGgeometry.class);

            pgconn.addDataType("geography", org.postgis.PGgeography.class);
            pgconn.addDataType("public.geography", org.postgis.PGgeography.class);
            pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeography.class);
        }

        /** {@inheritDoc} */
        @Override
		public void addBoxen(final Connection conn) throws SQLException {
            org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn;
            pgconn.addDataType("box3d", org.postgis.PGbox3d.class);
            pgconn.addDataType("box2d", org.postgis.PGbox2d.class);
        }

        /** {@inheritDoc} */
        @Override
        public void addBinaryGeometries(final Connection conn) throws SQLException {
            org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn;
            pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class);
            pgconn.addDataType("geography", org.postgis.PGgeographyLW.class);
        }
    }


    /** addGISTypes for V8.0 (and hopefully newer) pgjdbc */
    protected static class TypesAdder80 extends TypesAdder {

        /** {@inheritDoc} */
        @Override
        public void addGeometries(final Connection conn) throws SQLException {
            PGConnection pgconn = (PGConnection) conn;
            pgconn.addDataType("geometry", org.postgis.PGgeometry.class);
            pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class);
            pgconn.addDataType("\"public\".\"geometry\"", org.postgis.PGgeometry.class);

            pgconn.addDataType("geography", org.postgis.PGgeometry.class);
            pgconn.addDataType("public.geography", org.postgis.PGgeometry.class);
            pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeometry.class);
        }

        /** {@inheritDoc} */
        @Override
        public void addBoxen(final Connection conn) throws SQLException {
            PGConnection pgconn = (PGConnection) conn;
            pgconn.addDataType("box3d", org.postgis.PGbox3d.class);
            pgconn.addDataType("box2d", org.postgis.PGbox2d.class);
        }

        /** {@inheritDoc} */
        @Override
        public void addBinaryGeometries(final Connection conn) throws SQLException {
            PGConnection pgconn = (PGConnection) conn;
            pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class);
            pgconn.addDataType("geography", org.postgis.PGgeographyLW.class);
        }
    }


    /** {@inheritDoc} */
    @Override
    public Logger getParentLogger() {
        throw new UnsupportedOperationException("Not supported yet.");
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy