Debug, Correction de bug, Classe Log, affichage des distances amélioré

- Ajout d'un mode debuggage utilisé par l'ORM pour afficher les requêtes envoyés au serveur BDD
- Corrections de nombreux bugs présent dans le nouvel ORM et dans son utilisation
- Meilleure affichage des distances : unité m et km choisi selon distance
- Ajout d'une classe Log qui permet de simplifier l'utilisation du logger
This commit is contained in:
Marc Baloup 2016-07-14 01:46:44 +02:00
parent b2a19e09c1
commit c5af1bd213
11 changed files with 228 additions and 56 deletions

View File

@ -50,6 +50,25 @@ public class EnumUtil {
return null;
}
/**
* Permet de rechercher l'existance d'un élément dans un enum, de façon insensible à la casse
* La validité de la classe passé en premier paramètre est vérifiée dynamiquement et non
* statiquement. Préférez l'utilisation de {@link #searchEnum(Class, String)} quand c'est possible.
* @param enumType la classe correpondant à l'enum à lister
* @param search l'élément à rechercher, insensible à la casse
* @return l'élément de l'énumération, si elle a été trouvée et si la classe passée en paramètre est un enum, null dans les autres cas
*/
public static Enum<?> searchUncheckedEnum(Class<?> enumType, String search) {
if (!enumType.isEnum())
return null;
Enum<?>[] elements = (Enum<?>[]) enumType.getEnumConstants();
for (Enum<?> el : elements)
if (el.name().equalsIgnoreCase(search))
return el;
return null;
}

View File

@ -1,11 +1,22 @@
package fr.pandacube.java.util;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Log {
private static Logger logger;
private static AtomicBoolean logDebug = new AtomicBoolean(false);
public static void setDebugState(boolean newVal) {
logDebug.set(newVal);
}
public static boolean getDebugState() {
return logDebug.get();
}
public static Logger getLogger() {
return logger;
@ -42,5 +53,20 @@ public class Log {
public static void severe(String message) {
logger.severe(message);
}
public static void debug(String message, Throwable t) {
if (!logDebug.get()) return;
logger.log(Level.INFO, message, t);
}
public static void debug(Throwable t) {
if (!logDebug.get()) return;
logger.log(Level.INFO, "", t);
}
public static void debug(String message) {
if (!logDebug.get()) return;
logger.info(message);
}
}

View File

@ -1,25 +0,0 @@
package fr.pandacube.java.util;
import java.text.DecimalFormat;
public class MemoryUtil {
public static String humanReadableSize(long octet)
{
DecimalFormat format = new DecimalFormat("#####0.00");
double size = octet;
if (size < 1024)
return size+"o";
size /= 1024;
if (size < 1024)
return format.format(size)+"kio";
size /= 1024;
if (size < 1024)
return format.format(size)+"Mio";
size /= 1024;
if (size < 1024)
return format.format(size)+"Gio";
size /= 1024;
return format.format(size)+"Tio";
}
}

View File

@ -4,6 +4,7 @@ import java.sql.Date;
import java.util.UUID;
import fr.pandacube.java.util.db2.sql_tools.ORM;
import fr.pandacube.java.util.db2.sql_tools.ORMException;
import fr.pandacube.java.util.db2.sql_tools.SQLElement;
import fr.pandacube.java.util.db2.sql_tools.SQLField;
import fr.pandacube.java.util.db2.sql_tools.SQLType;
@ -90,7 +91,7 @@ public class SQLPlayer extends SQLElement {
public static SQLPlayer getPlayerFromUUID(UUID playerId) throws Exception {
public static SQLPlayer getPlayerFromUUID(UUID playerId) throws ORMException {
return ORM.getFirst(SQLPlayer.class,
new SQLWhereComp(SQLPlayer.playerId, SQLComparator.EQ, playerId.toString()),
null);

View File

@ -8,6 +8,7 @@ import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import fr.pandacube.java.util.EnumUtil;
import fr.pandacube.java.util.Log;
import fr.pandacube.java.util.db2.SQLContact;
import fr.pandacube.java.util.db2.SQLForumCategorie;
@ -127,7 +128,7 @@ public final class ORM {
ps.setObject(i++, val);
}
try {
System.out.println(ps.toString());
Log.info("Creating table "+elem.tableName()+":\n"+ps.toString());
ps.executeUpdate();
} finally {
ps.close();
@ -222,11 +223,11 @@ public final class ORM {
int i = 1;
for (Object val : params) {
if (val instanceof Enum<?>)
val = ((Enum<?>)val).name();
ps.setObject(i++, val);
}
System.out.println(ps.toString());
Log.debug(ps.toString());
ResultSet set = ps.executeQuery();
try {
@ -259,7 +260,7 @@ public final class ORM {
private static <T extends SQLElement> T getElementInstance(ResultSet set, Class<T> elemClass) throws ReflectiveOperationException, SQLException {
private static <T extends SQLElement> T getElementInstance(ResultSet set, Class<T> elemClass) throws ORMException {
try {
T instance = elemClass.getConstructor(int.class).newInstance(set.getInt("id"));
@ -271,12 +272,37 @@ public final class ORM {
continue; // ignore when field is present in database but not handled by SQLElement instance
@SuppressWarnings("unchecked")
SQLField<Object> sqlField = (SQLField<Object>) instance.getFields().get(fieldName);
instance.set(sqlField, set.getObject(c), false);
if (sqlField.type.getJavaType().isEnum()) {
// JDBC ne supporte pas les enums
String enumStrValue = set.getString(c);
if (enumStrValue == null || set.wasNull())
instance.set(sqlField, null, false);
else {
Enum<?> enumValue = EnumUtil.searchUncheckedEnum(sqlField.type.getJavaType(), enumStrValue);
if (enumValue == null)
throw new ORMException("The enum constant '"+enumStrValue+"' is not found in enum class "+sqlField.type.getJavaType().getName());
instance.set(sqlField, enumValue, false);
}
}
else {
Object val = set.getObject(c, sqlField.type.getJavaType());
if (val == null || set.wasNull())
instance.set(sqlField, null, false);
else
instance.set(sqlField, val, false);
}
// la valeur venant de la BDD est marqué comme "non modifié" dans l'instance
// car le constructeur de l'instance met tout les champs comme modifiés
instance.modifiedSinceLastSave.remove(sqlField.name);
}
if (!instance.isValidForSave())
throw new ORMException("This SQLElement representing a database entry is not valid for save : "+instance.toString());
return instance;
} catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
throw new ReflectiveOperationException("Can't instanciate " + elemClass.getName(), e);
} catch (ReflectiveOperationException | IllegalArgumentException | SecurityException | SQLException e) {
throw new ORMException("Can't instanciate " + elemClass.getName(), e);
}
}
@ -293,9 +319,6 @@ public final class ORM {
private ORM() { } // rend la classe non instanciable
/*

View File

@ -37,7 +37,7 @@ public abstract class SQLElement {
private final SQLFieldMap fields;
private final Map<SQLField<?>, Object> values;
private final Set<String> modifiedSinceLastSave;
/* package */ final Set<String> modifiedSinceLastSave;
public SQLElement() {
@ -206,7 +206,7 @@ public abstract class SQLElement {
public boolean isValidForSave() {
return values.keySet().containsAll(fields.keySet());
return values.keySet().containsAll(fields.values());
}
@ -214,7 +214,7 @@ public abstract class SQLElement {
private Map<SQLField<?>, Object> getOnlyModifiedValues() {
Map<SQLField<?>, Object> modifiedValues = new LinkedHashMap<>();
values.forEach((k, v) -> {
if (modifiedSinceLastSave.contains(k))
if (modifiedSinceLastSave.contains(k.name))
modifiedValues.put(k, v);
});
return modifiedValues;
@ -230,10 +230,10 @@ public abstract class SQLElement {
public void save() throws ORMException {
if (!isValidForSave())
throw new IllegalStateException("this instance of " + getClass().getName() + " has at least one undefined value and can't be saved.");
throw new IllegalStateException(toString() + " has at least one undefined value and can't be saved.");
ORM.initTable(getClass());
String toStringStatement = "";
try {
Connection conn = db.getNativeConnection();
@ -249,14 +249,20 @@ public abstract class SQLElement {
modifiedSinceLastSave.remove("id");
Map<SQLField<?>, Object> modifiedValues = getOnlyModifiedValues();
if (modifiedValues.isEmpty())
return;
String sql = "";
List<Object> psValues = new ArrayList<>();
for(Map.Entry<SQLField<?>, Object> entry : modifiedValues.entrySet()) {
sql += entry.getKey() + " = ? ,";
psValues.add(entry.getValue());
sql += entry.getKey().name + " = ? ,";
if (entry.getKey().type.getJavaType().isEnum()) {
// prise en charge enum (non prise en charge par JDBC)
psValues.add(((Enum<?>)entry.getValue()).name());
}
else
psValues.add(entry.getValue());
}
if (sql.length() > 0)
@ -270,7 +276,8 @@ public abstract class SQLElement {
for (Object val : psValues) {
ps.setObject(i++, val);
}
toStringStatement = ps.toString();
ps.executeUpdate();
} finally {
ps.close();
@ -295,8 +302,13 @@ public abstract class SQLElement {
}
first = false;
concat_vals += " ? ";
concat_fields += entry.getKey();
psValues.add(entry.getValue());
concat_fields += entry.getKey().name;
if (entry.getKey().type.getJavaType().isEnum()) {
// prise en charge enum (non prise en charge par JDBC)
psValues.add(((Enum<?>)entry.getValue()).name());
}
else
psValues.add(entry.getValue());
}
@ -307,7 +319,8 @@ public abstract class SQLElement {
for (Object val : psValues) {
ps.setObject(i++, val);
}
toStringStatement = ps.toString();
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
@ -329,8 +342,9 @@ public abstract class SQLElement {
modifiedSinceLastSave.clear();
} catch(SQLException e) {
throw new ORMException("Error while saving data in table "+tableName(), e);
throw new ORMException("Error while executing SQL statement "+toStringStatement, e);
}
Log.debug(toStringStatement);
}
@ -356,6 +370,7 @@ public abstract class SQLElement {
{ // supprimer la ligne de la base
PreparedStatement st = db.getNativeConnection().prepareStatement("DELETE FROM "+tableName+" WHERE id="+id);
try {
Log.debug(st.toString());
st.executeUpdate();
markAsNotStored();
} finally {
@ -411,7 +426,7 @@ public abstract class SQLElement {
try {
b.append(f.name, get(f));
} catch(IllegalArgumentException e) {
b.append(f.name, "(Must be defined before saving)");
b.append(f.name, "(Undefined)");
}
}

View File

@ -7,6 +7,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import fr.pandacube.java.util.Log;
/**
*
* @param <E>
@ -32,11 +34,11 @@ public class SQLElementList<E extends SQLElement> extends ArrayList<E> {
* @param value la valeur à lui appliquer
*/
public synchronized <T> void setCommon(SQLField<T> field, T value) {
if (isEmpty()) throw new IllegalStateException("This SQLElementList is empty");
if (field != null && field.name == "id")
throw new IllegalArgumentException("Can't modify id field in a SQLElementList");
@SuppressWarnings("unchecked")
Class<E> elemClass = (Class<E>) get(0).getClass();
Class<E> elemClass = (Class<E>) field.getSQLElementType();
try {
E emptyElement = elemClass.newInstance();
emptyElement.set(field, value, false);
@ -71,7 +73,12 @@ public class SQLElementList<E extends SQLElement> extends ArrayList<E> {
for(Map.Entry<SQLField<?>, Object> entry : modifiedValues.entrySet()) {
sqlSet += entry.getKey().name + " = ? ,";
psValues.add(entry.getValue());
if (entry.getKey().type.getJavaType().isEnum()) {
// prise en charge enum (non prise en charge par JDBC)
psValues.add(((Enum<?>)entry.getValue()).name());
}
else
psValues.add(entry.getValue());
}
if (sqlSet.length() > 0)
@ -93,6 +100,7 @@ public class SQLElementList<E extends SQLElement> extends ArrayList<E> {
ps.setObject(i++, val);
}
Log.debug(ps.toString());
ps.executeUpdate();
applyNewValuesToElements(storedEl);
@ -140,6 +148,7 @@ public class SQLElementList<E extends SQLElement> extends ArrayList<E> {
PreparedStatement st = ORM.getConnection().getNativeConnection().prepareStatement("DELETE FROM "+storedEl.get(0).tableName()+" WHERE "+sqlWhere);
try {
Log.debug(st.toString());
st.executeUpdate();
for (E el : storedEl) {

View File

@ -6,7 +6,7 @@ public class SQLType<T> {
private final String sqlType;
private final String sqlTypeParam;
private final Class<?> javaTypes;
private final Class<T> javaTypes;
public SQLType(String sqlT, String sqlP, Class<T> javaT) {
sqlType = sqlT;
@ -37,6 +37,10 @@ public class SQLType<T> {
return toString().equals(((SQLType<?>)obj).toString());
}
public Class<T> getJavaType() {
return javaTypes;
}

View File

@ -0,0 +1,63 @@
package fr.pandacube.java.util.measurement;
import java.text.DecimalFormat;
import java.util.Arrays;
public class DistanceUtil {
public static String distanceToString(double meterDist, int precision, DistanceUnit... desiredUnits) {
Arrays.sort(desiredUnits);
DistanceUnit choosenUnit = desiredUnits[0]; // la plus petite unitée
for (DistanceUnit unit : desiredUnits) {
if (meterDist / unit.multiplicator < 1)
continue;
choosenUnit = unit;
}
if (choosenUnit != desiredUnits[0] && precision <= 2)
precision = 2;
String precisionFormat = "##0";
if (precision > 0)
precisionFormat += ".";
for (int i=0;i<precision; i++)
precisionFormat += "0";
DecimalFormat df = new DecimalFormat(precisionFormat);
double dist = meterDist / choosenUnit.multiplicator;
return df.format(dist)+choosenUnit.unitStr;
}
public static String distanceToString(double meterDist, int precision) {
return distanceToString(meterDist, precision, DistanceUnit.M, DistanceUnit.KM);
}
public enum DistanceUnit implements Comparable<DistanceUnit> {
NM(0.000000001, "nm"),
µM(0.000001, "µm"),
MM(0.001, "mm"),
CM(0.01, "cm"),
M(1, "m"),
KM(1000, "km");
private final double multiplicator;
private final String unitStr;
private DistanceUnit(double mult, String s) {
multiplicator = mult;
unitStr = s;
}
}
}

View File

@ -0,0 +1,37 @@
package fr.pandacube.java.util.measurement;
import java.text.DecimalFormat;
public class MemoryUtil {
private static final DecimalFormat format = new DecimalFormat("#####0.00");
public static String humanReadableSize(long octet, boolean si)
{
double size = octet;
int diveBy = si ? 1000 : 1024;
if (size < diveBy)
return size+"o";
size /= diveBy;
if (size < diveBy)
return format.format(size) + (si ? "ko" : "kio");
size /= diveBy;
if (size < diveBy)
return format.format(size) + (si ? "Mo" : "Mio");
size /= diveBy;
if (size < diveBy)
return format.format(size) + (si ? "Go" : "Gio");
size /= diveBy;
return format.format(size) + (si ? "To" : "Tio");
}
public static String humanReadableSize(long octet) {
return humanReadableSize(octet, false);
}
}

View File

@ -1,4 +1,4 @@
package fr.pandacube.java.util;
package fr.pandacube.java.util.measurement;
public class TimeUtil {
public static String durationToString (long msec_time, boolean dec_seconde)