diff geo-backend/src/main/java/de/intevation/gnv/geobackend/sde/datasources/ArcSDEConnectionPool.java @ 129:110e3ac1b7d2

Library Dependencies Added to pom.xml-File Import of SDE-Datasources geo-backend/trunk@5 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Tim Englich <tim.englich@intevation.de>
date Wed, 02 Sep 2009 09:07:03 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/geo-backend/src/main/java/de/intevation/gnv/geobackend/sde/datasources/ArcSDEConnectionPool.java	Wed Sep 02 09:07:03 2009 +0000
@@ -0,0 +1,288 @@
+/*******************************************************************************
+ * Copyright © 2007 52°North Initiative for Geospatial Open Source Software GmbH
+ *
+ * Author: Oliver Meyer, University of Muenster
+ *
+ * Contact: Andreas Wytzisk, 52°North Initiative for Geospatial Open Source
+ * Software GmbH, Martin-Luther-King-Weg 24, 48155 Muenster, Germany,
+ * info@52north.org
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; even without the implied WARRANTY OF MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program (see gnu-gpl v2.txt). If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA or
+ * visit the Free Software Foundation’s web page, http://www.fsf.org.
+ *
+ ******************************************************************************/
+// Last changes on: 2007-06-03
+// Last changes by: Oliver Meyer
+
+package de.intevation.gnv.geobackend.sde.datasources;
+
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.Map.Entry;
+
+import org.apache.log4j.Logger;
+
+import com.esri.sde.sdk.client.SeConnection;
+import com.esri.sde.sdk.client.SeException;
+
+import de.intevation.gnv.geobackend.sde.datasources.exception.ConnectionException;
+import de.intevation.gnv.geobackend.sde.datasources.exception.TechnicalException;
+
+/**
+ * Connection Pool for ArcSDE databases.
+ *
+ * @author Oliver Meyer
+ * @version 1.0
+ */
+public class ArcSDEConnectionPool {
+
+    /**
+     * Default Logging instance
+     */
+    private static final Logger sLogger = Logger.getLogger(ArcSDEConnectionPool.class);
+    private static boolean sDebug = sLogger.isDebugEnabled();
+
+    /**
+     * timer for holding connections
+     */
+    private Timer timer;
+
+    /**
+     * the logger, used to log exceptions and additonaly information
+     */
+    private static Logger log = Logger.getLogger(ArcSDEConnectionPool.class);
+
+    /**
+     * Hashtable containing the connections as keys and Boolean as value (False if the connection is not used)
+     */
+    private Hashtable<SeConnection, Boolean> connections;
+
+    private static ArcSDEConnectionPool sInstance = null;
+
+    private static ArcSDEConnectionParams sParams = null;
+
+    public static ArcSDEConnectionPool getInstance() throws TechnicalException {
+        if (sInstance == null) {
+            throw new TechnicalException("The ArcSDEConnectionPool has to be configured first!");
+        }
+        return sInstance;
+    }
+
+    public static boolean isConfigured() {
+        return sParams != null;
+    }
+
+    public static void configure(ArcSDEConnectionParams pParams) throws TechnicalException {
+        if (sDebug) sLogger.debug("configure()");
+
+        if (sInstance == null) {
+            synchronized (ArcSDEConnectionPool.class) {
+                sInstance = new ArcSDEConnectionPool(pParams);
+            }
+        } else {
+            throw new TechnicalException("The ArcSDEConnectionPool is already configured: " + pParams.toString());
+        }
+
+    }
+
+
+    private ArcSDEConnectionPool(ArcSDEConnectionParams pParams) throws ConnectionException {
+        if (sDebug) sLogger.debug("ArcSDEConnectionPool()");
+        sParams = pParams;
+
+        connections = new Hashtable<SeConnection, Boolean>();
+        initPool(sParams.getInitConnections());
+        timer = new Timer("ArcSDEConnectionPoolTimer");
+        startConnectionTask();
+    }
+
+    /**
+     * help method for initializing the connection pool
+     *
+     * @param initConnections number of initial connections
+     * @throws OwsExceptionReport if creating connections failed while initializing the connection pool
+     */
+    protected void initPool(int initConnections) throws ConnectionException {
+
+        // initialize connections;
+        // "false" indicates that the connection is not used yet
+        for (int i = 0; i < initConnections; ++i) {
+            SeConnection con = getNewConnection();
+            connections.put(con, Boolean.FALSE);
+        }
+    }
+
+    /**
+     * Method returns an available connection from the pool, and sets it on "not available". After the query
+     * operation, you have to "give back" the connection to the pool with the returnConnection method!
+     *
+     * @return ArcSDE connection to execute the query
+     * @throws OwsExceptionReport If all connections are in use and no further connection could be established
+     * @throws OwsExceptionReport
+     */
+    protected SeConnection getConnection() throws ConnectionException {
+
+        SeConnection con = null;
+
+        Enumeration<SeConnection> cons = connections.keys();
+
+        // no other operation (maybe adding a connection) while checking which
+        // (or whether a) connection is available
+        synchronized (connections) {
+
+            while (cons.hasMoreElements()) {
+                con = cons.nextElement();
+                Boolean b = connections.get(con);
+
+                // checking whether connection is available
+                if (b == Boolean.FALSE) {
+                    // connection is available, now test, whether connection is
+                    // OK (with setAutoCommit)
+                    try {
+                        con.setTransactionAutoCommit(1000);
+                    }
+                    catch (SeException sdeEx) {
+                        // problem with connection, so remove and create new
+                        // connection
+                        connections.remove(con);
+
+                        con = getNewConnection();
+
+                    }
+                    // set connection "not available" (Value=true)
+                    connections.put(con, Boolean.TRUE);
+                    return con;
+                }
+            }
+        }
+
+        // if no connections are available, create new one
+        if (connections.size() <= sParams.getMaxConnections()) {
+
+            con = getNewConnection();
+
+            connections.put(con, Boolean.TRUE);
+        }
+        // if maximal number of connections is arrived, throw exception!
+        else {
+            throw new ConnectionException("All db connections are in use. Please try again later!");
+        }
+
+        // return new Connection
+        return con;
+    }
+
+    /**
+     * abstract method creates a new connection; must be implemented by all subclasses!
+     *
+     * @return Returns connection - new connection to the database
+     * @throws OwsExceptionReport if creating a new connection failed
+     */
+    private SeConnection getNewConnection() throws ConnectionException {
+        SeConnection con;
+
+        // creating new connection
+        try {
+
+            con = new SeConnection(sParams.getServer(), sParams.getInstance(), sParams.getDatabase(), sParams.getUser(), sParams.getPwd());
+
+            //            Class.forName("org.postgresql.Driver");
+            //            con = DriverManager.getConnection(props.getProperty("CONNECTION"), props);
+
+        }
+        catch (SeException sdeEx) {
+            throw new ConnectionException("Establishing a connection to database failed: " + sdeEx.toString(), sdeEx);
+        }
+
+        return con;
+    }
+
+    /**
+     * Invoke this method after executing the query with this connection, so that the connection is already
+     * available in the pool
+     *
+     * @param con the connection which was used and now is available again
+     */
+    public void returnConnection(SeConnection con) {
+        if (connections.containsKey(con)) {
+            connections.put(con, Boolean.FALSE);
+        }
+    }
+
+    /**
+     * method sends a query for every connection
+     */
+    private void holdConnections() {
+        Set<Entry<SeConnection, Boolean>> entrySet = connections.entrySet();
+        Iterator<Entry<SeConnection, Boolean>> iter = entrySet.iterator();
+        SeConnection con = null;
+        while (iter.hasNext()) {
+            Entry<SeConnection, Boolean> entry = iter.next();
+
+            //Connection in use?
+            if (entry.getValue() == false) {
+                con = entry.getKey();
+                try {
+                    con.setTransactionAutoCommit(1000);
+                }
+                catch (SeException sdeEx) {
+
+                    //if sql exception occurs, try to built new connection and put connection into pool
+                    connections.remove(con);
+                    try {
+                        SeConnection conNew = getNewConnection();
+                        connections.put(conNew, Boolean.FALSE);
+                    }
+                    catch (ConnectionException e) {
+                        log.debug("Erroe while refreshing connections: " + e.getMessage());
+                    }
+                    log.error("An error occurred while holding connections through query!", sdeEx);
+                }
+            }
+        }
+    }
+
+    /**
+     * method invokes the schedule method of the timer with a new InstantFeederTask, the actual date and the
+     * period from the config file as parameters.
+     *
+     * @throws OwsExceptionReport if creation of the InstantFeederTask failed
+     */
+    private void startConnectionTask() throws ConnectionException {
+        timer.schedule(new ConnectionTask(), new Date(), sParams.getTimeToHold());
+    }
+
+    /**
+     * connection task used for holding connections and making sure, that these
+     *
+     * @author Christoph Stasch
+     */
+    protected class ConnectionTask extends TimerTask {
+
+        /**
+         * overwritten run method of TimerTask which queries offeringIDs from db to make sure, that
+         * connections won't be blocked by the firewalls
+         */
+        public void run() {
+            holdConnections();
+        }
+
+    }
+
+}
\ No newline at end of file

http://dive4elements.wald.intevation.org