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