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);