1 package org.onap.dcae.dmaapbc.dbcapp.controller;
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.Comparator;
11 import java.util.HashMap;
12 import java.util.List;
15 import javax.servlet.http.HttpServletRequest;
16 import javax.servlet.http.HttpServletResponse;
18 import org.onap.dcae.dmaapbc.client.DmaapBcRestClient;
19 import org.onap.dcae.dmaapbc.client.HttpStatusAndResponse;
20 import org.onap.dcae.dmaapbc.dbcapp.domain.DmaapAccess;
21 import org.onap.dcae.dmaapbc.dbcapp.rest.DbcUsvcRestClient;
22 import org.onap.dcae.dmaapbc.dbcapp.service.DmaapAccessService;
23 import org.onap.dcae.dmaapbc.dbcapp.util.DbcappProperties;
24 import org.onap.dcae.dmaapbc.model.DR_Pub;
25 import org.onap.dcae.dmaapbc.model.DR_Sub;
26 import org.onap.dcae.dmaapbc.model.DcaeLocation;
27 import org.onap.dcae.dmaapbc.model.Dmaap;
28 import org.onap.dcae.dmaapbc.model.DmaapObject;
29 import org.onap.dcae.dmaapbc.model.ErrorResponse;
30 import org.onap.dcae.dmaapbc.model.Feed;
31 import org.onap.dcae.dmaapbc.model.MR_Client;
32 import org.onap.dcae.dmaapbc.model.Topic;
33 import org.openecomp.portalsdk.core.controller.RestrictedBaseController;
34 import org.openecomp.portalsdk.core.domain.User;
35 import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate;
36 import org.openecomp.portalsdk.core.onboarding.util.CipherUtil;
37 import org.openecomp.portalsdk.core.web.support.UserUtils;
38 import org.springframework.beans.factory.annotation.Autowired;
40 import com.fasterxml.jackson.annotation.JsonInclude;
41 import com.fasterxml.jackson.core.JsonProcessingException;
42 import com.fasterxml.jackson.databind.ObjectMapper;
45 * This base class provides utility methods to child controllers. All of the
46 * requests are forwarded on to a remote REST API, so there's a large degree of
47 * commonality among the implementations. Combining them kept the lines-of-code
48 * count down, at the expense of some complexity.
50 public class DbcappRestrictedBaseController extends RestrictedBaseController {
53 * Query parameter for desired page number
55 protected static final String PAGE_NUM_QUERY_PARAM = "pageNum";
58 * Query parameter for desired items per page
60 protected static final String VIEW_PER_PAGE_QUERY_PARAM = "viewPerPage";
63 * Tag for status code in JSON responses - ALWAYS PRESENT.
65 protected static final String STATUS_RESPONSE_KEY = "status";
68 * Tag for data in JSON responses.
70 protected static final String DATA_RESPONSE_KEY = "data";
73 * Tag for error message in JSON responses; absent on success.
75 protected static final String ERROR_RESPONSE_KEY = "error";
78 * Tag for response integer, pages required to display complete result list
80 protected static final String TOTAL_PAGES_RESPONSE_KEY = "totalPages";
83 * Tag for DMaaP name obtained from REST client.
85 protected static final String PROFILE_NAME_RESPONSE_KEY = "profileName";
88 * Tag for DMaaP name obtained from REST client.
90 protected static final String DMAAP_NAME_RESPONSE_KEY = "dmaapName";
93 * Tag for DCAE location name list obtained from REST client.
95 protected static final String DCAE_LOCATIONS_RESPONSE_KEY = "dcaeLocations";
98 * Logger that conforms with ECOMP guidelines
100 private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(DbcappRestrictedBaseController.class);
103 * For general use in these methods and subclasses
105 protected final ObjectMapper mapper = new ObjectMapper();
108 * DAO accesses the profiles via a local database. REST accesses the
109 * profiles via a remote REST service.
111 public enum AccessMethod {
116 * Enum for selecting an item type.
118 public enum DmaapDataItem {
119 DR_FEED, DR_PUB, DR_SUB, MR_TOPIC, MR_CLIENT;
123 * Application properties - NOT available to constructor.
126 private DbcappProperties appProperties;
129 * Database access - which might not be used.
132 private DmaapAccessService dmaapAccessDaoServiceAuto;
135 * Read from application properties.
137 private String mechIdName, mechIdPass;
140 * This is set by {@link #getDmaapAccessService()} to the DAO or REST
141 * implementation as configured in properties.
143 private DmaapAccessService dmaapAccessService;
146 * Hello Spring, here's your no-arg constructor.
148 public DbcappRestrictedBaseController() {
149 // Do not serialize null values
150 mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
154 * Access method for subclasses.
156 * @return DbcappProperties object that was autowired by Spring.
158 protected DbcappProperties getAppProperties() {
159 return appProperties;
163 * Lazy initialization. As a side effect, caches mech ID and password.
165 * @return Either DAO or REST client that implements the access service
168 protected DmaapAccessService getDmaapAccessService() {
169 if (dmaapAccessService != null)
170 return dmaapAccessService;
172 // Get the application's mechid
173 mechIdName = appProperties.getProperty(DbcappProperties.DMAAP_MECHID_NAME);
175 String cipher = appProperties.getProperty(DbcappProperties.DMAAP_MECHID_PASSWORD);
176 if (mechIdName == null || cipher == null)
177 throw new RuntimeException("Failed to get MECH_ID name and/or password from properties");
179 mechIdPass = CipherUtil.decrypt(cipher);
180 } catch (Exception ex) {
181 throw new RuntimeException("Failed to decrypt password from config file", ex);
184 String accessMethod = appProperties.getProperty(DbcappProperties.PROFILE_ACCESS_METHOD);
185 if (accessMethod == null)
186 throw new RuntimeException("Failed to get property " + DbcappProperties.PROFILE_ACCESS_METHOD);
187 AccessMethod profileAccessMethod = AccessMethod.valueOf(accessMethod.toUpperCase());
188 if (AccessMethod.DAO == profileAccessMethod) {
189 // Spring auto-wired this field
190 dmaapAccessService = dmaapAccessDaoServiceAuto;
192 String url = appProperties.getProperty(DbcappProperties.PROFILE_USVC_URL);
193 String user = appProperties.getProperty(DbcappProperties.PROFILE_USVC_USER);
194 String pass = appProperties.getProperty(DbcappProperties.PROFILE_USVC_PASS);
195 if (url == null || user == null || pass == null)
196 throw new RuntimeException("getDmaapAccessService: missing property: one of url, user, pass");
197 String clearText = null;
199 clearText = CipherUtil.decrypt(pass);
200 } catch (Exception ex) {
201 throw new RuntimeException("getDmaapAccessService: failed to decrypt password from config");
203 dmaapAccessService = new DbcUsvcRestClient(url, user, clearText);
205 return dmaapAccessService;
209 * Creates a REST client with appropriate credentials, the user/pass from
210 * the access profile if present, otherwise with the default mech ID and
215 * @return REST client.
217 protected DmaapBcRestClient getDmaapBcRestClient(DmaapAccess dmaapAccess) {
218 DmaapBcRestClient restClient = null;
219 if (dmaapAccess.getMechId() == null || dmaapAccess.getMechId().length() == 0)
220 restClient = new DmaapBcRestClient(dmaapAccess.getDmaapUrl(), mechIdName, mechIdPass);
222 restClient = new DmaapBcRestClient(dmaapAccess.getDmaapUrl(), dmaapAccess.getMechId(),
223 dmaapAccess.getPassword());
228 * Pulls out of the specified list the appropriate items for the page of
229 * results specified by the page number and view-per-page parameters.
232 * Page number requested by user
234 * Number of items per page
236 * List of items available
237 * @return List of items to display
239 @SuppressWarnings("rawtypes")
240 private static List shrinkListToPage(final int pageNum, final int viewPerPage, final List itemList) {
241 // user-friendly page numbers index from 1
242 int firstIndexOnThisPage = viewPerPage * (pageNum - 1);
243 int firstIndexOnNextPage = viewPerPage * pageNum;
244 int fromIndex = firstIndexOnThisPage < itemList.size() ? firstIndexOnThisPage : itemList.size();
245 int toIndex = firstIndexOnNextPage < itemList.size() ? firstIndexOnNextPage : itemList.size();
246 // answers empty list if from==to
247 return itemList.subList(fromIndex, toIndex);
251 * Gets the body of a HTTP request assuming UTF-8 encoding.
255 * @return String version of request body
256 * @throws IOException
259 protected static String getBody(HttpServletRequest request) throws IOException {
260 StringBuilder stringBuilder = new StringBuilder();
261 BufferedReader bufferedReader = null;
263 InputStream inputStream = request.getInputStream();
264 if (inputStream != null) {
265 bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
266 char[] charBuffer = new char[512];
268 while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
269 stringBuilder.append(charBuffer, 0, bytesRead);
272 stringBuilder.append("");
275 if (bufferedReader != null) {
277 bufferedReader.close();
278 } catch (IOException ex) {
284 return stringBuilder.toString();
288 * Builds a JSON success response from the specified inputs.
293 * Plain old Java object to serialize as JSON; ignored if null.
294 * @throws JsonProcessingException
295 * If the POJO cannot be serialized
296 * @return JSON block with items "status" : 200 and "data" : (data..)
298 protected String buildJsonSuccess(int statusCode, Object dataPojo) throws JsonProcessingException {
299 Map<String, Object> model = new HashMap<String, Object>();
300 model.put(STATUS_RESPONSE_KEY, statusCode);
301 if (dataPojo != null)
302 model.put(DATA_RESPONSE_KEY, dataPojo);
303 String json = mapper.writeValueAsString(model);
308 * Builds a JSON error response from the specified inputs.
311 * e.g., 500 for internal server error
313 * Information about the operation that failed
315 * Converted to string; ignored if null.
316 * @return JSON block with tags "status" and "error".
318 protected String buildJsonError(int statusCode, String errMsg, Exception exception) {
319 Map<String, Object> model = new HashMap<String, Object>();
320 model.put(STATUS_RESPONSE_KEY, new Integer(500));
321 if (exception == null) {
322 model.put(ERROR_RESPONSE_KEY, errMsg);
324 final int enough = 512;
325 String exString = exception.toString();
326 String exceptionMsg = exString.length() > enough ? exString.substring(0, enough) : exString;
327 model.put(ERROR_RESPONSE_KEY, errMsg + ": " + exceptionMsg);
331 json = mapper.writeValueAsString(model);
332 } catch (JsonProcessingException ex) {
333 // serializing the trivial map should never fail
334 String err = "buildJsonError: failed to serialize";
335 logger.error(EELFLoggerDelegate.errorLogger, err, ex);
336 throw new RuntimeException(err, ex);
342 * Gets a list of DMaaP access profiles for this user from the database. The
343 * profiles have passwords in the clear - this method decrypts the database
346 * Initializes the list for new users and/or configuration changes. Checks
347 * the database list against the configured list of URLs, and creates new
348 * rows for any configured URLs not present for the user. Most environments
349 * are expected to have exactly one valid URL, and the webapp uses a fixed
350 * MechID to authenticate itself to the DMaaP bus controller, so this
351 * approach means new users can start without any setup of URLs.
355 * @return List of DmaapAccess objects
357 * If the URL list is not available in properties
359 protected List<DmaapAccess> getOrInitDmaapAccessList(String userId) throws Exception {
360 String[] configUrls = getAppProperties().getCsvListProperty(DbcappProperties.DMAAP_REST_URL_LIST);
361 if (configUrls == null || configUrls.length == 0)
362 throw new Exception("getOrInitDmaapAccessList: Failed to get DMAAP REST URL list");
363 // Update this list to track which URLs are in the database.
364 List<String> configUrlList = new ArrayList<String>(configUrls.length);
365 for (String c : configUrls) {
366 // Validate URL to detect config botches
367 URL url = new URL(c);
368 configUrlList.add(url.toExternalForm());
371 List<DmaapAccess> dbAccessList = getDmaapAccessService().getDmaapAccessList(userId);
373 // Check the database entries against the configuration. Also
374 // build a list of non-DAO objects with clear-text passwords.
375 List<DmaapAccess> clearList = new ArrayList<DmaapAccess>(dbAccessList.size());
376 for (DmaapAccess dmaapAccess : dbAccessList) {
377 // drop this URL from the list.
378 // If it's not known to config, complain because that's a bogus row.
379 if (!configUrlList.remove(dmaapAccess.getDmaapUrl()))
380 logger.warn(EELFLoggerDelegate.errorLogger, "getOrInitDmaapAccessList: detected extra URL {}",
381 dmaapAccess.getDmaapUrl());
382 // Return cleartext in JSON
383 DmaapAccess clone = new DmaapAccess(dmaapAccess);
384 clone.setPassword(clone.decryptPassword());
385 clearList.add(clone);
388 // Create new rows for any configured URLs not found for this user.
389 for (int i = 0; i < configUrlList.size(); ++i) {
390 String missUrl = configUrlList.get(i);
391 logger.debug(EELFLoggerDelegate.debugLogger, "getOrInitDmaapAccessList: adding missing URL {}", missUrl);
392 DmaapAccess newDmaapAccess = new DmaapAccess();
393 // Create a semi-reasonable name for the table
394 newDmaapAccess.setName("dmaap-" + Integer.toString(i + 1));
395 newDmaapAccess.setUserId(userId);
396 newDmaapAccess.setDmaapUrl(missUrl);
398 getDmaapAccessService().saveDmaapAccess(newDmaapAccess);
399 // Add to response, which assumes the write was successful.
400 clearList.add(newDmaapAccess);
407 * Gets the user's selected DMaaP access profile.
411 * @return DmaapAccess object that is currently selected, or the first one
412 * found if none are selected; null if no access profiles are
415 * If the profile is not found
417 protected DmaapAccess getSelectedDmaapAccess(String userId) throws Exception {
418 List<DmaapAccess> profiles = getOrInitDmaapAccessList(userId);
419 if (profiles.size() == 0) {
420 logger.debug("getSelectedDmaapAccess: no rows found, returning null");
424 // Return the first one by default if nothing is selected.
425 DmaapAccess selected = profiles.get(0);
426 for (DmaapAccess da : profiles)
427 if (da.getSelected())
434 * Supports sorting a list of feeds by the first column displayed: ID
436 private static Comparator<DmaapObject> feedComparator = new Comparator<DmaapObject>() {
438 public int compare(DmaapObject o1, DmaapObject o2) {
441 // sort these numbers lexicographically, same as the front end
443 return f1.getFeedId().compareTo(f2.getFeedId());
448 * Supports sorting a list of publishers by the first column displayed: pub
451 private static Comparator<DmaapObject> pubComparator = new Comparator<DmaapObject>() {
453 public int compare(DmaapObject o1, DmaapObject o2) {
454 DR_Pub p1 = (DR_Pub) o1;
455 DR_Pub p2 = (DR_Pub) o2;
456 return p1.getPubId().compareTo(p2.getPubId());
461 * Supports sorting a list of subscribers by the first column displayed: sub
464 private static Comparator<DmaapObject> subComparator = new Comparator<DmaapObject>() {
466 public int compare(DmaapObject o1, DmaapObject o2) {
467 DR_Sub s1 = (DR_Sub) o1;
468 DR_Sub s2 = (DR_Sub) o2;
469 // sort these numbers lexicographically, same as the front end
471 return s1.getSubId().compareTo(s2.getSubId());
476 * Supports sorting a list of topics by the first column displayed: FQTN
478 private static Comparator<DmaapObject> topicComparator = new Comparator<DmaapObject>() {
480 public int compare(DmaapObject o1, DmaapObject o2) {
481 Topic t1 = (Topic) o1;
482 Topic t2 = (Topic) o2;
483 return t1.getFqtn().compareTo(t2.getFqtn());
488 * Supports sorting a list of clients by the first column displayed: client
491 private static Comparator<DmaapObject> clientComparator = new Comparator<DmaapObject>() {
493 public int compare(DmaapObject o1, DmaapObject o2) {
494 MR_Client c1 = (MR_Client) o1;
495 MR_Client c2 = (MR_Client) o2;
496 // sort these numbers lexicographically, same as the front end
498 return c1.getMrClientId().compareTo(c2.getMrClientId());
503 * Gets one page of DMaaP objects and supporting information via the Bus
504 * Controller REST client. On success, returns a JSON object as String with
505 * the following tags:
507 * <LI>status: Integer; HTTP status code 200.
508 * <LI>dmaapName: String, name returned by the remote DMaaP instance.
509 * <LI>dcaeLocations: Array of string, locations returned by the remote
511 * <LI>data: Array of the desired items; e.g., data router feeds.
512 * <LI>totalPages: Integer, the number of pages required to display the
513 * complete list of items using the submitted page size
516 * This duplicates all of {@link #buildJsonSuccess(int, Object)}.
519 * Access details for the DMaaP REST API
521 * Specifies which item list type to get: data router feeds, etc.
523 * Page number of results
525 * Number of items per page
526 * @return JSON block as String, see above.
530 private String getItemListForPage(DmaapAccess dmaapAccess, DmaapDataItem option, int pageNum, int viewPerPage)
532 DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess);
533 // Get the instance so the page can display its name
534 DmaapObject dmaap = restClient.getDmaap();
535 if (dmaap instanceof ErrorResponse) {
536 // Bad password is caught here.
537 ErrorResponse err = (ErrorResponse) dmaap;
538 throw new Exception(err.getMessage());
540 // Get locations for editing
541 List<DmaapObject> dcaeLocations = restClient.getDcaeLocations();
542 if (dcaeLocations.size() == 1 && dcaeLocations.get(0) instanceof ErrorResponse) {
543 // Should never happen - bad password is caught right above - but be
545 ErrorResponse err = (ErrorResponse) dcaeLocations.get(0);
546 throw new Exception(err.getMessage());
548 // Pass them back as String array
549 String[] dcaeLocs = new String[dcaeLocations.size()];
550 for (int i = 0; i < dcaeLocs.length; ++i) {
551 DcaeLocation dcaeLoc = (DcaeLocation) dcaeLocations.get(i);
552 dcaeLocs[i] = dcaeLoc.getDcaeLocationName();
554 // Get the requested item list
555 List<DmaapObject> itemList = null;
558 itemList = restClient.getFeeds();
559 // size 1 may be error response
560 if (itemList.size() > 1)
561 Collections.sort(itemList, feedComparator);
564 itemList = restClient.getDRPubs();
565 // size 1 may be error response
566 if (itemList.size() > 1)
567 Collections.sort(itemList, pubComparator);
570 itemList = restClient.getDRSubs();
571 // size 1 may be error response
572 if (itemList.size() > 1)
573 Collections.sort(itemList, subComparator);
576 itemList = restClient.getTopics();
577 // size 1 may be error response
578 if (itemList.size() > 1)
579 Collections.sort(itemList, topicComparator);
582 itemList = restClient.getMRClients();
583 // size 1 may be error response
584 if (itemList.size() > 1)
585 Collections.sort(itemList, clientComparator);
588 throw new Exception("getItemListForPage: pgmr error, unimplemented case: " + option.name());
591 logger.debug("getItemListForPage: list size is {}", itemList.size());
592 int pageCount = (int) Math.ceil((double) itemList.size() / viewPerPage);
593 @SuppressWarnings("unchecked")
594 List<DmaapObject> subList = shrinkListToPage(pageNum, viewPerPage, itemList);
596 // Build response here
597 Map<String, Object> model = new HashMap<String, Object>();
598 model.put(STATUS_RESPONSE_KEY, new Integer(200));
599 model.put(PROFILE_NAME_RESPONSE_KEY, dmaapAccess.getName());
600 model.put(DMAAP_NAME_RESPONSE_KEY, ((Dmaap) dmaap).getDmaapName());
601 model.put(DCAE_LOCATIONS_RESPONSE_KEY, dcaeLocs);
602 model.put(DATA_RESPONSE_KEY, itemList);
603 model.put(TOTAL_PAGES_RESPONSE_KEY, pageCount);
605 // build the response
606 String outboundJson = null;
608 outboundJson = mapper.writeValueAsString(model);
609 } catch (Exception ex) {
610 // should never happen
611 logger.error("getItemListForPage: failed to serialize model: ", ex);
612 throw new Exception("sendItemListForPage", ex);
619 * Gets a page of the specified DMaaP items. This method traps errors and
620 * constructs an appropriate JSON block if an error happens.
622 * See {@link #getItemListForPage(DmaapAccess, DmaapDataItem, int, int)}.
627 * DMaaP item type to get
628 * @return JSON with list of serialized objects, or an error.
630 protected String getItemListForPageWrapper(HttpServletRequest request, DmaapDataItem option) {
631 String outboundJson = null;
633 User appUser = UserUtils.getUserSession(request);
634 if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0)
635 throw new Exception("getItemListForPageWrapper: Failed to get Login UID");
636 DmaapAccess selected = getSelectedDmaapAccess(appUser.getLoginId());
637 if (selected == null) // leap into exception handler
638 throw new Exception("No DMaaP access profiles are configured.");
639 int pageNum = Integer.parseInt(request.getParameter(PAGE_NUM_QUERY_PARAM));
640 int viewPerPage = Integer.parseInt(request.getParameter(VIEW_PER_PAGE_QUERY_PARAM));
641 outboundJson = getItemListForPage(selected, option, pageNum, viewPerPage);
642 } catch (Exception ex) {
643 outboundJson = buildJsonError(500, "Failed to get DMaaP item type " + option.name(), ex);
649 * Adds an item of the specified type with the specified content. Constructs
650 * an object by deserializing the JSON block, but ignores any ID field that
653 * On success, returns a JSON block as String with any data returned by the
654 * REST client. Throws an exception on any failure.
657 * Access details for the DMaaP REST API
659 * The login ID of the user making the request
661 * DMaaP item type to add
663 * JSON block to deserialize as an object
664 * @param scAddlStatus
665 * HTTP status code 200 is always accepted. If this parameter is
666 * not null, the value is also considered a valid HTTP status
667 * code on success; e.g., 204.
668 * @return JSON object with result of the operation
672 private String addDmaapItem(DmaapAccess dmaapAccess, String userId, DmaapDataItem itemType, String itemContent,
673 Integer scAddlStatus) throws Exception {
674 DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess);
675 HttpStatusAndResponse<Object> hsr = null;
678 Feed feed = mapper.readValue(itemContent, Feed.class);
679 logger.debug("addDmaapItem: received feed: {} ", feed);
680 // Null out any ID to get an auto-generated ID
681 feed.setFeedId(null);
682 // Assign the owner to be the webapp user
683 feed.setOwner(userId);
684 hsr = restClient.postFeed(feed);
687 DR_Pub pub = mapper.readValue(itemContent, DR_Pub.class);
688 logger.debug("addDmaapItem: received pub: {} ", pub);
689 // Null out any ID to get an auto-generated ID
691 hsr = restClient.postDRPub(pub);
694 DR_Sub sub = mapper.readValue(itemContent, DR_Sub.class);
695 logger.debug("addDmaapItem: received sub: {} ", sub);
696 // Null out any ID to get an auto-generated ID
698 // Assign the owner to be the webapp user
699 sub.setOwner(userId);
700 hsr = restClient.postDRSub(sub);
703 Topic topic = mapper.readValue(itemContent, Topic.class);
704 logger.debug("addDmaapItem: received topic: {} ", topic);
706 topic.setOwner(userId);
707 hsr = restClient.postTopic(topic);
710 MR_Client client = mapper.readValue(itemContent, MR_Client.class);
711 logger.debug("addDmaapItem: received client: {} ", client);
712 client.setMrClientId(null);
713 hsr = restClient.postMRClient(client);
716 throw new Exception("addDmaapItem: pgmr error, unimplemented case: " + itemType.name());
720 String outboundJson = null;
721 if (hsr.getStatusCode() == HttpServletResponse.SC_OK
722 || (scAddlStatus != null && hsr.getStatusCode() == scAddlStatus)) {
723 outboundJson = buildJsonSuccess(hsr.getStatusCode(), hsr.getResponseString());
725 throw new Exception("Unexpected HTTP response code " + Integer.toString(hsr.getStatusCode())
726 + " with content " + hsr.getResponseString());
732 * Adds the specified DMaaP item that is read from the request body. This
733 * method traps errors and constructs an appropriate JSON block if an error
737 * Used to obtain user info from the active session
739 * DMaaP item type to add
740 * @param scAddlStatus
741 * HTTP status code 200 is always accepted. If this parameter is
742 * not null, the value is also considered a valid HTTP status
743 * code on success; e.g., 204.
744 * @return JSON block with success or failure object
746 protected String addItem(HttpServletRequest request, DmaapDataItem itemType, Integer scAddlStatus) {
747 String outboundJson = null;
749 User appUser = UserUtils.getUserSession(request);
750 if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0)
751 throw new Exception("addDmaapItem: Failed to get Login ID");
753 DmaapAccess access = getSelectedDmaapAccess(appUser.getLoginId());
754 if (access == null) // leap into exception handler
755 throw new Exception("No DMaaP access profiles are configured.");
756 String jsonContent = getBody(request);
757 outboundJson = addDmaapItem(access, appUser.getLoginId(), itemType, jsonContent, scAddlStatus);
758 } catch (Exception ex) {
759 outboundJson = buildJsonError(500, "Failed to add DMaaP item " + itemType.name(), ex);
766 * Updates an item of the specified type with the specified content.
767 * Constructs an object by deserializing the JSON block.
769 * On success, returns a JSON block as String with any data returned by the
770 * REST client. Throws an exception on any failure.
773 * Access details for the DMaaP REST API
775 * The Login ID of the user making the request
777 * DMaaP item type to update
779 * Item identification
781 * JSON block to deserialize as an object
782 * @param scAddlStatus
783 * HTTP status code 200 is always accepted. If this parameter is
784 * not null, the value is also considered a valid HTTP status
785 * code on success; e.g., 204.
786 * @return JSON object with result of the operation
790 private String updateDmaapItem(DmaapAccess dmaapAccess, String userId, DmaapDataItem itemType, String itemId,
791 String itemContent, Integer scAddlStatus) throws Exception {
792 DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess);
793 HttpStatusAndResponse<Object> hsr = null;
796 Feed feed = mapper.readValue(itemContent, Feed.class);
797 logger.debug("updateDmaapItem: received feed: {} ", feed);
798 // Ensure the owner is the webapp user
799 feed.setOwner(userId);
800 hsr = restClient.putFeed(feed);
803 DR_Pub pub = mapper.readValue(itemContent, DR_Pub.class);
804 logger.debug("updateDmaapItem: received pub: {} ", pub);
805 hsr = restClient.putDRPub(pub);
808 DR_Sub sub = mapper.readValue(itemContent, DR_Sub.class);
809 logger.debug("updateDmaapItem: received sub: {} ", sub);
810 // Ensure the owner is the webapp user
811 sub.setOwner(userId);
812 hsr = restClient.putDRSub(sub);
815 Topic topic = mapper.readValue(itemContent, Topic.class);
816 logger.debug("updateDmaapItem: received topic: {} ", topic);
817 // Ensure the owner is the webapp user
818 topic.setOwner(userId);
819 // DCAE backend may implement PUT someday.
820 if (true && userId != null)
821 throw new UnsupportedOperationException("put topic not supported (yet)");
824 MR_Client client = mapper.readValue(itemContent, MR_Client.class);
825 logger.debug("updateDmaapItem: received client: {} ", client);
826 hsr = restClient.putMRClient(client);
829 throw new Exception("updateDmaapItem: pgmr error, unimplemented case: " + itemType.name());
833 String outboundJson = null;
834 if (hsr.getStatusCode() == HttpServletResponse.SC_OK
835 || (scAddlStatus != null && hsr.getStatusCode() == scAddlStatus)) {
836 outboundJson = buildJsonSuccess(hsr.getStatusCode(), hsr.getResponseString());
838 throw new Exception("Unexpected HTTP response code " + Integer.toString(hsr.getStatusCode())
839 + " with content " + hsr.getResponseString());
845 * Updates the specified DMaaP item that is read from the request body. This
846 * method traps errors and constructs an appropriate JSON block if an error
850 * Used to obtain user info from the active session
852 * DMaaP item type to update
854 * Item identification to update
855 * @param scUpdatelStatus
856 * HTTP status code 200 is always accepted. If this parameter is
857 * not null, the value is also considered a valid HTTP status
858 * code on success; e.g., 204.
859 * @return JSON object with success or error information.
861 protected String updateItem(HttpServletRequest request, DmaapDataItem itemType, String itemId,
862 Integer scUpdatelStatus) {
863 String outboundJson = null;
865 User appUser = UserUtils.getUserSession(request);
866 if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0)
867 throw new Exception("updateItem: Failed to get Login ID");
868 DmaapAccess access = getSelectedDmaapAccess(appUser.getLoginId());
869 if (access == null) // leap into exception handler
870 throw new Exception("No DMaaP access profiles are configured.");
871 String jsonContent = getBody(request);
872 outboundJson = updateDmaapItem(access, appUser.getLoginId(), itemType, itemId, jsonContent,
874 } catch (Exception ex) {
875 outboundJson = buildJsonError(500, "Failed to update DMaaP item " + itemType.name(), ex);
882 * Deletes an item of the specified type with the specified ID.
885 * Access details for the DMaaP REST API
887 * DMaaP item type to delete
889 * Item identification
890 * @param scAddlStatus
891 * HTTP status code 200 is always accepted. If this parameter is
892 * not null, the value is also considered a valid HTTP status
893 * code on success; e.g., 204.
894 * @return On success, returns a JSON block as String with any data returned
895 * by the REST client.
899 private String deleteDmaapItem(DmaapAccess dmaapAccess, DmaapDataItem itemType, String itemId, Integer scAddlStatus)
901 DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess);
902 HttpStatusAndResponse<Object> hsr = null;
905 hsr = restClient.deleteFeed(itemId);
908 hsr = restClient.deleteDRPub(itemId);
911 hsr = restClient.deleteDRSub(itemId);
914 hsr = restClient.deleteTopic(itemId);
917 hsr = restClient.deleteMRClient(itemId);
920 throw new Exception("deleteDmaapItem: pgmr error, unimplemented case: " + itemType.name());
924 String outboundJson = null;
925 if (hsr.getStatusCode() == HttpServletResponse.SC_OK
926 || (scAddlStatus != null && hsr.getStatusCode() == scAddlStatus)) {
927 outboundJson = buildJsonSuccess(hsr.getStatusCode(), hsr.getResponseString());
929 throw new Exception("Unexpected HTTP response code " + Integer.toString(hsr.getStatusCode())
930 + " with content " + hsr.getResponseString());
936 * Deletes the specified DMaaP item. This method traps errors and constructs
937 * an appropriate JSON block if an error happens.
940 * Used to obtain user info from the active session
942 * DMaaP item type to delete
945 * @param scAddlStatus
946 * HTTP status code 200 is always accepted. If this parameter is
947 * not null, the value is also considered a valid HTTP status
948 * code on success; e.g., 204.
949 * @return JSON object with success or error information.
951 protected String deleteItem(HttpServletRequest request, DmaapDataItem itemType, String itemId,
952 Integer scAddlStatus) {
953 String outboundJson = null;
955 User appUser = UserUtils.getUserSession(request);
956 if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0)
957 throw new Exception("deleteItem: Failed to get Login ID");
958 DmaapAccess selected = getSelectedDmaapAccess(appUser.getLoginId());
959 if (selected == null) // leap into exception handler
960 throw new Exception("No DMaaP access profiles are configured.");
961 outboundJson = deleteDmaapItem(selected, itemType, itemId, scAddlStatus);
962 } catch (Exception ex) {
963 outboundJson = buildJsonError(500, "Failed to delete DMaaP item " + itemType.name() + " ID " + itemId, ex);