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