Update junits
[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             } else {
170                 if (counter == 0 )  fieldsString.append("" + entry.getKey() + " " + entry.getValue() + "");
171                 else fieldsString.append("," + entry.getKey() + " " + entry.getValue() + "");
172             }
173
174             if (counter != (fields.size() - 1) ) {
175                 counter = counter + 1; 
176             } else {
177         
178                 if((primaryKey != null) && (partitionKey == null)) {
179                     primaryKey = primaryKey.trim();
180                     int count1 = StringUtils.countMatches(primaryKey, ')');
181                     int count2 = StringUtils.countMatches(primaryKey, '(');
182                     if (count1 != count2) {
183                         throw new MusicQueryException(
184                                 "Create Table Error: primary key '(' and ')' do not match, primary key=" + primaryKey,
185                                 Status.BAD_REQUEST.getStatusCode());
186                     }
187
188                     if ( primaryKey.indexOf('(') == -1  || ( count2 == 1 && (primaryKey.lastIndexOf(')') +1) ==  primaryKey.length() ) ) {
189                         if (primaryKey.contains(",") ) {
190                             partitionKey= primaryKey.substring(0,primaryKey.indexOf(','));
191                             partitionKey=partitionKey.replaceAll("[\\(]+","");
192                             clusterKey=primaryKey.substring(primaryKey.indexOf(',')+1);  // make sure index
193                             clusterKey=clusterKey.replaceAll("[)]+", "");
194                         } else {
195                             partitionKey=primaryKey;
196                             partitionKey=partitionKey.replaceAll("[\\)]+","");
197                             partitionKey=partitionKey.replaceAll("[\\(]+","");
198                             clusterKey="";
199                         }
200                     } else {   // not null and has ) before the last char
201                         partitionKey= primaryKey.substring(0,primaryKey.indexOf(')'));
202                         partitionKey=partitionKey.replaceAll("[\\(]+","");
203                         partitionKey = partitionKey.trim();
204                         clusterKey= primaryKey.substring(primaryKey.indexOf(')'));
205                         clusterKey=clusterKey.replaceAll("[\\(]+","");
206                         clusterKey=clusterKey.replaceAll("[\\)]+","");
207                         clusterKey = clusterKey.trim();
208                         if (clusterKey.indexOf(',') == 0) {
209                             clusterKey=clusterKey.substring(1);
210                         }
211                         clusterKey = clusterKey.trim();
212                         if (clusterKey.equals(",") ) clusterKey=""; // print error if needed    ( ... ),)
213                     }
214
215                     if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
216                         && (partitionKey.equalsIgnoreCase(clusterKey) ||
217                         clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) {
218                         logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey + " and primary key=" + primaryKey );
219                         /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
220                             "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")  of"
221                             + " primary key=" + primaryKey)
222                             .toMap()).build();*/
223                         throw new MusicQueryException("Create Table primary key error: clusterKey(" + clusterKey
224                                 + ") equals/contains/overlaps partitionKey(" + partitionKey + ")  of" + " primary key="
225                                 + primaryKey, Status.BAD_REQUEST.getStatusCode());
226
227                     }
228
229                     if (partitionKey.isEmpty() )  primaryKey="";
230                     else  if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey  + ")";
231                     else  primaryKey=" (" + partitionKey + ")," + clusterKey;
232
233             
234                     if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
235
236                 } else { // end of length > 0
237                 
238                     if (!(partitionKey.isEmpty() || clusterKey.isEmpty())
239                         && (partitionKey.equalsIgnoreCase(clusterKey) ||
240                         clusterKey.contains(partitionKey) || partitionKey.contains(clusterKey)) ) {
241                         logger.error("DataAPI createTable partition/cluster key ERROR: partitionKey="+partitionKey+", clusterKey=" + clusterKey);
242                         /*return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(
243                             "Create Table primary key error: clusterKey(" + clusterKey + ") equals/contains/overlaps partitionKey(" +partitionKey+ ")")
244                             .toMap()).build();*/
245                         throw new MusicQueryException(
246                                 "Create Table primary key error: clusterKey(" + clusterKey
247                                         + ") equals/contains/overlaps partitionKey(" + partitionKey + ")",
248                                 Status.BAD_REQUEST.getStatusCode());
249                     }
250
251                     if (partitionKey.isEmpty() )  primaryKey="";
252                     else  if (clusterKey.isEmpty() ) primaryKey=" (" + partitionKey  + ")";
253                     else  primaryKey=" (" + partitionKey + ")," + clusterKey;
254
255                     if (primaryKey != null) fieldsString.append(", PRIMARY KEY (" + primaryKey + " )");
256                 }
257                 fieldsString.append(")");
258
259             } // end of last field check
260
261         } // end of for each
262         // information about the name-value style properties
263         Map<String, Object> propertiesMap = this.getProperties();
264         StringBuilder propertiesString = new StringBuilder();
265         if (propertiesMap != null) {
266             counter = 0;
267             for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) {
268                 Object ot = entry.getValue();
269                 String value = ot + "";
270                 if (ot instanceof String) {
271                     value = "'" + value + "'";
272                 } else if (ot instanceof Map) {
273                     @SuppressWarnings("unchecked")
274                     Map<String, Object> otMap = (Map<String, Object>) ot;
275                     try {
276                         value = "{" + MusicUtil.jsonMaptoSqlString(otMap, ",") + "}";
277                     } catch (Exception e) {
278                         throw new MusicQueryException(e.getMessage(),
279                                 Status.BAD_REQUEST.getStatusCode());
280                     }
281                 }
282
283                 propertiesString.append(entry.getKey() + "=" + value + "");
284                 if (counter != propertiesMap.size() - 1)
285                     propertiesString.append(" AND ");
286
287                 counter = counter + 1;
288             }
289         }
290
291         String clusteringOrder = this.getClusteringOrder();
292
293         if (clusteringOrder != null && !(clusteringOrder.isEmpty())) {
294             String[] arrayClusterOrder = clusteringOrder.split("[,]+");
295
296             for (int i = 0; i < arrayClusterOrder.length; i++) {
297                 String[] clusterS = arrayClusterOrder[i].trim().split("[ ]+");
298                 if ( (clusterS.length ==2)  && (clusterS[1].equalsIgnoreCase("ASC") || clusterS[1].equalsIgnoreCase("DESC"))) {
299                     continue;
300                 } else {
301                     /*return response.status(Status.BAD_REQUEST)
302                     .entity(new JsonResponse(ResultType.FAILURE)
303                     .setError("createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname  order; please correct clusteringOrder:"+ clusteringOrder+".")
304                     .toMap()).build();*/
305                     
306                     throw new MusicQueryException(
307                             "createTable/Clustering Order vlaue ERROR: valid clustering order is ASC or DESC or expecting colname  order; please correct clusteringOrder:"
308                                     + clusteringOrder + ".",
309                             Status.BAD_REQUEST.getStatusCode());
310                 }
311                 // add validation for column names in cluster key
312             }
313
314             if (!(clusterKey.isEmpty())) {
315                 clusteringOrder = "CLUSTERING ORDER BY (" +clusteringOrder +")";
316                 //cjc check if propertiesString.length() >0 instead propertiesMap
317                 if (propertiesMap != null) {
318                     propertiesString.append(" AND  "+ clusteringOrder);
319                 } else {
320                     propertiesString.append(clusteringOrder);
321                 }
322             } else {
323                 logger.warn("Skipping clustering order=("+clusteringOrder+ ") since clustering key is empty ");
324             }
325         } //if non empty
326
327         queryObject.appendQueryString(
328             "CREATE TABLE " + this.getKeyspaceName() + "." + this.getTableName() + " " + fieldsString);
329
330
331         if (propertiesString != null &&  propertiesString.length()>0 )
332             queryObject.appendQueryString(" WITH " + propertiesString);
333         queryObject.appendQueryString(";");
334
335         return queryObject;
336     }
337
338     /**
339      * genDropTableQuery
340      * 
341      * @return PreparedQueryObject
342      */
343     public PreparedQueryObject genDropTableQuery() {
344         PreparedQueryObject query = new PreparedQueryObject();
345         query.appendQueryString("DROP TABLE  " + this.getKeyspaceName() + "." + this.getTableName() + ";");
346         logger.info("Delete Query ::::: " + query.getQuery());
347
348         return query;
349     }
350
351
352 }