/*
* codjo.net
*
* Common Apache License 2.0
*/
package net.codjo.persistent.sql;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.ResourceBundle;
/**
* Classe responsable de la correspondance colonne (en Base) / propriete (objet).
*
* <p>
* Cette classe est initialise par un ResourceBundle contenant la definition de la
* correspondance. Exemple :
* <pre>
* property.tableId = DB_TABLE_NAME_ID
* property.DBTableName = DB_TABLE_NAME
* property.tableName = TABLE_NAME
* property.tableStep = STEP
* </pre>
* <br> Dans cette exemple, la propriete <code>tableId</code> correspond a la colonne
* <code>DB_TABLE_NAME_ID</code> .
* </p>
*
* @author $Author: spinae $
* @version $Revision: 1.2 $
*/
class SimpleHomeMapping {
/** Masque pour initialiser les methode "get" des proprietes. */
public static final int INIT_GETTER = 0x01;
/** Masque pour initialiser les methode "set" des proprietes. */
public static final int INIT_SETTER = 0x10;
private static final int MASK = 0x11;
private List dbColumnNames = new ArrayList();
private List propertyNames = new ArrayList();
private Method[] getterMethods;
private Method[] setterMethods;
/**
* Constructeur.
*
* <p>
* L'argument <code>initMask</code> indique quelles sont les methodes accesseurs qui
* seront recherch�es (cf. setPropertyValue et getPropertyValue). Si
* <code>initMask=INIT_GETTER</code> , alors les methodes "get" seront utilisable.
* Si <code> initMask=INIT_GETTER & INIT_SETTER</code> , alors les methodes "get" et
* "set" seront utilisable.
* </p>
*
* @param resb ResourceBundle contenant la description
* @param prefix Le prefix du mapping (ex : "property.")
* @param objectClass La classe de l'objet mappe.
* @param initMask Le masque d'initialisation des accesseurs
*
* @exception IntrospectionException Recherche des accesseurs impossible
* @exception NoSuchMethodException Methode accesseur introuvable
*
* @see #setPropertyValue()
* @see #getPropertyValue()
*/
public SimpleHomeMapping(ResourceBundle resb, String prefix, Class objectClass,
int initMask) throws IntrospectionException, NoSuchMethodException {
for (Enumeration e = resb.getKeys(); e.hasMoreElements();) {
String id = (String)e.nextElement();
if (id.startsWith(prefix)) {
propertyNames.add(id.substring(prefix.length()));
dbColumnNames.add(resb.getString(id));
}
}
initAccessors(objectClass, initMask);
}
/**
* Positionne la valeur de la propriete (indexe par i) porte par l'objet obj.
*
* <p>
* Cette methode n'est utilisable que dans le cas ou cette objet Mapping a ete
* initialise avec un initMask = INIT_SETTER.
* </p>
*
* @param i L'index de la property
* @param obj L'objet possedant la property
* @param value La nouvelle valeur de la property
*
* @exception InvocationTargetException La methode set a lance une exception
* @exception IllegalAccessException La methode set est private
*/
public void setPropertyValue(int i, Object obj, Object value)
throws InvocationTargetException, IllegalAccessException {
Object[] args = {value};
setterMethods[i].invoke(obj, args);
}
/**
* Retourne le nom de la property d'index i.
*
* @param i L'index de la property
*
* @return Le nom
*/
public String getName(int i) {
return (String)propertyNames.get(i);
}
/**
* Retourne le nom de la colonne correspondant a la property d'index i.
*
* @param i L'index de la property
*
* @return Le nom physique de la colonne
*/
public String getColumn(int i) {
return (String)dbColumnNames.get(i);
}
/**
* Retourne la valeur de la propriete (indexe par i) porte par l'objet obj.
*
* <p>
* Cette methode n'est utilisable que dans le cas ou cette objet Mapping a ete
* initialise avec un initMask = INIT_GETTER.
* </p>
*
* @param i L'index de la property
* @param obj L'objet possedant la property
*
* @return La valeur de la property
*
* @exception InvocationTargetException La methode get a lance une exception
* @exception IllegalAccessException La methode get est private
*/
public Object getPropertyValue(int i, Object obj)
throws InvocationTargetException, IllegalAccessException {
return getterMethods[i].invoke(obj, null);
}
/**
* Retourne l'index de la colonne.
*
* @param columnName Le nom de la colonne
*
* @return L'index
*/
public int columnIndex(String columnName) {
return dbColumnNames.indexOf(columnName);
}
/**
* Retourne la taille du tableau de correspondance.
*
* @return Le nombre de couple (property / colonne)
*/
public int size() {
return propertyNames.size();
}
/**
* Retourne le nom de la propriete attache a la colonne.
*
* <p>
* Exemple, si le fichier de configuration contient :
* <pre>
* property.targetId = TARGET_ID</pre>
* la methode renverra pour <code>TARGET_ID</code> la valeur <code>targetId </code> .
* </p>
*
* @param columnName Nom physique de la colonne
*
* @return Nom de la propriete attache
*
* @throws IllegalArgumentException TODO
*/
public String columnToProperty(String columnName) {
int idx = dbColumnNames.indexOf(columnName);
if (idx < 0) {
throw new IllegalArgumentException("Nom inconnu : " + columnName);
}
return (String)propertyNames.get(idx);
}
/**
* Initialisation.
*
* @param objectClass La classe de l'objet
* @param initMask Le masque d'initialisation
*
* @exception IntrospectionException Recherche des accesseurs impossible
* @exception NoSuchMethodException Methode accesseur introuvable
*/
private void initAccessors(Class objectClass, int initMask)
throws IntrospectionException, NoSuchMethodException {
// Init
if ((initMask & MASK) == INIT_GETTER) {
getterMethods = new Method[dbColumnNames.size()];
}
if ((initMask & MASK) == INIT_SETTER) {
setterMethods = new Method[dbColumnNames.size()];
}
// Cherche les methodes
BeanInfo info = Introspector.getBeanInfo(objectClass);
PropertyDescriptor[] desc = info.getPropertyDescriptors();
for (int i = 0; i < desc.length; i++) {
int idx = propertyNames.indexOf(desc[i].getName());
if (idx != -1 && (initMask & MASK) == INIT_GETTER) {
getterMethods[idx] = desc[i].getReadMethod();
}
if (idx != -1 && (initMask & MASK) == INIT_SETTER) {
setterMethods[idx] = desc[i].getWriteMethod();
}
}
// Verification que les methodes ont ete trouve
if ((initMask & MASK) == INIT_GETTER) {
for (int i = 0; i < getterMethods.length; i++) {
if (getterMethods[i] == null) {
throw new NoSuchMethodException("Manque getter pour "
+ propertyNames.get(i));
}
}
}
if ((initMask & MASK) == INIT_SETTER) {
for (int i = 0; i < setterMethods.length; i++) {
if (setterMethods[i] == null) {
throw new NoSuchMethodException("Manque setter pour "
+ propertyNames.get(i));
}
}
}
}
}