/*
* codjo.net
*
* Common Apache License 2.0
*/
package net.codjo.persistent.sql;
// Persistance
import net.codjo.persistent.PersistenceException;
import net.codjo.persistent.Reference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import org.apache.log4j.Logger;
/**
* Class de fabrique d'objet. Cette classe est utilise par le SimpleHome afin de
* construire des instances de la Classe administr�.
*
* @author $Author: rivierv $
* @version $Revision: 1.3 $
*/
class SimpleHomeFactory {
// Log
private static final Logger APP = Logger.getLogger(SimpleHomeFactory.class);
private SimpleHomeMapping property;
private SimpleHomeTranslator translator;
private List constructorArgs = new ArrayList();
private boolean referenceInConstructor = false;
private Constructor constructor;
private Class objectClass;
/**
* Constructeur.
*
* @param resb ResourceBundle contenant la description
* @param prefix le prefix "object." ou "primaryKey."
*
* @exception ClassNotFoundException Class administre inexistante
* @exception NoSuchMethodException Constructeur non trouve
*/
public SimpleHomeFactory(ResourceBundle resb, String prefix)
throws ClassNotFoundException, NoSuchMethodException {
referenceInConstructor = true;
init(resb, prefix);
}
/**
* Constructor.
*/
protected SimpleHomeFactory() {}
/**
* Positionne l'objet responsable des correspondances colonne / property
*
* @param p Le SimpleHomeMapping faisant la correspondance pour la classe administr�
*/
public void setPropertyMapping(SimpleHomeMapping p) {
property = p;
}
/**
* Positionne l'objet responsable de la traduction d'une property
*
* @param p Le SimpleHomeTranslator faisant la traduction
*/
public void setTranslator(SimpleHomeTranslator p) {
translator = p;
}
/**
* Retourne l'objet responsable des correspondances colonne / property
*
* @return Le SimpleHomeMapping
*/
public SimpleHomeMapping getPropertyMapping() {
return property;
}
/**
* Retourne la classe des objets administr�.
*
* @return La classe
*/
public Class getObjectClass() {
return objectClass;
}
/**
* Retourne un tableau des valeurs (rempli a partir du ResultSet donn�) utilisable
* pour instanci� un objet administr�.
*
* @param rs Le ResultSet contenant les donn�es d'instanciation
*
* @return Un tableau rempli
*
* @exception SQLException Erreur d'acces base
* @throws Error s'il y a un probl�me de persistence
*/
public Object[] fillConstructorVals(ResultSet rs)
throws SQLException {
try {
return fillConstructorVals(rs, null);
}
catch (PersistenceException ex) {
// Impossible ??
throw new Error("Gros Bleme " + ex);
}
}
/**
* Iterator sur les colonnes utilise pour construire un objet administre.
*
* @return Iterator sur des nom de colonne
*/
public Iterator columns() {
return constructorArgs.iterator();
}
/**
* Creation d'une instance.
*
* @param rs Le ResultSet contenant les donn�es
* @param reference Reference de l'objet
*
* @return une instance d'objet administr�
*
* @exception SQLException Erreur acces base
* @exception PersistenceException Traduction impossible
* @exception InvocationTargetException Constructeur a renvoye une exception
* @exception IllegalAccessException Le constructeur n'est pas public
* @exception InstantiationException L'instanciation a echoue
*/
public Object newInstance(ResultSet rs, Reference reference)
throws SQLException, PersistenceException, InvocationTargetException,
IllegalAccessException, InstantiationException {
Object[] vals = fillConstructorVals(rs, reference);
return newInstance(vals);
}
/**
* Creation d'une instance.
*
* @param val Tableau de valeur utilise par le constructeur
*
* @return une instance d'objet administr�
*
* @exception InvocationTargetException Constructeur a renvoye une exception
* @exception IllegalAccessException Le constructeur n'est pas public
* @exception InstantiationException L'instanciation a echoue
*/
public Object newInstance(Object[] val)
throws InvocationTargetException, IllegalAccessException,
InstantiationException {
return constructor.newInstance(val);
}
/**
* Retourne la liste des arguments utilise par le constructeur
*
* @return Liste de nom de colonne
*/
protected List getConstructorArgs() {
return constructorArgs;
}
/**
* Init.
*
* @param resb ResourceBundle contenant la description
* @param prefix Le prefixe de definition
*
* @exception ClassNotFoundException Class administre inexistante
* @exception NoSuchMethodException Constructeur non trouve
*/
protected void init(ResourceBundle resb, String prefix)
throws ClassNotFoundException, NoSuchMethodException {
objectClass = findClass(resb, prefix + "class");
fillArgumentsList(resb.getString(prefix + "constructor"), constructorArgs);
constructor = findConstructor(objectClass);
}
/**
* Description of the Method
*
* @return Description of the Return Value
*/
protected Object[] newConstructorVals() {
if (referenceInConstructor) {
return new Object[constructorArgs.size() + 1];
}
else {
return new Object[constructorArgs.size()];
}
}
/**
* Recherche la classe des objets administr�.
*
* @param resb Le ResourceBundle
* @param classProperty Le nom de la property Class
*
* @return La Classe
*
* @exception ClassNotFoundException Classe introuvable
*/
protected Class findClass(ResourceBundle resb, String classProperty)
throws ClassNotFoundException {
return Class.forName(resb.getString(classProperty));
}
/**
* Retourne le premier constructeur public definie sur la classe <code>c </code>
*
* @param c La classe de recherche
*
* @return Le premier constructeur public
*
* @exception NoSuchMethodException Si aucun constructeur public
*/
protected Constructor findConstructor(Class c)
throws NoSuchMethodException {
Constructor[] classConstructors = c.getDeclaredConstructors();
for (int i = 0; i < classConstructors.length; i++) {
if (classConstructors[i].getModifiers() == Modifier.PUBLIC) {
debug("Constructeur : " + classConstructors[i]);
return classConstructors[i];
}
}
throw new NoSuchMethodException("Aucun constructeur public : " + c);
}
/**
* Log en mode Debug.
*
* @param msg message de debug
*/
protected void debug(String msg) {
APP.debug(msg);
}
/**
* Retourne un tableau des valeurs (rempli et traduite a partir du ResultSet donn�)
* utilisable pour instanci� un objet administr�.
*
* @param rs Le ResultSet contenant les donn�es
* @param reference La reference de l'objet instanci�
*
* @return Un tableau rempli
*
* @exception SQLException Erreur d'acces base.=
* @exception PersistenceException Traduction a echoue
*/
private Object[] fillConstructorVals(ResultSet rs, Reference reference)
throws SQLException, PersistenceException {
int idx = 0;
Object[] constructorVals = newConstructorVals();
if (referenceInConstructor) {
idx = 1;
constructorVals[0] = reference;
}
for (int i = 0; i < constructorArgs.size(); i++) {
String dbColumnName = (String)constructorArgs.get(i);
if (translator != null) {
constructorVals[i + idx] =
translator.translateValue(property.columnToProperty(dbColumnName),
rs.getObject(dbColumnName));
}
else {
constructorVals[i + idx] = rs.getObject(dbColumnName);
}
}
return constructorVals;
}
/**
* Remplit la liste <code>args</code> a partir des mots contenu dans <code>str
* </code>, separe par ";".
*
* @param str Une String de type "motA;motB;motC.."
* @param args La liste des mots contenu dans str
*/
private void fillArgumentsList(String str, List args) {
StringTokenizer tokenizer = new StringTokenizer(str, ";");
while (tokenizer.hasMoreElements()) {
args.add(args.size(), tokenizer.nextElement());
}
}
}