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