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