Format Java code to ONAP standard
[aai/search-data-service.git] / 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
156         StringBuilder sb = new StringBuilder();
157         List<QueryStatement> notMatchQueries = new ArrayList<QueryStatement>();
158         List<QueryStatement> mustQueries = new ArrayList<QueryStatement>();
159         List<QueryStatement> shouldQueries = new ArrayList<QueryStatement>();
160
161         createQueryLists(queries, mustQueries, shouldQueries, notMatchQueries);
162
163         sb.append("{");
164
165         sb.append("\"version\": true,");
166
167         // If the client has specified an index into the results for the first
168         // document in the result set then include that in the ElasticSearch
169         // query.
170         if (resultsStart != null) {
171             sb.append("\"from\": ").append(resultsStart).append(", ");
172         }
173
174         // If the client has specified a maximum number of documents to be returned
175         // in the result set then include that in the ElasticSearch query.
176         if (size != null) {
177             sb.append("\"size\": ").append(size).append(", ");
178         }
179
180         sb.append("\"query\": {");
181         sb.append("\"bool\": {");
182
183         sb.append("\"must\": [");
184         AtomicBoolean firstQuery = new AtomicBoolean(true);
185         for (QueryStatement query : mustQueries) {
186
187             if (!firstQuery.compareAndSet(true, false)) {
188                 sb.append(", ");
189             }
190
191             sb.append(query.toElasticSearch());
192         }
193         sb.append("], ");
194
195         sb.append("\"should\": [");
196
197         firstQuery = new AtomicBoolean(true);
198         for (QueryStatement query : shouldQueries) {
199
200             if (!firstQuery.compareAndSet(true, false)) {
201                 sb.append(", ");
202             }
203
204             sb.append(query.toElasticSearch());
205         }
206
207         sb.append("],"); // close should list
208
209         sb.append("\"must_not\": [");
210         firstQuery.set(true);
211         for (QueryStatement query : notMatchQueries) {
212             sb.append(query.toElasticSearch());
213         }
214         sb.append("]");
215
216         // Add the filter stanza, if one is required.
217         if (isFiltered()) {
218             sb.append(", \"filter\": ").append(filter.toElasticSearch());
219         }
220
221         sb.append("}"); // close bool clause
222         sb.append("}"); // close query clause
223
224         // Add the sort directive, if one is required.
225         if (sort != null) {
226             sb.append(", \"sort\": ").append(sort.toElasticSearch());
227         }
228
229         // Add aggregations
230         if (hasAggregations()) {
231             sb.append(", \"aggs\": {");
232
233             for (int i = 0; i < aggregations.length; i++) {
234                 if (i > 0) {
235                     sb.append(",");
236                 }
237                 sb.append(aggregations[i].toElasticSearch());
238             }
239
240             sb.append("}");
241         }
242
243         sb.append("}");
244
245         Logger.debug("Generated raw ElasticSearch query statement: " + sb.toString());
246         return sb.toString();
247     }
248
249     private void createQueryLists(Query[] queries, List<QueryStatement> mustList, List<QueryStatement> mayList,
250             List<QueryStatement> mustNotList) {
251
252         for (Query query : queries) {
253
254             if (query.isMust()) {
255
256                 if (query.getQueryStatement().isNotMatch()) {
257                     mustNotList.add(query.getQueryStatement());
258                 } else {
259                     mustList.add(query.getQueryStatement());
260                 }
261             } else {
262
263                 if (query.getQueryStatement().isNotMatch()) {
264                     mustNotList.add(query.getQueryStatement());
265                 } else {
266                     mayList.add(query.getQueryStatement());
267                 }
268             }
269         }
270     }
271
272
273     @Override
274     public String toString() {
275
276         StringBuilder sb = new StringBuilder();
277
278         sb.append("SEARCH STATEMENT: {");
279
280         if (size != null) {
281             sb.append("from: ").append(resultsStart).append(", size: ").append(size).append(", ");
282         }
283
284         if (filter != null) {
285             sb.append("filter: ").append(filter.toString()).append(", ");
286         }
287
288         sb.append("queries: [");
289         AtomicBoolean firstQuery = new AtomicBoolean(true);
290         if (queries != null) {
291             for (Query query : queries) {
292
293                 if (!firstQuery.compareAndSet(true, false)) {
294                     sb.append(", ");
295                 }
296                 sb.append(query.toString());
297             }
298         }
299         sb.append("]");
300
301         sb.append("aggregations: [");
302         firstQuery = new AtomicBoolean(true);
303
304         if (aggregations != null) {
305             for (Aggregation agg : aggregations) {
306
307                 if (!firstQuery.compareAndSet(true, false)) {
308                     sb.append(", ");
309                 }
310                 sb.append(agg.toString());
311             }
312         }
313         sb.append("]");
314
315         sb.append("]}");
316
317         return sb.toString();
318     }
319
320 }