/* * File : JNDIConnectionBeanProvider.java * Created : 10-nov-2005 19:28 * By : fbusquets * * JClic - Authoring and playing system for educational activities * * Copyright (C) 2000 - 2005 Francesc Busquets & Departament * d'Educacio de la Generalitat de Catalunya * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details (see the LICENSE file). */ package edu.xtec.util.db; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.util.Date; import java.util.Map; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; /** * This class is a special {@link edu.xtec.util.db.ConnectionBeanProvider} that obtains * the {@link java.sql.Connection} objects from a JNDI datasource. In order to * obtain objects of this class, the static method <CODE>getConnectionBeanProvider</CODE> of * <CODE>ConnectionBeanProvider</CODE> must be called, passing the text <CODE>JNDI</CODE> as * value of the <CODE>dbDriver</CODE> parameter, and the JNDI name of the datasource * as the value of <CODE>dbServer</CODE> param. * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.09.16 */ public class JNDIConnectionBeanProvider extends ConnectionBeanProvider{ /** * Key used for the <CODE>dbContext</CODE> property */ public static final String DB_CONTEXT="dbContext"; /** * String "JNDI", used to indicate <CODE>ConnectionBeanProvider</CODE> that an * object of this class is required. */ public static final String JNDI="JNDI"; /** * Object used to obtain valid {@link java.sql.Connection} objects. */ protected DataSource ds; /** * Context where to look for the indicated JNDI resource. In <a * href="http://tomcat.apache.org/">Apache Tomcat</a>, this value should be * <CODE>java:comp/env</CODE>. */ protected String dbContext; private int totalCBRequests; private Date started; private Date lastUse; private String logFileString; private PrintWriter log; private int debugLevel; private int totalStatements; private String lastRequest; /** Creates a new instance of JNDIConnectionBeanProvider */ public JNDIConnectionBeanProvider() { } /** * Main initialization function, called immediatelly after constructor by * getConnectionBeanProvider functions. * @param map Collection of key - value pairs that must specify the JNDI Datasource name and * context params. * @throws Exception Throwed if the DataSource can't be * instantiated. */ @Override protected void setUp(Map<String, String> map) throws Exception{ super.setUp(map); started=new Date(); dbDriver=JNDI; if(dbServer==null) throw new Exception("JNDI datasource name not specified!"); dbContext = getValue(map, DB_CONTEXT, null); debugLevel = Integer.parseInt(getValue(map, "dbDebugLevel", "2")); if(debugLevel>0){ try{ logFileString = getValue(map, "dbLogFile", null); if(logFileString!=null){ File f=new File(logFileString); if(!f.isAbsolute()){ f=new File(System.getProperty("user.home")); f=new File(f, logFileString); logFileString=f.getAbsolutePath(); } boolean logAppend = Boolean.valueOf(getValue(map, "dbLogAppend", "true")).booleanValue(); log = new PrintWriter(new FileOutputStream(logFileString, logAppend),true); } } catch(IOException ioex){ System.err.println(new Date().toString()+" - Error creating log file for JNDIConnectionProvider - "+ioex); } } Context ctx=new InitialContext(); if(dbContext!=null && dbContext.trim().length()>0) ctx=(Context)ctx.lookup(dbContext); ds=(DataSource)ctx.lookup(dbServer); if(log!=null){ log.println("-----------------------------------------"); log.println(started); log.println("Starting JNDIConnectionBeanProvider"); log.println("dbContext = " + dbContext); log.println("dbServer = " + dbServer); log.println("Context = " + ctx); log.println("Datasource = " + ds); log.println("-----------------------------------------"); } } /** Provides information about the current state of this ConnectionBeanProvider. * @return Information string, formatted in HTML. */ @Override public String getInfo(){ StringBuilder sb=new StringBuilder(); sb.append("<b>JNDIConnectionBeanProvider ").append(hashCode()).append("</b><br>\n"); sb.append(super.getInfo()); sb.append("started: ").append(started).append("<br>\n"); sb.append("dbContext: ").append(dbContext).append("<br>\n"); sb.append("Total requests: ").append(totalCBRequests).append("<br>\n"); sb.append("Total statements: ").append(totalStatements).append("<br>\n"); sb.append("Last use: ").append(lastUse).append("<br>\n"); sb.append("Last request: ").append(lastRequest).append("<br>\n"); return sb.toString(); } /** * Performs cleanup */ protected void destroy() { } /** This method must be called when the obtained ConnectionBean is no longer needed, * usualy inside the <I>finally</I> block of a <I>try - catch</I> statement. * @param conn The ConnectionBean object to be disposed * @return A descriptive String, useful only for debug purposes. */ public String freeConnectionBean(ConnectionBean conn) { if(conn!=null){ try{ lastRequest=conn.getLastStatement(); totalStatements+=conn.getNumStatements(); conn.closeConnection(); } catch(Exception ex){ if(log!=null) log.println(new Date().toString() + " Unable to close DB connection: "+ex); } } return ""; } /** This is the main function that all ConnectionbeanProvider objects must * implement.<P> * <B>Important:</B> You must ever call FreeConnectionBean after the use of the ConnectionBean * object. Typical inmplementation use a try - catch - finally statement block in * order to ensure that all ConnectionBean objects will be properly disposed after * use.<P> * Example:<P> * <PRE> * ConectionBeanProvider cbp; * java.util.Properties prop=new Java.util.Properties(); * // ... * // ... fill-up properties with values for dbDriver, dbServer, dbLogin, etc. * // ... * cbp=ConnectionBeanProvider.getConnectionBeanProvider(map); * ConnectionBean cb=cbp.getConnectionBean(); * try { * // ... use of the ConnectionBean object * } catch(Exception ex){ * // ... process possible exceptions done while database access * } finally { * // Very important: free the ConnectionBean object: * cbp.freeConnectionBean(cb); * } * </PRE> * @return A ready-to-use ConnectionBean. Remember to return it by calling * FreeConnectionBean. */ public ConnectionBean getConnectionBean() { ConnectionBean result=null; try{ if(ds!=null){ Connection con=ds.getConnection(); result=new ConnectionBean(con, mapStatements); totalCBRequests++; lastUse=new Date(); } if(log!=null && debugLevel>2) log.println(new Date().toString()+" - connection request"); } catch(Exception ex){ if(log!=null) log.println(new Date().toString() + " Unable to get DB connection: "+ex.getMessage()); } return result; } }