From c5af1bd213182443e92fe37752aba7fa405b4ab8 Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Thu, 14 Jul 2016 01:46:44 +0200 Subject: [PATCH] =?UTF-8?q?Debug,=20Correction=20de=20bug,=20Classe=20Log,?= =?UTF-8?q?=20affichage=20des=20distances=20am=C3=A9lior=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/fr/pandacube/java/util/EnumUtil.java | 19 ++++++ src/fr/pandacube/java/util/Log.java | 26 ++++++++ src/fr/pandacube/java/util/MemoryUtil.java | 25 -------- src/fr/pandacube/java/util/db2/SQLPlayer.java | 3 +- .../java/util/db2/sql_tools/ORM.java | 45 +++++++++---- .../java/util/db2/sql_tools/SQLElement.java | 43 ++++++++----- .../util/db2/sql_tools/SQLElementList.java | 15 ++++- .../java/util/db2/sql_tools/SQLType.java | 6 +- .../java/util/measurement/DistanceUtil.java | 63 +++++++++++++++++++ .../java/util/measurement/MemoryUtil.java | 37 +++++++++++ .../java/util/{ => measurement}/TimeUtil.java | 2 +- 11 files changed, 228 insertions(+), 56 deletions(-) delete mode 100644 src/fr/pandacube/java/util/MemoryUtil.java create mode 100644 src/fr/pandacube/java/util/measurement/DistanceUtil.java create mode 100644 src/fr/pandacube/java/util/measurement/MemoryUtil.java rename src/fr/pandacube/java/util/{ => measurement}/TimeUtil.java (95%) diff --git a/src/fr/pandacube/java/util/EnumUtil.java b/src/fr/pandacube/java/util/EnumUtil.java index f3fb75e..8aff869 100644 --- a/src/fr/pandacube/java/util/EnumUtil.java +++ b/src/fr/pandacube/java/util/EnumUtil.java @@ -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; + } + diff --git a/src/fr/pandacube/java/util/Log.java b/src/fr/pandacube/java/util/Log.java index d0101b8..81a9358 100644 --- a/src/fr/pandacube/java/util/Log.java +++ b/src/fr/pandacube/java/util/Log.java @@ -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); + } } diff --git a/src/fr/pandacube/java/util/MemoryUtil.java b/src/fr/pandacube/java/util/MemoryUtil.java deleted file mode 100644 index c22ce2d..0000000 --- a/src/fr/pandacube/java/util/MemoryUtil.java +++ /dev/null @@ -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"; - } -} diff --git a/src/fr/pandacube/java/util/db2/SQLPlayer.java b/src/fr/pandacube/java/util/db2/SQLPlayer.java index c2d8bc9..fdad506 100644 --- a/src/fr/pandacube/java/util/db2/SQLPlayer.java +++ b/src/fr/pandacube/java/util/db2/SQLPlayer.java @@ -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); diff --git a/src/fr/pandacube/java/util/db2/sql_tools/ORM.java b/src/fr/pandacube/java/util/db2/sql_tools/ORM.java index 7bd48e6..735b295 100644 --- a/src/fr/pandacube/java/util/db2/sql_tools/ORM.java +++ b/src/fr/pandacube/java/util/db2/sql_tools/ORM.java @@ -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 getElementInstance(ResultSet set, Class elemClass) throws ReflectiveOperationException, SQLException { + private static T getElementInstance(ResultSet set, Class 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 sqlField = (SQLField) 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 /* diff --git a/src/fr/pandacube/java/util/db2/sql_tools/SQLElement.java b/src/fr/pandacube/java/util/db2/sql_tools/SQLElement.java index 3f8b8dc..2b537cb 100644 --- a/src/fr/pandacube/java/util/db2/sql_tools/SQLElement.java +++ b/src/fr/pandacube/java/util/db2/sql_tools/SQLElement.java @@ -37,7 +37,7 @@ public abstract class SQLElement { private final SQLFieldMap fields; private final Map, Object> values; - private final Set modifiedSinceLastSave; + /* package */ final Set 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, Object> getOnlyModifiedValues() { Map, 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, Object> modifiedValues = getOnlyModifiedValues(); - + if (modifiedValues.isEmpty()) + return; String sql = ""; List psValues = new ArrayList<>(); for(Map.Entry, 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)"); } } diff --git a/src/fr/pandacube/java/util/db2/sql_tools/SQLElementList.java b/src/fr/pandacube/java/util/db2/sql_tools/SQLElementList.java index 52499a8..2030aaa 100644 --- a/src/fr/pandacube/java/util/db2/sql_tools/SQLElementList.java +++ b/src/fr/pandacube/java/util/db2/sql_tools/SQLElementList.java @@ -7,6 +7,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import fr.pandacube.java.util.Log; + /** * * @param @@ -32,11 +34,11 @@ public class SQLElementList extends ArrayList { * @param value la valeur à lui appliquer */ public synchronized void setCommon(SQLField 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 elemClass = (Class) get(0).getClass(); + + Class elemClass = (Class) field.getSQLElementType(); try { E emptyElement = elemClass.newInstance(); emptyElement.set(field, value, false); @@ -71,7 +73,12 @@ public class SQLElementList extends ArrayList { for(Map.Entry, 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 extends ArrayList { ps.setObject(i++, val); } + Log.debug(ps.toString()); ps.executeUpdate(); applyNewValuesToElements(storedEl); @@ -140,6 +148,7 @@ public class SQLElementList extends ArrayList { 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) { diff --git a/src/fr/pandacube/java/util/db2/sql_tools/SQLType.java b/src/fr/pandacube/java/util/db2/sql_tools/SQLType.java index a084b40..904c774 100644 --- a/src/fr/pandacube/java/util/db2/sql_tools/SQLType.java +++ b/src/fr/pandacube/java/util/db2/sql_tools/SQLType.java @@ -6,7 +6,7 @@ public class SQLType { private final String sqlType; private final String sqlTypeParam; - private final Class javaTypes; + private final Class javaTypes; public SQLType(String sqlT, String sqlP, Class javaT) { sqlType = sqlT; @@ -37,6 +37,10 @@ public class SQLType { return toString().equals(((SQLType)obj).toString()); } + public Class getJavaType() { + return javaTypes; + } + diff --git a/src/fr/pandacube/java/util/measurement/DistanceUtil.java b/src/fr/pandacube/java/util/measurement/DistanceUtil.java new file mode 100644 index 0000000..11bba47 --- /dev/null +++ b/src/fr/pandacube/java/util/measurement/DistanceUtil.java @@ -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 { + 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; + } + } + +} diff --git a/src/fr/pandacube/java/util/measurement/MemoryUtil.java b/src/fr/pandacube/java/util/measurement/MemoryUtil.java new file mode 100644 index 0000000..f371938 --- /dev/null +++ b/src/fr/pandacube/java/util/measurement/MemoryUtil.java @@ -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); + } +} diff --git a/src/fr/pandacube/java/util/TimeUtil.java b/src/fr/pandacube/java/util/measurement/TimeUtil.java similarity index 95% rename from src/fr/pandacube/java/util/TimeUtil.java rename to src/fr/pandacube/java/util/measurement/TimeUtil.java index 0aa1603..5860ad6 100644 --- a/src/fr/pandacube/java/util/TimeUtil.java +++ b/src/fr/pandacube/java/util/measurement/TimeUtil.java @@ -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)