de18d951b5400e907f6849fb13d877cdee3c5d8a
[dmaap/dbcapi.git] / src / main / java / org / onap / dmaap / dbcapi / service / FeedService.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.onap.dmaap
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  *
7  * Modifications Copyright (C) 2019 IBM.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.dmaap.dbcapi.service;
24
25 import org.onap.dmaap.dbcapi.util.RandomInteger;
26
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.ws.rs.core.Response.Status;
32
33 import org.apache.log4j.Logger;
34 import org.onap.dmaap.dbcapi.client.DrProvConnection;
35 import org.onap.dmaap.dbcapi.database.DatabaseClass;
36 import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
37 import org.onap.dmaap.dbcapi.model.ApiError;
38 import org.onap.dmaap.dbcapi.model.DR_Pub;
39 import org.onap.dmaap.dbcapi.model.DR_Sub;
40 import org.onap.dmaap.dbcapi.model.Feed;
41 import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
42 import org.onap.dmaap.dbcapi.util.DmaapConfig;
43
44 public class FeedService  extends BaseLoggingClass {
45         
46         private Map<String, Feed> feeds = DatabaseClass.getFeeds();
47         private DR_PubService pubService = new DR_PubService();
48         private DR_SubService subService = new DR_SubService();
49         private DcaeLocationService dcaeLocations = new DcaeLocationService();
50         private String deleteHandling;
51         private String unit_test;
52         
53         public FeedService() {
54                 logger.info( "new FeedService");
55                 DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
56                 deleteHandling = p.getProperty("Feed.deleteHandling", "DeleteOnDR");
57                 unit_test = p.getProperty( "UnitTest", "No" );
58
59         }
60         
61         public Map<String, Feed> getFeeds() {                   
62                 return feeds;
63         }
64         
65         private void getSubObjects( Feed f ) {
66                 ArrayList<DR_Pub> pubs = pubService.getDr_PubsByFeedId( f.getFeedId() );
67                 f.setPubs(pubs);
68                 ArrayList<DR_Sub> subs = subService.getDr_SubsByFeedId( f.getFeedId() );
69                 f.setSubs(subs);        
70         }
71                 
72         public List<Feed> getAllFeeds( String name, String ver, String match ) {
73                 logger.info( "getAllFeeds: name=" + name + " ver=" + ver + " match=" + match);
74                 ArrayList<Feed> fatFeeds = new ArrayList<Feed>();
75                 for( Feed f:  feeds.values() ) {
76                         boolean keep = true;
77                         if ( name != null ) {
78                                 if ( match != null && "startsWith".equals(match) ) {
79                                         if ( ! f.getFeedName().startsWith( name ) ) {
80                                                 logger.info( "getAllFeeds: feedName=" + f.getFeedName() + " doesn't start with=" + name);
81                                                 keep = false;
82                                         }
83                                 } else if ( match != null && match.equals("contains") ) {
84                                         if ( ! f.getFeedName().contains( name ) ) {
85                                                 logger.info( "getAllFeeds: feedName=" + f.getFeedName() + " doesn't contain=" + name);
86                                                 keep = false;
87                                         }
88                                 } else {
89                                         if ( ! f.getFeedName().equals( name ) ) {
90                                                 logger.info( "getAllFeeds: feedName=" + f.getFeedName() + " doesn't equal=" + name);
91                                                 keep = false;
92                                         }
93                                 }
94
95                         }
96                         if ( keep && ver != null ) {
97                                 if ( ! f.getFeedVersion().equals(ver)) {
98                                         logger.info( "getAllFeeds: feedVersion=" + f.getFeedName() + " doesn't match " + ver);
99                                         keep = false;
100                                 } else {
101                                         logger.info( "getAllFeeds: feedVersion=" + f.getFeedName() + " matches " + ver);
102                                 }
103                         }
104                                         
105                         if (keep){
106                                 getSubObjects(f);
107                                 fatFeeds.add(f);
108                         }
109                 }
110                 return fatFeeds;
111         }
112         
113         
114         private Feed _getFeed( String key, ApiError err, boolean flag ) {
115                 Feed f = feeds.get( key );
116                 if ( f != null && ( flag || f.getStatus() != DmaapObject_Status.DELETED ) ) {
117                         getSubObjects( f );
118                 } else {
119                         err.setCode(Status.NOT_FOUND.getStatusCode());
120                         err.setMessage("feed not found");
121                         err.setFields("feedId=" + key );
122                         return null;
123                 }
124                 err.setCode(200);
125                 return f;
126         }
127         public Feed getFeed( String key, ApiError err ) {
128                 return _getFeed( key, err, false );
129         }
130         public Feed getFeedPure( String key, ApiError err ) {
131                 return _getFeed( key, err, true );
132         }
133         
134         public Feed getFeedByName( String name, String ver, ApiError err ) {
135                 for( Feed f:  feeds.values() ) {
136                         if ( f.getFeedName().equals( name ) && f.getFeedVersion().equals(ver) ) {
137                                 getSubObjects(f);
138                                 return f;
139                         }
140         
141                 }
142                 err.setCode(Status.NOT_FOUND.getStatusCode());
143                 err.setMessage("feed not found");
144                 err.setFields("feedName=" + name + " and ver=" + ver );
145                 return null;
146         
147         }
148
149         private boolean savePubs( Feed f ) {
150                 return savePubs( f, f );
151         }
152         // need to save the Pub objects independently and copy pubId from original request
153         private boolean savePubs( Feed fnew, Feed req ) {
154                 // save any pubs
155                 DR_PubService pubSvc = new DR_PubService();
156                 ArrayList<DR_Pub> reqPubs = req.getPubs();
157                 ArrayList<DR_Pub> newPubs = fnew.getPubs();
158                 
159
160                 
161                 int nSize = newPubs.size();
162                 int rSize = reqPubs.size();
163                 logger.info( "reqPubs size=" + rSize + " newPubs size=" + nSize );
164                 if ( nSize != rSize ) {
165                         errorLogger.error( "Resulting set of publishers do not match requested set of publishers " + nSize + " vs " + rSize );
166                         fnew.setStatus( DmaapObject_Status.INVALID);
167                         return false;
168                 }
169                 // NOTE: when i > 1 newPubs are in reverse order from reqPubs
170                 for( int i = 0; i < reqPubs.size(); i++ ) {
171                         DR_Pub reqPub = reqPubs.get(i); 
172                         ApiError err = new ApiError();
173                         if ( pubSvc.getDr_Pub( reqPub.getPubId(), err ) == null ) {
174                                 DR_Pub newPub = newPubs.get(nSize - i - 1);
175                                 reqPub.setPubId(newPub.getPubId());
176                                 reqPub.setFeedId(newPub.getFeedId());
177                                 reqPub.setStatus(DmaapObject_Status.VALID);
178                                 if ( reqPub.getDcaeLocationName() == null ) {
179                                         reqPub.setDcaeLocationName("notSpecified");
180                                 }
181                                 pubSvc.addDr_Pub( reqPub );
182                         }
183                         
184                 }
185                 
186                 fnew.setPubs(reqPubs);
187                 fnew.setStatus(DmaapObject_Status.VALID);
188                 return true;
189
190         }
191         
192         private boolean saveSubs( Feed f ) {
193                 return saveSubs( f, f );
194         }
195         // need to save the Sub objects independently
196         private boolean saveSubs( Feed fnew, Feed req ) {       
197                 ArrayList<DR_Sub> subs = req.getSubs();
198                 if ( subs == null || subs.size() == 0 ) {
199                         logger.info( "No subs specified");
200                 } else {
201                         DR_SubService subSvc = new DR_SubService( fnew.getSubscribeURL() );
202                         ApiError err = new ApiError();
203                         for( int i = 0; i <  subs.size(); i++ ) {
204                                 DR_Sub sub = subs.get(i);
205                                 if ( subSvc.getDr_Sub( sub.getSubId(), err) == null ) {
206                                         subs.set( i,  subSvc.addDr_Sub(sub, err));
207                                         if ( ! err.is2xx())  {
208                                                 logger.error( "i=" + i + " url=" + sub.getDeliveryURL() + " err=" + err.getCode() );
209                                                 return false;
210                                         }
211                                 }
212                                 
213                         }
214                         fnew.setSubs(subs);
215                 }
216
217
218                 fnew.setStatus(DmaapObject_Status.VALID);
219                 return true;
220
221         }
222
223         public  Feed addFeed( Feed req, ApiError err ) {
224
225                 // at least 1 pub is required by DR, so create a default pub if none is specified
226                 if ( req.getPubs().size() == 0 ) {
227                         logger.info( "No pubs specified - creating tmp pub");
228                         ArrayList<DR_Pub> pubs = new ArrayList<DR_Pub>();
229                         pubs.add( new DR_Pub( dcaeLocations.getCentralLocation())
230                                                                 .setRandomUserName()
231                                                                 .setRandomPassword());
232                         req.setPubs(pubs);
233                 } 
234                 
235
236                 DrProvConnection prov = new DrProvConnection();
237                 prov.makeFeedConnection();      
238                 String resp = prov.doPostFeed( req, err );
239                 if ( unit_test.equals( "Yes" ) ) {
240                         // assume resp is null, so need to simulate it
241                         resp = simulateResp( req, "POST" );
242                 }
243                 logger.info( "resp=" + resp );
244                 if ( resp == null ) {
245                         switch( err.getCode() ) {
246                         case 400: 
247                                 err.setFields( "feedName=" + req.getFeedName() + " + feedVersion=" + req.getFeedVersion() );
248                                 break;
249                         case 403:
250                                 err.setCode(500);
251                                 err.setMessage("API deployment/configuration error - contact support");
252                                 err.setFields( "PROV_AUTH_ADDRESSES");
253                                 logger.error( "Prov response: 403. " + err.getMessage() + " regarding " + err.getFields() );
254                                 break;
255                         default:
256                                 err.setCode(500);
257                                 err.setMessage( "Unexpected response from DR backend" );
258                                 err.setFields("response");
259                         }
260                         return null;
261
262                 }
263
264
265                 Feed fnew = new Feed( resp );
266                 logger.info( "fnew status is:" + fnew.getStatus() );
267                 if ( ! fnew.isStatusValid()) {          
268                         err.setCode(500);
269                         err.setMessage( "Unexpected response from DR backend" );
270                         err.setFields("response");              
271                         return null;
272                 }
273                 
274                 //saveChildren( fnew, req );
275                 if ( ! savePubs( fnew, req ) || ! saveSubs( fnew, req ) ) {
276                         err.setCode(Status.BAD_REQUEST.getStatusCode());
277                         err.setMessage("Unable to save Pub or Sub objects");
278                         return null;
279                 }
280                 fnew.setFormatUuid(req.getFormatUuid());
281                 fnew.setLastMod();
282                 feeds.put( fnew.getFeedId(), fnew );
283                 return fnew;
284         }
285                 
286         public Feed updateFeed( Feed req, ApiError err ) {
287         
288                 // at least 1 pub is required by DR, so create a default pub if none is specified
289                 if ( req.getPubs().size() == 0 ) {
290                         logger.info( "No pubs specified - creating tmp pub");
291                         ArrayList<DR_Pub> pubs = new ArrayList<DR_Pub>();
292                         pubs.add( new DR_Pub( dcaeLocations.getCentralLocation())
293                                                                 .setRandomUserName()
294                                                                 .setRandomPassword());
295                         req.setPubs(pubs);
296                 } 
297                 
298                 DrProvConnection prov = new DrProvConnection();
299                 prov.makeFeedConnection( req.getFeedId() );
300                 String resp = prov.doPutFeed( req, err );
301                 if ( unit_test.equals( "Yes" ) ) {
302                         // assume resp is null, so need to simulate it
303                         resp = simulateResp( req, "PUT" );
304                         err.setCode(200);
305                 }
306                 logger.info( "resp=" + resp );
307                 if ( resp == null ) {
308                         switch( err.getCode() ) {
309                         case 400: 
310                                 err.setFields( "feedName=" + req.getFeedName() + " + feedVersion=" + req.getFeedVersion() );
311                                 break;
312                         case 403:
313                                 err.setCode(500);
314                                 err.setMessage("API deployment/configuration error - contact support");
315                                 err.setFields( "PROV_AUTH_ADDRESSES");
316                                 break;
317                         default:
318                                 err.setCode(500);
319                                 err.setMessage( "Unexpected response from DR backend" );
320                                 err.setFields("response");
321                         }
322                         return null;
323                 }
324
325
326                 Feed fnew = new Feed( resp );
327                 logger.info( "fnew status is:" + fnew.getStatus() );
328                 if ( ! fnew.isStatusValid()) {          
329                         err.setCode(500);
330                         err.setMessage( "Unexpected response from DR backend" );
331                         err.setFields("response");              
332                         return null;
333                 }
334
335                 if ( ! savePubs( fnew, req ) || ! saveSubs( fnew, req ) ) {
336                         err.setCode(Status.BAD_REQUEST.getStatusCode());
337                         err.setMessage("Unable to save Pub or Sub objects");
338                         return null;
339                 }
340                 fnew.setFormatUuid(req.getFormatUuid());
341                 fnew.setLastMod();
342                 feeds.put( fnew.getFeedId(), fnew );
343                 return fnew;
344         }
345         
346         
347         //
348         // DR does not actually delete a feed, so we provide two behaviors:
349         // 1) clean up the feed by removing all subs and pubs, mark it here as DELETED.
350         //    then client can add it back if desired.
351         // 2) Call the DR Delete function.  Feed with the same name and version can never be added again
352         //
353         public Feed removeFeed( Feed req, ApiError err ) {
354                 
355                 // strip pubs and subs from feed first no matter what
356                 ArrayList<DR_Pub> pubs = pubService.getDr_PubsByFeedId( req.getFeedId() );
357                 for( DR_Pub pub: pubs ) {
358                         pubService.removeDr_Pub(pub.getPubId(), err);
359                         if ( ! err.is2xx()) {
360                                 return req;
361                         }
362                 }
363                 ArrayList<DR_Sub> subs = subService.getDr_SubsByFeedId( req.getFeedId() );
364                 for ( DR_Sub sub: subs ) {
365                         subService.removeDr_Sub(sub.getSubId(), err);
366                         if ( ! err.is2xx()) {
367                                 return req;
368                         }
369                 }
370         
371                 if ( deleteHandling.equalsIgnoreCase("DeleteOnDR")) {
372                         DrProvConnection prov = new DrProvConnection();
373                         prov.makeFeedConnection( req.getFeedId() );
374                         String resp = prov.doDeleteFeed( req, err );
375                         if ( unit_test.equals( "Yes" ) ) {
376                                 // assume resp is null, so need to simulate it
377                                 resp = simulateDelResp( req );
378                         }
379                         logger.info( "resp=" + resp );
380                         if ( resp == null ) {
381                                 switch( err.getCode() ) {
382                                 case 400: 
383                                         err.setFields( "feedName=" + req.getFeedName() + " + feedVersion=" + req.getFeedVersion() );
384                                         break;
385                                 case 403:
386                                         err.setCode(500);
387                                         err.setMessage("API deployment/configuration error - contact support");
388                                         err.setFields( "PROV_AUTH_ADDRESSES");
389                                         break;
390                                 default:
391                                         err.setCode(500);
392                                         err.setMessage( "Unexpected response from DR backend" );
393                                         err.setFields("response");
394                                 }
395                                 return req;  // return back the requested feed - implies it wasn't removed
396                         }
397                         return feeds.remove(req.getFeedId());
398                 } else {
399                 
400                         logger.info( "Disable pubs for deleted feed - creating tmp pub");
401                         ArrayList<DR_Pub> tmppub = new ArrayList<DR_Pub>();
402                         tmppub.add( new DR_Pub( dcaeLocations.getCentralLocation())
403                                                                 .setRandomUserName()
404                                                                 .setRandomPassword());
405                         req.setPubs(tmppub);
406                         req.setSubs(null);
407                         Feed fnew = updateFeed( req, err );
408                         if ( ! err.is2xx()) {
409                                 return req;
410                         }
411                         fnew.setStatus(DmaapObject_Status.DELETED);
412                         feeds.put( fnew.getFeedId(), fnew );
413                         return null;    
414                 }
415
416                 
417         }       
418
419         private String simulateResp( Feed f, String action ){
420                 String server = "localhost";
421                 String feedid;
422                 if ( action.equals( "POST" ) ) { 
423                         RandomInteger ran = new RandomInteger(10000);
424                         feedid = Integer.toString( ran.next() );
425                 } else if ( action.equals( "PUT" ) ) {
426                         feedid = f.getFeedId();
427                 } else {
428                         feedid = "99";
429                 }
430                 String ret = String.format( 
431 "{\"suspend\":false,\"groupid\":0,\"description\":\"%s\",\"version\":\"1.0\",\"authorization\":",
432                         f.getFeedDescription() );
433
434                 String endpoints = "{\"endpoint_addrs\":[],\"classification\":\"unclassified\",\"endpoint_ids\":[";
435                 String sep = "";
436                 for( DR_Pub pub: f.getPubs()) {
437                         endpoints +=  String.format( "%s{\"password\":\"%s\",\"id\":\"%s\"}", 
438                                         sep, pub.getUserpwd(), pub.getUsername() );
439                         sep = ",";
440                         
441                 }
442                 endpoints += "]},";
443                 ret += endpoints;
444                 
445                 ret += String.format(
446                 "\"name\":\"%s\",\"business_description\":\"\",\"publisher\":\"sim\",\"links\":{\"subscribe\":\"https://%s/subscribe/%s\",\"log\":\"https://%s/feedlog/%s\",\"publish\":\"https://%s/publish/%s\",\"self\":\"https://%s/feed/%s\"}}",
447
448                         f.getFeedName(),
449                         server, feedid,
450                         server, feedid,
451                         server, feedid,
452                         server, feedid
453                                 );
454                 logger.info( "simulateResp ret=" + ret );
455                 return ret;
456         }
457         private String simulateDelResp( Feed f ){
458                 String server = "localhost";
459                 String feedid = f.getFeedId();
460                 String ret = String.format( 
461 "{\"suspend\":true,\"groupid\":0,\"description\":\"%s\",\"version\":\"1.0\",\"authorization\":{\"endpoint_addrs\":[],\"classification\":\"unclassified\",\"endpoint_ids\":[{\"password\":\"topSecret123\",\"id\":\"sim\"}]},\"name\":\"%s\",\"business_description\":\"\",\"publisher\":\"sim\",\"links\":{\"subscribe\":\"https://%s/subscribe/%s\",\"log\":\"https://%s/feedlog/%s\",\"publish\":\"https://%s/publish/%s\",\"self\":\"https://%s/feed/%s\"}}",
462                 f.getFeedDescription(),
463                 f.getFeedName(),
464                 server, feedid,
465                 server, feedid,
466                 server, feedid,
467                 server, feedid
468
469                 );
470                 return ret;
471         }
472 }