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