removed code smells
[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)
178                                         clusteringKey=clusteringKey.substring(1);
179                 clusteringKey = clusteringKey.trim();
180                 if (clusteringKey.equals(",") )
181                                         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", required = false) @HeaderParam("X-minorVersion") String minorVersion,
231         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
232         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
233         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
234         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
235         JsonInsert insObj,
236         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
237         @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename) {
238         
239         ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
240         if (insObj.getValues().isEmpty()) {
241             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
242             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
243             return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
244                 .setError("Required HTTP Request body is missing.").toMap()).build();
245         }
246         return new RestMusicDataAPI().insertIntoTable(version, minorVersion, patchVersion, aid, ns,
247             authorization, insObj, keyspace, tablename);
248     }
249
250     /**
251     * 
252     * @param updateObj
253     * @param keyspace
254     * @param tablename
255     * @param info
256     * @return
257     * @throws Exception
258     */
259     @PUT
260     @Path("/keyspaces/{keyspace}/{qname}/rows")
261     @ApiOperation(value = "updateQ", response = String.class)
262     @Consumes(MediaType.APPLICATION_JSON)
263     @Produces(MediaType.APPLICATION_JSON)
264     public Response updateQ(
265         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
266         @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
267         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
268         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
269         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
270         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
271         JsonUpdate updateObj,
272         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
273         @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
274         @Context UriInfo info) throws MusicServiceException, MusicQueryException {
275
276         ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
277         if (updateObj.getValues().isEmpty()) {
278             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
279                 ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
280             return response.status(Status.BAD_REQUEST)
281                 .entity(new JsonResponse(ResultType.FAILURE)
282                 .setError("Required HTTP Request body is missing. JsonUpdate updateObj.getValues() is empty. ")
283                 .toMap())
284                 .build();
285         }
286         return new RestMusicDataAPI().updateTable(version, minorVersion, patchVersion, aid, ns, 
287             authorization,updateObj, keyspace, tablename, info);
288     }
289
290     /**
291     * 
292     * @param delObj
293     * @param keyspace
294     * @param tablename
295     * @param info
296     * 
297     * @return
298     * @throws Exception
299     */
300
301     @DELETE
302     @Path("/keyspaces/{keyspace}/{qname}/rows")
303     @ApiOperation(value = "deleteQ", response = String.class)
304     @Consumes(MediaType.APPLICATION_JSON)
305     @Produces(MediaType.APPLICATION_JSON)
306     public Response deleteFromQ(
307     @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
308     @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
309     @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
310     @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
311     @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
312     @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
313     JsonDelete delObj,
314     @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
315     @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
316     @Context UriInfo info) throws MusicServiceException, MusicQueryException {
317     // added checking as per RestMusicDataAPI
318     ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
319     if (delObj == null) {
320         logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA,
321             ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR);
322         return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE)
323             .setError("deleteFromQ JsonDelete delObjis empty").toMap()).build();
324     }
325
326     return new RestMusicDataAPI().deleteFromTable(version, minorVersion, patchVersion, aid, ns,         
327         authorization, delObj, keyspace, tablename, info);
328     }
329
330     /**
331     * 
332     * @param keyspace
333     * @param tablename
334     * @param info
335     * @return
336     * @throws Exception
337     */
338     @GET
339     @Path("/keyspaces/{keyspace}/{qname}/peek")
340     @ApiOperation(value = "", response = Map.class)
341     @Produces(MediaType.APPLICATION_JSON)
342     //public Map<String, HashMap<String, Object>> peek(
343     public Response peek(
344         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
345         @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
346         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
347         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
348         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
349         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
350         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
351         @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
352         @Context UriInfo info)  {
353         int limit =1; //peek must return just the top row
354         // Map<String ,String> auth = new HashMap<>();
355         // String userId =auth.get(MusicUtil.USERID);
356         // String password =auth.get(MusicUtil.PASSWORD);  
357         ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion);
358
359         PreparedQueryObject queryObject = new PreparedQueryObject();
360         if (info.getQueryParameters() == null ) { //|| info.getQueryParameters().isEmpty())
361             queryObject.appendQueryString(
362                 "SELECT *  FROM " + keyspace + "." + tablename + " LIMIT " + limit + ";");
363         } else {
364             try {
365                 queryObject = new RestMusicDataAPI().selectSpecificQuery(keyspace, tablename, info, limit);
366             } catch (MusicServiceException ex) {
367                 logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.UNKNOWNERROR,
368                 ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, ex);
369                 return response.status(Status.BAD_REQUEST)
370                     .entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap())
371                     .build();
372             }
373         }
374
375         try {
376             ResultSet results = MusicCore.get(queryObject);
377             return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS)
378                 .setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build();
379         } catch (MusicServiceException ex) {
380             logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.UNKNOWNERROR,
381                 ErrorSeverity.ERROR, ErrorTypes.MUSICSERVICEERROR, ex);
382             return response.status(Status.BAD_REQUEST)
383                 .entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap())
384                 .build();
385         }
386     }
387
388     /**
389     * 
390     *
391     * @param keyspace
392     * @param tablename
393     * @param info
394     * @return
395     * @throws Exception
396     */
397     @GET
398     @Path("/keyspaces/{keyspace}/{qname}/filter")
399     @ApiOperation(value = "filter", response = Map.class)
400     @Produces(MediaType.APPLICATION_JSON)
401     // public Map<String, HashMap<String, Object>> filter(
402     public Response filter(
403         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
404         @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion,
405         @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion,
406         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
407         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
408         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
409         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
410         @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename,
411         @Context UriInfo info) throws Exception {
412
413         return new RestMusicDataAPI().selectWithCritical(version, minorVersion, patchVersion, aid, ns, authorization,null, keyspace, tablename, info);// , limit)
414
415     }
416
417     /**
418     * 
419     * @param tabObj
420     * @param keyspace
421     * @param tablename
422     * @throws Exception
423     */
424     @DELETE
425     @ApiOperation(value = "DropQ", response = String.class)
426     @Path("/keyspaces/{keyspace}/{qname}")
427     @Produces(MediaType.APPLICATION_JSON)
428     public Response dropQ(
429         @ApiParam(value = "Major Version", required = true) @PathParam("version") String version,
430         @ApiParam(value = "Minor Version",
431         required = false) @HeaderParam("X-minorVersion") String minorVersion,
432         @ApiParam(value = "Patch Version",
433         required = false) @HeaderParam("X-patchVersion") String patchVersion,
434         @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid,
435         @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns,
436         @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization,
437         @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace,
438           @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename) throws Exception {
439
440         return new RestMusicDataAPI().dropTable(version, minorVersion, patchVersion, aid, ns, authorization, keyspace, tablename);
441
442     }
443 }