Mercurial > dive4elements > gnv-client
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