a883534e916300628413706994457fa12ef05c99
[music.git] / src / main / java / org / onap / music / rest / RestMusicQAPI.java
1 /*
2  * ============LICENSE_START========================================== org.onap.music
3  * =================================================================== Copyright (c) 2017 AT&T
4  * Intellectual Property ===================================================================Modifications Copyright (c) 2018 IBM
5  * Intellectual Property =================================================================== * 
6  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7  * in compliance with the License. You may obtain a copy of the License at
8  * 
9  * http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software distributed under the License
12  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing permissions and limitations under
14  * the License.
15  * 
16  * ============LICENSE_END=============================================
17  * ====================================================================
18  */
19 package org.onap.music.rest;
20
21 import java.util.HashMap;
22 import java.util.Map;
23 import javax.ws.rs.Consumes;
24 import javax.ws.rs.DELETE;
25 import javax.ws.rs.GET;
26 import javax.ws.rs.HeaderParam;
27 import javax.ws.rs.POST;
28 import javax.ws.rs.PUT;
29 import javax.ws.rs.Path;
30 import javax.ws.rs.PathParam;
31 import javax.ws.rs.Produces;
32 import javax.ws.rs.core.Context;
33 import javax.ws.rs.core.MediaType;
34 import javax.ws.rs.core.UriInfo;
35 import javax.ws.rs.core.Response;
36 import javax.ws.rs.core.Response.ResponseBuilder;
37 import javax.ws.rs.core.Response.Status;
38 import org.onap.music.datastore.jsonobjects.JsonDelete;
39 import org.onap.music.datastore.jsonobjects.JsonInsert;
40 import org.onap.music.datastore.jsonobjects.JsonTable;
41 import org.onap.music.datastore.jsonobjects.JsonUpdate;
42 import org.onap.music.eelf.logging.EELFLoggerDelegate;
43
44 import org.onap.music.eelf.logging.format.AppMessages;
45 import org.onap.music.eelf.logging.format.ErrorSeverity;
46 import org.onap.music.eelf.logging.format.ErrorTypes;
47 import org.apache.commons.lang3.StringUtils;
48 import org.onap.music.datastore.PreparedQueryObject;
49 import com.datastax.driver.core.ResultSet;
50 import org.onap.music.exceptions.MusicServiceException;
51 import org.onap.music.main.MusicCore;
52 import org.onap.music.main.MusicUtil;
53 import org.onap.music.main.ResultType;
54 import org.onap.music.response.jsonobjects.JsonResponse;
55 import io.swagger.annotations.Api;
56 import io.swagger.annotations.ApiOperation;
57 import io.swagger.annotations.ApiParam;
58
59
60 // @Path("/v{version: [0-9]+}/priorityq/")
61 @Path("{version}/priorityq/")
62 @Api(value = "Q Api")
63 public class RestMusicQAPI {
64
65   private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicQAPI.class);
66   
67
68   /**
69    * 
70    * @param tableObj
71    * @param keyspace
72    * @param tablename
73    * @throws Exception
74    */
75  
76   @POST
77   @Path("/keyspaces/{keyspace}/{qname}") // is it same as tablename?down
78   @ApiOperation(value = "Create Q", response = String.class)
79   @Consumes(MediaType.APPLICATION_JSON)
80   @Produces(MediaType.APPLICATION_JSON)
81   
82   /* old
83   @POST
84   @Path("/keyspaces/{keyspace}/{qname}")
85   @ApiOperation(value = "", response = Void.class)
86   @Consumes(MediaType.APPLICATION_JSON)
87   */
88   public Response createQ(
89   // public Map<String,Object> createQ(
90           @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
91           @ApiParam(value = "Minor Version",
92                   required = false) @HeaderParam("X-minorVersion") String minorVersion,
93           @ApiParam(value = "Patch Version",
94                   required = false) @HeaderParam("X-patchVersion") String patchVersion,
95           @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
96           @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
97           @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
98           JsonTable tableObj, 
99           @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
100           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename)
101           throws Exception {
102     
103
104     ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
105
106     Map<String, String> fields = tableObj.getFields();
107     if (fields == null) {
108       logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
109               ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
110       return response.status(Status.BAD_REQUEST)
111               .entity(new JsonResponse(ResultType.FAILURE)
112                       .setError("CreateQ/Required table fields are empty or not set").toMap())
113               .build();
114     }
115
116     String primaryKey = tableObj.getPrimaryKey();
117     String partitionKey = tableObj.getPartitionKey();
118     String clusteringKey = tableObj.getClusteringKey();
119     String filteringKey = tableObj.getFilteringKey();
120     String clusteringOrder = tableObj.getClusteringOrder();
121
122     if(primaryKey == null) {
123         primaryKey = tableObj.getFields().get("PRIMARY KEY");
124     }
125
126     if ((primaryKey == null) && (partitionKey == null)) {
127         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
128                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
129         return response.status(Status.BAD_REQUEST)
130                 .entity(new JsonResponse(ResultType.FAILURE)
131                         .setError("CreateQ: Partition key cannot be empty").toMap())
132                 .build();
133       }
134
135     if ((primaryKey == null) && (clusteringKey == null)) {
136         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
137                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
138         return response.status(Status.BAD_REQUEST)
139                 .entity(new JsonResponse(ResultType.FAILURE)
140                         .setError("CreateQ: Clustering key cannot be empty").toMap())
141                 .build();
142       }
143
144     if (clusteringOrder == null) {
145         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
146                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
147         return response.status(Status.BAD_REQUEST)
148                 .entity(new JsonResponse(ResultType.FAILURE)
149                         .setError("CreateQ: Clustering Order cannot be empty").toMap())
150                 .build();
151       }
152
153     if ((primaryKey!=null) && (partitionKey == null)) {
154         primaryKey.trim();
155         int count1 = StringUtils.countMatches(primaryKey, ')');
156         int count2 = StringUtils.countMatches(primaryKey, '(');
157         if (count1 != count2) {
158             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
159                       .setError("CreateQ Error: primary key '(' and ')' do not match, primary key=" + primaryKey)
160                       .toMap()).build();
161         }
162
163         if ( primaryKey.indexOf('(') == -1  || ( count2 == 1 && (primaryKey.lastIndexOf(")") +1) ==  primaryKey.length() ) )
164         {
165             if (primaryKey.contains(",") ) {
166                 partitionKey= primaryKey.substring(0,primaryKey.indexOf(","));
167                 partitionKey=partitionKey.replaceAll("[\\(]+","");
168                 clusteringKey=primaryKey.substring(primaryKey.indexOf(',')+1);  // make sure index
169                 clusteringKey=clusteringKey.replaceAll("[)]+", "");
170             } else {
171               partitionKey=primaryKey;
172               partitionKey=partitionKey.replaceAll("[\\)]+","");
173               partitionKey=partitionKey.replaceAll("[\\(]+","");
174               clusteringKey="";
175            }
176       } else {
177             partitionKey= primaryKey.substring(0,primaryKey.indexOf(')'));
178             partitionKey=partitionKey.replaceAll("[\\(]+","");
179             partitionKey.trim();
180             clusteringKey= primaryKey.substring(primaryKey.indexOf(')'));
181             clusteringKey=clusteringKey.replaceAll("[\\(]+","");
182             clusteringKey=clusteringKey.replaceAll("[\\)]+","");
183             clusteringKey.trim();
184             if (clusteringKey.indexOf(",") == 0) {
185                 clusteringKey=clusteringKey.substring(1);
186             }
187             clusteringKey.trim();
188             if (",".equals(clusteringKey) ) {
189                 clusteringKey=""; // print error if needed    ( ... ),)
190             }
191          }
192     }
193
194     if (partitionKey.trim().isEmpty()) {
195         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
196                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
197         return response.status(Status.BAD_REQUEST)
198                 .entity(new JsonResponse(ResultType.FAILURE)
199                         .setError("CreateQ: Partition key cannot be empty").toMap())
200                 .build();
201     }
202
203     if (clusteringKey.trim().isEmpty()) {
204         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
205                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
206         return response.status(Status.BAD_REQUEST)
207                 .entity(new JsonResponse(ResultType.FAILURE)
208                         .setError("CreateQ: Clustering key cannot be empty").toMap())
209                 .build();
210     }
211
212     if((filteringKey != null) && (filteringKey.equalsIgnoreCase(partitionKey))) {
213         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
214                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
215         return response.status(Status.BAD_REQUEST)
216                 .entity(new JsonResponse(ResultType.FAILURE)
217                         .setError("CreateQ: Filtering key cannot be same as Partition Key").toMap())
218                 .build();
219     }
220
221     return new RestMusicDataAPI().createTable(version, minorVersion, patchVersion, aid, ns, authorization, tableObj, keyspace, tablename);
222   }
223
224   /**
225    * 
226    * @param insObj
227    * @param keyspace
228    * @param tablename
229    * @throws Exception
230    */
231   @POST
232   @Path("/keyspaces/{keyspace}/{qname}/rows")
233   @ApiOperation(value = "", response = Void.class)
234   @Consumes(MediaType.APPLICATION_JSON)
235   @Produces(MediaType.APPLICATION_JSON)
236   // public Map<String, Object> insertIntoQ(
237   public Response insertIntoQ(
238           @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
239           @ApiParam(value = "Minor Version",
240                   required = false) @HeaderParam("X-minorVersion") String minorVersion,
241           @ApiParam(value = "Patch Version",
242                   required = false) @HeaderParam("X-patchVersion") String patchVersion,
243           @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
244           @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
245           @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
246           JsonInsert insObj,
247           @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
248           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename)
249           throws Exception {
250
251     // check valuesMap.isEmpty and proceed
252     // response.addHeader(xLatestVersion, MusicUtil.getVersion());
253     ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
254     if (insObj.getValues().isEmpty()) {
255       logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
256               ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
257       return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
258               .setError("Required HTTP Request body is missing.").toMap()).build();
259     }
260     return new RestMusicDataAPI().insertIntoTable(version, minorVersion, patchVersion, aid, ns,
261             authorization, insObj, keyspace, tablename);
262   }
263
264   /**
265    * 
266    * @param updateObj
267    * @param keyspace
268    * @param tablename
269    * @param info
270    * @return
271    * @throws Exception
272    */
273   @PUT
274   @Path("/keyspaces/{keyspace}/{qname}/rows")
275   @ApiOperation(value = "updateQ", response = String.class)
276   @Consumes(MediaType.APPLICATION_JSON)
277   @Produces(MediaType.APPLICATION_JSON)
278   public Response updateQ(
279           @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
280           @ApiParam(value = "Minor Version",
281                   required = false) @HeaderParam("X-minorVersion") String minorVersion,
282           @ApiParam(value = "Patch Version",
283                   required = false) @HeaderParam("X-patchVersion") String patchVersion,
284           @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
285           @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
286           @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
287           JsonUpdate updateObj,
288           @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
289           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
290           @Context UriInfo info) {
291
292     ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
293     if (updateObj.getValues().isEmpty()) {
294       logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
295               ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
296       return response.status(Status.BAD_REQUEST)
297               .entity(new JsonResponse(ResultType.FAILURE).setError(
298                       "Required HTTP Request body is missing. JsonUpdate updateObj.getValues() is empty. ")
299                       .toMap())
300               .build();
301
302  
303     }
304     return new RestMusicDataAPI().updateTable(version, minorVersion, patchVersion, aid, ns, 
305             authorization,updateObj, keyspace, tablename, info);
306   }
307
308   /**
309    * 
310    * @param delObj
311    * @param keyspace
312    * @param tablename
313    * @param info
314    * 
315    * @return
316    * @throws Exception
317    */
318
319   @DELETE
320   @Path("/keyspaces/{keyspace}/{qname}/rows")
321   @ApiOperation(value = "deleteQ", response = String.class)
322   @Consumes(MediaType.APPLICATION_JSON)
323   @Produces(MediaType.APPLICATION_JSON)
324   public Response deleteFromQ(
325           @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
326           @ApiParam(value = "Minor Version",
327                   required = false) @HeaderParam("X-minorVersion") String minorVersion,
328           @ApiParam(value = "Patch Version",
329                   required = false) @HeaderParam("X-patchVersion") String patchVersion,
330           @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
331           @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
332           @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
333          // @ApiParam(value = "userId", required = true) @HeaderParam("userId") String userId,
334          // @ApiParam(value = "Password", required = true) @HeaderParam("password") String password,
335           JsonDelete delObj,
336           @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
337           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
338           @Context UriInfo info) {
339     // added checking as per RestMusicDataAPI
340     ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
341     if (delObj == null) {
342       logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
343               ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
344       return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
345               .setError("deleteFromQ JsonDelete delObjis empty").toMap()).build();
346     }
347
348     return new RestMusicDataAPI().deleteFromTable(version, minorVersion, patchVersion, aid, ns,
349             authorization, delObj, keyspace, tablename, info);
350   }
351
352   /**
353    * 
354    * @param keyspace
355    * @param tablename
356    * @param info
357    * @return
358    * @throws Exception
359    */
360   @GET
361   @Path("/keyspaces/{keyspace}/{qname}/peek")
362   @ApiOperation(value = "", response = Map.class)
363   @Produces(MediaType.APPLICATION_JSON)
364   //public Map<String, HashMap<String, Object>> peek(
365   public Response peek(
366           @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
367           @ApiParam(value = "Minor Version",
368                   required = false) @HeaderParam("X-minorVersion") String minorVersion,
369           @ApiParam(value = "Patch Version",
370                   required = false) @HeaderParam("X-patchVersion") String patchVersion,
371           @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
372           @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
373           @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
374           @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
375           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
376           @Context UriInfo info) throws Exception {
377     int limit =1; //peek must return just the top row
378     Map<String ,String> auth = new HashMap<>();
379     String userId =auth.get(MusicUtil.USERID);
380     String password =auth.get(MusicUtil.PASSWORD);  
381     ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
382    
383     PreparedQueryObject queryObject = new PreparedQueryObject();
384     if (info.getQueryParameters() == null ) //|| info.getQueryParameters().isEmpty())
385       queryObject.appendQueryString(
386               "SELECT *  FROM " + keyspace + "." + tablename + " LIMIT " + limit + ";");
387     else {
388
389       try {
390         queryObject = new RestMusicDataAPI().selectSpecificQuery(version, minorVersion,
391                 patchVersion, aid, ns, userId, password, keyspace, tablename, info, limit);
392       } catch (MusicServiceException ex) {
393         logger.error(EELFLoggerDelegate.errorLogger, "MusicServiceException occured in peek"+ ex);
394         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.UNKNOWNERROR,
395                 ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR);
396         return response.status(Status.BAD_REQUEST)
397                 .entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap())
398                 .build();
399       }
400     }
401
402     try {
403       ResultSet results = MusicCore.get(queryObject);
404       return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS)
405               .setDataResult(MusicCore.marshallResults(results)).toMap()).build();
406     } catch (MusicServiceException ex) {
407       logger.error(EELFLoggerDelegate.errorLogger, "MusicServiceException occured in peek"+ ex);
408       logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.UNKNOWNERROR,
409               ErrorSeverity.ERROR, ErrorTypes.MUSICSERVICEERROR);
410       return response.status(Status.BAD_REQUEST)
411               .entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap())
412               .build();
413     }
414   }
415
416   /**
417    * 
418    *
419    * @param keyspace
420    * @param tablename
421    * @param info
422    * @return
423    * @throws Exception
424    */
425   @GET
426   @Path("/keyspaces/{keyspace}/{qname}/filter")
427   @ApiOperation(value = "filter", response = Map.class)
428   @Produces(MediaType.APPLICATION_JSON)
429   // public Map<String, HashMap<String, Object>> filter(
430   public Response filter(
431           @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
432           @ApiParam(value = "Minor Version",
433                   required = false) @HeaderParam("X-minorVersion") String minorVersion,
434           @ApiParam(value = "Patch Version",
435                   required = false) @HeaderParam("X-patchVersion") String patchVersion,
436           @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
437           @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
438           @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
439          // @ApiParam(value = "userId", required = true) @HeaderParam("userId") String userId,
440           //@ApiParam(value = "Password", required = true) @HeaderParam("password") String password,
441           @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
442           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
443           @Context UriInfo info) throws Exception {
444     
445     return new RestMusicDataAPI().select(version, minorVersion, patchVersion, aid, ns, authorization, keyspace, tablename, info);// , limit)
446     
447   }
448
449   /**
450    * 
451    * @param tabObj
452    * @param keyspace
453    * @param tablename
454    * @throws Exception
455    */
456   @DELETE
457   @ApiOperation(value = "DropQ", response = String.class)
458   @Path("/keyspaces/{keyspace}/{qname}")
459   @Produces(MediaType.APPLICATION_JSON)
460   public Response dropQ(
461           @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
462           @ApiParam(value = "Minor Version",
463                   required = false) @HeaderParam("X-minorVersion") String minorVersion,
464           @ApiParam(value = "Patch Version",
465                   required = false) @HeaderParam("X-patchVersion") String patchVersion,
466           @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
467           @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
468           @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
469          // @ApiParam(value = "userId", required = true) @HeaderParam("userId") String userId,
470           //@ApiParam(value = "Password", required = true) @HeaderParam("password") String password,
471           // cjc JsonTable tabObj,
472           @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
473           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename)
474           throws Exception {
475
476
477     return new RestMusicDataAPI().dropTable(version, minorVersion, patchVersion, aid, ns, authorization, keyspace, tablename);
478   }
479 }