diff --git a/.classpath b/Core/.classpath similarity index 100% rename from .classpath rename to Core/.classpath diff --git a/.gitignore b/Core/.gitignore similarity index 100% rename from .gitignore rename to Core/.gitignore diff --git a/.project b/Core/.project similarity index 100% rename from .project rename to Core/.project diff --git a/.settings/org.eclipse.core.resources.prefs b/Core/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from .settings/org.eclipse.core.resources.prefs rename to Core/.settings/org.eclipse.core.resources.prefs diff --git a/.settings/org.eclipse.jdt.core.prefs b/Core/.settings/org.eclipse.jdt.core.prefs similarity index 100% rename from .settings/org.eclipse.jdt.core.prefs rename to Core/.settings/org.eclipse.jdt.core.prefs diff --git a/.settings/org.eclipse.m2e.core.prefs b/Core/.settings/org.eclipse.m2e.core.prefs similarity index 100% rename from .settings/org.eclipse.m2e.core.prefs rename to Core/.settings/org.eclipse.m2e.core.prefs diff --git a/pom.xml b/Core/pom.xml similarity index 100% rename from pom.xml rename to Core/pom.xml diff --git a/src/main/java/fr/pandacube/Pandacube.java b/Core/src/main/java/fr/pandacube/Pandacube.java similarity index 100% rename from src/main/java/fr/pandacube/Pandacube.java rename to Core/src/main/java/fr/pandacube/Pandacube.java diff --git a/src/main/java/fr/pandacube/util/AmountPerTimeLimiter.java b/Core/src/main/java/fr/pandacube/util/AmountPerTimeLimiter.java similarity index 100% rename from src/main/java/fr/pandacube/util/AmountPerTimeLimiter.java rename to Core/src/main/java/fr/pandacube/util/AmountPerTimeLimiter.java diff --git a/src/main/java/fr/pandacube/util/BiMap.java b/Core/src/main/java/fr/pandacube/util/BiMap.java similarity index 100% rename from src/main/java/fr/pandacube/util/BiMap.java rename to Core/src/main/java/fr/pandacube/util/BiMap.java diff --git a/src/main/java/fr/pandacube/util/Callback.java b/Core/src/main/java/fr/pandacube/util/Callback.java similarity index 100% rename from src/main/java/fr/pandacube/util/Callback.java rename to Core/src/main/java/fr/pandacube/util/Callback.java diff --git a/src/main/java/fr/pandacube/util/DirUtils.java b/Core/src/main/java/fr/pandacube/util/DirUtils.java similarity index 100% rename from src/main/java/fr/pandacube/util/DirUtils.java rename to Core/src/main/java/fr/pandacube/util/DirUtils.java diff --git a/src/main/java/fr/pandacube/util/EnumUtil.java b/Core/src/main/java/fr/pandacube/util/EnumUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/EnumUtil.java rename to Core/src/main/java/fr/pandacube/util/EnumUtil.java diff --git a/src/main/java/fr/pandacube/util/GifDecoder.java b/Core/src/main/java/fr/pandacube/util/GifDecoder.java similarity index 100% rename from src/main/java/fr/pandacube/util/GifDecoder.java rename to Core/src/main/java/fr/pandacube/util/GifDecoder.java diff --git a/src/main/java/fr/pandacube/util/JArithmeticInterpreter.java b/Core/src/main/java/fr/pandacube/util/JArithmeticInterpreter.java similarity index 100% rename from src/main/java/fr/pandacube/util/JArithmeticInterpreter.java rename to Core/src/main/java/fr/pandacube/util/JArithmeticInterpreter.java diff --git a/src/main/java/fr/pandacube/util/LevenshteinDistance.java b/Core/src/main/java/fr/pandacube/util/LevenshteinDistance.java similarity index 100% rename from src/main/java/fr/pandacube/util/LevenshteinDistance.java rename to Core/src/main/java/fr/pandacube/util/LevenshteinDistance.java diff --git a/src/main/java/fr/pandacube/util/ListUtil.java b/Core/src/main/java/fr/pandacube/util/ListUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/ListUtil.java rename to Core/src/main/java/fr/pandacube/util/ListUtil.java diff --git a/src/main/java/fr/pandacube/util/Log.java b/Core/src/main/java/fr/pandacube/util/Log.java similarity index 100% rename from src/main/java/fr/pandacube/util/Log.java rename to Core/src/main/java/fr/pandacube/util/Log.java diff --git a/src/main/java/fr/pandacube/util/MappedListView.java b/Core/src/main/java/fr/pandacube/util/MappedListView.java similarity index 100% rename from src/main/java/fr/pandacube/util/MappedListView.java rename to Core/src/main/java/fr/pandacube/util/MappedListView.java diff --git a/src/main/java/fr/pandacube/util/MinecraftVersion.java b/Core/src/main/java/fr/pandacube/util/MinecraftVersion.java similarity index 100% rename from src/main/java/fr/pandacube/util/MinecraftVersion.java rename to Core/src/main/java/fr/pandacube/util/MinecraftVersion.java diff --git a/src/main/java/fr/pandacube/util/MinecraftWebUtil.java b/Core/src/main/java/fr/pandacube/util/MinecraftWebUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/MinecraftWebUtil.java rename to Core/src/main/java/fr/pandacube/util/MinecraftWebUtil.java diff --git a/src/main/java/fr/pandacube/util/OfflineUUID.java b/Core/src/main/java/fr/pandacube/util/OfflineUUID.java similarity index 100% rename from src/main/java/fr/pandacube/util/OfflineUUID.java rename to Core/src/main/java/fr/pandacube/util/OfflineUUID.java diff --git a/src/main/java/fr/pandacube/util/RandomUtil.java b/Core/src/main/java/fr/pandacube/util/RandomUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/RandomUtil.java rename to Core/src/main/java/fr/pandacube/util/RandomUtil.java diff --git a/src/main/java/fr/pandacube/util/ReflexionUtil.java b/Core/src/main/java/fr/pandacube/util/ReflexionUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/ReflexionUtil.java rename to Core/src/main/java/fr/pandacube/util/ReflexionUtil.java diff --git a/src/main/java/fr/pandacube/util/ServerPropertyFile.java b/Core/src/main/java/fr/pandacube/util/ServerPropertyFile.java similarity index 100% rename from src/main/java/fr/pandacube/util/ServerPropertyFile.java rename to Core/src/main/java/fr/pandacube/util/ServerPropertyFile.java diff --git a/src/main/java/fr/pandacube/util/StringUtil.java b/Core/src/main/java/fr/pandacube/util/StringUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/StringUtil.java rename to Core/src/main/java/fr/pandacube/util/StringUtil.java diff --git a/src/main/java/fr/pandacube/util/ThrowableUtil.java b/Core/src/main/java/fr/pandacube/util/ThrowableUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/ThrowableUtil.java rename to Core/src/main/java/fr/pandacube/util/ThrowableUtil.java diff --git a/src/main/java/fr/pandacube/util/TypeConverter.java b/Core/src/main/java/fr/pandacube/util/TypeConverter.java similarity index 100% rename from src/main/java/fr/pandacube/util/TypeConverter.java rename to Core/src/main/java/fr/pandacube/util/TypeConverter.java diff --git a/src/main/java/fr/pandacube/util/commands/AbstractCommand.java b/Core/src/main/java/fr/pandacube/util/commands/AbstractCommand.java similarity index 100% rename from src/main/java/fr/pandacube/util/commands/AbstractCommand.java rename to Core/src/main/java/fr/pandacube/util/commands/AbstractCommand.java diff --git a/src/main/java/fr/pandacube/util/commands/BadCommandUsage.java b/Core/src/main/java/fr/pandacube/util/commands/BadCommandUsage.java similarity index 100% rename from src/main/java/fr/pandacube/util/commands/BadCommandUsage.java rename to Core/src/main/java/fr/pandacube/util/commands/BadCommandUsage.java diff --git a/src/main/java/fr/pandacube/util/commands/SuggestionsSupplier.java b/Core/src/main/java/fr/pandacube/util/commands/SuggestionsSupplier.java similarity index 100% rename from src/main/java/fr/pandacube/util/commands/SuggestionsSupplier.java rename to Core/src/main/java/fr/pandacube/util/commands/SuggestionsSupplier.java diff --git a/src/main/java/fr/pandacube/util/config/AbstractConfig.java b/Core/src/main/java/fr/pandacube/util/config/AbstractConfig.java similarity index 100% rename from src/main/java/fr/pandacube/util/config/AbstractConfig.java rename to Core/src/main/java/fr/pandacube/util/config/AbstractConfig.java diff --git a/src/main/java/fr/pandacube/util/config/AbstractConfigManager.java b/Core/src/main/java/fr/pandacube/util/config/AbstractConfigManager.java similarity index 100% rename from src/main/java/fr/pandacube/util/config/AbstractConfigManager.java rename to Core/src/main/java/fr/pandacube/util/config/AbstractConfigManager.java diff --git a/src/main/java/fr/pandacube/util/measurement/DistanceUtil.java b/Core/src/main/java/fr/pandacube/util/measurement/DistanceUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/measurement/DistanceUtil.java rename to Core/src/main/java/fr/pandacube/util/measurement/DistanceUtil.java diff --git a/src/main/java/fr/pandacube/util/measurement/MemoryUtil.java b/Core/src/main/java/fr/pandacube/util/measurement/MemoryUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/measurement/MemoryUtil.java rename to Core/src/main/java/fr/pandacube/util/measurement/MemoryUtil.java diff --git a/src/main/java/fr/pandacube/util/measurement/Tick.java b/Core/src/main/java/fr/pandacube/util/measurement/Tick.java similarity index 100% rename from src/main/java/fr/pandacube/util/measurement/Tick.java rename to Core/src/main/java/fr/pandacube/util/measurement/Tick.java diff --git a/src/main/java/fr/pandacube/util/measurement/TimeUtil.java b/Core/src/main/java/fr/pandacube/util/measurement/TimeUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/measurement/TimeUtil.java rename to Core/src/main/java/fr/pandacube/util/measurement/TimeUtil.java diff --git a/src/main/java/fr/pandacube/util/net/Array8Bit.java b/Core/src/main/java/fr/pandacube/util/net/Array8Bit.java similarity index 100% rename from src/main/java/fr/pandacube/util/net/Array8Bit.java rename to Core/src/main/java/fr/pandacube/util/net/Array8Bit.java diff --git a/src/main/java/fr/pandacube/util/net/ByteBuffer.java b/Core/src/main/java/fr/pandacube/util/net/ByteBuffer.java similarity index 100% rename from src/main/java/fr/pandacube/util/net/ByteBuffer.java rename to Core/src/main/java/fr/pandacube/util/net/ByteBuffer.java diff --git a/src/main/java/fr/pandacube/util/net/PPacket.java b/Core/src/main/java/fr/pandacube/util/net/PPacket.java similarity index 100% rename from src/main/java/fr/pandacube/util/net/PPacket.java rename to Core/src/main/java/fr/pandacube/util/net/PPacket.java diff --git a/src/main/java/fr/pandacube/util/net/PPacketAnswer.java b/Core/src/main/java/fr/pandacube/util/net/PPacketAnswer.java similarity index 100% rename from src/main/java/fr/pandacube/util/net/PPacketAnswer.java rename to Core/src/main/java/fr/pandacube/util/net/PPacketAnswer.java diff --git a/src/main/java/fr/pandacube/util/net/PPacketListener.java b/Core/src/main/java/fr/pandacube/util/net/PPacketListener.java similarity index 100% rename from src/main/java/fr/pandacube/util/net/PPacketListener.java rename to Core/src/main/java/fr/pandacube/util/net/PPacketListener.java diff --git a/src/main/java/fr/pandacube/util/net/PServer.java b/Core/src/main/java/fr/pandacube/util/net/PServer.java similarity index 100% rename from src/main/java/fr/pandacube/util/net/PServer.java rename to Core/src/main/java/fr/pandacube/util/net/PServer.java diff --git a/src/main/java/fr/pandacube/util/net/PSocket.java b/Core/src/main/java/fr/pandacube/util/net/PSocket.java similarity index 100% rename from src/main/java/fr/pandacube/util/net/PSocket.java rename to Core/src/main/java/fr/pandacube/util/net/PSocket.java diff --git a/src/main/java/fr/pandacube/util/net/PSocketConnectionListener.java b/Core/src/main/java/fr/pandacube/util/net/PSocketConnectionListener.java similarity index 100% rename from src/main/java/fr/pandacube/util/net/PSocketConnectionListener.java rename to Core/src/main/java/fr/pandacube/util/net/PSocketConnectionListener.java diff --git a/src/main/java/fr/pandacube/util/network_api/client/AbstractRequest.java b/Core/src/main/java/fr/pandacube/util/network_api/client/AbstractRequest.java similarity index 100% rename from src/main/java/fr/pandacube/util/network_api/client/AbstractRequest.java rename to Core/src/main/java/fr/pandacube/util/network_api/client/AbstractRequest.java diff --git a/src/main/java/fr/pandacube/util/network_api/client/NetworkAPISender.java b/Core/src/main/java/fr/pandacube/util/network_api/client/NetworkAPISender.java similarity index 100% rename from src/main/java/fr/pandacube/util/network_api/client/NetworkAPISender.java rename to Core/src/main/java/fr/pandacube/util/network_api/client/NetworkAPISender.java diff --git a/src/main/java/fr/pandacube/util/network_api/client/ResponseAnalyser.java b/Core/src/main/java/fr/pandacube/util/network_api/client/ResponseAnalyser.java similarity index 100% rename from src/main/java/fr/pandacube/util/network_api/client/ResponseAnalyser.java rename to Core/src/main/java/fr/pandacube/util/network_api/client/ResponseAnalyser.java diff --git a/src/main/java/fr/pandacube/util/network_api/server/AbstractRequestExecutor.java b/Core/src/main/java/fr/pandacube/util/network_api/server/AbstractRequestExecutor.java similarity index 100% rename from src/main/java/fr/pandacube/util/network_api/server/AbstractRequestExecutor.java rename to Core/src/main/java/fr/pandacube/util/network_api/server/AbstractRequestExecutor.java diff --git a/src/main/java/fr/pandacube/util/network_api/server/NetworkAPIListener.java b/Core/src/main/java/fr/pandacube/util/network_api/server/NetworkAPIListener.java similarity index 100% rename from src/main/java/fr/pandacube/util/network_api/server/NetworkAPIListener.java rename to Core/src/main/java/fr/pandacube/util/network_api/server/NetworkAPIListener.java diff --git a/src/main/java/fr/pandacube/util/network_api/server/PacketExecutor.java b/Core/src/main/java/fr/pandacube/util/network_api/server/PacketExecutor.java similarity index 100% rename from src/main/java/fr/pandacube/util/network_api/server/PacketExecutor.java rename to Core/src/main/java/fr/pandacube/util/network_api/server/PacketExecutor.java diff --git a/src/main/java/fr/pandacube/util/network_api/server/RequestAnalyser.java b/Core/src/main/java/fr/pandacube/util/network_api/server/RequestAnalyser.java similarity index 100% rename from src/main/java/fr/pandacube/util/network_api/server/RequestAnalyser.java rename to Core/src/main/java/fr/pandacube/util/network_api/server/RequestAnalyser.java diff --git a/src/main/java/fr/pandacube/util/network_api/server/Response.java b/Core/src/main/java/fr/pandacube/util/network_api/server/Response.java similarity index 100% rename from src/main/java/fr/pandacube/util/network_api/server/Response.java rename to Core/src/main/java/fr/pandacube/util/network_api/server/Response.java diff --git a/src/main/java/fr/pandacube/util/orm/DBConnection.java b/Core/src/main/java/fr/pandacube/util/orm/DBConnection.java similarity index 100% rename from src/main/java/fr/pandacube/util/orm/DBConnection.java rename to Core/src/main/java/fr/pandacube/util/orm/DBConnection.java diff --git a/src/main/java/fr/pandacube/util/orm/ORM.java b/Core/src/main/java/fr/pandacube/util/orm/ORM.java similarity index 97% rename from src/main/java/fr/pandacube/util/orm/ORM.java rename to Core/src/main/java/fr/pandacube/util/orm/ORM.java index ccacd24..7121d15 100644 --- a/src/main/java/fr/pandacube/util/orm/ORM.java +++ b/Core/src/main/java/fr/pandacube/util/orm/ORM.java @@ -1,391 +1,391 @@ -package fr.pandacube.util.orm; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; - -import org.javatuples.Pair; - -import fr.pandacube.util.Log; - -/** - * ORM = Object-Relational Mapping - * - * @author Marc Baloup - * - */ -public final class ORM { - - private static List>> tables = new ArrayList<>(); - private static Map>, String> tableNames = new HashMap<>(); - - private static DBConnection connection; - - public static DBConnection getConnection() { - return connection; - } - - public synchronized static > void init(DBConnection conn) { - - connection = conn; - - - } - - public static synchronized > void initTable(Class elemClass) throws ORMInitTableException { - if (tables.contains(elemClass)) return; - try { - tables.add(elemClass); - Log.debug("[ORM] Start Init SQL table "+elemClass.getSimpleName()); - E instance = elemClass.getConstructor().newInstance(); - String tableName = instance.tableName(); - tableNames.put(elemClass, tableName); - if (!tableExistInDB(tableName)) createTable(instance); - Log.debug("[ORM] End init SQL table "+elemClass.getSimpleName()); - } catch (Exception|ExceptionInInitializerError e) { - throw new ORMInitTableException(elemClass, e); - } - } - - private static > void createTable(E elem) throws SQLException { - - String sql = "CREATE TABLE IF NOT EXISTS " + elem.tableName() + " ("; - List params = new ArrayList<>(); - - Collection> tableFields = elem.getFields().values(); - boolean first = true; - for (SQLField f : tableFields) { - Pair> statementPart = f.forSQLPreparedStatement(); - params.addAll(statementPart.getValue1()); - - if (!first) sql += ", "; - first = false; - sql += statementPart.getValue0(); - } - - sql += ", PRIMARY KEY id(id))"; - - try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) { - int i = 1; - for (Object val : params) - ps.setObject(i++, val); - Log.info("Creating table " + elem.tableName() + ":\n" + ps.toString()); - ps.executeUpdate(); - } - } - - public static > String getTableName(Class elemClass) throws ORMException { - initTable(elemClass); - return tableNames.get(elemClass); - } - - private static boolean tableExistInDB(String tableName) throws SQLException { - boolean exist = false; - try (ResultSet set = connection.getNativeConnection().getMetaData().getTables(null, null, tableName, null)) { - exist = set.next(); - } - return exist; - } - - @SuppressWarnings("unchecked") - public static > SQLField getSQLIdField(Class elemClass) - throws ORMInitTableException { - initTable(elemClass); - return (SQLField) SQLElement.fieldsCache.get(elemClass).get("id"); - } - - public static > SQLElementList getByIds(Class elemClass, Integer... ids) throws ORMException { - return getByIds(elemClass, Arrays.asList(ids)); - } - - public static > SQLElementList getByIds(Class elemClass, Collection ids) - throws ORMException { - return getAll(elemClass, getSQLIdField(elemClass).in(ids), SQLOrderBy.asc(getSQLIdField(elemClass)), 1, null); - } - - public static > E getById(Class elemClass, int id) throws ORMException { - return getFirst(elemClass, getSQLIdField(elemClass).eq(id)); - } - - public static > E getFirst(Class elemClass, SQLWhere where) - throws ORMException { - return getFirst(elemClass, where, null, null); - } - - public static > E getFirst(Class elemClass, SQLOrderBy orderBy) - throws ORMException { - return getFirst(elemClass, null, orderBy, null); - } - - public static > E getFirst(Class elemClass, SQLWhere where, SQLOrderBy orderBy) - throws ORMException { - return getFirst(elemClass, where, orderBy, null); - } - - public static > E getFirst(Class elemClass, SQLWhere where, SQLOrderBy orderBy, Integer offset) - throws ORMException { - SQLElementList elts = getAll(elemClass, where, orderBy, 1, offset); - return (elts.size() == 0) ? null : elts.get(0); - } - - public static > SQLElementList getAll(Class elemClass) throws ORMException { - return getAll(elemClass, null, null, null, null); - } - - public static > SQLElementList getAll(Class elemClass, SQLWhere where) throws ORMException { - return getAll(elemClass, where, null, null, null); - } - - public static > SQLElementList getAll(Class elemClass, SQLWhere where, - SQLOrderBy orderBy) throws ORMException { - return getAll(elemClass, where, orderBy, null, null); - } - - public static > SQLElementList getAll(Class elemClass, SQLWhere where, - SQLOrderBy orderBy, Integer limit) throws ORMException { - return getAll(elemClass, where, orderBy, limit, null); - } - - public static > SQLElementList getAll(Class elemClass, SQLWhere where, - SQLOrderBy orderBy, Integer limit, Integer offset) throws ORMException { - SQLElementList elmts = new SQLElementList<>(); - forEach(elemClass, where, orderBy, limit, offset, elmts::add); - return elmts; - } - - public static > void forEach(Class elemClass, Consumer action) throws ORMException { - forEach(elemClass, null, null, null, null, action); - } - - public static > void forEach(Class elemClass, SQLWhere where, - Consumer action) throws ORMException { - forEach(elemClass, where, null, null, null, action); - } - - public static > void forEach(Class elemClass, SQLWhere where, - SQLOrderBy orderBy, Consumer action) throws ORMException { - forEach(elemClass, where, orderBy, null, null, action); - } - - public static > void forEach(Class elemClass, SQLWhere where, - SQLOrderBy orderBy, Integer limit, Consumer action) throws ORMException { - forEach(elemClass, where, orderBy, limit, null, action); - } - - public static > void forEach(Class elemClass, SQLWhere where, - SQLOrderBy orderBy, Integer limit, Integer offset, Consumer action) throws ORMException { - initTable(elemClass); - - try { - String sql = "SELECT * FROM " + getTableName(elemClass); - - List params = new ArrayList<>(); - - if (where != null) { - Pair> ret = where.toSQL(); - sql += " WHERE " + ret.getValue0(); - params.addAll(ret.getValue1()); - } - if (orderBy != null) sql += " ORDER BY " + orderBy.toSQL(); - if (limit != null) sql += " LIMIT " + limit; - if (offset != null) sql += " OFFSET " + offset; - sql += ";"; - - try (ResultSet set = customQueryStatement(sql, params)) { - while (set.next()) { - E elm = getElementInstance(set, elemClass); - action.accept(elm); - } - } - } catch (SQLException e) { - throw new ORMException(e); - } - - } - - - - public static > long count(Class elemClass) throws ORMException { - return count(elemClass, null); - } - - public static > long count(Class elemClass, SQLWhere where) throws ORMException { - initTable(elemClass); - - try { - String sql = "SELECT COUNT(*) as count FROM " + getTableName(elemClass); - - List params = new ArrayList<>(); - - if (where != null) { - Pair> ret = where.toSQL(); - sql += " WHERE " + ret.getValue0(); - params.addAll(ret.getValue1()); - } - sql += ";"; - - try (ResultSet set = customQueryStatement(sql, params)) { - if (set.next()) { - return set.getLong(1); - } - } - } catch (SQLException e) { - throw new ORMException(e); - } - - throw new ORMException("Can’t retrieve element count from database (The ResultSet may be empty)"); - - } - - - - - public static ResultSet customQueryStatement(String sql, List params) throws ORMException { - try { - PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql); - int i = 1; - for (Object val : params) { - if (val instanceof Enum) val = ((Enum) val).name(); - ps.setObject(i++, val); - } - Log.debug(ps.toString()); - - ResultSet rs = ps.executeQuery(); - - ps.closeOnCompletion(); - - return rs; - } catch (SQLException e) { - throw new ORMException(e); - } - - } - - - - - public static > SQLUpdate update(Class elemClass, SQLWhere where) throws ORMException { - return new SQLUpdate<>(elemClass, where); - } - - /* package */ static > int update(Class elemClass, SQLWhere where, Map, Object> values) throws ORMException { - return new SQLUpdate<>(elemClass, where, values).execute(); - } - - - /** - * Delete the elements of the table represented by {@code elemClass} which meet the condition {@code where}. - * @param elemClass the SQLElement representing the table. - * @param where the condition to meet for an element to be deleted from the table. If null, the table is truncated using {@link #truncateTable(Class)}. - * @return The return value of {@link PreparedStatement#executeUpdate()}, for an SQL query {@code DELETE}. - * @throws ORMException - */ - public static > int delete(Class elemClass, SQLWhere where) throws ORMException { - initTable(elemClass); - - if (where == null) { - return truncateTable(elemClass); - } - - Pair> whereData = where.toSQL(); - - String sql = "DELETE FROM " + getTableName(elemClass) - + " WHERE " + whereData.getValue0() - + ";"; - List params = new ArrayList<>(whereData.getValue1()); - - return customUpdateStatement(sql, params); - - } - - - - public static int customUpdateStatement(String sql, List params) throws ORMException { - try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) { - - int i = 1; - for (Object val : params) { - if (val instanceof Enum) val = ((Enum) val).name(); - ps.setObject(i++, val); - } - Log.debug(ps.toString()); - - return ps.executeUpdate(); - } catch (SQLException e) { - throw new ORMException(e); - } - } - - - - public static > int truncateTable(Class elemClass) throws ORMException { - try (Statement stmt = connection.getNativeConnection().createStatement()) { - return stmt.executeUpdate("TRUNCATE `" + getTableName(elemClass) + "`"); - } catch(SQLException e) { - throw new ORMException(e); - } - } - - @SuppressWarnings("unchecked") - private static > E getElementInstance(ResultSet set, Class elemClass) throws ORMException { - try { - E instance = elemClass.getConstructor(int.class).newInstance(set.getInt("id")); - - int fieldCount = set.getMetaData().getColumnCount(); - - for (int c = 1; c <= fieldCount; c++) { - String fieldName = set.getMetaData().getColumnLabel(c); - - // ignore when field is present in database but not handled by SQLElement instance - if (!instance.getFields().containsKey(fieldName)) continue; - - SQLField sqlField = (SQLField) instance.getFields().get(fieldName); - - boolean customType = sqlField.type instanceof SQLCustomType; - - Object val = set.getObject(c, - (Class)(customType ? ((SQLCustomType)sqlField.type).intermediateJavaType - : sqlField.type.getJavaType())); - - if (val == null || set.wasNull()) { - instance.set(sqlField, null, false); - } - else { - if (customType) { - try { - val = ((SQLCustomType)sqlField.type).dbToJavaConv.apply(val); - } catch (Exception e) { - throw new ORMException("Error while converting value of field '"+sqlField.getName()+"' with SQLCustomType from "+((SQLCustomType)sqlField.type).intermediateJavaType - +"(jdbc source) to "+sqlField.type.getJavaType()+"(java destination). The original value is '"+val.toString()+"'", e); - } - } - - 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.getName()); - - } - } - - 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 | SQLException e) { - throw new ORMException("Can't instanciate " + elemClass.getName(), e); - } - } - - private ORM() {} // rend la classe non instanciable - -} +package fr.pandacube.util.orm; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.javatuples.Pair; + +import fr.pandacube.util.Log; + +/** + * ORM = Object-Relational Mapping + * + * @author Marc Baloup + * + */ +public final class ORM { + + private static List>> tables = new ArrayList<>(); + private static Map>, String> tableNames = new HashMap<>(); + + private static DBConnection connection; + + public static DBConnection getConnection() { + return connection; + } + + public synchronized static > void init(DBConnection conn) { + + connection = conn; + + + } + + public static synchronized > void initTable(Class elemClass) throws ORMInitTableException { + if (tables.contains(elemClass)) return; + try { + tables.add(elemClass); + Log.debug("[ORM] Start Init SQL table "+elemClass.getSimpleName()); + E instance = elemClass.getConstructor().newInstance(); + String tableName = instance.tableName(); + tableNames.put(elemClass, tableName); + if (!tableExistInDB(tableName)) createTable(instance); + Log.debug("[ORM] End init SQL table "+elemClass.getSimpleName()); + } catch (Exception|ExceptionInInitializerError e) { + throw new ORMInitTableException(elemClass, e); + } + } + + private static > void createTable(E elem) throws SQLException { + + String sql = "CREATE TABLE IF NOT EXISTS " + elem.tableName() + " ("; + List params = new ArrayList<>(); + + Collection> tableFields = elem.getFields().values(); + boolean first = true; + for (SQLField f : tableFields) { + Pair> statementPart = f.forSQLPreparedStatement(); + params.addAll(statementPart.getValue1()); + + if (!first) sql += ", "; + first = false; + sql += statementPart.getValue0(); + } + + sql += ", PRIMARY KEY id(id))"; + + try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) { + int i = 1; + for (Object val : params) + ps.setObject(i++, val); + Log.info("Creating table " + elem.tableName() + ":\n" + ps.toString()); + ps.executeUpdate(); + } + } + + public static > String getTableName(Class elemClass) throws ORMException { + initTable(elemClass); + return tableNames.get(elemClass); + } + + private static boolean tableExistInDB(String tableName) throws SQLException { + boolean exist = false; + try (ResultSet set = connection.getNativeConnection().getMetaData().getTables(null, null, tableName, null)) { + exist = set.next(); + } + return exist; + } + + @SuppressWarnings("unchecked") + public static > SQLField getSQLIdField(Class elemClass) + throws ORMInitTableException { + initTable(elemClass); + return (SQLField) SQLElement.fieldsCache.get(elemClass).get("id"); + } + + public static > SQLElementList getByIds(Class elemClass, Integer... ids) throws ORMException { + return getByIds(elemClass, Arrays.asList(ids)); + } + + public static > SQLElementList getByIds(Class elemClass, Collection ids) + throws ORMException { + return getAll(elemClass, getSQLIdField(elemClass).in(ids), SQLOrderBy.asc(getSQLIdField(elemClass)), 1, null); + } + + public static > E getById(Class elemClass, int id) throws ORMException { + return getFirst(elemClass, getSQLIdField(elemClass).eq(id)); + } + + public static > E getFirst(Class elemClass, SQLWhere where) + throws ORMException { + return getFirst(elemClass, where, null, null); + } + + public static > E getFirst(Class elemClass, SQLOrderBy orderBy) + throws ORMException { + return getFirst(elemClass, null, orderBy, null); + } + + public static > E getFirst(Class elemClass, SQLWhere where, SQLOrderBy orderBy) + throws ORMException { + return getFirst(elemClass, where, orderBy, null); + } + + public static > E getFirst(Class elemClass, SQLWhere where, SQLOrderBy orderBy, Integer offset) + throws ORMException { + SQLElementList elts = getAll(elemClass, where, orderBy, 1, offset); + return (elts.size() == 0) ? null : elts.get(0); + } + + public static > SQLElementList getAll(Class elemClass) throws ORMException { + return getAll(elemClass, null, null, null, null); + } + + public static > SQLElementList getAll(Class elemClass, SQLWhere where) throws ORMException { + return getAll(elemClass, where, null, null, null); + } + + public static > SQLElementList getAll(Class elemClass, SQLWhere where, + SQLOrderBy orderBy) throws ORMException { + return getAll(elemClass, where, orderBy, null, null); + } + + public static > SQLElementList getAll(Class elemClass, SQLWhere where, + SQLOrderBy orderBy, Integer limit) throws ORMException { + return getAll(elemClass, where, orderBy, limit, null); + } + + public static > SQLElementList getAll(Class elemClass, SQLWhere where, + SQLOrderBy orderBy, Integer limit, Integer offset) throws ORMException { + SQLElementList elmts = new SQLElementList<>(); + forEach(elemClass, where, orderBy, limit, offset, elmts::add); + return elmts; + } + + public static > void forEach(Class elemClass, Consumer action) throws ORMException { + forEach(elemClass, null, null, null, null, action); + } + + public static > void forEach(Class elemClass, SQLWhere where, + Consumer action) throws ORMException { + forEach(elemClass, where, null, null, null, action); + } + + public static > void forEach(Class elemClass, SQLWhere where, + SQLOrderBy orderBy, Consumer action) throws ORMException { + forEach(elemClass, where, orderBy, null, null, action); + } + + public static > void forEach(Class elemClass, SQLWhere where, + SQLOrderBy orderBy, Integer limit, Consumer action) throws ORMException { + forEach(elemClass, where, orderBy, limit, null, action); + } + + public static > void forEach(Class elemClass, SQLWhere where, + SQLOrderBy orderBy, Integer limit, Integer offset, Consumer action) throws ORMException { + initTable(elemClass); + + try { + String sql = "SELECT * FROM " + getTableName(elemClass); + + List params = new ArrayList<>(); + + if (where != null) { + Pair> ret = where.toSQL(); + sql += " WHERE " + ret.getValue0(); + params.addAll(ret.getValue1()); + } + if (orderBy != null) sql += " ORDER BY " + orderBy.toSQL(); + if (limit != null) sql += " LIMIT " + limit; + if (offset != null) sql += " OFFSET " + offset; + sql += ";"; + + try (ResultSet set = customQueryStatement(sql, params)) { + while (set.next()) { + E elm = getElementInstance(set, elemClass); + action.accept(elm); + } + } + } catch (SQLException e) { + throw new ORMException(e); + } + + } + + + + public static > long count(Class elemClass) throws ORMException { + return count(elemClass, null); + } + + public static > long count(Class elemClass, SQLWhere where) throws ORMException { + initTable(elemClass); + + try { + String sql = "SELECT COUNT(*) as count FROM " + getTableName(elemClass); + + List params = new ArrayList<>(); + + if (where != null) { + Pair> ret = where.toSQL(); + sql += " WHERE " + ret.getValue0(); + params.addAll(ret.getValue1()); + } + sql += ";"; + + try (ResultSet set = customQueryStatement(sql, params)) { + if (set.next()) { + return set.getLong(1); + } + } + } catch (SQLException e) { + throw new ORMException(e); + } + + throw new ORMException("Can’t retrieve element count from database (The ResultSet may be empty)"); + + } + + + + + public static ResultSet customQueryStatement(String sql, List params) throws ORMException { + try { + PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql); + int i = 1; + for (Object val : params) { + if (val instanceof Enum) val = ((Enum) val).name(); + ps.setObject(i++, val); + } + Log.debug(ps.toString()); + + ResultSet rs = ps.executeQuery(); + + ps.closeOnCompletion(); + + return rs; + } catch (SQLException e) { + throw new ORMException(e); + } + + } + + + + + public static > SQLUpdate update(Class elemClass, SQLWhere where) throws ORMException { + return new SQLUpdate<>(elemClass, where); + } + + /* package */ static > int update(Class elemClass, SQLWhere where, Map, Object> values) throws ORMException { + return new SQLUpdate<>(elemClass, where, values).execute(); + } + + + /** + * Delete the elements of the table represented by {@code elemClass} which meet the condition {@code where}. + * @param elemClass the SQLElement representing the table. + * @param where the condition to meet for an element to be deleted from the table. If null, the table is truncated using {@link #truncateTable(Class)}. + * @return The return value of {@link PreparedStatement#executeUpdate()}, for an SQL query {@code DELETE}. + * @throws ORMException + */ + public static > int delete(Class elemClass, SQLWhere where) throws ORMException { + initTable(elemClass); + + if (where == null) { + return truncateTable(elemClass); + } + + Pair> whereData = where.toSQL(); + + String sql = "DELETE FROM " + getTableName(elemClass) + + " WHERE " + whereData.getValue0() + + ";"; + List params = new ArrayList<>(whereData.getValue1()); + + return customUpdateStatement(sql, params); + + } + + + + public static int customUpdateStatement(String sql, List params) throws ORMException { + try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) { + + int i = 1; + for (Object val : params) { + if (val instanceof Enum) val = ((Enum) val).name(); + ps.setObject(i++, val); + } + Log.debug(ps.toString()); + + return ps.executeUpdate(); + } catch (SQLException e) { + throw new ORMException(e); + } + } + + + + public static > int truncateTable(Class elemClass) throws ORMException { + try (Statement stmt = connection.getNativeConnection().createStatement()) { + return stmt.executeUpdate("TRUNCATE `" + getTableName(elemClass) + "`"); + } catch(SQLException e) { + throw new ORMException(e); + } + } + + @SuppressWarnings("unchecked") + private static > E getElementInstance(ResultSet set, Class elemClass) throws ORMException { + try { + E instance = elemClass.getConstructor(int.class).newInstance(set.getInt("id")); + + int fieldCount = set.getMetaData().getColumnCount(); + + for (int c = 1; c <= fieldCount; c++) { + String fieldName = set.getMetaData().getColumnLabel(c); + + // ignore when field is present in database but not handled by SQLElement instance + if (!instance.getFields().containsKey(fieldName)) continue; + + SQLField sqlField = (SQLField) instance.getFields().get(fieldName); + + boolean customType = sqlField.type instanceof SQLCustomType; + + Object val = set.getObject(c, + (Class)(customType ? ((SQLCustomType)sqlField.type).intermediateJavaType + : sqlField.type.getJavaType())); + + if (val == null || set.wasNull()) { + instance.set(sqlField, null, false); + } + else { + if (customType) { + try { + val = ((SQLCustomType)sqlField.type).dbToJavaConv.apply(val); + } catch (Exception e) { + throw new ORMException("Error while converting value of field '"+sqlField.getName()+"' with SQLCustomType from "+((SQLCustomType)sqlField.type).intermediateJavaType + +"(jdbc source) to "+sqlField.type.getJavaType()+"(java destination). The original value is '"+val.toString()+"'", e); + } + } + + 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.getName()); + + } + } + + 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 | SQLException e) { + throw new ORMException("Can't instanciate " + elemClass.getName(), e); + } + } + + private ORM() {} // rend la classe non instanciable + +} diff --git a/src/main/java/fr/pandacube/util/orm/ORMException.java b/Core/src/main/java/fr/pandacube/util/orm/ORMException.java similarity index 100% rename from src/main/java/fr/pandacube/util/orm/ORMException.java rename to Core/src/main/java/fr/pandacube/util/orm/ORMException.java diff --git a/src/main/java/fr/pandacube/util/orm/ORMInitTableException.java b/Core/src/main/java/fr/pandacube/util/orm/ORMInitTableException.java similarity index 100% rename from src/main/java/fr/pandacube/util/orm/ORMInitTableException.java rename to Core/src/main/java/fr/pandacube/util/orm/ORMInitTableException.java diff --git a/src/main/java/fr/pandacube/util/orm/SQLCustomType.java b/Core/src/main/java/fr/pandacube/util/orm/SQLCustomType.java similarity index 100% rename from src/main/java/fr/pandacube/util/orm/SQLCustomType.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLCustomType.java diff --git a/src/main/java/fr/pandacube/util/orm/SQLElement.java b/Core/src/main/java/fr/pandacube/util/orm/SQLElement.java similarity index 97% rename from src/main/java/fr/pandacube/util/orm/SQLElement.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLElement.java index 46bb32e..775427a 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLElement.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLElement.java @@ -1,501 +1,501 @@ -package fr.pandacube.util.orm; - -import java.lang.reflect.Modifier; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -import org.apache.commons.lang.builder.ToStringBuilder; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; - -import fr.pandacube.util.EnumUtil; -import fr.pandacube.util.Log; - -public abstract class SQLElement> { - /** cache for fields for each subclass of SQLElement */ - /* package */ static final Map>, SQLFieldMap>> fieldsCache = new HashMap<>(); - - DBConnection db = ORM.getConnection(); - - private boolean stored = false; - private int id; - - private final SQLFieldMap fields; - - private final Map, Object> values; - /* package */ final Set modifiedSinceLastSave; - - @SuppressWarnings("unchecked") - public SQLElement() { - - try { - ORM.initTable((Class)getClass()); - } catch (ORMInitTableException e) { - throw new RuntimeException(e); - } - - if (fieldsCache.get(getClass()) == null) { - fields = new SQLFieldMap<>((Class)getClass()); - - // le champ id commun à toutes les tables - SQLField idF = new SQLField<>(INT, false, true, 0); - idF.setName("id"); - fields.addField(idF); - - generateFields(fields); - fieldsCache.put((Class)getClass(), fields); - } - else - fields = (SQLFieldMap) fieldsCache.get(getClass()); - - values = new LinkedHashMap<>(fields.size()); - modifiedSinceLastSave = new HashSet<>(fields.size()); - - initDefaultValues(); - - } - - protected SQLElement(int id) { - this(); - @SuppressWarnings("unchecked") - SQLField idField = (SQLField) fields.get("id"); - set(idField, id, false); - this.id = id; - stored = true; - } - - /** - * @return The name of the table in the database. - */ - protected abstract String tableName(); - - @SuppressWarnings("unchecked") - private void initDefaultValues() { - // remplissage des données par défaut (si peut être null ou si valeur - // par défaut existe) - for (@SuppressWarnings("rawtypes") - SQLField f : fields.values()) - if (f.defaultValue != null) set(f, f.defaultValue); - else if (f.canBeNull || (f.autoIncrement && !stored)) set(f, null); - } - - @SuppressWarnings("unchecked") - protected void generateFields(SQLFieldMap listToFill) { - - java.lang.reflect.Field[] declaredFields = getClass().getDeclaredFields(); - for (java.lang.reflect.Field field : declaredFields) { - if (!SQLField.class.isAssignableFrom(field.getType())) { - Log.debug("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " is of type " + field.getType().getName() + " so it will be ignored."); - continue; - } - if (!Modifier.isStatic(field.getModifiers())) { - Log.severe("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " can't be initialized because it is not static."); - continue; - } - field.setAccessible(true); - try { - Object val = field.get(null); - if (val == null || !(val instanceof SQLField)) { - Log.severe("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " can't be initialized because its value is null."); - continue; - } - SQLField checkedF = (SQLField) val; - checkedF.setName(field.getName()); - if (!Modifier.isPublic(field.getModifiers())) - Log.warning("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " should be public !"); - if (listToFill.containsKey(checkedF.getName())) throw new IllegalArgumentException( - "SQLField " + checkedF.getName() + " already exist in " + getClass().getName()); - checkedF.setSQLElementType((Class) getClass()); - listToFill.addField((SQLField) val); - } catch (IllegalArgumentException | IllegalAccessException e) { - Log.severe("Can't get value of static field " + field.toString(), e); - } - } - - } - - /* package */ Map> getFields() { - return Collections.unmodifiableMap(fields); - } - - public Map, Object> getValues() { - return Collections.unmodifiableMap(values); - } - - @SuppressWarnings("unchecked") - public E set(SQLField field, T value) { - set(field, value, true); - return (E) this; - } - - /* package */ void set(SQLField sqlField, T value, boolean setModified) { - if (sqlField == null) throw new IllegalArgumentException("sqlField can't be null"); - if (!fields.containsValue(sqlField)) // should not append at runtime because of generic type check at compilation - throw new IllegalStateException("In the table "+getClass().getName()+ ": the field asked for modification is not initialized properly."); - - boolean modify = false; - if (value == null) { - if (sqlField.canBeNull || (sqlField.autoIncrement && !stored)) modify = true; - else - throw new IllegalArgumentException( - "SQLField '" + sqlField.getName() + "' of " + getClass().getName() + " is a NOT NULL field"); - } - else if (sqlField.type.isAssignableFrom(value)) modify = true; - else - throw new IllegalArgumentException("SQLField '" + sqlField.getName() + "' of " + getClass().getName() - + " type is '" + sqlField.type.toString() + "' and can't accept values of type " - + value.getClass().getName()); - - if (modify) if (!values.containsKey(sqlField)) { - values.put(sqlField, value); - if (setModified) modifiedSinceLastSave.add(sqlField.getName()); - } - else { - Object oldVal = values.get(sqlField); - if (!Objects.equals(oldVal, value)) { - values.put(sqlField, value); - if (setModified) modifiedSinceLastSave.add(sqlField.getName()); - } - // sinon, rien n'est modifié - } - - } - - public T get(SQLField field) { - if (field == null) throw new IllegalArgumentException("field can't be null"); - if (values.containsKey(field)) { - @SuppressWarnings("unchecked") - T val = (T) values.get(field); - return val; - } - throw new IllegalArgumentException("The field '" + field.getName() + "' in this instance of " + getClass().getName() - + " does not exist or is not set"); - } - - /** - * @param the type of the specified field - * @param

the table class of the primary key targeted by the specified foreign key field - * @return the element in the table P that his primary key correspond to the foreign key value of this element. - */ - public > P getReferencedEntry(SQLFKField field) throws ORMException { - T fkValue = get(field); - if (fkValue == null) return null; - return ORM.getFirst(field.getForeignElementClass(), field.getPrimaryField().eq(fkValue), null); - } - - /** - * @param the type of the specified field - * @param the table class of the foreign key that reference a primary key of this element. - * @return all elements in the table F for which the specified foreign key value correspond to the primary key of this element. - */ - public > SQLElementList getReferencingForeignEntries(SQLFKField field, SQLOrderBy orderBy, Integer limit, Integer offset) throws ORMException { - T value = get(field.getPrimaryField()); - if (value == null) return new SQLElementList<>(); - return ORM.getAll(field.getSQLElementType(), field.eq(value), orderBy, limit, offset); - } - - public boolean isValidForSave() { - return values.keySet().containsAll(fields.values()); - } - - private Map, Object> getOnlyModifiedValues() { - Map, Object> modifiedValues = new LinkedHashMap<>(); - values.forEach((k, v) -> { - if (modifiedSinceLastSave.contains(k.getName())) modifiedValues.put(k, v); - }); - return modifiedValues; - } - - public boolean isModified(SQLField field) { - return modifiedSinceLastSave.contains(field.getName()); - } - - @SuppressWarnings("unchecked") - public E save() throws ORMException { - if (!isValidForSave()) - throw new IllegalStateException(toString() + " has at least one undefined value and can't be saved."); - - ORM.initTable((Class)getClass()); - try { - - if (stored) { // mettre à jour les valeurs dans la base - - // restaurer l'ID au cas il aurait été changé à la main dans - // values - SQLField idField = (SQLField) fields.get("id"); - values.put(idField, id); - modifiedSinceLastSave.remove("id"); - Map, Object> modifiedValues = getOnlyModifiedValues(); - - if (modifiedValues.isEmpty()) return (E) this; - - ORM.update((Class)getClass(), getFieldId().eq(getId()), modifiedValues); - } - else { // ajouter dans la base - - // restaurer l'ID au cas il aurait été changé à la main dans - // values - values.put(fields.get("id"), null); - - String concat_vals = ""; - String concat_fields = ""; - List psValues = new ArrayList<>(); - - boolean first = true; - for (Map.Entry, Object> entry : values.entrySet()) { - if (!first) { - concat_vals += ","; - concat_fields += ","; - } - first = false; - concat_vals += " ? "; - concat_fields += "`" + entry.getKey().getName() + "`"; - addValueToSQLObjectList(psValues, entry.getKey(), entry.getValue()); - } - - try (PreparedStatement ps = db.getNativeConnection().prepareStatement( - "INSERT INTO " + tableName() + " (" + concat_fields + ") VALUES (" + concat_vals + ")", - Statement.RETURN_GENERATED_KEYS)) { - - int i = 1; - for (Object val : psValues) - ps.setObject(i++, val); - - ps.executeUpdate(); - - try (ResultSet rs = ps.getGeneratedKeys()) { - if (rs.next()) id = rs.getInt(1); - stored = true; - } - } - - } - - modifiedSinceLastSave.clear(); - } catch (SQLException e) { - throw new ORMException("Error while saving data", e); - } - return (E) this; - } - - - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected static > void addValueToSQLObjectList(List list, SQLField field, Object jValue) throws ORMException { - if (jValue != null && field.type instanceof SQLCustomType) { - try { - jValue = ((SQLCustomType)field.type).javaToDbConv.apply(jValue); - } catch (Exception e) { - throw new ORMException("Error while converting value of field '"+field.getName()+"' with SQLCustomType from "+field.type.getJavaType() - +"(java source) to "+((SQLCustomType)field.type).intermediateJavaType+"(jdbc destination). The original value is '"+jValue.toString()+"'", e); - } - } - list.add(jValue); - } - - public boolean isStored() { - return stored; - } - - public Integer getId() { - return (stored) ? id : null; - } - - @SuppressWarnings("unchecked") - public SQLField getFieldId() { - return (SQLField) fields.get("id"); - } - - public void delete() throws ORMException { - - if (stored) { // supprimer la ligne de la base - try (PreparedStatement st = db.getNativeConnection() - .prepareStatement("DELETE FROM " + tableName() + " WHERE id=" + id)) { - Log.debug(st.toString()); - st.executeUpdate(); - markAsNotStored(); - } catch (SQLException e) { - throw new ORMException(e); - } - } - - } - - /** - * Méthode appelée quand l'élément courant est retirée de la base de données - * via une requête externe - */ - /* package */ void markAsNotStored() { - stored = false; - id = 0; - modifiedSinceLastSave.clear(); - values.forEach((k, v) -> modifiedSinceLastSave.add(k.getName())); - } - - protected static class SQLFieldMap> extends LinkedHashMap> { - private static final long serialVersionUID = 1L; - - private final Class sqlElemClass; - - private SQLFieldMap(Class elemClass) { - sqlElemClass = elemClass; - } - - private void addField(SQLField f) { - if (f == null) return; - if (containsKey(f.getName())) throw new IllegalArgumentException( - "SQLField " + f.getName() + " already exist in " + sqlElemClass.getName()); - @SuppressWarnings("unchecked") - SQLField checkedF = (SQLField) f; - checkedF.setSQLElementType(sqlElemClass); - put(checkedF.getName(), checkedF); - } - - } - - @Override - public String toString() { - ToStringBuilder b = new ToStringBuilder(this); - - for (SQLField f : fields.values()) - try { - b.append(f.getName(), get(f)); - } catch (IllegalArgumentException e) { - b.append(f.getName(), "(Undefined)"); - } - - return b.toString(); - } - - @Override - public boolean equals(Object o) { - if (o == null || !(getClass().isInstance(o))) return false; - SQLElement oEl = (SQLElement) o; - if (oEl.getId() == null) return false; - return oEl.getId().equals(getId()); - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - - - public JsonObject asJsonObject() { - JsonObject json = new JsonObject(); - for (SQLField f : getFields().values()) { - json.add(f.getName(), new Gson().toJsonTree(get(f))); - } - return json; - } - - - - - - - - - - - protected static , T> SQLField field(SQLType t, boolean nul, boolean autoIncr, T deflt) { - return new SQLField<>(t, nul, autoIncr, deflt); - } - - protected static , T> SQLField field(SQLType t, boolean nul) { - return new SQLField<>(t, nul); - } - - protected static , T> SQLField field(SQLType t, boolean nul, boolean autoIncr) { - return new SQLField<>(t, nul, autoIncr); - } - - protected static , T> SQLField field(SQLType t, boolean nul, T deflt) { - return new SQLField<>(t, nul, deflt); - } - - - protected static , F extends SQLElement> SQLFKField foreignKeyId(boolean nul, Class fkEl) { - return SQLFKField.idFK(nul, fkEl); - } - - protected static , F extends SQLElement> SQLFKField foreignKeyId(boolean nul, Integer deflt, Class fkEl) { - return SQLFKField.idFK(nul, deflt, fkEl); - } - - protected static , T, F extends SQLElement> SQLFKField foreignKey(boolean nul, Class fkEl, SQLField fkF) { - return SQLFKField.customFK(nul, fkEl, fkF); - } - - protected static , T, F extends SQLElement> SQLFKField foreignKey(boolean nul, T deflt, Class fkEl, SQLField fkF) { - return SQLFKField.customFK(nul, deflt, fkEl, fkF); - } - - - public static final SQLType BOOLEAN = new SQLType<>("BOOLEAN", Boolean.class); - - public static final SQLType TINYINT = new SQLType<>("TINYINT", Integer.class); // can’t be Byte due to MYSQL JDBC Connector limitations - public static final SQLType BYTE = TINYINT; - - public static final SQLType SMALLINT = new SQLType<>("SMALLINT", Integer.class); // can’t be Short due to MYSQL JDBC Connector limitations - public static final SQLType SHORT = SMALLINT; - - public static final SQLType INT = new SQLType<>("INT", Integer.class); - public static final SQLType INTEGER = INT; - - public static final SQLType BIGINT = new SQLType<>("BIGINT", Long.class); - public static final SQLType LONG = BIGINT; - - public static final SQLType DATE = new SQLType<>("DATE", Date.class); - - public static final SQLType FLOAT = new SQLType<>("FLOAT", Float.class); - - public static final SQLType DOUBLE = new SQLType<>("DOUBLE", Double.class); - - @Deprecated - public static final SQLType CHAR(int charCount) { - if (charCount <= 0) throw new IllegalArgumentException("charCount must be positive."); - return new SQLType<>("CHAR(" + charCount + ")", String.class); - } - - public static final SQLType VARCHAR(int charCount) { - if (charCount <= 0) throw new IllegalArgumentException("charCount must be positive."); - return new SQLType<>("VARCHAR(" + charCount + ")", String.class); - } - - public static final SQLType TEXT = new SQLType<>("TEXT", String.class); - public static final SQLType STRING = TEXT; - - public static final > SQLType ENUM(Class enumType) { - if (enumType == null) throw new IllegalArgumentException("enumType can't be null."); - String enumStr = "'"; - boolean first = true; - for (T el : enumType.getEnumConstants()) { - if (!first) enumStr += "', '"; - first = false; - enumStr += el.name(); - - } - enumStr += "'"; - - return new SQLCustomType<>("VARCHAR(" + enumStr + ")", String.class, enumType, s -> EnumUtil.searchEnum(enumType, s), Enum::name); - } - - public static final SQLType CHAR36_UUID = new SQLCustomType<>(CHAR(36), UUID.class, UUID::fromString, UUID::toString); - - -} +package fr.pandacube.util.orm; + +import java.lang.reflect.Modifier; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +import org.apache.commons.lang.builder.ToStringBuilder; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import fr.pandacube.util.EnumUtil; +import fr.pandacube.util.Log; + +public abstract class SQLElement> { + /** cache for fields for each subclass of SQLElement */ + /* package */ static final Map>, SQLFieldMap>> fieldsCache = new HashMap<>(); + + DBConnection db = ORM.getConnection(); + + private boolean stored = false; + private int id; + + private final SQLFieldMap fields; + + private final Map, Object> values; + /* package */ final Set modifiedSinceLastSave; + + @SuppressWarnings("unchecked") + public SQLElement() { + + try { + ORM.initTable((Class)getClass()); + } catch (ORMInitTableException e) { + throw new RuntimeException(e); + } + + if (fieldsCache.get(getClass()) == null) { + fields = new SQLFieldMap<>((Class)getClass()); + + // le champ id commun à toutes les tables + SQLField idF = new SQLField<>(INT, false, true, 0); + idF.setName("id"); + fields.addField(idF); + + generateFields(fields); + fieldsCache.put((Class)getClass(), fields); + } + else + fields = (SQLFieldMap) fieldsCache.get(getClass()); + + values = new LinkedHashMap<>(fields.size()); + modifiedSinceLastSave = new HashSet<>(fields.size()); + + initDefaultValues(); + + } + + protected SQLElement(int id) { + this(); + @SuppressWarnings("unchecked") + SQLField idField = (SQLField) fields.get("id"); + set(idField, id, false); + this.id = id; + stored = true; + } + + /** + * @return The name of the table in the database. + */ + protected abstract String tableName(); + + @SuppressWarnings("unchecked") + private void initDefaultValues() { + // remplissage des données par défaut (si peut être null ou si valeur + // par défaut existe) + for (@SuppressWarnings("rawtypes") + SQLField f : fields.values()) + if (f.defaultValue != null) set(f, f.defaultValue); + else if (f.canBeNull || (f.autoIncrement && !stored)) set(f, null); + } + + @SuppressWarnings("unchecked") + protected void generateFields(SQLFieldMap listToFill) { + + java.lang.reflect.Field[] declaredFields = getClass().getDeclaredFields(); + for (java.lang.reflect.Field field : declaredFields) { + if (!SQLField.class.isAssignableFrom(field.getType())) { + Log.debug("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " is of type " + field.getType().getName() + " so it will be ignored."); + continue; + } + if (!Modifier.isStatic(field.getModifiers())) { + Log.severe("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " can't be initialized because it is not static."); + continue; + } + field.setAccessible(true); + try { + Object val = field.get(null); + if (val == null || !(val instanceof SQLField)) { + Log.severe("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " can't be initialized because its value is null."); + continue; + } + SQLField checkedF = (SQLField) val; + checkedF.setName(field.getName()); + if (!Modifier.isPublic(field.getModifiers())) + Log.warning("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " should be public !"); + if (listToFill.containsKey(checkedF.getName())) throw new IllegalArgumentException( + "SQLField " + checkedF.getName() + " already exist in " + getClass().getName()); + checkedF.setSQLElementType((Class) getClass()); + listToFill.addField((SQLField) val); + } catch (IllegalArgumentException | IllegalAccessException e) { + Log.severe("Can't get value of static field " + field.toString(), e); + } + } + + } + + /* package */ Map> getFields() { + return Collections.unmodifiableMap(fields); + } + + public Map, Object> getValues() { + return Collections.unmodifiableMap(values); + } + + @SuppressWarnings("unchecked") + public E set(SQLField field, T value) { + set(field, value, true); + return (E) this; + } + + /* package */ void set(SQLField sqlField, T value, boolean setModified) { + if (sqlField == null) throw new IllegalArgumentException("sqlField can't be null"); + if (!fields.containsValue(sqlField)) // should not append at runtime because of generic type check at compilation + throw new IllegalStateException("In the table "+getClass().getName()+ ": the field asked for modification is not initialized properly."); + + boolean modify = false; + if (value == null) { + if (sqlField.canBeNull || (sqlField.autoIncrement && !stored)) modify = true; + else + throw new IllegalArgumentException( + "SQLField '" + sqlField.getName() + "' of " + getClass().getName() + " is a NOT NULL field"); + } + else if (sqlField.type.isAssignableFrom(value)) modify = true; + else + throw new IllegalArgumentException("SQLField '" + sqlField.getName() + "' of " + getClass().getName() + + " type is '" + sqlField.type.toString() + "' and can't accept values of type " + + value.getClass().getName()); + + if (modify) if (!values.containsKey(sqlField)) { + values.put(sqlField, value); + if (setModified) modifiedSinceLastSave.add(sqlField.getName()); + } + else { + Object oldVal = values.get(sqlField); + if (!Objects.equals(oldVal, value)) { + values.put(sqlField, value); + if (setModified) modifiedSinceLastSave.add(sqlField.getName()); + } + // sinon, rien n'est modifié + } + + } + + public T get(SQLField field) { + if (field == null) throw new IllegalArgumentException("field can't be null"); + if (values.containsKey(field)) { + @SuppressWarnings("unchecked") + T val = (T) values.get(field); + return val; + } + throw new IllegalArgumentException("The field '" + field.getName() + "' in this instance of " + getClass().getName() + + " does not exist or is not set"); + } + + /** + * @param the type of the specified field + * @param

the table class of the primary key targeted by the specified foreign key field + * @return the element in the table P that his primary key correspond to the foreign key value of this element. + */ + public > P getReferencedEntry(SQLFKField field) throws ORMException { + T fkValue = get(field); + if (fkValue == null) return null; + return ORM.getFirst(field.getForeignElementClass(), field.getPrimaryField().eq(fkValue), null); + } + + /** + * @param the type of the specified field + * @param the table class of the foreign key that reference a primary key of this element. + * @return all elements in the table F for which the specified foreign key value correspond to the primary key of this element. + */ + public > SQLElementList getReferencingForeignEntries(SQLFKField field, SQLOrderBy orderBy, Integer limit, Integer offset) throws ORMException { + T value = get(field.getPrimaryField()); + if (value == null) return new SQLElementList<>(); + return ORM.getAll(field.getSQLElementType(), field.eq(value), orderBy, limit, offset); + } + + public boolean isValidForSave() { + return values.keySet().containsAll(fields.values()); + } + + private Map, Object> getOnlyModifiedValues() { + Map, Object> modifiedValues = new LinkedHashMap<>(); + values.forEach((k, v) -> { + if (modifiedSinceLastSave.contains(k.getName())) modifiedValues.put(k, v); + }); + return modifiedValues; + } + + public boolean isModified(SQLField field) { + return modifiedSinceLastSave.contains(field.getName()); + } + + @SuppressWarnings("unchecked") + public E save() throws ORMException { + if (!isValidForSave()) + throw new IllegalStateException(toString() + " has at least one undefined value and can't be saved."); + + ORM.initTable((Class)getClass()); + try { + + if (stored) { // mettre à jour les valeurs dans la base + + // restaurer l'ID au cas il aurait été changé à la main dans + // values + SQLField idField = (SQLField) fields.get("id"); + values.put(idField, id); + modifiedSinceLastSave.remove("id"); + Map, Object> modifiedValues = getOnlyModifiedValues(); + + if (modifiedValues.isEmpty()) return (E) this; + + ORM.update((Class)getClass(), getFieldId().eq(getId()), modifiedValues); + } + else { // ajouter dans la base + + // restaurer l'ID au cas il aurait été changé à la main dans + // values + values.put(fields.get("id"), null); + + String concat_vals = ""; + String concat_fields = ""; + List psValues = new ArrayList<>(); + + boolean first = true; + for (Map.Entry, Object> entry : values.entrySet()) { + if (!first) { + concat_vals += ","; + concat_fields += ","; + } + first = false; + concat_vals += " ? "; + concat_fields += "`" + entry.getKey().getName() + "`"; + addValueToSQLObjectList(psValues, entry.getKey(), entry.getValue()); + } + + try (PreparedStatement ps = db.getNativeConnection().prepareStatement( + "INSERT INTO " + tableName() + " (" + concat_fields + ") VALUES (" + concat_vals + ")", + Statement.RETURN_GENERATED_KEYS)) { + + int i = 1; + for (Object val : psValues) + ps.setObject(i++, val); + + ps.executeUpdate(); + + try (ResultSet rs = ps.getGeneratedKeys()) { + if (rs.next()) id = rs.getInt(1); + stored = true; + } + } + + } + + modifiedSinceLastSave.clear(); + } catch (SQLException e) { + throw new ORMException("Error while saving data", e); + } + return (E) this; + } + + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected static > void addValueToSQLObjectList(List list, SQLField field, Object jValue) throws ORMException { + if (jValue != null && field.type instanceof SQLCustomType) { + try { + jValue = ((SQLCustomType)field.type).javaToDbConv.apply(jValue); + } catch (Exception e) { + throw new ORMException("Error while converting value of field '"+field.getName()+"' with SQLCustomType from "+field.type.getJavaType() + +"(java source) to "+((SQLCustomType)field.type).intermediateJavaType+"(jdbc destination). The original value is '"+jValue.toString()+"'", e); + } + } + list.add(jValue); + } + + public boolean isStored() { + return stored; + } + + public Integer getId() { + return (stored) ? id : null; + } + + @SuppressWarnings("unchecked") + public SQLField getFieldId() { + return (SQLField) fields.get("id"); + } + + public void delete() throws ORMException { + + if (stored) { // supprimer la ligne de la base + try (PreparedStatement st = db.getNativeConnection() + .prepareStatement("DELETE FROM " + tableName() + " WHERE id=" + id)) { + Log.debug(st.toString()); + st.executeUpdate(); + markAsNotStored(); + } catch (SQLException e) { + throw new ORMException(e); + } + } + + } + + /** + * Méthode appelée quand l'élément courant est retirée de la base de données + * via une requête externe + */ + /* package */ void markAsNotStored() { + stored = false; + id = 0; + modifiedSinceLastSave.clear(); + values.forEach((k, v) -> modifiedSinceLastSave.add(k.getName())); + } + + protected static class SQLFieldMap> extends LinkedHashMap> { + private static final long serialVersionUID = 1L; + + private final Class sqlElemClass; + + private SQLFieldMap(Class elemClass) { + sqlElemClass = elemClass; + } + + private void addField(SQLField f) { + if (f == null) return; + if (containsKey(f.getName())) throw new IllegalArgumentException( + "SQLField " + f.getName() + " already exist in " + sqlElemClass.getName()); + @SuppressWarnings("unchecked") + SQLField checkedF = (SQLField) f; + checkedF.setSQLElementType(sqlElemClass); + put(checkedF.getName(), checkedF); + } + + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + + for (SQLField f : fields.values()) + try { + b.append(f.getName(), get(f)); + } catch (IllegalArgumentException e) { + b.append(f.getName(), "(Undefined)"); + } + + return b.toString(); + } + + @Override + public boolean equals(Object o) { + if (o == null || !(getClass().isInstance(o))) return false; + SQLElement oEl = (SQLElement) o; + if (oEl.getId() == null) return false; + return oEl.getId().equals(getId()); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + + + public JsonObject asJsonObject() { + JsonObject json = new JsonObject(); + for (SQLField f : getFields().values()) { + json.add(f.getName(), new Gson().toJsonTree(get(f))); + } + return json; + } + + + + + + + + + + + protected static , T> SQLField field(SQLType t, boolean nul, boolean autoIncr, T deflt) { + return new SQLField<>(t, nul, autoIncr, deflt); + } + + protected static , T> SQLField field(SQLType t, boolean nul) { + return new SQLField<>(t, nul); + } + + protected static , T> SQLField field(SQLType t, boolean nul, boolean autoIncr) { + return new SQLField<>(t, nul, autoIncr); + } + + protected static , T> SQLField field(SQLType t, boolean nul, T deflt) { + return new SQLField<>(t, nul, deflt); + } + + + protected static , F extends SQLElement> SQLFKField foreignKeyId(boolean nul, Class fkEl) { + return SQLFKField.idFK(nul, fkEl); + } + + protected static , F extends SQLElement> SQLFKField foreignKeyId(boolean nul, Integer deflt, Class fkEl) { + return SQLFKField.idFK(nul, deflt, fkEl); + } + + protected static , T, F extends SQLElement> SQLFKField foreignKey(boolean nul, Class fkEl, SQLField fkF) { + return SQLFKField.customFK(nul, fkEl, fkF); + } + + protected static , T, F extends SQLElement> SQLFKField foreignKey(boolean nul, T deflt, Class fkEl, SQLField fkF) { + return SQLFKField.customFK(nul, deflt, fkEl, fkF); + } + + + public static final SQLType BOOLEAN = new SQLType<>("BOOLEAN", Boolean.class); + + public static final SQLType TINYINT = new SQLType<>("TINYINT", Integer.class); // can’t be Byte due to MYSQL JDBC Connector limitations + public static final SQLType BYTE = TINYINT; + + public static final SQLType SMALLINT = new SQLType<>("SMALLINT", Integer.class); // can’t be Short due to MYSQL JDBC Connector limitations + public static final SQLType SHORT = SMALLINT; + + public static final SQLType INT = new SQLType<>("INT", Integer.class); + public static final SQLType INTEGER = INT; + + public static final SQLType BIGINT = new SQLType<>("BIGINT", Long.class); + public static final SQLType LONG = BIGINT; + + public static final SQLType DATE = new SQLType<>("DATE", Date.class); + + public static final SQLType FLOAT = new SQLType<>("FLOAT", Float.class); + + public static final SQLType DOUBLE = new SQLType<>("DOUBLE", Double.class); + + @Deprecated + public static final SQLType CHAR(int charCount) { + if (charCount <= 0) throw new IllegalArgumentException("charCount must be positive."); + return new SQLType<>("CHAR(" + charCount + ")", String.class); + } + + public static final SQLType VARCHAR(int charCount) { + if (charCount <= 0) throw new IllegalArgumentException("charCount must be positive."); + return new SQLType<>("VARCHAR(" + charCount + ")", String.class); + } + + public static final SQLType TEXT = new SQLType<>("TEXT", String.class); + public static final SQLType STRING = TEXT; + + public static final > SQLType ENUM(Class enumType) { + if (enumType == null) throw new IllegalArgumentException("enumType can't be null."); + String enumStr = "'"; + boolean first = true; + for (T el : enumType.getEnumConstants()) { + if (!first) enumStr += "', '"; + first = false; + enumStr += el.name(); + + } + enumStr += "'"; + + return new SQLCustomType<>("VARCHAR(" + enumStr + ")", String.class, enumType, s -> EnumUtil.searchEnum(enumType, s), Enum::name); + } + + public static final SQLType CHAR36_UUID = new SQLCustomType<>(CHAR(36), UUID.class, UUID::fromString, UUID::toString); + + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLElementList.java b/Core/src/main/java/fr/pandacube/util/orm/SQLElementList.java similarity index 96% rename from src/main/java/fr/pandacube/util/orm/SQLElementList.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLElementList.java index 95ff0f2..b2eeb53 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLElementList.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLElementList.java @@ -1,201 +1,201 @@ -package fr.pandacube.util.orm; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import com.google.gson.JsonArray; - -import fr.pandacube.util.Log; - -/** - * - * @param - */ -public class SQLElementList> extends ArrayList { - private static final long serialVersionUID = 1L; - - private final Map, Object> modifiedValues = new LinkedHashMap<>(); - - @Override - public synchronized boolean add(E e) { - if (e == null || !e.isStored()) return false; - return super.add(e); - } - - /** - * Défini une valeur à un champ qui sera appliquée dans la base de données à - * tous les - * entrées présente dans cette liste lors de l'appel à {@link #saveCommon()} - * . - * Les valeurs stockés dans chaque élément de cette liste ne seront affectés - * que lors de - * l'appel à {@link #saveCommon()} - * - * @param - * @param field le champs à modifier - * @param value la valeur à lui appliquer - */ - public synchronized void setCommon(SQLField field, T value) { - if (field == null) - throw new IllegalArgumentException("field can't be null"); - if (field.getName() == "id") - throw new IllegalArgumentException("Can't modify id field in a SQLElementList"); - - Class elemClass = field.getSQLElementType(); - try { - E emptyElement = elemClass.getConstructor().newInstance(); - emptyElement.set(field, value, false); - } catch (Exception e) { - throw new IllegalArgumentException("Illegal field or value or can't instanciante an empty instance of " - + elemClass.getName() + ". (the instance is only created to test validity of field and value)", e); - } - - // ici, la valeur est bonne - modifiedValues.put(field, value); - - } - - /** - * Applique toutes les valeurs défini avec - * {@link #setCommon(SQLField, Object)} à toutes - * les entrées dans la base de données correspondants aux entrées de cette - * liste. Les nouvelles - * valeurs sont aussi mises à jour dans les objets contenus dans cette - * liste, si la valeur n'a pas été modifiée individuellement avec - * {@link SQLElement#set(SQLField, Object)}.
- * Les objets de cette liste qui n'ont pas leur données en base de données - * sont ignorées. - * - * @throws SQLException - */ - public synchronized int saveCommon() throws ORMException { - List storedEl = getStoredEl(); - if (storedEl.isEmpty()) return 0; - - @SuppressWarnings("unchecked") - Class classEl = (Class)storedEl.get(0).getClass(); - - int ret = ORM.update(classEl, - storedEl.get(0).getFieldId().in(storedEl.stream().map(SQLElement::getId).collect(Collectors.toList()) - ), - modifiedValues); - - applyNewValuesToElements(storedEl); - - return ret; - } - - @SuppressWarnings("unchecked") - private void applyNewValuesToElements(List storedEl) { - // applique les valeurs dans chaques objets de la liste - for (E el : storedEl) - for (@SuppressWarnings("rawtypes") - SQLField entry : modifiedValues.keySet()) - if (!el.isModified(entry)) el.set(entry, modifiedValues.get(entry), false); - } - - private List getStoredEl() { - return stream().filter(SQLElement::isStored).collect(Collectors.toCollection(() -> new ArrayList<>())); - } - - /** - * @deprecated please use {@link ORM#delete(Class, SQLWhere)} instead, - * except if you really want to fetch the data before removing them from database. - */ - @Deprecated - public synchronized void removeFromDB() { - List storedEl = getStoredEl(); - if (storedEl.isEmpty()) return; - - try { - @SuppressWarnings("unchecked") - Class classEl = (Class)storedEl.get(0).getClass(); - - ORM.delete(classEl, - storedEl.get(0).getFieldId().in(storedEl.stream().map(SQLElement::getId).collect(Collectors.toList())) - ); - for (E el : storedEl) - el.markAsNotStored(); - } catch (ORMException e) { - Log.severe(e); - } - - } - - - - public > SQLElementList

getReferencedEntries(SQLFKField foreignKey, SQLOrderBy

orderBy) throws ORMException { - Set values = new HashSet<>(); - forEach(v -> { - T val = v.get(foreignKey); - if (val != null) - values.add(val); - }); - - if (values.isEmpty()) { - return new SQLElementList<>(); - } - - return ORM.getAll(foreignKey.getForeignElementClass(), foreignKey.getPrimaryField().in(values), orderBy, null, null); - - } - - - public > Map getReferencedEntriesInGroups(SQLFKField foreignKey) throws ORMException { - SQLElementList

foreignElemts = getReferencedEntries(foreignKey, null); - - Map ret = new HashMap<>(); - foreignElemts.forEach(foreignVal -> ret.put(foreignVal.get(foreignKey.getPrimaryField()), foreignVal)); - return ret; - } - - - - public > SQLElementList getReferencingForeignEntries(SQLFKField foreignKey, SQLOrderBy orderBy, Integer limit, Integer offset) throws ORMException { - Set values = new HashSet<>(); - forEach(v -> { - T val = v.get(foreignKey.getPrimaryField()); - if (val != null) - values.add(val); - }); - - if (values.isEmpty()) { - return new SQLElementList<>(); - } - - return ORM.getAll(foreignKey.getSQLElementType(), foreignKey.in(values), orderBy, limit, offset); - - } - - - public > Map> getReferencingForeignEntriesInGroups(SQLFKField foreignKey, SQLOrderBy orderBy, Integer limit, Integer offset) throws ORMException { - SQLElementList foreignElements = getReferencingForeignEntries(foreignKey, orderBy, limit, offset); - - Map> map = new HashMap<>(); - foreignElements.forEach(foreignVal -> { - SQLElementList subList = map.getOrDefault(foreignVal.get(foreignKey), new SQLElementList<>()); - subList.add(foreignVal); - map.put(foreignVal.get(foreignKey), subList); - }); - - return map; - } - - - - - - public JsonArray asJsonArray() { - JsonArray json = new JsonArray(); - forEach(el -> json.add(el.asJsonObject())); - return json; - } - -} +package fr.pandacube.util.orm; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.gson.JsonArray; + +import fr.pandacube.util.Log; + +/** + * + * @param + */ +public class SQLElementList> extends ArrayList { + private static final long serialVersionUID = 1L; + + private final Map, Object> modifiedValues = new LinkedHashMap<>(); + + @Override + public synchronized boolean add(E e) { + if (e == null || !e.isStored()) return false; + return super.add(e); + } + + /** + * Défini une valeur à un champ qui sera appliquée dans la base de données à + * tous les + * entrées présente dans cette liste lors de l'appel à {@link #saveCommon()} + * . + * Les valeurs stockés dans chaque élément de cette liste ne seront affectés + * que lors de + * l'appel à {@link #saveCommon()} + * + * @param + * @param field le champs à modifier + * @param value la valeur à lui appliquer + */ + public synchronized void setCommon(SQLField field, T value) { + if (field == null) + throw new IllegalArgumentException("field can't be null"); + if (field.getName() == "id") + throw new IllegalArgumentException("Can't modify id field in a SQLElementList"); + + Class elemClass = field.getSQLElementType(); + try { + E emptyElement = elemClass.getConstructor().newInstance(); + emptyElement.set(field, value, false); + } catch (Exception e) { + throw new IllegalArgumentException("Illegal field or value or can't instanciante an empty instance of " + + elemClass.getName() + ". (the instance is only created to test validity of field and value)", e); + } + + // ici, la valeur est bonne + modifiedValues.put(field, value); + + } + + /** + * Applique toutes les valeurs défini avec + * {@link #setCommon(SQLField, Object)} à toutes + * les entrées dans la base de données correspondants aux entrées de cette + * liste. Les nouvelles + * valeurs sont aussi mises à jour dans les objets contenus dans cette + * liste, si la valeur n'a pas été modifiée individuellement avec + * {@link SQLElement#set(SQLField, Object)}.
+ * Les objets de cette liste qui n'ont pas leur données en base de données + * sont ignorées. + * + * @throws SQLException + */ + public synchronized int saveCommon() throws ORMException { + List storedEl = getStoredEl(); + if (storedEl.isEmpty()) return 0; + + @SuppressWarnings("unchecked") + Class classEl = (Class)storedEl.get(0).getClass(); + + int ret = ORM.update(classEl, + storedEl.get(0).getFieldId().in(storedEl.stream().map(SQLElement::getId).collect(Collectors.toList()) + ), + modifiedValues); + + applyNewValuesToElements(storedEl); + + return ret; + } + + @SuppressWarnings("unchecked") + private void applyNewValuesToElements(List storedEl) { + // applique les valeurs dans chaques objets de la liste + for (E el : storedEl) + for (@SuppressWarnings("rawtypes") + SQLField entry : modifiedValues.keySet()) + if (!el.isModified(entry)) el.set(entry, modifiedValues.get(entry), false); + } + + private List getStoredEl() { + return stream().filter(SQLElement::isStored).collect(Collectors.toCollection(() -> new ArrayList<>())); + } + + /** + * @deprecated please use {@link ORM#delete(Class, SQLWhere)} instead, + * except if you really want to fetch the data before removing them from database. + */ + @Deprecated + public synchronized void removeFromDB() { + List storedEl = getStoredEl(); + if (storedEl.isEmpty()) return; + + try { + @SuppressWarnings("unchecked") + Class classEl = (Class)storedEl.get(0).getClass(); + + ORM.delete(classEl, + storedEl.get(0).getFieldId().in(storedEl.stream().map(SQLElement::getId).collect(Collectors.toList())) + ); + for (E el : storedEl) + el.markAsNotStored(); + } catch (ORMException e) { + Log.severe(e); + } + + } + + + + public > SQLElementList

getReferencedEntries(SQLFKField foreignKey, SQLOrderBy

orderBy) throws ORMException { + Set values = new HashSet<>(); + forEach(v -> { + T val = v.get(foreignKey); + if (val != null) + values.add(val); + }); + + if (values.isEmpty()) { + return new SQLElementList<>(); + } + + return ORM.getAll(foreignKey.getForeignElementClass(), foreignKey.getPrimaryField().in(values), orderBy, null, null); + + } + + + public > Map getReferencedEntriesInGroups(SQLFKField foreignKey) throws ORMException { + SQLElementList

foreignElemts = getReferencedEntries(foreignKey, null); + + Map ret = new HashMap<>(); + foreignElemts.forEach(foreignVal -> ret.put(foreignVal.get(foreignKey.getPrimaryField()), foreignVal)); + return ret; + } + + + + public > SQLElementList getReferencingForeignEntries(SQLFKField foreignKey, SQLOrderBy orderBy, Integer limit, Integer offset) throws ORMException { + Set values = new HashSet<>(); + forEach(v -> { + T val = v.get(foreignKey.getPrimaryField()); + if (val != null) + values.add(val); + }); + + if (values.isEmpty()) { + return new SQLElementList<>(); + } + + return ORM.getAll(foreignKey.getSQLElementType(), foreignKey.in(values), orderBy, limit, offset); + + } + + + public > Map> getReferencingForeignEntriesInGroups(SQLFKField foreignKey, SQLOrderBy orderBy, Integer limit, Integer offset) throws ORMException { + SQLElementList foreignElements = getReferencingForeignEntries(foreignKey, orderBy, limit, offset); + + Map> map = new HashMap<>(); + foreignElements.forEach(foreignVal -> { + SQLElementList subList = map.getOrDefault(foreignVal.get(foreignKey), new SQLElementList<>()); + subList.add(foreignVal); + map.put(foreignVal.get(foreignKey), subList); + }); + + return map; + } + + + + + + public JsonArray asJsonArray() { + JsonArray json = new JsonArray(); + forEach(el -> json.add(el.asJsonObject())); + return json; + } + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLFKField.java b/Core/src/main/java/fr/pandacube/util/orm/SQLFKField.java similarity index 97% rename from src/main/java/fr/pandacube/util/orm/SQLFKField.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLFKField.java index 080c398..d285f64 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLFKField.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLFKField.java @@ -1,69 +1,69 @@ -package fr.pandacube.util.orm; - -import fr.pandacube.util.Log; - -/** - * - * @author Marc - * - * @param the table class of this current foreign key field - * @param the Java type of this field - * @param

the table class of the targeted primary key - */ -public class SQLFKField, T, P extends SQLElement

> extends SQLField { - - private SQLField sqlPrimaryKeyField; - private Class

sqlForeignKeyElemClass; - - protected SQLFKField(SQLType t, boolean nul, T deflt, Class

fkEl, SQLField fkF) { - super(t, nul, deflt); - construct(fkEl, fkF); - } - - /* package */ static , F extends SQLElement> SQLFKField idFK(boolean nul, Class fkEl) { - return idFK(nul, null, fkEl); - } - - /* package */ static , F extends SQLElement> SQLFKField idFK(boolean nul, Integer deflt, Class fkEl) { - if (fkEl == null) throw new IllegalArgumentException("foreignKeyElement can't be null"); - try { - SQLField f = ORM.getSQLIdField(fkEl); - return new SQLFKField<>(f.type, nul, deflt, fkEl, f); - } catch (ORMInitTableException e) { - Log.severe("Can't create Foreign key Field targetting id field of '"+fkEl+"'", e); - return null; - } - } - - /* package */ static , T, F extends SQLElement> SQLFKField customFK(boolean nul, Class fkEl, SQLField fkF) { - return customFK(nul, null, fkEl, fkF); - } - - /* package */ static , T, F extends SQLElement> SQLFKField customFK(boolean nul, T deflt, Class fkEl, SQLField fkF) { - if (fkEl == null) throw new IllegalArgumentException("foreignKeyElement can't be null"); - return new SQLFKField<>(fkF.type, nul, deflt, fkEl, fkF); - } - - private void construct(Class

fkEl, SQLField fkF) { - if (fkF == null) throw new IllegalArgumentException("foreignKeyField can't be null"); - try { - ORM.initTable(fkEl); - } catch (ORMInitTableException e) { - throw new RuntimeException(e); - } - - if (fkF.getSQLElementType() == null) - throw new RuntimeException("Can't initialize foreign key. The primary key in the table " + fkEl.getName() + " is not properly initialized and can't be targetted by a forein key"); - sqlPrimaryKeyField = fkF; - sqlForeignKeyElemClass = fkEl; - } - - public SQLField getPrimaryField() { - return sqlPrimaryKeyField; - } - - public Class

getForeignElementClass() { - return sqlForeignKeyElemClass; - } - -} +package fr.pandacube.util.orm; + +import fr.pandacube.util.Log; + +/** + * + * @author Marc + * + * @param the table class of this current foreign key field + * @param the Java type of this field + * @param

the table class of the targeted primary key + */ +public class SQLFKField, T, P extends SQLElement

> extends SQLField { + + private SQLField sqlPrimaryKeyField; + private Class

sqlForeignKeyElemClass; + + protected SQLFKField(SQLType t, boolean nul, T deflt, Class

fkEl, SQLField fkF) { + super(t, nul, deflt); + construct(fkEl, fkF); + } + + /* package */ static , F extends SQLElement> SQLFKField idFK(boolean nul, Class fkEl) { + return idFK(nul, null, fkEl); + } + + /* package */ static , F extends SQLElement> SQLFKField idFK(boolean nul, Integer deflt, Class fkEl) { + if (fkEl == null) throw new IllegalArgumentException("foreignKeyElement can't be null"); + try { + SQLField f = ORM.getSQLIdField(fkEl); + return new SQLFKField<>(f.type, nul, deflt, fkEl, f); + } catch (ORMInitTableException e) { + Log.severe("Can't create Foreign key Field targetting id field of '"+fkEl+"'", e); + return null; + } + } + + /* package */ static , T, F extends SQLElement> SQLFKField customFK(boolean nul, Class fkEl, SQLField fkF) { + return customFK(nul, null, fkEl, fkF); + } + + /* package */ static , T, F extends SQLElement> SQLFKField customFK(boolean nul, T deflt, Class fkEl, SQLField fkF) { + if (fkEl == null) throw new IllegalArgumentException("foreignKeyElement can't be null"); + return new SQLFKField<>(fkF.type, nul, deflt, fkEl, fkF); + } + + private void construct(Class

fkEl, SQLField fkF) { + if (fkF == null) throw new IllegalArgumentException("foreignKeyField can't be null"); + try { + ORM.initTable(fkEl); + } catch (ORMInitTableException e) { + throw new RuntimeException(e); + } + + if (fkF.getSQLElementType() == null) + throw new RuntimeException("Can't initialize foreign key. The primary key in the table " + fkEl.getName() + " is not properly initialized and can't be targetted by a forein key"); + sqlPrimaryKeyField = fkF; + sqlForeignKeyElemClass = fkEl; + } + + public SQLField getPrimaryField() { + return sqlPrimaryKeyField; + } + + public Class

getForeignElementClass() { + return sqlForeignKeyElemClass; + } + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLField.java b/Core/src/main/java/fr/pandacube/util/orm/SQLField.java similarity index 95% rename from src/main/java/fr/pandacube/util/orm/SQLField.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLField.java index 6096a16..5448be2 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLField.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLField.java @@ -1,141 +1,141 @@ -package fr.pandacube.util.orm; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.javatuples.Pair; - -import fr.pandacube.util.orm.SQLWhereComp.SQLComparator; - -public class SQLField, T> { - - private Class sqlElemClass; - private String name = null; - public final SQLType type; - public final boolean canBeNull; - public final boolean autoIncrement; - /* package */ final T defaultValue; - - /* package */ SQLField(SQLType t, boolean nul, boolean autoIncr, T deflt) { - type = t; - canBeNull = nul; - autoIncrement = autoIncr; - defaultValue = deflt; - } - - /* package */ SQLField(SQLType t, boolean nul) { - this(t, nul, false, null); - } - - /* package */ SQLField(SQLType t, boolean nul, boolean autoIncr) { - this(t, nul, autoIncr, null); - } - - /* package */ SQLField(SQLType t, boolean nul, T deflt) { - this(t, nul, false, deflt); - } - - /* package */ Pair> forSQLPreparedStatement() { - List params = new ArrayList<>(1); - if (defaultValue != null && !autoIncrement) params.add(defaultValue); - return new Pair<>("`" + getName() + "` " + type.toString() + (canBeNull ? " NULL" : " NOT NULL") - + (autoIncrement ? " AUTO_INCREMENT" : "") - + ((defaultValue == null || autoIncrement) ? "" : " DEFAULT ?"), params); - } - - /* package */ void setSQLElementType(Class elemClass) { - sqlElemClass = elemClass; - } - - public Class getSQLElementType() { - return sqlElemClass; - } - - /* package */ void setName(String n) { - name = n; - } - - public String getName() { - return name; - } - - /** - * Don't use this {@link #toString()} method in a SQL query, because - * the default value is not escaped correctly - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return forSQLPreparedStatement().getValue0().replaceFirst("\\?", - (defaultValue != null && !autoIncrement) ? defaultValue.toString() : ""); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) return false; - if (!(obj instanceof SQLField)) return false; - SQLField f = (SQLField) obj; - if (!f.getName().equals(getName())) return false; - if (!f.sqlElemClass.equals(sqlElemClass)) return false; - return true; - } - - @Override - public int hashCode() { - return getName().hashCode() + sqlElemClass.hashCode(); - } - - - - - - - public SQLWhere eq(T r) { - return comp(SQLComparator.EQ, r); - } - public SQLWhere geq(T r) { - return comp(SQLComparator.GEQ, r); - } - public SQLWhere gt(T r) { - return comp(SQLComparator.GT, r); - } - public SQLWhere leq(T r) { - return comp(SQLComparator.LEQ, r); - } - public SQLWhere lt(T r) { - return comp(SQLComparator.LT, r); - } - public SQLWhere neq(T r) { - return comp(SQLComparator.NEQ, r); - } - - private SQLWhere comp(SQLComparator c, T r) { - if (r == null) - throw new IllegalArgumentException("The value cannot be null. Use SQLField#isNull(value) or SQLField#isNotNull(value) to check for null values"); - return new SQLWhereComp<>(this, c, r); - } - - - public SQLWhere like(String like) { - return new SQLWhereLike<>(this, like); - } - - - - public SQLWhere in(Collection v) { - return new SQLWhereIn<>(this, v); - } - - - - public SQLWhere isNull() { - return new SQLWhereNull<>(this, true); - } - - public SQLWhere isNotNull() { - return new SQLWhereNull<>(this, false); - } - -} +package fr.pandacube.util.orm; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.javatuples.Pair; + +import fr.pandacube.util.orm.SQLWhereComp.SQLComparator; + +public class SQLField, T> { + + private Class sqlElemClass; + private String name = null; + public final SQLType type; + public final boolean canBeNull; + public final boolean autoIncrement; + /* package */ final T defaultValue; + + /* package */ SQLField(SQLType t, boolean nul, boolean autoIncr, T deflt) { + type = t; + canBeNull = nul; + autoIncrement = autoIncr; + defaultValue = deflt; + } + + /* package */ SQLField(SQLType t, boolean nul) { + this(t, nul, false, null); + } + + /* package */ SQLField(SQLType t, boolean nul, boolean autoIncr) { + this(t, nul, autoIncr, null); + } + + /* package */ SQLField(SQLType t, boolean nul, T deflt) { + this(t, nul, false, deflt); + } + + /* package */ Pair> forSQLPreparedStatement() { + List params = new ArrayList<>(1); + if (defaultValue != null && !autoIncrement) params.add(defaultValue); + return new Pair<>("`" + getName() + "` " + type.toString() + (canBeNull ? " NULL" : " NOT NULL") + + (autoIncrement ? " AUTO_INCREMENT" : "") + + ((defaultValue == null || autoIncrement) ? "" : " DEFAULT ?"), params); + } + + /* package */ void setSQLElementType(Class elemClass) { + sqlElemClass = elemClass; + } + + public Class getSQLElementType() { + return sqlElemClass; + } + + /* package */ void setName(String n) { + name = n; + } + + public String getName() { + return name; + } + + /** + * Don't use this {@link #toString()} method in a SQL query, because + * the default value is not escaped correctly + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return forSQLPreparedStatement().getValue0().replaceFirst("\\?", + (defaultValue != null && !autoIncrement) ? defaultValue.toString() : ""); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (!(obj instanceof SQLField)) return false; + SQLField f = (SQLField) obj; + if (!f.getName().equals(getName())) return false; + if (!f.sqlElemClass.equals(sqlElemClass)) return false; + return true; + } + + @Override + public int hashCode() { + return getName().hashCode() + sqlElemClass.hashCode(); + } + + + + + + + public SQLWhere eq(T r) { + return comp(SQLComparator.EQ, r); + } + public SQLWhere geq(T r) { + return comp(SQLComparator.GEQ, r); + } + public SQLWhere gt(T r) { + return comp(SQLComparator.GT, r); + } + public SQLWhere leq(T r) { + return comp(SQLComparator.LEQ, r); + } + public SQLWhere lt(T r) { + return comp(SQLComparator.LT, r); + } + public SQLWhere neq(T r) { + return comp(SQLComparator.NEQ, r); + } + + private SQLWhere comp(SQLComparator c, T r) { + if (r == null) + throw new IllegalArgumentException("The value cannot be null. Use SQLField#isNull(value) or SQLField#isNotNull(value) to check for null values"); + return new SQLWhereComp<>(this, c, r); + } + + + public SQLWhere like(String like) { + return new SQLWhereLike<>(this, like); + } + + + + public SQLWhere in(Collection v) { + return new SQLWhereIn<>(this, v); + } + + + + public SQLWhere isNull() { + return new SQLWhereNull<>(this, true); + } + + public SQLWhere isNotNull() { + return new SQLWhereNull<>(this, false); + } + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLOrderBy.java b/Core/src/main/java/fr/pandacube/util/orm/SQLOrderBy.java similarity index 95% rename from src/main/java/fr/pandacube/util/orm/SQLOrderBy.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLOrderBy.java index 2e98c48..9534da0 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLOrderBy.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLOrderBy.java @@ -1,97 +1,97 @@ -package fr.pandacube.util.orm; - -import java.util.ArrayList; -import java.util.List; - -public class SQLOrderBy> { - - private List orderByFields = new ArrayList<>(); - - /** - * Construit une nouvelle clause ORDER BY - */ - private SQLOrderBy() {} - - /** - * Ajoute un champ dans la clause ORDER BY en construction - * - * @param field le champ SQL à ordonner - * @param d le sens de tri (croissant ASC ou décroissant DESC) - * @return l'objet courant (permet de chainer les ajouts de champs) - */ - private SQLOrderBy add(SQLField field, Direction d) { - orderByFields.add(new OBField(field, d)); - return this; - } - - /** - * Ajoute un champ dans la clause ORDER BY en construction avec pour direction ASC - * - * @param field le champ SQL à ordonner - * @return l'objet courant (permet de chainer les ajouts de champs) - */ - public SQLOrderBy thenAsc(SQLField field) { - return add(field, Direction.ASC); - } - - /** - * Ajoute un champ dans la clause ORDER BY en construction avec pour direction DESC - * - * @param field le champ SQL à ordonner - * @return l'objet courant (permet de chainer les ajouts de champs) - */ - public SQLOrderBy thenDesc(SQLField field) { - return add(field, Direction.DESC); - } - - /* package */ String toSQL() { - String ret = ""; - boolean first = true; - for (OBField f : orderByFields) { - if (!first) ret += ", "; - first = false; - ret += "`" + f.field.getName() + "` " + f.direction.name(); - } - return ret; - } - - @Override - public String toString() { - return toSQL(); - } - - private class OBField { - public final SQLField field; - public final Direction direction; - - public OBField(SQLField f, Direction d) { - field = f; - direction = d; - } - - } - - private enum Direction { - ASC, DESC; - } - - - - - - - - - - public static > SQLOrderBy asc(SQLField field) { - return new SQLOrderBy().thenAsc(field); - } - - public static > SQLOrderBy desc(SQLField field) { - return new SQLOrderBy().thenDesc(field); - } - - - - -} +package fr.pandacube.util.orm; + +import java.util.ArrayList; +import java.util.List; + +public class SQLOrderBy> { + + private List orderByFields = new ArrayList<>(); + + /** + * Construit une nouvelle clause ORDER BY + */ + private SQLOrderBy() {} + + /** + * Ajoute un champ dans la clause ORDER BY en construction + * + * @param field le champ SQL à ordonner + * @param d le sens de tri (croissant ASC ou décroissant DESC) + * @return l'objet courant (permet de chainer les ajouts de champs) + */ + private SQLOrderBy add(SQLField field, Direction d) { + orderByFields.add(new OBField(field, d)); + return this; + } + + /** + * Ajoute un champ dans la clause ORDER BY en construction avec pour direction ASC + * + * @param field le champ SQL à ordonner + * @return l'objet courant (permet de chainer les ajouts de champs) + */ + public SQLOrderBy thenAsc(SQLField field) { + return add(field, Direction.ASC); + } + + /** + * Ajoute un champ dans la clause ORDER BY en construction avec pour direction DESC + * + * @param field le champ SQL à ordonner + * @return l'objet courant (permet de chainer les ajouts de champs) + */ + public SQLOrderBy thenDesc(SQLField field) { + return add(field, Direction.DESC); + } + + /* package */ String toSQL() { + String ret = ""; + boolean first = true; + for (OBField f : orderByFields) { + if (!first) ret += ", "; + first = false; + ret += "`" + f.field.getName() + "` " + f.direction.name(); + } + return ret; + } + + @Override + public String toString() { + return toSQL(); + } + + private class OBField { + public final SQLField field; + public final Direction direction; + + public OBField(SQLField f, Direction d) { + field = f; + direction = d; + } + + } + + private enum Direction { + ASC, DESC; + } + + + + + + + + + + public static > SQLOrderBy asc(SQLField field) { + return new SQLOrderBy().thenAsc(field); + } + + public static > SQLOrderBy desc(SQLField field) { + return new SQLOrderBy().thenDesc(field); + } + + + + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLType.java b/Core/src/main/java/fr/pandacube/util/orm/SQLType.java similarity index 94% rename from src/main/java/fr/pandacube/util/orm/SQLType.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLType.java index 544aab8..f1dc055 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLType.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLType.java @@ -1,39 +1,39 @@ -package fr.pandacube.util.orm; - -public class SQLType { - - protected final String sqlDeclaration; - private final Class javaTypes; - - /* package */ SQLType(String sqlD, Class javaT) { - sqlDeclaration = sqlD; - javaTypes = javaT; - } - - @Override - public String toString() { - return sqlDeclaration; - } - - public boolean isAssignableFrom(Object val) { - if (javaTypes.isInstance(val)) return true; - return false; - } - - @Override - public int hashCode() { - return toString().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof SQLType)) return false; - return toString().equals(((SQLType) obj).toString()); - } - - public Class getJavaType() { - return javaTypes; - } - - -} +package fr.pandacube.util.orm; + +public class SQLType { + + protected final String sqlDeclaration; + private final Class javaTypes; + + /* package */ SQLType(String sqlD, Class javaT) { + sqlDeclaration = sqlD; + javaTypes = javaT; + } + + @Override + public String toString() { + return sqlDeclaration; + } + + public boolean isAssignableFrom(Object val) { + if (javaTypes.isInstance(val)) return true; + return false; + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !(obj instanceof SQLType)) return false; + return toString().equals(((SQLType) obj).toString()); + } + + public Class getJavaType() { + return javaTypes; + } + + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLUpdate.java b/Core/src/main/java/fr/pandacube/util/orm/SQLUpdate.java similarity index 100% rename from src/main/java/fr/pandacube/util/orm/SQLUpdate.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLUpdate.java diff --git a/src/main/java/fr/pandacube/util/orm/SQLWhere.java b/Core/src/main/java/fr/pandacube/util/orm/SQLWhere.java similarity index 95% rename from src/main/java/fr/pandacube/util/orm/SQLWhere.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLWhere.java index 997842c..53ff67c 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLWhere.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLWhere.java @@ -1,43 +1,43 @@ -package fr.pandacube.util.orm; - -import java.util.List; - -import org.javatuples.Pair; - -import fr.pandacube.util.Log; - -public abstract class SQLWhere> { - - public abstract Pair> toSQL() throws ORMException; - - @Override - public String toString() { - try { - return toSQL().getValue0(); - } catch (ORMException e) { - Log.warning(e); - return "[SQLWhere.toString() error (see logs)]"; - } - } - - public SQLWhereAnd and(SQLWhere other) { - return new SQLWhereAnd().and(this).and(other); - } - - public SQLWhereOr or(SQLWhere other) { - return new SQLWhereOr().or(this).or(other); - } - - public static > SQLWhereAnd and() { - return new SQLWhereAnd<>(); - } - - public static > SQLWhereOr or() { - return new SQLWhereOr<>(); - } - - public static String escapeLike(String str) { - return str.replace("\\", "\\\\").replace("_", "\\_").replace("%", "\\%"); - } - -} +package fr.pandacube.util.orm; + +import java.util.List; + +import org.javatuples.Pair; + +import fr.pandacube.util.Log; + +public abstract class SQLWhere> { + + public abstract Pair> toSQL() throws ORMException; + + @Override + public String toString() { + try { + return toSQL().getValue0(); + } catch (ORMException e) { + Log.warning(e); + return "[SQLWhere.toString() error (see logs)]"; + } + } + + public SQLWhereAnd and(SQLWhere other) { + return new SQLWhereAnd().and(this).and(other); + } + + public SQLWhereOr or(SQLWhere other) { + return new SQLWhereOr().or(this).or(other); + } + + public static > SQLWhereAnd and() { + return new SQLWhereAnd<>(); + } + + public static > SQLWhereOr or() { + return new SQLWhereOr<>(); + } + + public static String escapeLike(String str) { + return str.replace("\\", "\\\\").replace("_", "\\_").replace("%", "\\%"); + } + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLWhereAnd.java b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereAnd.java similarity index 100% rename from src/main/java/fr/pandacube/util/orm/SQLWhereAnd.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLWhereAnd.java diff --git a/src/main/java/fr/pandacube/util/orm/SQLWhereChain.java b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereChain.java similarity index 95% rename from src/main/java/fr/pandacube/util/orm/SQLWhereChain.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLWhereChain.java index 550f72a..45b649f 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLWhereChain.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereChain.java @@ -1,58 +1,58 @@ -package fr.pandacube.util.orm; - -import java.util.ArrayList; -import java.util.List; - -import org.javatuples.Pair; - -public abstract class SQLWhereChain> extends SQLWhere { - - private SQLBoolOp operator; - protected List> conditions = new ArrayList<>(); - - /* package */ SQLWhereChain(SQLBoolOp op) { - if (op == null) throw new IllegalArgumentException("op can't be null"); - operator = op; - } - - protected void add(SQLWhere sqlWhere) { - if (sqlWhere == null) throw new IllegalArgumentException("sqlWhere can't be null"); - conditions.add(sqlWhere); - } - - @Override - public Pair> toSQL() throws ORMException { - if (conditions.isEmpty()) { - throw new ORMException("SQLWhereChain needs at least one element inside !"); - } - - String sql = ""; - List params = new ArrayList<>(); - boolean first = true; - - for (SQLWhere w : conditions) { - if (!first) sql += " " + operator.sql + " "; - first = false; - - Pair> ret = w.toSQL(); - sql += "(" + ret.getValue0() + ")"; - params.addAll(ret.getValue1()); - } - - return new Pair<>(sql, params); - } - - /* package */ enum SQLBoolOp { - /** Equivalent to SQL "AND" */ - AND("AND"), - /** Equivalent to SQL "OR" */ - OR("OR"); - /* package */ final String sql; - - private SQLBoolOp(String s) { - sql = s; - } - - } - -} +package fr.pandacube.util.orm; + +import java.util.ArrayList; +import java.util.List; + +import org.javatuples.Pair; + +public abstract class SQLWhereChain> extends SQLWhere { + + private SQLBoolOp operator; + protected List> conditions = new ArrayList<>(); + + /* package */ SQLWhereChain(SQLBoolOp op) { + if (op == null) throw new IllegalArgumentException("op can't be null"); + operator = op; + } + + protected void add(SQLWhere sqlWhere) { + if (sqlWhere == null) throw new IllegalArgumentException("sqlWhere can't be null"); + conditions.add(sqlWhere); + } + + @Override + public Pair> toSQL() throws ORMException { + if (conditions.isEmpty()) { + throw new ORMException("SQLWhereChain needs at least one element inside !"); + } + + String sql = ""; + List params = new ArrayList<>(); + boolean first = true; + + for (SQLWhere w : conditions) { + if (!first) sql += " " + operator.sql + " "; + first = false; + + Pair> ret = w.toSQL(); + sql += "(" + ret.getValue0() + ")"; + params.addAll(ret.getValue1()); + } + + return new Pair<>(sql, params); + } + + /* package */ enum SQLBoolOp { + /** Equivalent to SQL "AND" */ + AND("AND"), + /** Equivalent to SQL "OR" */ + OR("OR"); + /* package */ final String sql; + + private SQLBoolOp(String s) { + sql = s; + } + + } + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLWhereComp.java b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereComp.java similarity index 96% rename from src/main/java/fr/pandacube/util/orm/SQLWhereComp.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLWhereComp.java index 15543c9..7f3b739 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLWhereComp.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereComp.java @@ -1,58 +1,58 @@ -package fr.pandacube.util.orm; - -import java.util.ArrayList; -import java.util.List; - -import org.javatuples.Pair; - -/* package */ class SQLWhereComp> extends SQLWhere { - - private SQLField left; - private SQLComparator comp; - private Object right; - - /** - * Compare a field with a value - * - * @param l the field at left of the comparison operator. Can't be null - * @param c the comparison operator, can't be null - * @param r the value at right of the comparison operator. Can't be null - */ - /* package */ SQLWhereComp(SQLField l, SQLComparator c, T r) { - if (l == null || r == null || c == null) - throw new IllegalArgumentException("All arguments for SQLWhereComp constructor can't be null"); - left = l; - comp = c; - right = r; - } - - @Override - public Pair> toSQL() throws ORMException { - List params = new ArrayList<>(); - SQLElement.addValueToSQLObjectList(params, left, right); - return new Pair<>("`" + left.getName() + "` " + comp.sql + " ? ", params); - } - - /* package */ enum SQLComparator { - /** Equivalent to SQL "=" */ - EQ("="), - /** Equivalent to SQL ">" */ - GT(">"), - /** Equivalent to SQL ">=" */ - GEQ(">="), - /** Equivalent to SQL "<" */ - LT("<"), - /** Equivalent to SQL "<=" */ - LEQ("<="), - /** Equivalent to SQL "!=" */ - NEQ("!="); - - /* package */ final String sql; - - private SQLComparator(String s) { - sql = s; - } - - } - -} +package fr.pandacube.util.orm; + +import java.util.ArrayList; +import java.util.List; + +import org.javatuples.Pair; + +/* package */ class SQLWhereComp> extends SQLWhere { + + private SQLField left; + private SQLComparator comp; + private Object right; + + /** + * Compare a field with a value + * + * @param l the field at left of the comparison operator. Can't be null + * @param c the comparison operator, can't be null + * @param r the value at right of the comparison operator. Can't be null + */ + /* package */ SQLWhereComp(SQLField l, SQLComparator c, T r) { + if (l == null || r == null || c == null) + throw new IllegalArgumentException("All arguments for SQLWhereComp constructor can't be null"); + left = l; + comp = c; + right = r; + } + + @Override + public Pair> toSQL() throws ORMException { + List params = new ArrayList<>(); + SQLElement.addValueToSQLObjectList(params, left, right); + return new Pair<>("`" + left.getName() + "` " + comp.sql + " ? ", params); + } + + /* package */ enum SQLComparator { + /** Equivalent to SQL "=" */ + EQ("="), + /** Equivalent to SQL ">" */ + GT(">"), + /** Equivalent to SQL ">=" */ + GEQ(">="), + /** Equivalent to SQL "<" */ + LT("<"), + /** Equivalent to SQL "<=" */ + LEQ("<="), + /** Equivalent to SQL "!=" */ + NEQ("!="); + + /* package */ final String sql; + + private SQLComparator(String s) { + sql = s; + } + + } + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLWhereIn.java b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereIn.java similarity index 100% rename from src/main/java/fr/pandacube/util/orm/SQLWhereIn.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLWhereIn.java diff --git a/src/main/java/fr/pandacube/util/orm/SQLWhereLike.java b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereLike.java similarity index 96% rename from src/main/java/fr/pandacube/util/orm/SQLWhereLike.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLWhereLike.java index ab5a349..b0950fb 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLWhereLike.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereLike.java @@ -1,33 +1,33 @@ -package fr.pandacube.util.orm; - -import java.util.ArrayList; -import java.util.List; - -import org.javatuples.Pair; - -/* package */ class SQLWhereLike> extends SQLWhere { - - private SQLField field; - private String likeExpr; - - /** - * Compare a field with a value - * - * @param f the field at left of the LIKE keyword. Can't be null - * @param like the like expression. - */ - /* package */ SQLWhereLike(SQLField f, String like) { - if (f == null || like == null) - throw new IllegalArgumentException("All arguments for SQLWhereLike constructor can't be null"); - field = f; - likeExpr = like; - } - - @Override - public Pair> toSQL() { - ArrayList params = new ArrayList<>(); - params.add(likeExpr); - return new Pair<>("`" + field.getName() + "` LIKE ? ", params); - } - -} +package fr.pandacube.util.orm; + +import java.util.ArrayList; +import java.util.List; + +import org.javatuples.Pair; + +/* package */ class SQLWhereLike> extends SQLWhere { + + private SQLField field; + private String likeExpr; + + /** + * Compare a field with a value + * + * @param f the field at left of the LIKE keyword. Can't be null + * @param like the like expression. + */ + /* package */ SQLWhereLike(SQLField f, String like) { + if (f == null || like == null) + throw new IllegalArgumentException("All arguments for SQLWhereLike constructor can't be null"); + field = f; + likeExpr = like; + } + + @Override + public Pair> toSQL() { + ArrayList params = new ArrayList<>(); + params.add(likeExpr); + return new Pair<>("`" + field.getName() + "` LIKE ? ", params); + } + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLWhereNull.java b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereNull.java similarity index 96% rename from src/main/java/fr/pandacube/util/orm/SQLWhereNull.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLWhereNull.java index a78b6c8..33089b5 100644 --- a/src/main/java/fr/pandacube/util/orm/SQLWhereNull.java +++ b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereNull.java @@ -1,37 +1,37 @@ -package fr.pandacube.util.orm; - -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; - -import org.javatuples.Pair; - -import fr.pandacube.util.Log; - -/* package */ class SQLWhereNull> extends SQLWhere { - - private SQLField fild; - private boolean nulll; - - /** - * Init a IS NULL / IS NOT NULL expression for a SQL WHERE condition. - * - * @param field the field to check null / not null state - * @param isNull true if we want to ckeck if "IS NULL", or false to check if - * "IS NOT NULL" - */ - /* package */ SQLWhereNull(SQLField field, boolean isNull) { - if (field == null) throw new IllegalArgumentException("field can't be null"); - if (!field.canBeNull) Log.getLogger().log(Level.WARNING, - "Useless : Trying to check IS [NOT] NULL on the field " + field.getSQLElementType().getName() + "#" - + field.getName() + " which is declared in the ORM as 'can't be null'"); - fild = field; - nulll = isNull; - } - - @Override - public Pair> toSQL() { - return new Pair<>("`" + fild.getName() + "` IS " + ((nulll) ? "NULL" : "NOT NULL"), new ArrayList<>()); - } - -} +package fr.pandacube.util.orm; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +import org.javatuples.Pair; + +import fr.pandacube.util.Log; + +/* package */ class SQLWhereNull> extends SQLWhere { + + private SQLField fild; + private boolean nulll; + + /** + * Init a IS NULL / IS NOT NULL expression for a SQL WHERE condition. + * + * @param field the field to check null / not null state + * @param isNull true if we want to ckeck if "IS NULL", or false to check if + * "IS NOT NULL" + */ + /* package */ SQLWhereNull(SQLField field, boolean isNull) { + if (field == null) throw new IllegalArgumentException("field can't be null"); + if (!field.canBeNull) Log.getLogger().log(Level.WARNING, + "Useless : Trying to check IS [NOT] NULL on the field " + field.getSQLElementType().getName() + "#" + + field.getName() + " which is declared in the ORM as 'can't be null'"); + fild = field; + nulll = isNull; + } + + @Override + public Pair> toSQL() { + return new Pair<>("`" + fild.getName() + "` IS " + ((nulll) ? "NULL" : "NOT NULL"), new ArrayList<>()); + } + +} diff --git a/src/main/java/fr/pandacube/util/orm/SQLWhereOr.java b/Core/src/main/java/fr/pandacube/util/orm/SQLWhereOr.java similarity index 100% rename from src/main/java/fr/pandacube/util/orm/SQLWhereOr.java rename to Core/src/main/java/fr/pandacube/util/orm/SQLWhereOr.java diff --git a/src/main/java/fr/pandacube/util/search/SearchEngine.java b/Core/src/main/java/fr/pandacube/util/search/SearchEngine.java similarity index 100% rename from src/main/java/fr/pandacube/util/search/SearchEngine.java rename to Core/src/main/java/fr/pandacube/util/search/SearchEngine.java diff --git a/src/main/java/fr/pandacube/util/search/SearchResult.java b/Core/src/main/java/fr/pandacube/util/search/SearchResult.java similarity index 100% rename from src/main/java/fr/pandacube/util/search/SearchResult.java rename to Core/src/main/java/fr/pandacube/util/search/SearchResult.java diff --git a/src/main/java/fr/pandacube/util/text_display/Chat.java b/Core/src/main/java/fr/pandacube/util/text_display/Chat.java similarity index 100% rename from src/main/java/fr/pandacube/util/text_display/Chat.java rename to Core/src/main/java/fr/pandacube/util/text_display/Chat.java diff --git a/src/main/java/fr/pandacube/util/text_display/ChatColorUtil.java b/Core/src/main/java/fr/pandacube/util/text_display/ChatColorUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/text_display/ChatColorUtil.java rename to Core/src/main/java/fr/pandacube/util/text_display/ChatColorUtil.java diff --git a/src/main/java/fr/pandacube/util/text_display/ChatStatic.java b/Core/src/main/java/fr/pandacube/util/text_display/ChatStatic.java similarity index 100% rename from src/main/java/fr/pandacube/util/text_display/ChatStatic.java rename to Core/src/main/java/fr/pandacube/util/text_display/ChatStatic.java diff --git a/src/main/java/fr/pandacube/util/text_display/ChatUtil.java b/Core/src/main/java/fr/pandacube/util/text_display/ChatUtil.java similarity index 100% rename from src/main/java/fr/pandacube/util/text_display/ChatUtil.java rename to Core/src/main/java/fr/pandacube/util/text_display/ChatUtil.java diff --git a/src/main/java/fr/pandacube/util/text_display/TextProgressBar.java b/Core/src/main/java/fr/pandacube/util/text_display/TextProgressBar.java similarity index 100% rename from src/main/java/fr/pandacube/util/text_display/TextProgressBar.java rename to Core/src/main/java/fr/pandacube/util/text_display/TextProgressBar.java