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