Table.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. package db;
  2. import java.util.List;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.math.BigDecimal;
  6. import java.sql.SQLException;
  7. import java.util.ArrayList;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. import java.util.Optional;
  11. import db.annotation.DbField;
  12. import db.annotation.DbId;
  13. import db.annotation.DbTable;
  14. public abstract class Table<T extends Persistable> {
  15. private Map<Long, T> cacheMap = new HashMap<>();
  16. public T getById(long id) {
  17. if (cacheMap.containsKey(id)) {
  18. return cacheMap.get(id);
  19. }
  20. Optional<T> opt = getFromDbById(id);
  21. if(opt.isEmpty()) {
  22. return null;
  23. }
  24. return cache(opt.get());
  25. }
  26. public Optional<T> findById(long id) {
  27. T obj = getById(id);
  28. if (obj == null) {
  29. return Optional.empty();
  30. }
  31. return Optional.of(obj);
  32. }
  33. public List<T> getByField(String fieldname, Object value) {
  34. List<T> list = getFromDbByField(fieldname, value);
  35. list.forEach(elt -> cache(elt));
  36. return list;
  37. }
  38. public List<T> getWhere(List<String> fields, List<Object> values) {
  39. List<T> list = getWhereFromDb(fields, values);
  40. list.forEach(elt -> cache(elt));
  41. return list;
  42. }
  43. public List<T> getAll() {
  44. List<T> list = getAllFromDb();
  45. list.forEach(elt -> cache(elt));
  46. return list;
  47. }
  48. public T refresh(long id) {
  49. if (!cacheMap.containsKey(id)) {
  50. throw new IllegalArgumentException("Entity is not load, can't refresh");
  51. }
  52. Optional<T> optObj = getFromDbById(id);
  53. if(optObj.isEmpty()) {
  54. throw new IllegalStateException("Unable to find entity in the database");
  55. }
  56. T obj = optObj.get();
  57. cache(obj);
  58. return obj;
  59. }
  60. public T refresh(T obj) {
  61. return refresh(obj.getId());
  62. }
  63. public void save(T obj) {
  64. if (cacheMap.containsKey(obj.getId())) {
  65. update(obj);
  66. } else {
  67. insert(obj);
  68. }
  69. cache(obj);
  70. }
  71. public final void delete(long id) {
  72. DbTable dbTable = getDbTableAnnotation();
  73. // Cherche l'id
  74. String idField = null;
  75. for(Field field : dbTable.entity().getFields()) {
  76. if(!field.isAnnotationPresent(DbId.class)) {
  77. continue;
  78. }
  79. // Lecture du nom de l'id dans la base
  80. if(field.isAnnotationPresent(DbField.class)) {
  81. idField = field.getAnnotation(DbField.class).name();
  82. } else {
  83. throw new IllegalStateException("Unable to find DbField annotation on id");
  84. }
  85. }
  86. if (idField == null) {
  87. throw new IllegalStateException("Unable to find find DbField annotation");
  88. }
  89. // Requete SQL
  90. String sql = "Delete From " + dbTable.name() + " Where " + idField + " = ?";
  91. List<Object> params = new ArrayList<>();
  92. params.add(id);
  93. // Execution requete
  94. if (!Database.execute(sql, params)) {
  95. throw new IllegalStateException("Unable to delete data");
  96. }
  97. // Retire du cache
  98. remove(id);
  99. }
  100. public void delete(T obj) {
  101. delete(obj.getId());
  102. }
  103. private T cache(T obj) {
  104. if (cacheMap.containsKey(obj.getId())) {
  105. cacheMap.replace(obj.getId(), obj);
  106. } else {
  107. cacheMap.put(obj.getId(), obj);
  108. }
  109. //System.out.println("Cache size: " + cacheMap.size());
  110. //cacheMap.forEach((key, val) -> System.out.println("Cache: " + key));
  111. return obj;
  112. }
  113. private void remove(long id) {
  114. if (cacheMap.containsKey(id)) {
  115. cacheMap.remove(id);
  116. }
  117. }
  118. private DbTable getDbTableAnnotation() {
  119. Class<?> clazz = this.getClass();
  120. // Recupération info anotation DbTable
  121. if (!clazz.isAnnotationPresent(DbTable.class)) {
  122. throw new IllegalStateException("Unable ton find DbTable annotation");
  123. }
  124. return clazz.getAnnotation(DbTable.class);
  125. }
  126. private Optional<T> getFromDbById(long id) {
  127. DbTable dbTable = getDbTableAnnotation();
  128. // Cherche l'id
  129. String idField = null;
  130. for(Field field : dbTable.entity().getFields()) {
  131. if(!field.isAnnotationPresent(DbId.class)) {
  132. continue;
  133. }
  134. // Lecture du nom de l'id dans la base
  135. if(field.isAnnotationPresent(DbField.class)) {
  136. idField = field.getAnnotation(DbField.class).name();
  137. } else {
  138. throw new IllegalStateException("Unable to find DbField annotation on id");
  139. }
  140. }
  141. if (idField == null) {
  142. throw new IllegalStateException("Unable to find find DbField annotation");
  143. }
  144. // Requete sql
  145. String sql = "Select * From " + dbTable.name() + " Where " + idField + " = ?";
  146. List<Object> params = new ArrayList<>();
  147. params.add(id);
  148. Optional<T> result = Database.query(sql, params, rs -> {
  149. try {
  150. T obj = (T) dbTable.entity().getConstructor().newInstance();
  151. rs.next();
  152. for(Field field : dbTable.entity().getFields()) {
  153. if(!field.isAnnotationPresent(DbField.class)) {
  154. continue;
  155. }
  156. obj.getClass().getField(field.getName()).set(obj, rs.getObject(field.getAnnotation(DbField.class).name()));
  157. }
  158. return obj;
  159. } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | NoSuchFieldException | SQLException e) {
  160. throw new IllegalStateException("Unable to map value to the entity");
  161. }
  162. });
  163. // Return
  164. return result;
  165. }
  166. private List<T> getFromDbByField(String fieldname, Object value) {
  167. DbTable dbTable = getDbTableAnnotation();
  168. // Requete sql
  169. String sql = "Select * From " + dbTable.name() + " Where " + fieldname + " = ?";
  170. List<Object> params = new ArrayList<>();
  171. params.add(value);
  172. Optional<List<T>> result = Database.query(sql, params, rs -> {
  173. try {
  174. List<T> list = new ArrayList<>();
  175. while(rs.next()) {
  176. T obj = (T) dbTable.entity().getConstructor().newInstance();
  177. for(Field field : dbTable.entity().getFields()) {
  178. if(!field.isAnnotationPresent(DbField.class)) {
  179. continue;
  180. }
  181. obj.getClass().getField(field.getName()).set(obj, rs.getObject(field.getAnnotation(DbField.class).name()));
  182. }
  183. list.add(obj);
  184. }
  185. return list;
  186. } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | NoSuchFieldException | SQLException e) {
  187. throw new IllegalStateException("Unable to map value to the entity");
  188. }
  189. });
  190. // Return
  191. if(result.isEmpty()) {
  192. return new ArrayList<>();
  193. }
  194. return result.get();
  195. }
  196. private List<T> getWhereFromDb(List<String> where, List<Object> params) {
  197. DbTable dbTable = getDbTableAnnotation();
  198. // Requete sql
  199. StringBuilder sql = new StringBuilder();
  200. sql.append("Select * From " + dbTable.name() + "Where 1=1");
  201. where.forEach(elt -> sql.append(" And " + elt + " = ?"));
  202. // Execution requete
  203. Optional<List<T>> result = Database.query(sql.toString(), params, rs -> {
  204. try {
  205. List<T> list = new ArrayList<>();
  206. while(rs.next()) {
  207. T obj = (T) dbTable.entity().getConstructor().newInstance();
  208. for(Field field : dbTable.entity().getFields()) {
  209. if(!field.isAnnotationPresent(DbField.class)) {
  210. continue;
  211. }
  212. obj.getClass().getField(field.getName()).set(obj, rs.getObject(field.getAnnotation(DbField.class).name()));
  213. }
  214. list.add(obj);
  215. }
  216. return list;
  217. } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | NoSuchFieldException | SQLException e) {
  218. throw new IllegalStateException("Unable to map value to the entity");
  219. }
  220. });
  221. // Return
  222. if(result.isEmpty()) {
  223. return new ArrayList<>();
  224. }
  225. return result.get();
  226. }
  227. private List<T> getAllFromDb() {
  228. DbTable dbTable = getDbTableAnnotation();
  229. // Requete sql
  230. String sql = "Select * From " + dbTable.name();
  231. Optional<List<T>> result = Database.query(sql, rs -> {
  232. try {
  233. List<T> list = new ArrayList<>();
  234. while(rs.next()) {
  235. T obj = (T) dbTable.entity().getConstructor().newInstance();
  236. for(Field field : dbTable.entity().getFields()) {
  237. if(!field.isAnnotationPresent(DbField.class)) {
  238. continue;
  239. }
  240. obj.getClass().getField(field.getName()).set(obj, rs.getObject(field.getAnnotation(DbField.class).name()));
  241. }
  242. list.add(obj);
  243. }
  244. return list;
  245. } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | NoSuchFieldException | SQLException e) {
  246. throw new IllegalStateException("Unable to map value to the entity");
  247. }
  248. });
  249. // Return
  250. if(result.isEmpty()) {
  251. return new ArrayList<>();
  252. }
  253. return result.get();
  254. }
  255. private void insert(T obj) {
  256. DbTable dbTable = getDbTableAnnotation();
  257. // Requete SQL
  258. StringBuilder sql = new StringBuilder();
  259. StringBuilder values = new StringBuilder();
  260. String dbIdName = null; // Nom de l'id en base
  261. String attrIdName = null; // Nom de l'id dans la class
  262. List<Object> params = new ArrayList<>();
  263. sql.append("Insert Into " + dbTable.name() + "(");
  264. boolean first = true;
  265. try {
  266. for(Field field : obj.getClass().getFields()) {
  267. if (!field.isAnnotationPresent(DbField.class)) {
  268. continue;
  269. }
  270. // Cherche l'id
  271. if (dbIdName == null && field.isAnnotationPresent(DbId.class)) {
  272. dbIdName = field.getAnnotation(DbField.class).name();
  273. attrIdName = field.getName();
  274. continue;
  275. }
  276. // Recupere la valeur des autres attributs
  277. if (!first) {
  278. sql.append(",");
  279. values.append(",");
  280. }
  281. sql.append(field.getAnnotation(DbField.class).name());
  282. values.append("?");
  283. params.add(field.get(obj));
  284. first = false;
  285. }
  286. } catch (IllegalArgumentException | IllegalAccessException e) {
  287. throw new IllegalStateException("Unable to access to the attribute", e);
  288. }
  289. sql.append(") Values (");
  290. sql.append(values);
  291. sql.append(")");
  292. // Verif que l'on a bien le nom de l'id
  293. if(dbIdName == null) {
  294. throw new IllegalStateException("Unable to find id field");
  295. }
  296. // Execution de la requete
  297. Map<String, Object> newId = Database.insert(sql.toString(), params, new String[]{dbIdName});
  298. if (newId.isEmpty()) {
  299. throw new IllegalStateException("Unable to save data");
  300. }
  301. // Application nouvelle id
  302. Object val = newId.get(dbIdName);
  303. try {
  304. if (val instanceof BigDecimal) {
  305. BigDecimal b = (BigDecimal) val;
  306. obj.getClass().getField(attrIdName).set(obj, b.longValue());
  307. } else {
  308. obj.getClass().getField(attrIdName).set(obj, val);
  309. }
  310. } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
  311. throw new IllegalStateException("Unable to set id", e);
  312. }
  313. }
  314. private void update(T obj) {
  315. DbTable dbTable = getDbTableAnnotation();
  316. // Requete SQL
  317. StringBuilder sql = new StringBuilder();
  318. StringBuilder where = new StringBuilder();
  319. List<Object> params = new ArrayList<>();
  320. sql.append("Update " + dbTable.name() + " Set ");
  321. where.append(" Where ");
  322. boolean first = true;
  323. for (Field field : obj.getClass().getFields()) {
  324. try {
  325. if (!field.isAnnotationPresent(DbField.class)) {
  326. continue;
  327. }
  328. // Si c'est l'id
  329. if (field.isAnnotationPresent(DbId.class)) {
  330. where.append(field.getAnnotation(DbField.class).name() + " = ?");
  331. continue;
  332. }
  333. // Sinon ajoute dans le set
  334. if (!first) {
  335. sql.append(",");
  336. }
  337. sql.append(field.getAnnotation(DbField.class).name() + " = ?");
  338. params.add(field.get(obj));
  339. first = false;
  340. } catch (IllegalArgumentException | IllegalAccessException e) {
  341. throw new IllegalStateException("Unable to access to the attribute", e);
  342. }
  343. }
  344. sql.append(where);
  345. params.add(obj.getId());
  346. // Execution requete
  347. if(!Database.execute(sql.toString(), params)) {
  348. throw new IllegalStateException("Unable to save data");
  349. }
  350. }
  351. }