PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/services/core/src/main/java/org/jage/query/GenericQuery.java

https://gitlab.com/age-agh/age-legacy
Java | 244 lines | 86 code | 29 blank | 129 comment | 16 complexity | 550b18713ab323149eb289ceb74ad6ae MD5 | raw file
  1. /**
  2. * Copyright (C) 2006 - 2012
  3. * Pawel Kedzior
  4. * Tomasz Kmiecik
  5. * Kamil Pietak
  6. * Krzysztof Sikora
  7. * Adam Wos
  8. * Lukasz Faber
  9. * Daniel Krzywicki
  10. * and other students of AGH University of Science and Technology.
  11. *
  12. * This file is part of AgE.
  13. *
  14. * AgE is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation, either version 3 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * AgE is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with AgE. If not, see <http://www.gnu.org/licenses/>.
  26. */
  27. /*
  28. * Created: 2011-09-12
  29. * $Id$
  30. */
  31. package org.jage.query;
  32. import java.util.Collection;
  33. import java.util.List;
  34. import com.google.common.collect.Lists;
  35. /**
  36. * The base class for all built-in queries used in the component introspection. It provides common operations for them.
  37. *
  38. * <p>
  39. * Three basic operations are defined here:
  40. * <ol>
  41. * <li>matching a component on the basis of its properties,
  42. * <li>selection of values of properties from the component,
  43. * <li>execution of aggregate function over the results.
  44. * </ol>
  45. * They are performed in the sequence shown above.
  46. *
  47. * <p>
  48. * Note: this query does not support operations required to work with collections. For more general mechanism check the
  49. * {@link MultiElementQuery} class.
  50. *
  51. * <p>
  52. * Additionally, this query supports targets that implements an {@link IQueryAware} interface.
  53. *
  54. * @param <Q>
  55. * A type of a queried object.
  56. * @param <R>
  57. * A type of results.
  58. *
  59. * @author AGH AgE Team
  60. *
  61. * @see MultiElementQuery
  62. * @see IQueryAware
  63. */
  64. public class GenericQuery<Q, R> implements IQuery<Q, R> {
  65. /**
  66. * Constructed filtering (WHERE) clause.
  67. */
  68. protected IValueFilter<Q> valueFilter;
  69. /**
  70. * Selectors for values (SELECT) clause.
  71. */
  72. protected List<IValueSelector<Q, ?>> valueSelectors = Lists.newArrayList();
  73. /**
  74. * A list of functions to execute over results.
  75. */
  76. protected List<IQueryFunction<R>> functions = Lists.newArrayList();
  77. /**
  78. * A class of the queried object.
  79. */
  80. protected Class<?> targetClass;
  81. /**
  82. * A class of results.
  83. */
  84. protected Class<?> resultClass;
  85. /**
  86. * Constructs a new GenericQuery instance. GenericQuery requires both the target and result class being provided. It
  87. * will use them for creating the result object.
  88. * <p>
  89. * The execution of an empty query will result in the same object being returned. No operation will be performed.
  90. *
  91. * @param targetClass
  92. * A class of the queried object.
  93. * @param resultClass
  94. * A class of the result.
  95. */
  96. public GenericQuery(Class<?> targetClass, Class<?> resultClass) {
  97. valueFilter = ValueFilters.any();
  98. functions.add(QueryFunctions.<R> noOperation());
  99. this.targetClass = targetClass;
  100. this.resultClass = resultClass;
  101. }
  102. @SuppressWarnings("unchecked")
  103. protected void addValueFilter(IValueFilter<Q> filter) {
  104. valueFilter = ValueFilters.allOf(valueFilter, filter);
  105. }
  106. protected void addQueryFunction(IQueryFunction<R> queryFunction) {
  107. functions.add(queryFunction);
  108. }
  109. protected <T> void addValueSelector(IValueSelector<Q, T> valueSelector) {
  110. valueSelectors.add(valueSelector);
  111. }
  112. @SuppressWarnings({ "cast", "unchecked" })
  113. @Override
  114. public R execute(final Q target) {
  115. Q realTarget = target;
  116. if (target instanceof IQueryAware) {
  117. IQueryAware<Q, R, IQuery<Q, R>> aware = (IQueryAware<Q, R, IQuery<Q, R>>)target;
  118. Q tempTarget = aware.beforeExecute(this);
  119. if (tempTarget != null) {
  120. realTarget = tempTarget;
  121. }
  122. }
  123. // Value filters - matching()
  124. if (!valueFilter.matches(realTarget)) {
  125. return null;
  126. }
  127. // Value selectors - select()
  128. R results = null;
  129. if (!valueSelectors.isEmpty()) {
  130. List<Object> list = Lists.newArrayList();
  131. for (IValueSelector<Q, ?> valueSelector : valueSelectors) {
  132. list.add((Object)valueSelector.selectValue(realTarget));
  133. }
  134. if (list.size() == 1 && !Collection.class.isAssignableFrom(resultClass)) {
  135. results = (R)list.get(0);
  136. } else if (resultClass.isAssignableFrom(list.getClass())) {
  137. results = (R)list;
  138. }
  139. } else if (resultClass.isAssignableFrom(targetClass)) {
  140. results = (R)resultClass.cast(realTarget);
  141. }
  142. // Functions - process()
  143. for (IQueryFunction<R> queryFunction : functions) {
  144. results = queryFunction.execute(results);
  145. }
  146. if (target instanceof IQueryAware) {
  147. IQueryAware<Q, R, IQuery<Q, R>> aware = (IQueryAware<Q, R, IQuery<Q, R>>)target;
  148. aware.afterExecute(this);
  149. }
  150. return results;
  151. }
  152. /**
  153. * Adds a value (field) selector to the query.
  154. *
  155. * @param valueSelector
  156. * A selector to add.
  157. * @param <T>
  158. * A type of the selected value.
  159. * @return This query.
  160. */
  161. public <T> GenericQuery<Q, R> select(final IValueSelector<Q, T> valueSelector) {
  162. addValueSelector(valueSelector);
  163. return this;
  164. }
  165. /**
  166. * Adds a value (field) selector to the query.
  167. *
  168. * @param fields
  169. * A fields to select. Fields needs to be accessible by getters in the JavaBean naming convention.
  170. * @return This query.
  171. */
  172. public GenericQuery<Q, R> select(final String... fields) {
  173. for (String field : fields) {
  174. addValueSelector(ValueSelectors.<Q, Object> field(field));
  175. }
  176. return this;
  177. }
  178. /**
  179. * Adds a value filter to the query.
  180. *
  181. * @param filter
  182. * A value filter to add.
  183. * @return This query.
  184. */
  185. public GenericQuery<Q, R> matching(final IValueFilter<Q> filter) {
  186. addValueFilter(filter);
  187. return this;
  188. }
  189. /**
  190. * Adds a value filter that operates on a specific field of the target class to the query.
  191. *
  192. * @param fieldName
  193. * A field name that will be used in matching.
  194. * @param filter
  195. * A value filter to add.
  196. * @param <S>
  197. * A type of the field.
  198. * @return This query.
  199. */
  200. public <S> GenericQuery<Q, R> matching(final String fieldName, final IValueFilter<S> filter) {
  201. addValueFilter(ValueFilters.<Q, S> fieldValue(fieldName, filter));
  202. return this;
  203. }
  204. /**
  205. * Adds a function that will process results.
  206. *
  207. * @param queryFunction
  208. * A function to execute on results.
  209. * @return This query.
  210. */
  211. public GenericQuery<Q, R> process(final IQueryFunction<R> queryFunction) {
  212. addQueryFunction(queryFunction);
  213. return this;
  214. }
  215. }