768f1a440dbb90d2142183f5635c9dec7a31e431
[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", required = false) @HeaderParam("X-minorVersion") String minorVersion,
92         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
93         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
94         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
95         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
96         JsonTable tableObj, 
97         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
98           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename) throws Exception {
99         ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
100
101         Map<String, String> fields = tableObj.getFields();
102     if (fields == null) {
103             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
104                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
105             return response.status(Status.BAD_REQUEST)
106                 .entity(new JsonResponse(ResultType.FAILURE)
107                 .setError("CreateQ/Required table fields are empty or not set").toMap())
108                 .build();
109         }
110
111         String primaryKey = tableObj.getPrimaryKey();
112         String partitionKey = tableObj.getPartitionKey();
113         String clusteringKey = tableObj.getClusteringKey();
114         String filteringKey = tableObj.getFilteringKey();
115         String clusteringOrder = tableObj.getClusteringOrder();
116
117         if(primaryKey == null) {
118             primaryKey = tableObj.getFields().get("PRIMARY KEY");
119         }
120
121         if ((primaryKey == null) && (partitionKey == null)) {
122             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
123                     ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
124             return response.status(Status.BAD_REQUEST)
125                     .entity(new JsonResponse(ResultType.FAILURE)
126                             .setError("CreateQ: Partition key cannot be empty").toMap())
127                     .build();
128         }
129
130         if ((primaryKey == null) && (clusteringKey == null)) {
131             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
132                     ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
133             return response.status(Status.BAD_REQUEST)
134                     .entity(new JsonResponse(ResultType.FAILURE)
135                             .setError("CreateQ: Clustering key cannot be empty").toMap())
136                     .build();
137         }
138
139         if (clusteringOrder == null) {
140             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
141                     ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
142             return response.status(Status.BAD_REQUEST)
143                     .entity(new JsonResponse(ResultType.FAILURE)
144                             .setError("CreateQ: Clustering Order cannot be empty").toMap())
145                     .build();
146         }
147
148         if ((primaryKey!=null) && (partitionKey == null)) {
149             primaryKey = primaryKey.trim();
150             int count1 = StringUtils.countMatches(primaryKey,')');
151             int count2 = StringUtils.countMatches(primaryKey,'(');
152             if (count1 != count2) {
153                 return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
154                     .setError("CreateQ Error: primary key '(' and ')' do not match, primary key=" + primaryKey)
155                     .toMap()).build();
156             }
157
158             if ( primaryKey.indexOf('(') == -1  || ( count2 == 1 && (primaryKey.lastIndexOf(')') +1) ==  primaryKey.length() ) ) {
159                 if (primaryKey.contains(",") ) {
160                     partitionKey= primaryKey.substring(0,primaryKey.indexOf(','));
161                     partitionKey=partitionKey.replaceAll("[\\(]+","");
162                     clusteringKey=primaryKey.substring(primaryKey.indexOf(',')+1);  // make sure index
163                     clusteringKey=clusteringKey.replaceAll("[)]+", "");
164                 } else {
165                     partitionKey=primaryKey;
166                     partitionKey=partitionKey.replaceAll("[\\)]+","");
167                     partitionKey=partitionKey.replaceAll("[\\(]+","");
168                     clusteringKey="";
169                 }
170             } else {
171                 partitionKey= primaryKey.substring(0,primaryKey.indexOf(')'));
172                 partitionKey=partitionKey.replaceAll("[\\(]+","");
173                 partitionKey = partitionKey.trim();
174                 clusteringKey= primaryKey.substring(primaryKey.indexOf(')'));
175                 clusteringKey=clusteringKey.replaceAll("[\\(]+","");
176                 clusteringKey=clusteringKey.replaceAll("[\\)]+","");
177                 clusteringKey = clusteringKey.trim();
178                 if (clusteringKey.indexOf(',') == 0) clusteringKey=clusteringKey.substring(1);
179                 clusteringKey = clusteringKey.trim();
180                 if (clusteringKey.equals(",") ) clusteringKey=""; // print error if needed    ( ... ),)
181             }
182         }
183
184         if (partitionKey.trim().isEmpty()) {
185             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
186                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
187             return response.status(Status.BAD_REQUEST)
188                 .entity(new JsonResponse(ResultType.FAILURE)
189                 .setError("CreateQ: Partition key cannot be empty").toMap())
190                 .build();
191         }
192
193         if (clusteringKey.trim().isEmpty()) {
194             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
195                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
196             return response.status(Status.BAD_REQUEST)
197                 .entity(new JsonResponse(ResultType.FAILURE)
198                 .setError("CreateQ: Clustering key cannot be empty").toMap())
199                 .build();
200         }
201
202         if((filteringKey != null) && (filteringKey.equalsIgnoreCase(partitionKey))) {
203             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
204                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
205             return response.status(Status.BAD_REQUEST)
206                 .entity(new JsonResponse(ResultType.FAILURE)
207                 .setError("CreateQ: Filtering key cannot be same as Partition Key").toMap())
208                 .build();
209         }
210
211         return new RestMusicDataAPI().createTable(version, minorVersion, patchVersion, aid, ns, authorization, tableObj, keyspace, tablename);
212     }
213
214   /**
215    * 
216    * @param insObj
217    * @param keyspace
218    * @param tablename
219    * @throws Exception
220    */
221     @POST
222     @Path("/keyspaces/{keyspace}/{qname}/rows")
223     @ApiOperation(value = "", response = Void.class)
224     @Consumes(MediaType.APPLICATION_JSON)
225     @Produces(MediaType.APPLICATION_JSON)
226     // public Map<String, Object> insertIntoQ(
227     public Response insertIntoQ(
228         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
229         @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
230         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
231         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
232         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
233         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
234         JsonInsert insObj,
235         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
236         @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename) {
237         
238         ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
239         if (insObj.getValues().isEmpty()) {
240             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
241             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
242             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
243                 .setError("Required HTTP Request body is missing.").toMap()).build();
244         }
245         return new RestMusicDataAPI().insertIntoTable(version, minorVersion, patchVersion, aid, ns,
246             authorization, insObj, keyspace, tablename);
247     }
248
249     /**
250     * 
251     * @param updateObj
252     * @param keyspace
253     * @param tablename
254     * @param info
255     * @return
256     * @throws Exception
257     */
258     @PUT
259     @Path("/keyspaces/{keyspace}/{qname}/rows")
260     @ApiOperation(value = "updateQ", response = String.class)
261     @Consumes(MediaType.APPLICATION_JSON)
262     @Produces(MediaType.APPLICATION_JSON)
263     public Response updateQ(
264         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
265         @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
266         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
267         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
268         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
269         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
270         JsonUpdate updateObj,
271         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
272         @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
273         @Context UriInfo info) throws MusicServiceException, MusicQueryException {
274
275         ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
276         if (updateObj.getValues().isEmpty()) {
277             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
278                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
279             return response.status(Status.BAD_REQUEST)
280                 .entity(new JsonResponse(ResultType.FAILURE)
281                 .setError("Required HTTP Request body is missing. JsonUpdate updateObj.getValues() is empty. ")
282                 .toMap())
283                 .build();
284         }
285         return new RestMusicDataAPI().updateTable(version, minorVersion, patchVersion, aid, ns, 
286             authorization,updateObj, keyspace, tablename, info);
287     }
288
289     /**
290     * 
291     * @param delObj
292     * @param keyspace
293     * @param tablename
294     * @param info
295     * 
296     * @return
297     * @throws Exception
298     */
299
300     @DELETE
301     @Path("/keyspaces/{keyspace}/{qname}/rows")
302     @ApiOperation(value = "deleteQ", response = String.class)
303     @Consumes(MediaType.APPLICATION_JSON)
304     @Produces(MediaType.APPLICATION_JSON)
305     public Response deleteFromQ(
306     @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
307     @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
308     @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
309     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
310     @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
311     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
312     JsonDelete delObj,
313     @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
314     @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
315     @Context UriInfo info) throws MusicServiceException, MusicQueryException {
316     // added checking as per RestMusicDataAPI
317     ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
318     if (delObj == null) {
319         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
320             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
321         return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
322             .setError("deleteFromQ JsonDelete delObjis empty").toMap()).build();
323     }
324
325     return new RestMusicDataAPI().deleteFromTable(version, minorVersion, patchVersion, aid, ns,         
326         authorization, delObj, keyspace, tablename, info);
327     }
328
329     /**
330     * 
331     * @param keyspace
332     * @param tablename
333     * @param info
334     * @return
335     * @throws Exception
336     */
337     @GET
338     @Path("/keyspaces/{keyspace}/{qname}/peek")
339     @ApiOperation(value = "", response = Map.class)
340     @Produces(MediaType.APPLICATION_JSON)
341     //public Map<String, HashMap<String, Object>> peek(
342     public Response peek(
343         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
344         @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
345         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
346         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
347         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
348         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
349         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
350         @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
351         @Context UriInfo info)  {
352         int limit =1; //peek must return just the top row
353         // Map<String ,String> auth = new HashMap<>();
354         // String userId =auth.get(MusicUtil.USERID);
355         // String password =auth.get(MusicUtil.PASSWORD);  
356         ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
357
358         PreparedQueryObject queryObject = new PreparedQueryObject();
359         if (info.getQueryParameters() == null ) { //|| info.getQueryParameters().isEmpty())
360             queryObject.appendQueryString(
361                 "SELECT *  FROM " + keyspace + "." + tablename + " LIMIT " + limit + ";");
362         } else {
363             try {
364                 queryObject = new RestMusicDataAPI().selectSpecificQuery(keyspace, tablename, info, limit);
365             } catch (MusicServiceException ex) {
366                 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.UNKNOWNERROR,
367                 ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, ex);
368                 return response.status(Status.BAD_REQUEST)
369                     .entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap())
370                     .build();
371             }
372         }
373
374         try {
375             ResultSet results = MusicCore.get(queryObject);
376             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS)
377                 .setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
378         } catch (MusicServiceException ex) {
379             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.UNKNOWNERROR,
380                 ErrorSeverity.ERROR, ErrorTypes.MUSICSERVICEERROR, ex);
381             return response.status(Status.BAD_REQUEST)
382                 .entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap())
383                 .build();
384         }
385     }
386
387     /**
388     * 
389     *
390     * @param keyspace
391     * @param tablename
392     * @param info
393     * @return
394     * @throws Exception
395     */
396     @GET
397     @Path("/keyspaces/{keyspace}/{qname}/filter")
398     @ApiOperation(value = "filter", response = Map.class)
399     @Produces(MediaType.APPLICATION_JSON)
400     // public Map<String, HashMap<String, Object>> filter(
401     public Response filter(
402         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
403         @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
404         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
405         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
406         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
407         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
408         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
409         @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
410         @Context UriInfo info) throws Exception {
411
412         return new RestMusicDataAPI().select(version, minorVersion, patchVersion, aid, ns, authorization, keyspace, tablename, info);// , limit)
413
414     }
415
416     /**
417     * 
418     * @param tabObj
419     * @param keyspace
420     * @param tablename
421     * @throws Exception
422     */
423     @DELETE
424     @ApiOperation(value = "DropQ", response = String.class)
425     @Path("/keyspaces/{keyspace}/{qname}")
426     @Produces(MediaType.APPLICATION_JSON)
427     public Response dropQ(
428         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
429         @ApiParam(value = "Minor Version",
430         required = false) @HeaderParam("X-minorVersion") String minorVersion,
431         @ApiParam(value = "Patch Version",
432         required = false) @HeaderParam("X-patchVersion") String patchVersion,
433         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
434         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
435         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
436         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
437           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename) throws Exception {
438
439         return new RestMusicDataAPI().dropTable(version, minorVersion, patchVersion, aid, ns, authorization, keyspace, tablename);
440
441     }
442 }