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