Description

Très souvent dans nos développements d’applications informatiques nous utilisons des listes de valeurs que nous allons chercher dans des fichiers « properties » ou des tables SQL ou dans le pire des cas codés « en dur » dans notre application.

Comme la plupart d’entres nous j’ai eu cette problématique et j’ai traité cela en créant des « Tables Mémoire ». Cela me permet de limiter les accès à la base de données (ou fichier), de diminuer l’occupation mémoire en ayant une seule instance de ces listes en mémoire et de simplifier mon code.

Ce code est relativement ancien et pourrait être amélioré (utilisation du patern singleton au lieu d’un classe pur static, optimisation des « synchronize »s, …), mais utilisant cela dans un grand nombre de projets et n’ayant aucun problème de performance ou de mémoire je reporte toujours ces changements.

Fonctions

Lors de la création de ce composant je souhaitais avoir les fonctions suivantes en simplifiant au maximum son utilisation dans une page JSP ou une Servlet :

  • « Connection » sql en externe
  • Ne pas recharger les données si elles sont déjà en mémoire
  • Chargement d’une liste à partir d’un ordre SQL : loadQuery(…)
  • Chargement d’une liste à partir d’une liste de valeurs : loadListe(…)
  • Lecture du libellé associé à un code (String) : getValue(…)
  • Lecture du libellé associé à un code (Combobox) : getListe(…)
  • Lecture du libellé associé à un code (Radio Bouton) : getRadio(…)

Téléchargement

memorytable.zip

Utilisation

Ce petit exemple de code (jsp) montre comment effectuer le chargement (initialisation) de la « MemoryTable ».

<%@ page language="java" import="com.berthou.sql.*"%>
<%
java.sql.Connection conn = .... ; // Initialize you connection
 
// Load a hard coded liste
MemoryTable.loadListe("TEST_L_ETAT","    = ;V=Valide;E=En erreur;I=Incomplete;" ) ;
 
// Load a SQL Query liste
// Recherche du code service et du libelle des services actifs
String sql = "select cdserv, libelle from service where status = 'O' " ;
MemoryTable.loadQuery(conn, "TBL_SERV",sql ) ;
%>

Une fois ce chargement effectué vous pouvez utiliser directement les « memory tables »

<%@ page language="java" import="com.berthou.sql.*"%>
....
<% String service = "1305" ; %>
Service : <%=service%> - <%=MemoryTable.getValue("TBL_SERV", service)%>
(affiche Service : 1305 - Libelle du service1305)
 
Service :
<select name="service"><%=MemoryTable.getListe("TBL_SERV", service)%></select>
(construit une combobox en activant le service demandé)

La classe MemoryTable

package com.berthou.sql;
 
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
 
import org.apache.log4j.Logger;
 
/**
 * @author rberthou
 *
 * Création 3 févr. 2001
 * Package  com.berthou.sql
 * Projet   tools
 * -------+------------+-------------------------------------------------------------------------
 *   Ver  | Date       | Commentaires
 * -------+------------+-------------------------------------------------------------------------
 *  2.00  | 04/04/2006 | Ajout des listes, et bouton radio (+ commentaires)
 *  1.00  | 03/02/2001 | Création
 * -------+------------+-------------------------------------------------------------------------
 */
public class MemoryTable {
 
	private static final Logger logger = Logger.getLogger(MemoryTable.class);
 
	static protected Hashtable h = new Hashtable(10, 1);
 
	/**
	 * rechargement des données d'un query
	 *
	 * @param Connection
	 *            conn : Connexion utilisée
	 * @param String
	 *            tableName : Nom du Query
	 * @param String
	 *            Sql : Ordre SQL à executer
	 * @param boolean
	 *            tr : true si trim automatique de la colonne code
	 *
	 * @return int rc : nombre d'enregistrements chargés
	 */
	static public synchronized int reloadQuery(Connection conn,
			String tableName, String sql, boolean tr) throws SQLException {
		/* Si la table est déja chargé on la recharge */
		freeTable(tableName);
 
		return loadQuery(conn, tableName, sql, tr);
	}
 
	/**
	 * rechargement des données d'un query
	 *
	 * @param Connection
	 *            conn : Connexion utilisée
	 * @param String
	 *            tableName : Nom du Query
	 * @param String
	 *            Sql : Ordre SQL à executer
	 *
	 * @return int rc : nombre d'enregistrements chargés
	 */
	static public synchronized int reloadQuery(Connection conn,
			String tableName, String sql) throws SQLException {
		return reloadQuery(conn, tableName, sql, false);
	}
 
	/**
	 * chargement des données d'une table
	 *
	 * @param Connection
	 *            conn : Connexion utilisée
	 * @param String
	 *            tableName : Nom du Query
	 * @param String
	 *            Sql : Ordre SQL à executer
	 *
	 * @return int rc : nombre d'enregistrements chargés
	 */
	static public synchronized int loadQuery(Connection conn, String queryName,
			String sql) throws SQLException {
		return loadQuery(conn, queryName, sql, false);
	}
 
	/**
	 * chargement des données d'une table
	 *
	 * @param Connection
	 *            conn : Connexion utilisée
	 * @param String
	 *            tableName : Nom du Query
	 * @param String
	 *            Sql : Ordre SQL à executer
	 * @param boolean
	 *            isTrim : Vrai si colonne code a trim
	 *
	 * @return int rc : nombre d'enregistrements chargés
	 */
	static public synchronized int loadQuery(Connection conn, String queryName,
			String sql, boolean isTrim) throws SQLException {
		if (isLoaded(queryName))
			return ((Vector) h.get(queryName)).size();
 
		int rc = 0;
		Vector v = new Vector(10, 5);
 
		try {
			Statement stmt = conn.createStatement();
 
			/* Execution */
			ResultSet rs = stmt.executeQuery(sql);
			if (rs != null) {
				ResultSetMetaData rsdt = rs.getMetaData();
				/* Si utile recherche de la liste des colonnes */
				int K = rsdt.getColumnCount();
				/* Lecture des données et mémorisation dans un Vecteur */
				while (rs.next()) {
					String[] s = new String[K];
					for (int I = 0; I < K; I++) {
						if (I == 0 && isTrim)
							s[I] = rs.getString(I+1).trim();
						else
							s[I] = rs.getString(I+1);
					}
					rc++;
					v.add(s);
				}
				/* Ajout de ce Vecteur dans la HashTable */
				h.put(queryName, v);
				rs.close();
			}
			stmt.close();
		} catch (SQLException e) {
			logger
					.error("unable to fetch table [" + queryName + "] err : "
							+ e);
			throw e;
		} finally {
 
		}
 
		if (rc > 0)
			logger.info("Chargement de la table/query [" + queryName + "] : "
					+ rc);
 
		return rc;
	}
 
	/**
	 * rechargement des données d'une liste
	 *
	 * @param String
	 *            tableName : Nom de la liste
	 * @param String
	 *            valeurs : liste des valeurs
	 *
	 * @return int rc : nombre d'enregistrements chargés
	 */
	static public synchronized int reloadListe(String tableName, String sql) {
		/* Si la table est déja chargé on la recharge */
		freeTable(tableName);
 
		return loadListe(tableName, sql);
	}
 
	/**
	 * rechargement des données d'une liste
	 *
	 * @param String
	 *            tableName : Nom de la liste
	 * @param String
	 *            valeurs : liste des valeurs
	 *
	 * @return int rc : nombre d'enregistrements chargés
	 */
	static public synchronized int loadListe(String tableName, String sql) {
		if (isLoaded(tableName))
			return ((Vector) h.get(tableName)).size();
 
		int rc = 0;
		Vector v = new Vector(5, 2);
		StringTokenizer stoken = new StringTokenizer(sql, ";");
 
		/* Lecture des données et mémorisation dans un Vecteur */
		while (stoken.hasMoreElements()) {
			String[] s = new String[2];
			String token = stoken.nextToken();
			int i = token.indexOf('=');
			s[0] = token.substring(0, i); // cle
			s[1] = token.substring(i + 1); // valeur
			rc++;
			v.add(s);
		}
		/* Ajout de ce Vecteur dans la HashTable */
		h.put(tableName, v);
 
		if (rc > 0)
			logger.info("Chargement de la table/liste [" + tableName + "] : "
					+ rc);
 
		return rc;
	}
 
	/**
	 * Nombre de tables chargées
	 *
	 * @return int r : nombre de table
	 */
	static public synchronized int size() {
		return h.size();
	}
 
	/**
	 * Test si une table est chargée
	 *
	 * @param String
	 *            tableName : Nom de la table
	 *
	 * @return boolean b : oui ou non...
	 */
	static public synchronized boolean isLoaded(String tableName) {
		return h.containsKey(tableName);
	}
 
	/**
	 * libération d'une table
	 *
	 * @param String
	 *            tableName : Nom de la table
	 */
	static public synchronized void freeTable(String tableName) {
		if (h.containsKey(tableName))
			h.remove(tableName);
	}
 
	/**
	 * Lecture des données d'une table
	 *
	 * @param String
	 *            tableName : Nom de la table
	 *
	 * @return Vector v : les données
	 */
	static public synchronized Vector getTable(String tableName)
			throws SQLException {
		return (Vector) h.get(tableName);
	}
 
	/**
	 * Formatage des données d'une table sous forme d'une combobox
	 *
	 * @param String
	 *            tableName : Nom de la table
	 * @param String
	 *            val : Valeur selectionnée
	 *
	 * @return String s : les données (format : &lt;option ... )
	 */
	static public synchronized String getListe(String tableName, String val)
			throws SQLException {
		StringBuffer sb = new StringBuffer("");
		Vector v = getTable(tableName);
 
		if (v != null) {
			int K = v.size();
			String[] s;
			for (int I = 0; I < K; I++) {
				s = (String[]) v.elementAt(I);
				if (s.length > 1) {
					if (s[0].equals(val))
						sb.append("<option value=\"" + s[0] + "\" selected>"
								+ s[1] + "</option>\r\n");
					else
						sb.append("<option value=\"" + s[0] + "\">" + s[1]
								+ "</option>\r\n");
				}
			}
		}
 
		return sb.toString();
	}
 
	/**
	 * Formatage des données d'une table sous forme de radio boutons
	 *
	 * @param String :
	 *            Nom de la zone HTML (name = )
	 * @param String
	 *            tableName : Nom de la table
	 * @param String
	 *            val : Valeur selectionnée
	 * @param String
	 *            after : Le code html a ajouter apres chaque ligne
	 *            (&lt;br/&gt;)
	 *
	 * @return String s : les données (format : &lt;option ... )
	 */
	static public synchronized String getRadio(String nm, String tableName,
			String val, String after) throws SQLException {
		StringBuffer sb = new StringBuffer("");
		Vector v = getTable(tableName);
 
		if (after == null)
			after = "\r\n";
 
		if (v != null) {
			int K = v.size();
			String[] s;
			for (int I = 0; I < K; I++) {
				s = (String[]) v.elementAt(I);
				if (s.length > 1) {
					sb.append("<input type=\"RADIO\" name=\"" + nm + "\" id=\""
							+ nm + "\" value=\"" + s[0] + "\"");
					if (s[0].equals(val))
						sb.append(" checked");
					sb.append(">" + s[1] + "</input>" + after);
				}
			}
		}
 
		return sb.toString();
	}
 
	/**
	 * Lecture d'une valeur
	 *
	 * @param String
	 *            tableName : Nom de la table
	 * @param String
	 *            val : Valeur selectionnée
	 *
	 * @return String s : le libelle
	 */
	static public synchronized String getValue(String tableName, String val) throws SQLException {
		String r = "";
		Vector v = getTable(tableName);
 
		if (v != null) {
			int K = v.size();
			String[] s;
			for (int I = 0; I < K; I++) {
				s = (String[]) v.elementAt(I);
				if (s.length > 1) {
					if (s[0].equals(val)) {
						r = s[1];
						break;
					}
				}
			}
		}
 
		return r;
	}
}
Be Sociable, Share!