PageRenderTime 74ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/jaxrs/eagledns/src/main/java/se/unlogic/standardutils/dao/SimplifiedOneToManyRelation.java

https://bitbucket.org/cprenzberg/resteasy
Java | 364 lines | 215 code | 127 blank | 22 comment | 49 complexity | 3a5109779e4bf8e19debfe81a3804c72 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2010 Robert "Unlogic" Olofsson (unlogic@unlogic.se).
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the GNU Lesser Public License v3
  5. * which accompanies this distribution, and is available at
  6. * http://www.gnu.org/licenses/lgpl-3.0-standalone.html
  7. ******************************************************************************/
  8. package se.unlogic.standardutils.dao;
  9. import se.unlogic.standardutils.collections.CollectionUtils;
  10. import se.unlogic.standardutils.dao.annotations.DAOManaged;
  11. import se.unlogic.standardutils.dao.annotations.Key;
  12. import se.unlogic.standardutils.dao.annotations.SimplifiedRelation;
  13. import se.unlogic.standardutils.dao.enums.Order;
  14. import se.unlogic.standardutils.dao.querys.ArrayListQuery;
  15. import se.unlogic.standardutils.dao.querys.PreparedStatementQuery;
  16. import se.unlogic.standardutils.dao.querys.UpdateQuery;
  17. import se.unlogic.standardutils.populators.BeanStringPopulator;
  18. import se.unlogic.standardutils.populators.QueryParameterPopulator;
  19. import se.unlogic.standardutils.reflection.ReflectionUtils;
  20. import se.unlogic.standardutils.string.StringUtils;
  21. import java.lang.reflect.Field;
  22. import java.lang.reflect.InvocationTargetException;
  23. import java.lang.reflect.Method;
  24. import java.sql.Connection;
  25. import java.sql.SQLException;
  26. import java.util.ArrayList;
  27. import java.util.List;
  28. public class SimplifiedOneToManyRelation<LocalType, RemoteType> implements OneToManyRelation<LocalType, RemoteType> {
  29. private final AnnotatedDAO<LocalType> localDAO;
  30. private final Field field;
  31. private String selectSQL;
  32. private String insertSQL;
  33. private String deleteSQL;
  34. private boolean preserveListOrder;
  35. private String indexColumnName;
  36. private QueryParameterPopulator<RemoteType> queryParameterPopulator;
  37. private Method preparedStatementMethod;
  38. private BeanResultSetPopulator<RemoteType> beanResultSetPopulator;
  39. private Field keyField;
  40. private Column<LocalType, ?> keyColumn;
  41. private final String remoteTableName;
  42. private String remoteKeyColumnName;
  43. private final String remoteValueColumnName;
  44. private Order order;
  45. private boolean initialized;
  46. @SuppressWarnings("unchecked")
  47. public SimplifiedOneToManyRelation(Class<LocalType> beanClass, Class<RemoteType> remoteClass, Field field, AnnotatedDAO<LocalType> localDAO, List<? extends BeanStringPopulator<?>> typePopulators, List<? extends QueryParameterPopulator<?>> queryParameterPopulators) {
  48. super();
  49. this.localDAO = localDAO;
  50. this.field = field;
  51. SimplifiedRelation simplifiedRelation = field.getAnnotation(SimplifiedRelation.class);
  52. remoteKeyColumnName = simplifiedRelation.remoteKeyColumnName();
  53. remoteValueColumnName = simplifiedRelation.remoteValueColumnName();
  54. order = simplifiedRelation.order();
  55. if(simplifiedRelation.addTablePrefix()){
  56. if(simplifiedRelation.deplurifyTablePrefix() && localDAO.getTableName().endsWith("s")){
  57. remoteTableName = localDAO.getTableName().substring(0, localDAO.getTableName().length()-1) + simplifiedRelation.table();
  58. }else{
  59. remoteTableName = localDAO.getTableName() + simplifiedRelation.table();
  60. }
  61. }else{
  62. remoteTableName = simplifiedRelation.table();
  63. }
  64. if (!StringUtils.isEmpty(simplifiedRelation.keyField())) {
  65. try {
  66. keyField = ReflectionUtils.getField(beanClass, simplifiedRelation.keyField());
  67. if (keyField == null) {
  68. throw new RuntimeException("Unable to find field " + simplifiedRelation.keyField() + " in " + beanClass.getClass());
  69. }
  70. } catch (SecurityException e) {
  71. throw new RuntimeException(e);
  72. }
  73. } else {
  74. List<Field> fields = ReflectionUtils.getFields(beanClass);
  75. for (Field localBeanField : fields) {
  76. if (localBeanField.isAnnotationPresent(DAOManaged.class) && localBeanField.isAnnotationPresent(Key.class)) {
  77. if (this.keyField == null) {
  78. keyField = localBeanField;
  79. } else {
  80. throw new RuntimeException("Multiple fields marked with @Key annotation found in class " + beanClass + " therefore keyField has to set on the @SimplifiedRelation annotation of field " + field.getName());
  81. }
  82. }
  83. }
  84. }
  85. if (queryParameterPopulators != null) {
  86. for (QueryParameterPopulator<?> queryParameterPopulator : queryParameterPopulators) {
  87. if (queryParameterPopulator.getType().equals(remoteClass)) {
  88. this.queryParameterPopulator = (QueryParameterPopulator<RemoteType>) queryParameterPopulator;
  89. }
  90. }
  91. }
  92. if (this.queryParameterPopulator == null) {
  93. preparedStatementMethod = PreparedStatementQueryMethods.getQueryMethod(remoteClass);
  94. if (preparedStatementMethod == null) {
  95. throw new RuntimeException("Unable to to find a query parameter populator or prepared statement method matching " + remoteClass + " of @SimplfiedRelation and @OneToMany annotated field " + field.getName() + " in " + beanClass);
  96. }
  97. }
  98. if (typePopulators != null) {
  99. for (BeanStringPopulator<?> typePopulator : typePopulators) {
  100. if (typePopulator.getType().equals(remoteClass)) {
  101. beanResultSetPopulator = new TypeBasedResultSetPopulator<RemoteType>((BeanStringPopulator<RemoteType>) typePopulator, remoteValueColumnName);
  102. }
  103. }
  104. }
  105. if (beanResultSetPopulator == null) {
  106. Method resultSetMethod = ResultSetMethods.getColumnNameMethod(remoteClass);
  107. if (resultSetMethod != null) {
  108. beanResultSetPopulator = new MethodBasedResultSetPopulator<RemoteType>(resultSetMethod, remoteValueColumnName);
  109. } else {
  110. throw new RuntimeException("Unable to to find a type populator or resultset method matching " + remoteClass + " of @SimplfiedRelation and @OneToMany annotated field " + field.getName() + " in " + beanClass);
  111. }
  112. }
  113. if(simplifiedRelation.preserveListOrder()){
  114. if(StringUtils.isEmpty(simplifiedRelation.indexColumn())){
  115. throw new RuntimeException("Preserve list order enabled but no index column specified for @SimplifiedRelation annotated field " + field.getName() + " in " + beanClass);
  116. }
  117. preserveListOrder = true;
  118. indexColumnName = simplifiedRelation.indexColumn();
  119. }
  120. }
  121. private void init() {
  122. this.keyColumn = localDAO.getColumn(keyField);
  123. if (StringUtils.isEmpty(remoteKeyColumnName)) {
  124. remoteKeyColumnName = keyColumn.getColumnName();
  125. }
  126. this.deleteSQL = "DELETE FROM " + remoteTableName + " WHERE " + remoteKeyColumnName + "=?";
  127. if(preserveListOrder){
  128. this.selectSQL = "SELECT * FROM " + remoteTableName + " WHERE " + remoteKeyColumnName + " = ? ORDER BY " + indexColumnName + " " + order;
  129. this.insertSQL = "INSERT INTO " + remoteTableName + "(" + remoteKeyColumnName + "," + remoteValueColumnName + "," + indexColumnName + ") VALUES (?,?,?)";
  130. }else{
  131. this.selectSQL = "SELECT * FROM " + remoteTableName + " WHERE " + remoteKeyColumnName + " = ? ORDER BY " + remoteValueColumnName + " " + order;
  132. this.insertSQL = "INSERT INTO " + remoteTableName + "(" + remoteKeyColumnName + "," + remoteValueColumnName + ") VALUES (?,?)";
  133. }
  134. this.initialized = true;
  135. }
  136. /*
  137. * (non-Javadoc)
  138. *
  139. * @see se.unlogic.utils.dao.OneToManyRelation#setValue(LocalType, java.sql.Connection, java.lang.reflect.Field[])
  140. */
  141. public void getRemoteValue(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException {
  142. if (!initialized) {
  143. init();
  144. }
  145. try {
  146. ArrayListQuery<RemoteType> query = new ArrayListQuery<RemoteType>(connection, false, selectSQL, beanResultSetPopulator);
  147. setKey(query, bean);
  148. ArrayList<RemoteType> list = query.executeQuery();
  149. if (list != null) {
  150. CollectionUtils.removeNullValues(list);
  151. }
  152. field.set(bean, list);
  153. } catch (IllegalArgumentException e) {
  154. throw new RuntimeException(e);
  155. } catch (IllegalAccessException e) {
  156. throw new RuntimeException(e);
  157. }
  158. }
  159. private void setKey(PreparedStatementQuery query, LocalType bean) throws SQLException {
  160. if (keyColumn.getQueryParameterPopulator() != null) {
  161. keyColumn.getQueryParameterPopulator().populate(query, 1, bean);
  162. } else {
  163. try {
  164. keyColumn.getQueryMethod().invoke(query, 1, keyColumn.getBeanValue(bean));
  165. } catch (IllegalArgumentException e) {
  166. throw new RuntimeException(e);
  167. } catch (IllegalAccessException e) {
  168. throw new RuntimeException(e);
  169. } catch (InvocationTargetException e) {
  170. throw new RuntimeException(e);
  171. }
  172. }
  173. }
  174. private void setValue(RemoteType value, UpdateQuery query) throws SQLException {
  175. if (queryParameterPopulator != null) {
  176. queryParameterPopulator.populate(query, 2, value);
  177. } else {
  178. try {
  179. preparedStatementMethod.invoke(query, 2, value);
  180. } catch (IllegalArgumentException e) {
  181. throw new RuntimeException(e);
  182. } catch (IllegalAccessException e) {
  183. throw new RuntimeException(e);
  184. } catch (InvocationTargetException e) {
  185. throw new RuntimeException(e);
  186. }
  187. }
  188. }
  189. /*
  190. * (non-Javadoc)
  191. *
  192. * @see se.unlogic.utils.dao.OneToManyRelation#add(LocalType, java.sql.Connection, java.lang.reflect.Field[])
  193. */
  194. @SuppressWarnings("unchecked")
  195. public void add(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException {
  196. if (!initialized) {
  197. init();
  198. }
  199. try {
  200. List<RemoteType> values = (List<RemoteType>) field.get(bean);
  201. if (values != null) {
  202. int listIndex = 0;
  203. for (RemoteType value : values) {
  204. UpdateQuery query = new UpdateQuery(connection, false, insertSQL);
  205. setKey(query, bean);
  206. setValue(value, query);
  207. if(preserveListOrder){
  208. query.setInt(3, listIndex);
  209. listIndex++;
  210. }
  211. query.executeUpdate();
  212. }
  213. }
  214. } catch (IllegalArgumentException e) {
  215. throw new RuntimeException(e);
  216. } catch (IllegalAccessException e) {
  217. throw new RuntimeException(e);
  218. }
  219. }
  220. /*
  221. * (non-Javadoc)
  222. *
  223. * @see se.unlogic.utils.dao.OneToManyRelation#update(LocalType, java.sql.Connection, java.lang.reflect.Field[])
  224. */
  225. public void update(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException {
  226. if (!initialized) {
  227. init();
  228. }
  229. UpdateQuery query = new UpdateQuery(connection, false, deleteSQL);
  230. setKey(query, bean);
  231. query.executeUpdate();
  232. this.add(bean, connection, relationQuery);
  233. }
  234. public static <LT, RT> OneToManyRelation<LT, RT> getGenericInstance(Class<LT> beanClass, Class<RT> remoteClass, Field field, AnnotatedDAO<LT> localDAO, List<? extends BeanStringPopulator<?>> typePopulators, List<? extends QueryParameterPopulator<?>> queryParameterPopulators) {
  235. return new SimplifiedOneToManyRelation<LT, RT>(beanClass, remoteClass, field, localDAO, typePopulators, queryParameterPopulators);
  236. }
  237. }