some code smells removed
[music.git] / music-core / src / main / java / org / onap / music / datastore / jsonobjects / JsonTable.java
1 /*
2  * ============LICENSE_START==========================================
3  * org.onap.music
4  * ===================================================================
5  *  Copyright (c) 2017 AT&T Intellectual Property
6  * ===================================================================
7  *  Modifications Copyright (C) 2019 IBM 
8  * ===================================================================
9  *  Licensed under the Apache License, Version 2.0 (the "License");
10  *  you may not use this file except in compliance with the License.
11  *  You may obtain a copy of the License at
12  * 
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  *  Unless required by applicable law or agreed to in writing, software
16  *  distributed under the License is distributed on an "AS IS" BASIS,
17  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  *  See the License for the specific language governing permissions and
19  *  limitations under the License.
20  * 
21  * ============LICENSE_END=============================================
22  * ====================================================================
23  */
24
25 package org.onap.music.datastore.jsonobjects;
26
27 import java.util.Map;
28
29 import javax.ws.rs.core.Response.Status;
30
31 import org.apache.commons.lang3.StringUtils;
32 import org.onap.music.datastore.PreparedQueryObject;
33 import org.onap.music.eelf.logging.EELFLoggerDelegate;
34 import org.onap.music.exceptions.MusicQueryException;
35 import org.onap.music.main.MusicUtil;
36
37 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
38
39 import io.swagger.annotations.ApiModel;
40 import io.swagger.annotations.ApiModelProperty;
41
42 @ApiModel(value = "JsonTable", description = "Defines the Json for Creating a new Table.")
43 @JsonIgnoreProperties(ignoreUnknown = true)
44 public class JsonTable {
45     private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(JsonTable.class);
46     
47     private String keyspaceName;
48     private String tableName;
49
50     private Map<String, String> fields;
51     private Map<String, Object> properties;
52     private String primaryKey;
53     private String partitionKey;
54     private String clusteringKey;
55     private String filteringKey;
56     private String clusteringOrder;
57     private Map<String, String> consistencyInfo;
58
59     @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
60     public Map<String, String> getConsistencyInfo() {
61         return consistencyInfo;
62     }
63
64     public void setConsistencyInfo(Map<String, String> consistencyInfo) {
65         this.consistencyInfo = consistencyInfo;
66     }
67
68     @ApiModelProperty(value = "Properties")
69     public Map<String, Object> getProperties() {
70         return properties;
71     }
72
73     public void setProperties(Map<String, Object> properties) {
74         this.properties = properties;
75     }
76
77     @ApiModelProperty(value = "Fields")
78     public Map<String, String> getFields() {
79         return fields;
80     }
81
82     public void setFields(Map<String, String> fields) {
83         this.fields = fields;
84     }
85
86     @ApiModelProperty(value = "KeySpace Name")
87     public String getKeyspaceName() {
88         return keyspaceName;
89     }
90
91     public void setKeyspaceName(String keyspaceName) {
92         this.keyspaceName = keyspaceName;
93     }
94
95     @ApiModelProperty(value = "Table Name")
96     public String getTableName() {
97         return tableName;
98     }
99
100     public void setTableName(String tableName) {
101         this.tableName = tableName;
102     }
103
104     @ApiModelProperty(value = "Clustering Order", notes = "")
105     public String getClusteringOrder() {
106         return clusteringOrder;
107     }
108
109     public void setClusteringOrder(String clusteringOrder) {
110         this.clusteringOrder = clusteringOrder;
111     }
112
113     @ApiModelProperty(value = "Primary Key")
114     public String getPrimaryKey() {
115         return primaryKey;
116     }
117
118     public void setPrimaryKey(String primaryKey) {
119         this.primaryKey = primaryKey;
120     }
121
122     public String getClusteringKey() {
123         return clusteringKey;
124     }
125
126     public void setClusteringKey(String clusteringKey) {
127         this.clusteringKey = clusteringKey;
128     }
129
130     public String getFilteringKey() {
131         return filteringKey;
132     }
133
134     public void setFilteringKey(String filteringKey) {
135         this.filteringKey = filteringKey;
136     }
137
138     public String getPartitionKey() {
139         return partitionKey;
140     }
141
142     public void setPartitionKey(String partitionKey) {
143         this.partitionKey = partitionKey;
144     }
145     
146     public PreparedQueryObject genCreateTableQuery()  throws MusicQueryException {
147         String primaryKey = null;
148         String partitionKey = this.getPartitionKey();
149         String clusterKey = this.getClusteringKey();
150         String filteringKey = this.getFilteringKey();
151         if (filteringKey != null) {
152             clusterKey = clusterKey + "," + filteringKey;
153         }
154         primaryKey = this.getPrimaryKey(); // get primaryKey if available
155
156         PreparedQueryObject queryObject = new PreparedQueryObject();
157         // first read the information about the table fields
158         Map<String, String> fields = this.getFields();
159         if (fields == null) {
160            throw new MusicQueryException(
161                     "Create Table Error: No fields in request", Status.BAD_REQUEST.getStatusCode());
162         }
163         StringBuilder fieldsString = new StringBuilder("(vector_ts text,");
164         int counter = 0;
165         for (Map.Entry<String, String> entry : fields.entrySet()) {
166             if (entry.getKey().equals("PRIMARY KEY")) {
167                 primaryKey = entry.getValue(); // replaces primaryKey
168                 primaryKey = primaryKey.trim();
169             } 
170                         else {
171                 if (counter == 0 ) 
172                                         fieldsString.append("" + entry.getKey() + " " + entry.getValue() + "");
173                 else fieldsString.append("," + entry.getKey() + " " + entry.getValue() + "");
174             }
175
176             if (counter != (fields.size() - 1) ) {
177                 counter = counter + 1; 
178             } else {
179         
180                 if((primaryKey != null) && (partitionKey == null)) {
181                     primaryKey = primaryKey.trim();
182                     int count1 = StringUtils.countMatches(primaryKey, ')');
183                     int count2 = StringUtils.countMatches(primaryKey, '(');
184                     if (count1 != count2) {
185                         throw new MusicQueryException(
186                                 "Create Table Error: primary key '(' and ')' do not match, primary key=" + primaryKey,
187                                 Status.BAD_REQUEST.getStatusCode());
188                     }
189
190                     if ( primaryKey.indexOf('(') == -1  || ( count2 == 1 && (primaryKey.lastIndexOf(')') +1) ==  primaryKey.length() ) ) {
191                         if (primaryKey.contains(",") ) {
192                             partitionKey= primaryKey.substring(0,primaryKey.indexOf(','));
193                             partitionKey=partitionKey.replaceAll("[\\(]+","");
194                             clusterKey=primaryKey.substring(primaryKey.indexOf(',')+1);  // make sure index
195                             clusterKey=clusterKey.replaceAll("[)]+", "");
196                         } else {
197                             partitionKey=primaryKey;
198                             partitionKey=partitionKey.replaceAll("[\\)]+","");
199                             partitionKey=partitionKey.replaceAll("[\\(]+","");
200                             clusterKey="";
201                         }
202                     } else {   // not null and has ) before the last char
203                         partitionKey= primaryKey.substring(0,primaryKey.indexOf(')'));
204                         partitionKey=partitionKey.replaceAll("[\\(]+","");
205                         partitionKey = partitionKey.trim();
206                         clusterKey= primaryKey.substring(primaryKey.indexOf(')'));
207                         clusterKey=clusterKey.replaceAll("[\\(]+","");
208                         clusterKey=clusterKey.replaceAll("[\\)]+","");
209                         clusterKey = clusterKey.trim();
210                         if (clusterKey.indexOf(',') == 0) {
211                             clusterKey=clusterKey.substring(1);
212                         }
213                         clusterKey = clusterKey.trim();
214                         if (clusterKey.equals(",") )
215                                                         clusterKey=""; // print error if needed    ( ... ),)
216                     }
217
218                     if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
219                         && (partitionKey.equalsIgnoreCase(clusterKey) ||
220                         clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) {
221                         logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey + " and primary key=" + primaryKey );
222                         /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
223                             "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")  of"
224                             + " primary key=" + primaryKey)
225                             .toMap()).build();*/
226                         throw new MusicQueryException("Create Table primary key error: clusterKey(" + clusterKey
227                                 + ") equals/contains/overlaps partitionKey(" + partitionKey + ")  of" + " primary key="
228                                 + primaryKey, Status.BAD_REQUEST.getStatusCode());
229
230                     }
231
232                     if (partitionKey.isEmpty() ) 
233                                                 primaryKey="";
234                     else  if (clusterKey.isEmpty() ) 
235                                                 primaryKey=" (" + partitionKey  + ")";
236                     else 
237                                                 primaryKey=" (" + partitionKey + ")," + clusterKey;
238
239             
240                     if (primaryKey != null) 
241                                                 fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
242
243                 } else { // end of length > 0
244                 
245                     if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
246                         && (partitionKey.equalsIgnoreCase(clusterKey) ||
247                         clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) {
248                         logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey);
249                         /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
250                             "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")")
251                             .toMap()).build();*/
252                         throw new MusicQueryException(
253                                 "Create Table primary key error: clusterKey(" + clusterKey
254                                         + ") equals/contains/overlaps partitionKey(" + partitionKey + ")",
255                                 Status.BAD_REQUEST.getStatusCode());
256                     }
257
258                     if (partitionKey.isEmpty() ) 
259                                                 primaryKey="";
260                     else  if (clusterKey.isEmpty() )
261                                                 primaryKey=" (" + partitionKey  + ")";
262                     else 
263                                                 primaryKey=" (" + partitionKey + ")," + clusterKey;
264
265                     if (primaryKey != null) 
266                                                 fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
267                 }
268                 fieldsString.append(")");
269
270             } // end of last field check
271
272         } // end of for each
273         // information about the name-value style properties
274         Map<String, Object> propertiesMap = this.getProperties();
275         StringBuilder propertiesString = new StringBuilder();
276         if (propertiesMap != null) {
277             counter = 0;
278             for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) {
279                 Object ot = entry.getValue();
280                 String value = ot + "";
281                 if (ot instanceof String) {
282                     value = "'" + value + "'";
283                 } else if (ot instanceof Map) {
284                     @SuppressWarnings("unchecked")
285                     Map<String, Object> otMap = (Map<String, Object>) ot;
286                     try {
287                         value = "{" + MusicUtil.jsonMaptoSqlString(otMap, ",") + "}";
288                     } catch (Exception e) {
289                         throw new MusicQueryException(e.getMessage(),
290                                 Status.BAD_REQUEST.getStatusCode());
291                     }
292                 }
293
294                 propertiesString.append(entry.getKey() + "=" + value + "");
295                 if (counter != propertiesMap.size() - 1)
296                     propertiesString.append(" AND ");
297
298                 counter = counter + 1;
299             }
300         }
301
302         String clusteringOrder = this.getClusteringOrder();
303
304         if (clusteringOrder != null && !(clusteringOrder.isEmpty())) {
305             String[] arrayClusterOrder = clusteringOrder.split("[,]+");
306
307             for (int i = 0; i < arrayClusterOrder.length; i++) {
308                 String[] clusterS = arrayClusterOrder[i].trim().split("[ ]+");
309                 if ( (clusterS.length ==2)  && (clusterS[1].equalsIgnoreCase("ASC") || clusterS[1].equalsIgnoreCase("DESC"))) {
310                     continue;
311                 } else {
312                     /*return response.status(Status.BAD_REQUEST)
313                     .entity(new JsonResponse(ResultType.FAILURE)
314                     .setError("createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname  order; please correct clusteringOrder:"+ clusteringOrder+".")
315                     .toMap()).build();*/
316                     
317                     throw new MusicQueryException(
318                             "createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname  order; please correct clusteringOrder:"
319                                     + clusteringOrder + ".",
320                             Status.BAD_REQUEST.getStatusCode());
321                 }
322                 // add validation for column names in cluster key
323             }
324
325             if (!(clusterKey.isEmpty())) {
326                 clusteringOrder = "CLUSTERING ORDER BY (" +clusteringOrder +")";
327                 //cjc check if propertiesString.length() >0 instead propertiesMap
328                 if (propertiesMap != null) {
329                     propertiesString.append(" AND  "+ clusteringOrder);
330                 } else {
331                     propertiesString.append(clusteringOrder);
332                 }
333             } else {
334                 logger.warn("Skipping clustering order=("+clusteringOrder+ ") since clustering key is empty ");
335             }
336         } //if non empty
337
338         queryObject.appendQueryString(
339             "CREATE TABLE " + this.getKeyspaceName() + "." + this.getTableName() + " " + fieldsString);
340
341
342         if (propertiesString != null &&  propertiesString.length()>0 )
343             queryObject.appendQueryString(" WITH " + propertiesString);
344         queryObject.appendQueryString(";");
345
346         return queryObject;
347     }
348
349     /**
350      * genDropTableQuery
351      * 
352      * @return PreparedQueryObject
353      */
354     public PreparedQueryObject genDropTableQuery() {
355         PreparedQueryObject query = new PreparedQueryObject();
356         query.appendQueryString("DROP TABLE  " + this.getKeyspaceName() + "." + this.getTableName() + ";");
357         logger.info("Delete Query ::::: " + query.getQuery());
358
359         return query;
360     }
361
362
363 }