Add missing distributionManagement section to poms
[aai/search-data-service.git] / search-data-service-app / src / main / java / org / onap / aai / sa / searchdbabstraction / searchapi / SearchStatement.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21 package org.onap.aai.sa.searchdbabstraction.searchapi;
22
23 import com.fasterxml.jackson.annotation.JsonProperty;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.concurrent.atomic.AtomicBoolean;
27 import org.radeox.util.logging.Logger;
28
29 /**
30  * This class represents the structure of a search statement.
31  *
32  * <p>
33  * The expected JSON structure to represent a search statement is as follows:
34  *
35  * <p>
36  *
37  * <pre>
38  *     {
39  *         "results-start": int,  - Optional: index of starting point in result set.
40  *         "results-size": int,   - Optional: maximum number of documents to include in result set.
41  *
42  *         "filter": {
43  *             { filter structure - see {@link Filter} }
44  *         },
45  *
46  *         "queries": [
47  *             { query structure - see {@link QueryStatement} },
48  *             { query structure - see {@link QueryStatement} },
49  *                              .
50  *                              .
51  *             { query structure - see {@link QueryStatement} },
52  *         ],
53  *
54  *         "aggregations": [
55  *             { aggregation structure - see {@link AggregationStatement} },
56  *             { aggregation structure - see {@link AggregationStatement} },
57  *                              .
58  *                              .
59  *             { aggregation structure - see {@link AggregationStatement} },
60  *         ]
61  *     }
62  * </pre>
63  */
64 public class SearchStatement {
65
66     /**
67      * Defines the filters that should be applied before running the actual queries. This is optional.
68      */
69     private Filter filter;
70
71     /**
72      * The list of queries to be applied to the document store.
73      */
74     private Query[] queries;
75
76     /**
77      * The list of aggregations to be applied to the search
78      */
79     private Aggregation[] aggregations;
80
81     /**
82      * Defines the sort criteria to apply to the query result set. This is optional.
83      */
84     private Sort sort;
85
86     @JsonProperty("results-start")
87     private Integer resultsStart;
88
89     @JsonProperty("results-size")
90     private Integer size;
91
92     public Filter getFilter() {
93         return filter;
94     }
95
96     public void setFilter(Filter filter) {
97         this.filter = filter;
98     }
99
100     public Query[] getQueries() {
101         return queries;
102     }
103
104     public void setQueries(Query[] queries) {
105         this.queries = queries;
106     }
107
108     public Sort getSort() {
109         return sort;
110     }
111
112     public void setSort(Sort sort) {
113         this.sort = sort;
114     }
115
116     public boolean isFiltered() {
117         return filter != null;
118     }
119
120     public Aggregation[] getAggregations() {
121         return aggregations;
122     }
123
124     public void setAggregations(Aggregation[] aggregations) {
125         this.aggregations = aggregations;
126     }
127
128     public boolean hasAggregations() {
129         return aggregations != null && aggregations.length > 0;
130     }
131
132     public Integer getFrom() {
133         return resultsStart;
134     }
135
136     public void setFrom(Integer from) {
137         this.resultsStart = from;
138     }
139
140     public Integer getSize() {
141         return size;
142     }
143
144     public void setSize(Integer size) {
145         this.size = size;
146     }
147
148     /**
149      * This method returns a string which represents this statement in syntax that is understandable by ElasticSearch
150      * and is suitable for inclusion in an ElasticSearch query string.
151      *
152      * @return - ElasticSearch syntax string.
153      */
154     public String toElasticSearch() {
155         StringBuilder sb = new StringBuilder();
156         List<QueryStatement> notMatchQueries = new ArrayList<>();
157         List<QueryStatement> mustQueries = new ArrayList<>();
158         List<QueryStatement> shouldQueries = new ArrayList<>();
159
160         createQueryLists(queries, mustQueries, shouldQueries, notMatchQueries);
161
162         sb.append("{");
163
164         sb.append("\"version\": true,");
165
166         // If the client has specified an index into the results for the first
167         // document in the result set then include that in the ElasticSearch
168         // query.
169         if (resultsStart != null) {
170             sb.append("\"from\": ").append(resultsStart).append(", ");
171         }
172
173         // If the client has specified a maximum number of documents to be returned
174         // in the result set then include that in the ElasticSearch query.
175         if (size != null) {
176             sb.append("\"size\": ").append(size).append(", ");
177         }
178
179         sb.append("\"query\": {");
180         sb.append("\"bool\": {");
181
182         sb.append("\"must\": [");
183         AtomicBoolean firstQuery = new AtomicBoolean(true);
184         for (QueryStatement query : mustQueries) {
185
186             if (!firstQuery.compareAndSet(true, false)) {
187                 sb.append(", ");
188             }
189
190             sb.append(query.toElasticSearch());
191         }
192         sb.append("], ");
193
194         sb.append("\"should\": [");
195
196         firstQuery = new AtomicBoolean(true);
197         for (QueryStatement query : shouldQueries) {
198
199             if (!firstQuery.compareAndSet(true, false)) {
200                 sb.append(", ");
201             }
202
203             sb.append(query.toElasticSearch());
204         }
205
206         sb.append("],"); // close should list
207
208         sb.append("\"must_not\": [");
209         firstQuery.set(true);
210         for (QueryStatement query : notMatchQueries) {
211             sb.append(query.toElasticSearch());
212         }
213         sb.append("]");
214
215         // Add the filter stanza, if one is required.
216         if (isFiltered()) {
217             sb.append(", \"filter\": ").append(filter.toElasticSearch());
218         }
219
220         sb.append("}"); // close bool clause
221         sb.append("}"); // close query clause
222
223         // Add the sort directive, if one is required.
224         if (sort != null) {
225             sb.append(", \"sort\": ").append(sort.toElasticSearch());
226         }
227
228         // Add aggregations
229         if (hasAggregations()) {
230             sb.append(", \"aggs\": {");
231
232             for (int i = 0; i < aggregations.length; i++) {
233                 if (i > 0) {
234                     sb.append(",");
235                 }
236                 sb.append(aggregations[i].toElasticSearch());
237             }
238
239             sb.append("}");
240         }
241
242         sb.append("}");
243
244         Logger.debug("Generated raw ElasticSearch query statement: " + sb.toString());
245         return sb.toString();
246     }
247
248     private void createQueryLists(Query[] queries, List<QueryStatement> mustList, List<QueryStatement> mayList,
249             List<QueryStatement> mustNotList) {
250
251         for (Query query : queries) {
252
253             if (query.isMust()) {
254
255                 if (query.getQueryStatement().isNotMatch()) {
256                     mustNotList.add(query.getQueryStatement());
257                 } else {
258                     mustList.add(query.getQueryStatement());
259                 }
260             } else {
261
262                 if (query.getQueryStatement().isNotMatch()) {
263                     mustNotList.add(query.getQueryStatement());
264                 } else {
265                     mayList.add(query.getQueryStatement());
266                 }
267             }
268         }
269     }
270
271
272     @Override
273     public String toString() {
274
275         StringBuilder sb = new StringBuilder();
276
277         sb.append("SEARCH STATEMENT: {");
278
279         if (size != null) {
280             sb.append("from: ").append(resultsStart).append(", size: ").append(size).append(", ");
281         }
282
283         if (filter != null) {
284             sb.append("filter: ").append(filter.toString()).append(", ");
285         }
286
287         sb.append("queries: [");
288         AtomicBoolean firstQuery = new AtomicBoolean(true);
289         if (queries != null) {
290             for (Query query : queries) {
291
292                 if (!firstQuery.compareAndSet(true, false)) {
293                     sb.append(", ");
294                 }
295                 sb.append(query.toString());
296             }
297         }
298         sb.append("]");
299
300         sb.append("aggregations: [");
301         firstQuery = new AtomicBoolean(true);
302
303         if (aggregations != null) {
304             for (Aggregation agg : aggregations) {
305
306                 if (!firstQuery.compareAndSet(true, false)) {
307                     sb.append(", ");
308                 }
309                 sb.append(agg.toString());
310             }
311         }
312         sb.append("]");
313
314         sb.append("]}");
315
316         return sb.toString();
317     }
318
319 }