diff options
Diffstat (limited to 'dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp')
14 files changed, 2714 insertions, 0 deletions
diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DataBusHomeController.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DataBusHomeController.java new file mode 100644 index 0000000..8ac462d --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DataBusHomeController.java @@ -0,0 +1,35 @@ +package org.onap.dcae.dmaapbc.dbcapp.controller; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.ModelAndView; + +/** + * This controller maps requests for the DMaaP-BC-App's landing page, which is + * an Angular single-page application. + */ +@Controller +@RequestMapping("/") +public class DataBusHomeController extends DbcappRestrictedBaseController { + + public static final String APP_NAME = "dmaap-bc-app"; + public static final DateFormat logDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + + /** + * At one time I published the landing page as simply "/dbc", but it can + * also be accessed with a default suffix; e.g., "/dbc.htm". + * + * @return View name key, which is resolved to a file using an Apache tiles + * "definitions.xml" file. + */ + @RequestMapping(value = { "/dbc" }, method = RequestMethod.GET) + public ModelAndView dbcDefaultController() { + // a model is only useful for JSP; this app is angular. + return new ModelAndView("dbc_home_tdkey"); + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DataRouterController.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DataRouterController.java new file mode 100644 index 0000000..c2fbb26 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DataRouterController.java @@ -0,0 +1,321 @@ +package org.onap.dcae.dmaapbc.dbcapp.controller; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.dcae.dmaapbc.dbcapp.util.DbcappProperties; +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.util.SystemProperties; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * Data Router controller: serves Ajax requests made by Angular scripts on pages + * that show feeds, publishers and subscribers. + */ +@Controller +@RequestMapping("/") +public class DataRouterController extends DbcappRestrictedBaseController { + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(DataRouterController.class); + + /** + * Application properties - NOT available to constructor. + */ + @Autowired + private DbcappProperties appProperties; + + private static final String FEED_PATH = "/dr_feed"; + private static final String PUB_PATH = "/dr_pub"; + private static final String SUB_PATH = "/dr_sub"; + + public DataRouterController() { + } + + /** + * Answers a request for one page of data router feeds. + * + * @param request + * HttpServletRequest + * @return Result of + * {@link #getItemListForPageWrapper(HttpServletRequest, DmaapDataItem)} + */ + @RequestMapping(value = { FEED_PATH }, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public String getDRFeedsByPage(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = getItemListForPageWrapper(request, DmaapDataItem.DR_FEED); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Answers a request for one page of data router publishers. + * + * @param request + * HttpServletRequest + * @return Result of + * {@link #getItemListForPageWrapper(HttpServletRequest, DmaapDataItem)} + */ + @RequestMapping(value = { PUB_PATH }, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public String getDRPubsByPage(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = getItemListForPageWrapper(request, DmaapDataItem.DR_PUB); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Answers a request for one page of data router subscribers. + * + * @param request + * HttpServletRequest + * @return Result of + * {@link #getItemListForPageWrapper(HttpServletRequest, DmaapDataItem)} + */ + @RequestMapping(value = { SUB_PATH }, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public String getDRSubsByPage(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = getItemListForPageWrapper(request, DmaapDataItem.DR_SUB); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Adds a feed with the specified information. Expects a JSON block in the + * request body - a Feed object. + * + * @param request + * HttpServletRequest + * @return a JSON object; on success it has a "status" and possibly a "data" + * item; on failure, also has an "error" item. + */ + @RequestMapping(value = { FEED_PATH }, method = RequestMethod.POST, produces = "application/json") + @ResponseBody + public String addDRFeed(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = addItem(request, DmaapDataItem.DR_FEED, null); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Adds a publisher with the specified information. Expects a JSON block in + * the request body - a DR_Pub object. + * + * @param request + * HttpServletRequest + * @return a JSON object; on success it has a "status" and possibly a "data" + * item; on failure, also has an "error" item. + */ + @RequestMapping(value = { PUB_PATH }, method = RequestMethod.POST, produces = "application/json") + @ResponseBody + public String addDRPub(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = addItem(request, DmaapDataItem.DR_PUB, HttpServletResponse.SC_CREATED); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Adds a subscriber with the specified information. Expects a JSON block in + * the request body - a DR_Sub object. + * + * @param request + * HttpServletRequest + * @return a JSON object; on success it has a "status" and possibly a "data" + * item; on failure, also has an "error" item. + */ + @RequestMapping(value = { SUB_PATH }, method = RequestMethod.POST, produces = "application/json") + @ResponseBody + public String addDRSub(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = addItem(request, DmaapDataItem.DR_SUB, HttpServletResponse.SC_CREATED); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Updates a feed with the specified information. Expects a JSON block in + * the request body - a Feed object. + * + * @param id + * Path parameter with object ID + * @param request + * HttpServletRequest + * @return a JSON object; on success it has a "status" and possibly a "data" + * item; on failure, also has an "error" item. + */ + @RequestMapping(value = { FEED_PATH + "/{id}" }, method = RequestMethod.PUT, produces = "application/json") + @ResponseBody + public String updateFeed(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = updateItem(request, DmaapDataItem.DR_FEED, Long.toString(id), null); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Updates a publisher with the specified information. Expects a JSON block + * in the request body - a DR_Pub object. + * + * The pubId may have a dot in it. Spring, in its infinite wisdom, truncates + * extensions on dotted path parameters; e.g., "foo.json" becomes "foo". + * Avoid truncation here with the extra ":.+" incantation at the end. + * + * @param id + * Path parameter with object ID + * @param request + * HttpServletRequest + * @return a JSON object; on success it has a "status" and possibly a "data" + * item; on failure, also has an "error" item. + */ + @RequestMapping(value = { PUB_PATH + "/{id:.+}" }, method = RequestMethod.PUT, produces = "application/json") + @ResponseBody + public String updateDRPub(@PathVariable("id") String id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = updateItem(request, DmaapDataItem.DR_PUB, id, null); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Updates a subscriber with the specified information. Expects a JSON block + * in the request body - a DR_Sub object. + * + * @param id + * Path parameter with object ID + * @param request + * HttpServletRequest + * @return a JSON object; on success it has a "status" and possibly a "data" + * item; on failure, also has an "error" item. + */ + @RequestMapping(value = { SUB_PATH + "/{id}" }, method = RequestMethod.PUT, produces = "application/json") + @ResponseBody + public String updateDRSub(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = updateItem(request, DmaapDataItem.DR_SUB, Long.toString(id), null); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Deletes a feed with the ID specified as a path parameter. On successful + * delete the endpoint returns 204 (confusingly). + * + * @param id + * Path parameter with object ID + * @param request + * HttpServletRequest + * @return A JSON object as an HTTP response; on success it only has + * "status" item; on failure, also has an "error" item. + */ + @RequestMapping(value = { FEED_PATH + "/{id}" }, method = RequestMethod.DELETE, produces = "application/json") + @ResponseBody + public String deleteDRFeed(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = deleteItem(request, DmaapDataItem.DR_FEED, Long.toString(id), 204); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Deletes the publisher with the ID specified as a path parameter. + * + * The pubId may have a dot in it. Spring, in its infinite wisdom, truncates + * extensions on dotted path parameters; e.g., "foo.json" becomes "foo". + * Avoid truncation here with the extra ":.+" incantation at the end. + * + * @param id + * Path parameter with object ID + * @param request + * HttpServletRequest + * @return a JSON object; on success it only has "status" item; on failure, + * also has an "error" item. + */ + @RequestMapping(value = { PUB_PATH + "/{id:.+}" }, method = RequestMethod.DELETE, produces = "application/json") + @ResponseBody + public String deleteDRPub(@PathVariable("id") String id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = deleteItem(request, DmaapDataItem.DR_PUB, id, null); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Deletes the subscriber with the ID specified as a path parameter. + * + * @param id + * Path parameter with object ID + * @param request + * HttpServletRequest + * @return A JSON object; on success it only has "status" item; on failure, + * also has an "error" item. + */ + @RequestMapping(value = { SUB_PATH + "/{id}" }, method = RequestMethod.DELETE, produces = "application/json") + @ResponseBody + public String deleteDRSub(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = deleteItem(request, DmaapDataItem.DR_SUB, Long.toString(id), 204); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Answers a request for data router feed classification labels, such as + * "Customer Proprietary", which are read from properties. + * + * @param request + * HttpServletRequest + * @return List of string values + */ + @RequestMapping(value = { FEED_PATH + "_pii_types" }, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public List<String> getDRFeedPiiType(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + ArrayList<String> response = new ArrayList<>(); + String[] propKeys = appProperties.getCsvListProperty(DbcappProperties.DMAAP_PII_TYPE_LIST); + for (String key : propKeys) + response.add(appProperties.getProperty(key)); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DbcappRestrictedBaseController.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DbcappRestrictedBaseController.java new file mode 100644 index 0000000..7964e45 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DbcappRestrictedBaseController.java @@ -0,0 +1,968 @@ +package org.onap.dcae.dmaapbc.dbcapp.controller; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.dcae.dmaapbc.client.DmaapBcRestClient; +import org.onap.dcae.dmaapbc.client.HttpStatusAndResponse; +import org.onap.dcae.dmaapbc.dbcapp.domain.DmaapAccess; +import org.onap.dcae.dmaapbc.dbcapp.rest.DbcUsvcRestClient; +import org.onap.dcae.dmaapbc.dbcapp.service.DmaapAccessService; +import org.onap.dcae.dmaapbc.dbcapp.util.DbcappProperties; +import org.onap.dcae.dmaapbc.model.DR_Pub; +import org.onap.dcae.dmaapbc.model.DR_Sub; +import org.onap.dcae.dmaapbc.model.DcaeLocation; +import org.onap.dcae.dmaapbc.model.Dmaap; +import org.onap.dcae.dmaapbc.model.DmaapObject; +import org.onap.dcae.dmaapbc.model.ErrorResponse; +import org.onap.dcae.dmaapbc.model.Feed; +import org.onap.dcae.dmaapbc.model.MR_Client; +import org.onap.dcae.dmaapbc.model.Topic; +import org.openecomp.portalsdk.core.controller.RestrictedBaseController; +import org.openecomp.portalsdk.core.domain.User; +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.onboarding.util.CipherUtil; +import org.openecomp.portalsdk.core.web.support.UserUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * This base class provides utility methods to child controllers. All of the + * requests are forwarded on to a remote REST API, so there's a large degree of + * commonality among the implementations. Combining them kept the lines-of-code + * count down, at the expense of some complexity. + */ +public class DbcappRestrictedBaseController extends RestrictedBaseController { + + /** + * Query parameter for desired page number + */ + protected static final String PAGE_NUM_QUERY_PARAM = "pageNum"; + + /** + * Query parameter for desired items per page + */ + protected static final String VIEW_PER_PAGE_QUERY_PARAM = "viewPerPage"; + + /** + * Tag for status code in JSON responses - ALWAYS PRESENT. + */ + protected static final String STATUS_RESPONSE_KEY = "status"; + + /** + * Tag for data in JSON responses. + */ + protected static final String DATA_RESPONSE_KEY = "data"; + + /** + * Tag for error message in JSON responses; absent on success. + */ + protected static final String ERROR_RESPONSE_KEY = "error"; + + /** + * Tag for response integer, pages required to display complete result list + */ + protected static final String TOTAL_PAGES_RESPONSE_KEY = "totalPages"; + + /** + * Tag for DMaaP name obtained from REST client. + */ + protected static final String PROFILE_NAME_RESPONSE_KEY = "profileName"; + + /** + * Tag for DMaaP name obtained from REST client. + */ + protected static final String DMAAP_NAME_RESPONSE_KEY = "dmaapName"; + + /** + * Tag for DCAE location name list obtained from REST client. + */ + protected static final String DCAE_LOCATIONS_RESPONSE_KEY = "dcaeLocations"; + + /** + * Logger that conforms with ECOMP guidelines + */ + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(DbcappRestrictedBaseController.class); + + /** + * For general use in these methods and subclasses + */ + protected final ObjectMapper mapper = new ObjectMapper(); + + /** + * DAO accesses the profiles via a local database. REST accesses the + * profiles via a remote REST service. + */ + public enum AccessMethod { + DAO, REST + }; + + /** + * Enum for selecting an item type. + */ + public enum DmaapDataItem { + DR_FEED, DR_PUB, DR_SUB, MR_TOPIC, MR_CLIENT; + } + + /** + * Application properties - NOT available to constructor. + */ + @Autowired + private DbcappProperties appProperties; + + /** + * Database access - which might not be used. + */ + @Autowired + private DmaapAccessService dmaapAccessDaoServiceAuto; + + /** + * Read from application properties. + */ + private String mechIdName, mechIdPass; + + /** + * This is set by {@link #getDmaapAccessService()} to the DAO or REST + * implementation as configured in properties. + */ + private DmaapAccessService dmaapAccessService; + + /** + * Hello Spring, here's your no-arg constructor. + */ + public DbcappRestrictedBaseController() { + // Do not serialize null values + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + + /** + * Access method for subclasses. + * + * @return DbcappProperties object that was autowired by Spring. + */ + protected DbcappProperties getAppProperties() { + return appProperties; + } + + /** + * Lazy initialization. As a side effect, caches mech ID and password. + * + * @return Either DAO or REST client that implements the access service + * interface. + */ + protected DmaapAccessService getDmaapAccessService() { + if (dmaapAccessService != null) + return dmaapAccessService; + + // Get the application's mechid + mechIdName = appProperties.getProperty(DbcappProperties.DMAAP_MECHID_NAME); + // This is encrypted + String cipher = appProperties.getProperty(DbcappProperties.DMAAP_MECHID_PASSWORD); + if (mechIdName == null || cipher == null) + throw new RuntimeException("Failed to get MECH_ID name and/or password from properties"); + try { + mechIdPass = CipherUtil.decrypt(cipher); + } catch (Exception ex) { + throw new RuntimeException("Failed to decrypt password from config file", ex); + } + + String accessMethod = appProperties.getProperty(DbcappProperties.PROFILE_ACCESS_METHOD); + if (accessMethod == null) + throw new RuntimeException("Failed to get property " + DbcappProperties.PROFILE_ACCESS_METHOD); + AccessMethod profileAccessMethod = AccessMethod.valueOf(accessMethod.toUpperCase()); + if (AccessMethod.DAO == profileAccessMethod) { + // Spring auto-wired this field + dmaapAccessService = dmaapAccessDaoServiceAuto; + } else { + String url = appProperties.getProperty(DbcappProperties.PROFILE_USVC_URL); + String user = appProperties.getProperty(DbcappProperties.PROFILE_USVC_USER); + String pass = appProperties.getProperty(DbcappProperties.PROFILE_USVC_PASS); + if (url == null || user == null || pass == null) + throw new RuntimeException("getDmaapAccessService: missing property: one of url, user, pass"); + String clearText = null; + try { + clearText = CipherUtil.decrypt(pass); + } catch (Exception ex) { + throw new RuntimeException("getDmaapAccessService: failed to decrypt password from config"); + } + dmaapAccessService = new DbcUsvcRestClient(url, user, clearText); + } + return dmaapAccessService; + } + + /** + * Creates a REST client with appropriate credentials, the user/pass from + * the access profile if present, otherwise with the default mech ID and + * password. + * + * @param dmaapAccess + * Profile + * @return REST client. + */ + protected DmaapBcRestClient getDmaapBcRestClient(DmaapAccess dmaapAccess) { + DmaapBcRestClient restClient = null; + if (dmaapAccess.getMechId() == null || dmaapAccess.getMechId().length() == 0) + restClient = new DmaapBcRestClient(dmaapAccess.getDmaapUrl(), mechIdName, mechIdPass); + else + restClient = new DmaapBcRestClient(dmaapAccess.getDmaapUrl(), dmaapAccess.getMechId(), + dmaapAccess.getPassword()); + return restClient; + } + + /** + * Pulls out of the specified list the appropriate items for the page of + * results specified by the page number and view-per-page parameters. + * + * @param pageNum + * Page number requested by user + * @param viewPerPage + * Number of items per page + * @param itemList + * List of items available + * @return List of items to display + */ + @SuppressWarnings("rawtypes") + private static List shrinkListToPage(final int pageNum, final int viewPerPage, final List itemList) { + // user-friendly page numbers index from 1 + int firstIndexOnThisPage = viewPerPage * (pageNum - 1); + int firstIndexOnNextPage = viewPerPage * pageNum; + int fromIndex = firstIndexOnThisPage < itemList.size() ? firstIndexOnThisPage : itemList.size(); + int toIndex = firstIndexOnNextPage < itemList.size() ? firstIndexOnNextPage : itemList.size(); + // answers empty list if from==to + return itemList.subList(fromIndex, toIndex); + } + + /** + * Gets the body of a HTTP request assuming UTF-8 encoding. + * + * @param request + * HttpServletRequest + * @return String version of request body + * @throws IOException + * If the read fails + */ + protected static String getBody(HttpServletRequest request) throws IOException { + StringBuilder stringBuilder = new StringBuilder(); + BufferedReader bufferedReader = null; + try { + InputStream inputStream = request.getInputStream(); + if (inputStream != null) { + bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + char[] charBuffer = new char[512]; + int bytesRead = -1; + while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { + stringBuilder.append(charBuffer, 0, bytesRead); + } + } else { + stringBuilder.append(""); + } + } finally { + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (IOException ex) { + throw ex; + } + } + + } + return stringBuilder.toString(); + } + + /** + * Builds a JSON success response from the specified inputs. + * + * @param statusCode + * e.g., 200 for OK + * @param dataPojo + * Plain old Java object to serialize as JSON; ignored if null. + * @throws JsonProcessingException + * If the POJO cannot be serialized + * @return JSON block with items "status" : 200 and "data" : (data..) + */ + protected String buildJsonSuccess(int statusCode, Object dataPojo) throws JsonProcessingException { + Map<String, Object> model = new HashMap<String, Object>(); + model.put(STATUS_RESPONSE_KEY, statusCode); + if (dataPojo != null) + model.put(DATA_RESPONSE_KEY, dataPojo); + String json = mapper.writeValueAsString(model); + return json; + } + + /** + * Builds a JSON error response from the specified inputs. + * + * @param statusCode + * e.g., 500 for internal server error + * @param errMsg + * Information about the operation that failed + * @param exception + * Converted to string; ignored if null. + * @return JSON block with tags "status" and "error". + */ + protected String buildJsonError(int statusCode, String errMsg, Exception exception) { + Map<String, Object> model = new HashMap<String, Object>(); + model.put(STATUS_RESPONSE_KEY, new Integer(500)); + if (exception == null) { + model.put(ERROR_RESPONSE_KEY, errMsg); + } else { + final int enough = 512; + String exString = exception.toString(); + String exceptionMsg = exString.length() > enough ? exString.substring(0, enough) : exString; + model.put(ERROR_RESPONSE_KEY, errMsg + ": " + exceptionMsg); + } + String json = null; + try { + json = mapper.writeValueAsString(model); + } catch (JsonProcessingException ex) { + // serializing the trivial map should never fail + String err = "buildJsonError: failed to serialize"; + logger.error(EELFLoggerDelegate.errorLogger, err, ex); + throw new RuntimeException(err, ex); + } + return json; + } + + /** + * Gets a list of DMaaP access profiles for this user from the database. The + * profiles have passwords in the clear - this method decrypts the database + * entries. + * + * Initializes the list for new users and/or configuration changes. Checks + * the database list against the configured list of URLs, and creates new + * rows for any configured URLs not present for the user. Most environments + * are expected to have exactly one valid URL, and the webapp uses a fixed + * MechID to authenticate itself to the DMaaP bus controller, so this + * approach means new users can start without any setup of URLs. + * + * @param userId + * User ID + * @return List of DmaapAccess objects + * @throws Exception + * If the URL list is not available in properties + */ + protected List<DmaapAccess> getOrInitDmaapAccessList(String userId) throws Exception { + String[] configUrls = getAppProperties().getCsvListProperty(DbcappProperties.DMAAP_REST_URL_LIST); + if (configUrls == null || configUrls.length == 0) + throw new Exception("getOrInitDmaapAccessList: Failed to get DMAAP REST URL list"); + // Update this list to track which URLs are in the database. + List<String> configUrlList = new ArrayList<String>(configUrls.length); + for (String c : configUrls) { + // Validate URL to detect config botches + URL url = new URL(c); + configUrlList.add(url.toExternalForm()); + } + + List<DmaapAccess> dbAccessList = getDmaapAccessService().getDmaapAccessList(userId); + + // Check the database entries against the configuration. Also + // build a list of non-DAO objects with clear-text passwords. + List<DmaapAccess> clearList = new ArrayList<DmaapAccess>(dbAccessList.size()); + for (DmaapAccess dmaapAccess : dbAccessList) { + // drop this URL from the list. + // If it's not known to config, complain because that's a bogus row. + if (!configUrlList.remove(dmaapAccess.getDmaapUrl())) + logger.warn(EELFLoggerDelegate.errorLogger, "getOrInitDmaapAccessList: detected extra URL {}", + dmaapAccess.getDmaapUrl()); + // Return cleartext in JSON + DmaapAccess clone = new DmaapAccess(dmaapAccess); + clone.setPassword(clone.decryptPassword()); + clearList.add(clone); + } + + // Create new rows for any configured URLs not found for this user. + for (int i = 0; i < configUrlList.size(); ++i) { + String missUrl = configUrlList.get(i); + logger.debug(EELFLoggerDelegate.debugLogger, "getOrInitDmaapAccessList: adding missing URL {}", missUrl); + DmaapAccess newDmaapAccess = new DmaapAccess(); + // Create a semi-reasonable name for the table + newDmaapAccess.setName("dmaap-" + Integer.toString(i + 1)); + newDmaapAccess.setUserId(userId); + newDmaapAccess.setDmaapUrl(missUrl); + // Write to db. + getDmaapAccessService().saveDmaapAccess(newDmaapAccess); + // Add to response, which assumes the write was successful. + clearList.add(newDmaapAccess); + } + + return clearList; + } + + /** + * Gets the user's selected DMaaP access profile. + * + * @param userId + * User ID + * @return DmaapAccess object that is currently selected, or the first one + * found if none are selected; null if no access profiles are + * configured. + * @throws Exception + * If the profile is not found + */ + protected DmaapAccess getSelectedDmaapAccess(String userId) throws Exception { + List<DmaapAccess> profiles = getOrInitDmaapAccessList(userId); + if (profiles.size() == 0) { + logger.debug("getSelectedDmaapAccess: no rows found, returning null"); + return null; + } + + // Return the first one by default if nothing is selected. + DmaapAccess selected = profiles.get(0); + for (DmaapAccess da : profiles) + if (da.getSelected()) + selected = da; + + return selected; + } + + /** + * Supports sorting a list of feeds by the first column displayed: ID + */ + private static Comparator<DmaapObject> feedComparator = new Comparator<DmaapObject>() { + @Override + public int compare(DmaapObject o1, DmaapObject o2) { + Feed f1 = (Feed) o1; + Feed f2 = (Feed) o2; + // sort these numbers lexicographically, same as the front end + // table. + return f1.getFeedId().compareTo(f2.getFeedId()); + } + }; + + /** + * Supports sorting a list of publishers by the first column displayed: pub + * ID + */ + private static Comparator<DmaapObject> pubComparator = new Comparator<DmaapObject>() { + @Override + public int compare(DmaapObject o1, DmaapObject o2) { + DR_Pub p1 = (DR_Pub) o1; + DR_Pub p2 = (DR_Pub) o2; + return p1.getPubId().compareTo(p2.getPubId()); + } + }; + + /** + * Supports sorting a list of subscribers by the first column displayed: sub + * ID + */ + private static Comparator<DmaapObject> subComparator = new Comparator<DmaapObject>() { + @Override + public int compare(DmaapObject o1, DmaapObject o2) { + DR_Sub s1 = (DR_Sub) o1; + DR_Sub s2 = (DR_Sub) o2; + // sort these numbers lexicographically, same as the front end + // table. + return s1.getSubId().compareTo(s2.getSubId()); + } + }; + + /** + * Supports sorting a list of topics by the first column displayed: FQTN + */ + private static Comparator<DmaapObject> topicComparator = new Comparator<DmaapObject>() { + @Override + public int compare(DmaapObject o1, DmaapObject o2) { + Topic t1 = (Topic) o1; + Topic t2 = (Topic) o2; + return t1.getFqtn().compareTo(t2.getFqtn()); + } + }; + + /** + * Supports sorting a list of clients by the first column displayed: client + * ID. + */ + private static Comparator<DmaapObject> clientComparator = new Comparator<DmaapObject>() { + @Override + public int compare(DmaapObject o1, DmaapObject o2) { + MR_Client c1 = (MR_Client) o1; + MR_Client c2 = (MR_Client) o2; + // sort these numbers lexicographically, same as the front end + // table. + return c1.getMrClientId().compareTo(c2.getMrClientId()); + } + }; + + /** + * Gets one page of DMaaP objects and supporting information via the Bus + * Controller REST client. On success, returns a JSON object as String with + * the following tags: + * <UL> + * <LI>status: Integer; HTTP status code 200. + * <LI>dmaapName: String, name returned by the remote DMaaP instance. + * <LI>dcaeLocations: Array of string, locations returned by the remote + * DMaaP instance. + * <LI>data: Array of the desired items; e.g., data router feeds. + * <LI>totalPages: Integer, the number of pages required to display the + * complete list of items using the submitted page size + * </UL> + * + * This duplicates all of {@link #buildJsonSuccess(int, Object)}. + * + * @param dmaapAccess + * Access details for the DMaaP REST API + * @param option + * Specifies which item list type to get: data router feeds, etc. + * @param pageNum + * Page number of results + * @param viewPerPage + * Number of items per page + * @return JSON block as String, see above. + * @throws Exception + * On any error + */ + private String getItemListForPage(DmaapAccess dmaapAccess, DmaapDataItem option, int pageNum, int viewPerPage) + throws Exception { + DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess); + // Get the instance so the page can display its name + DmaapObject dmaap = restClient.getDmaap(); + if (dmaap instanceof ErrorResponse) { + // Bad password is caught here. + ErrorResponse err = (ErrorResponse) dmaap; + throw new Exception(err.getMessage()); + } + // Get locations for editing + List<DmaapObject> dcaeLocations = restClient.getDcaeLocations(); + if (dcaeLocations.size() == 1 && dcaeLocations.get(0) instanceof ErrorResponse) { + // Should never happen - bad password is caught right above - but be + // careful. + ErrorResponse err = (ErrorResponse) dcaeLocations.get(0); + throw new Exception(err.getMessage()); + } + // Pass them back as String array + String[] dcaeLocs = new String[dcaeLocations.size()]; + for (int i = 0; i < dcaeLocs.length; ++i) { + DcaeLocation dcaeLoc = (DcaeLocation) dcaeLocations.get(i); + dcaeLocs[i] = dcaeLoc.getDcaeLocationName(); + } + // Get the requested item list + List<DmaapObject> itemList = null; + switch (option) { + case DR_FEED: + itemList = restClient.getFeeds(); + // size 1 may be error response + if (itemList.size() > 1) + Collections.sort(itemList, feedComparator); + break; + case DR_PUB: + itemList = restClient.getDRPubs(); + // size 1 may be error response + if (itemList.size() > 1) + Collections.sort(itemList, pubComparator); + break; + case DR_SUB: + itemList = restClient.getDRSubs(); + // size 1 may be error response + if (itemList.size() > 1) + Collections.sort(itemList, subComparator); + break; + case MR_TOPIC: + itemList = restClient.getTopics(); + // size 1 may be error response + if (itemList.size() > 1) + Collections.sort(itemList, topicComparator); + break; + case MR_CLIENT: + itemList = restClient.getMRClients(); + // size 1 may be error response + if (itemList.size() > 1) + Collections.sort(itemList, clientComparator); + break; + default: + throw new Exception("getItemListForPage: pgmr error, unimplemented case: " + option.name()); + } + + logger.debug("getItemListForPage: list size is {}", itemList.size()); + int pageCount = (int) Math.ceil((double) itemList.size() / viewPerPage); + @SuppressWarnings("unchecked") + List<DmaapObject> subList = shrinkListToPage(pageNum, viewPerPage, itemList); + itemList = subList; + // Build response here + Map<String, Object> model = new HashMap<String, Object>(); + model.put(STATUS_RESPONSE_KEY, new Integer(200)); + model.put(PROFILE_NAME_RESPONSE_KEY, dmaapAccess.getName()); + model.put(DMAAP_NAME_RESPONSE_KEY, ((Dmaap) dmaap).getDmaapName()); + model.put(DCAE_LOCATIONS_RESPONSE_KEY, dcaeLocs); + model.put(DATA_RESPONSE_KEY, itemList); + model.put(TOTAL_PAGES_RESPONSE_KEY, pageCount); + + // build the response + String outboundJson = null; + try { + outboundJson = mapper.writeValueAsString(model); + } catch (Exception ex) { + // should never happen + logger.error("getItemListForPage: failed to serialize model: ", ex); + throw new Exception("sendItemListForPage", ex); + } + + return outboundJson; + } + + /** + * Gets a page of the specified DMaaP items. This method traps errors and + * constructs an appropriate JSON block if an error happens. + * + * See {@link #getItemListForPage(DmaapAccess, DmaapDataItem, int, int)}. + * + * @param request + * Inbound request + * @param option + * DMaaP item type to get + * @return JSON with list of serialized objects, or an error. + */ + protected String getItemListForPageWrapper(HttpServletRequest request, DmaapDataItem option) { + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("getItemListForPageWrapper: Failed to get Login UID"); + DmaapAccess selected = getSelectedDmaapAccess(appUser.getLoginId()); + if (selected == null) // leap into exception handler + throw new Exception("No DMaaP access profiles are configured."); + int pageNum = Integer.parseInt(request.getParameter(PAGE_NUM_QUERY_PARAM)); + int viewPerPage = Integer.parseInt(request.getParameter(VIEW_PER_PAGE_QUERY_PARAM)); + outboundJson = getItemListForPage(selected, option, pageNum, viewPerPage); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to get DMaaP item type " + option.name(), ex); + } + return outboundJson; + } + + /** + * Adds an item of the specified type with the specified content. Constructs + * an object by deserializing the JSON block, but ignores any ID field that + * is supplied. + * + * On success, returns a JSON block as String with any data returned by the + * REST client. Throws an exception on any failure. + * + * @param dmaapAccess + * Access details for the DMaaP REST API + * @param userId + * The login ID of the user making the request + * @param itemType + * DMaaP item type to add + * @param itemContent + * JSON block to deserialize as an object + * @param scAddlStatus + * HTTP status code 200 is always accepted. If this parameter is + * not null, the value is also considered a valid HTTP status + * code on success; e.g., 204. + * @return JSON object with result of the operation + * @throws Exception + * on any problem + */ + private String addDmaapItem(DmaapAccess dmaapAccess, String userId, DmaapDataItem itemType, String itemContent, + Integer scAddlStatus) throws Exception { + DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess); + HttpStatusAndResponse<Object> hsr = null; + switch (itemType) { + case DR_FEED: + Feed feed = mapper.readValue(itemContent, Feed.class); + logger.debug("addDmaapItem: received feed: {} ", feed); + // Null out any ID to get an auto-generated ID + feed.setFeedId(null); + // Assign the owner to be the webapp user + feed.setOwner(userId); + hsr = restClient.postFeed(feed); + break; + case DR_PUB: + DR_Pub pub = mapper.readValue(itemContent, DR_Pub.class); + logger.debug("addDmaapItem: received pub: {} ", pub); + // Null out any ID to get an auto-generated ID + pub.setPubId(null); + hsr = restClient.postDRPub(pub); + break; + case DR_SUB: + DR_Sub sub = mapper.readValue(itemContent, DR_Sub.class); + logger.debug("addDmaapItem: received sub: {} ", sub); + // Null out any ID to get an auto-generated ID + sub.setSubId(null); + // Assign the owner to be the webapp user + sub.setOwner(userId); + hsr = restClient.postDRSub(sub); + break; + case MR_TOPIC: + Topic topic = mapper.readValue(itemContent, Topic.class); + logger.debug("addDmaapItem: received topic: {} ", topic); + // No ID on topic + topic.setOwner(userId); + hsr = restClient.postTopic(topic); + break; + case MR_CLIENT: + MR_Client client = mapper.readValue(itemContent, MR_Client.class); + logger.debug("addDmaapItem: received client: {} ", client); + client.setMrClientId(null); + hsr = restClient.postMRClient(client); + break; + default: + throw new Exception("addDmaapItem: pgmr error, unimplemented case: " + itemType.name()); + } + + // Build result here + String outboundJson = null; + if (hsr.getStatusCode() == HttpServletResponse.SC_OK + || (scAddlStatus != null && hsr.getStatusCode() == scAddlStatus)) { + outboundJson = buildJsonSuccess(hsr.getStatusCode(), hsr.getResponseString()); + } else { + throw new Exception("Unexpected HTTP response code " + Integer.toString(hsr.getStatusCode()) + + " with content " + hsr.getResponseString()); + } + return outboundJson; + } + + /** + * Adds the specified DMaaP item that is read from the request body. This + * method traps errors and constructs an appropriate JSON block if an error + * happens. + * + * @param request + * Used to obtain user info from the active session + * @param itemType + * DMaaP item type to add + * @param scAddlStatus + * HTTP status code 200 is always accepted. If this parameter is + * not null, the value is also considered a valid HTTP status + * code on success; e.g., 204. + * @return JSON block with success or failure object + */ + protected String addItem(HttpServletRequest request, DmaapDataItem itemType, Integer scAddlStatus) { + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("addDmaapItem: Failed to get Login ID"); + + DmaapAccess access = getSelectedDmaapAccess(appUser.getLoginId()); + if (access == null) // leap into exception handler + throw new Exception("No DMaaP access profiles are configured."); + String jsonContent = getBody(request); + outboundJson = addDmaapItem(access, appUser.getLoginId(), itemType, jsonContent, scAddlStatus); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to add DMaaP item " + itemType.name(), ex); + } + + return outboundJson; + } + + /** + * Updates an item of the specified type with the specified content. + * Constructs an object by deserializing the JSON block. + * + * On success, returns a JSON block as String with any data returned by the + * REST client. Throws an exception on any failure. + * + * @param dmaapAccess + * Access details for the DMaaP REST API + * @param userId + * The Login ID of the user making the request + * @param itemType + * DMaaP item type to update + * @param itemId + * Item identification + * @param itemContent + * JSON block to deserialize as an object + * @param scAddlStatus + * HTTP status code 200 is always accepted. If this parameter is + * not null, the value is also considered a valid HTTP status + * code on success; e.g., 204. + * @return JSON object with result of the operation + * @throws Exception + * on any problem + */ + private String updateDmaapItem(DmaapAccess dmaapAccess, String userId, DmaapDataItem itemType, String itemId, + String itemContent, Integer scAddlStatus) throws Exception { + DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess); + HttpStatusAndResponse<Object> hsr = null; + switch (itemType) { + case DR_FEED: + Feed feed = mapper.readValue(itemContent, Feed.class); + logger.debug("updateDmaapItem: received feed: {} ", feed); + // Ensure the owner is the webapp user + feed.setOwner(userId); + hsr = restClient.putFeed(feed); + break; + case DR_PUB: + DR_Pub pub = mapper.readValue(itemContent, DR_Pub.class); + logger.debug("updateDmaapItem: received pub: {} ", pub); + hsr = restClient.putDRPub(pub); + break; + case DR_SUB: + DR_Sub sub = mapper.readValue(itemContent, DR_Sub.class); + logger.debug("updateDmaapItem: received sub: {} ", sub); + // Ensure the owner is the webapp user + sub.setOwner(userId); + hsr = restClient.putDRSub(sub); + break; + case MR_TOPIC: + Topic topic = mapper.readValue(itemContent, Topic.class); + logger.debug("updateDmaapItem: received topic: {} ", topic); + // Ensure the owner is the webapp user + topic.setOwner(userId); + // DCAE backend may implement PUT someday. + if (true && userId != null) + throw new UnsupportedOperationException("put topic not supported (yet)"); + break; + case MR_CLIENT: + MR_Client client = mapper.readValue(itemContent, MR_Client.class); + logger.debug("updateDmaapItem: received client: {} ", client); + hsr = restClient.putMRClient(client); + break; + default: + throw new Exception("updateDmaapItem: pgmr error, unimplemented case: " + itemType.name()); + } + + // Build result here + String outboundJson = null; + if (hsr.getStatusCode() == HttpServletResponse.SC_OK + || (scAddlStatus != null && hsr.getStatusCode() == scAddlStatus)) { + outboundJson = buildJsonSuccess(hsr.getStatusCode(), hsr.getResponseString()); + } else { + throw new Exception("Unexpected HTTP response code " + Integer.toString(hsr.getStatusCode()) + + " with content " + hsr.getResponseString()); + } + return outboundJson; + } + + /** + * Updates the specified DMaaP item that is read from the request body. This + * method traps errors and constructs an appropriate JSON block if an error + * happens. + * + * @param request + * Used to obtain user info from the active session + * @param itemType + * DMaaP item type to update + * @param itemId + * Item identification to update + * @param scUpdatelStatus + * HTTP status code 200 is always accepted. If this parameter is + * not null, the value is also considered a valid HTTP status + * code on success; e.g., 204. + * @return JSON object with success or error information. + */ + protected String updateItem(HttpServletRequest request, DmaapDataItem itemType, String itemId, + Integer scUpdatelStatus) { + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("updateItem: Failed to get Login ID"); + DmaapAccess access = getSelectedDmaapAccess(appUser.getLoginId()); + if (access == null) // leap into exception handler + throw new Exception("No DMaaP access profiles are configured."); + String jsonContent = getBody(request); + outboundJson = updateDmaapItem(access, appUser.getLoginId(), itemType, itemId, jsonContent, + scUpdatelStatus); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to update DMaaP item " + itemType.name(), ex); + } + + return outboundJson; + } + + /** + * Deletes an item of the specified type with the specified ID. + * + * @param dmaapAccess + * Access details for the DMaaP REST API + * @param itemType + * DMaaP item type to delete + * @param itemId + * Item identification + * @param scAddlStatus + * HTTP status code 200 is always accepted. If this parameter is + * not null, the value is also considered a valid HTTP status + * code on success; e.g., 204. + * @return On success, returns a JSON block as String with any data returned + * by the REST client. + * @throws Exception + * On any failure. + */ + private String deleteDmaapItem(DmaapAccess dmaapAccess, DmaapDataItem itemType, String itemId, Integer scAddlStatus) + throws Exception { + DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess); + HttpStatusAndResponse<Object> hsr = null; + switch (itemType) { + case DR_FEED: + hsr = restClient.deleteFeed(itemId); + break; + case DR_PUB: + hsr = restClient.deleteDRPub(itemId); + break; + case DR_SUB: + hsr = restClient.deleteDRSub(itemId); + break; + case MR_TOPIC: + hsr = restClient.deleteTopic(itemId); + break; + case MR_CLIENT: + hsr = restClient.deleteMRClient(itemId); + break; + default: + throw new Exception("deleteDmaapItem: pgmr error, unimplemented case: " + itemType.name()); + } + + // Build result here + String outboundJson = null; + if (hsr.getStatusCode() == HttpServletResponse.SC_OK + || (scAddlStatus != null && hsr.getStatusCode() == scAddlStatus)) { + outboundJson = buildJsonSuccess(hsr.getStatusCode(), hsr.getResponseString()); + } else { + throw new Exception("Unexpected HTTP response code " + Integer.toString(hsr.getStatusCode()) + + " with content " + hsr.getResponseString()); + } + return outboundJson; + } + + /** + * Deletes the specified DMaaP item. This method traps errors and constructs + * an appropriate JSON block if an error happens. + * + * @param request + * Used to obtain user info from the active session + * @param itemType + * DMaaP item type to delete + * @param itemId + * item ID to delete + * @param scAddlStatus + * HTTP status code 200 is always accepted. If this parameter is + * not null, the value is also considered a valid HTTP status + * code on success; e.g., 204. + * @return JSON object with success or error information. + */ + protected String deleteItem(HttpServletRequest request, DmaapDataItem itemType, String itemId, + Integer scAddlStatus) { + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("deleteItem: Failed to get Login ID"); + DmaapAccess selected = getSelectedDmaapAccess(appUser.getLoginId()); + if (selected == null) // leap into exception handler + throw new Exception("No DMaaP access profiles are configured."); + outboundJson = deleteDmaapItem(selected, itemType, itemId, scAddlStatus); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to delete DMaaP item " + itemType.name() + " ID " + itemId, ex); + } + return outboundJson; + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DmaapAccessController.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DmaapAccessController.java new file mode 100644 index 0000000..bd5c420 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/DmaapAccessController.java @@ -0,0 +1,356 @@ +package org.onap.dcae.dmaapbc.dbcapp.controller; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.dcae.dmaapbc.client.DmaapBcRestClient; +import org.onap.dcae.dmaapbc.dbcapp.domain.DmaapAccess; +import org.onap.dcae.dmaapbc.model.Dmaap; +import org.onap.dcae.dmaapbc.model.DmaapObject; +import org.onap.dcae.dmaapbc.model.ErrorResponse; +import org.openecomp.portalsdk.core.domain.User; +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.util.SystemProperties; +import org.openecomp.portalsdk.core.web.support.UserUtils; +import org.slf4j.MDC; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * DMaaP Access controller: serves Ajax requests made by Angular on pages where + * the user adds, edits and deletes DMaaP access profiles. This controller must + * defend the database against rogue requests including SQL injection attacks. + */ +@Controller +@RequestMapping("/") +public class DmaapAccessController extends DbcappRestrictedBaseController { + + /** + * Logger that conforms with ECOMP guidelines + */ + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(DmaapAccessController.class); + + private static final String DMAAP_ACCESS_PATH = "/dmaap_access"; + private static final String SELECT_DMAAP_ACCESS_PATH = "/select_dmaap_access"; + + /** + * For general use in these methods + */ + private final ObjectMapper mapper; + + /** + * Never forget that Spring autowires fields AFTER the constructor is + * called. + */ + public DmaapAccessController() { + mapper = new ObjectMapper(); + } + + /** + * Gets a list of DMaaP access profiles for this user from the database and + * returns them in a JSON array nested within a response object. Traps errors and constructs an appropriate JSON block if an error + * happens. + * + * See {@link #getOrInitDmaapAccessList(String)}. + * + * @param request + * HttpServletRequest + * @return JSON with access profiles, or an error JSON if the request fails. + */ + @RequestMapping(value = { DMAAP_ACCESS_PATH }, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public String getDmaapAccessList(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("getDmaapAccessList: Failed to get Login ID"); + List<DmaapAccess> dbAccessList = getOrInitDmaapAccessList(appUser.getLoginId()); + // Wrap the list in the status indicator. + Map<String, Object> model = new HashMap<String, Object>(); + model.put(STATUS_RESPONSE_KEY, new Integer(200)); + model.put(DATA_RESPONSE_KEY, dbAccessList); + outboundJson = mapper.writeValueAsString(model); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to get DMaaP access profile list", ex); + } + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return outboundJson; + } + + /** + * Adds a DMaaP access profile for the requesting user ID; ignores any + * values for row ID and user ID in the body. Traps errors and + * constructs an appropriate JSON block if an error happens. + * + * @param request + * HttpServletRequest + * @return Trivial JSON object indicating success or failure. + */ + @RequestMapping(value = { DMAAP_ACCESS_PATH }, method = RequestMethod.POST, produces = "application/json") + @ResponseBody + public String addDmaapAccess(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("addDmaapAccess: Failed to get Login ID"); + + DmaapAccess dmaapAccess = mapper.readValue(request.getReader(), DmaapAccess.class); + logger.debug("addDmaapAccess: received object: {} ", dmaapAccess); + + // Null out ID to get an auto-generated ID + dmaapAccess.setId(null); + // Overwrite any submitted user id + dmaapAccess.setUserId(appUser.getLoginId()); + // Encrypt password + if (dmaapAccess.getPassword() != null) + dmaapAccess.encryptPassword(dmaapAccess.getPassword()); + + // Create a new row + getDmaapAccessService().saveDmaapAccess(dmaapAccess); + + // Answer success + outboundJson = buildJsonSuccess(200, null); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to add DMaaP access profile", ex); + } + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return outboundJson; + } + + /** + * Updates a DMaaP access profile if the row user ID matches the requesting + * user ID. Traps errors and + * constructs an appropriate JSON block if an error happens. + * + * @param id + * Path parameter with ID of the DMaaP access profile + * @param request + * HttpServletRequest + * @return Trivial JSON object indicating success or failure. + */ + @RequestMapping(value = { DMAAP_ACCESS_PATH + "/{id}" }, method = RequestMethod.PUT, produces = "application/json") + @ResponseBody + public String updateDmaapAccess(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("updateDmaapAccess: Failed to get Login ID"); + + DmaapAccess domainObj = getDmaapAccessService().getDmaapAccess(id); + if (!appUser.getLoginId().equals(domainObj.getUserId())) + throw new Exception("updateDmaapAccess: mismatch of appUser and row user ID"); + + DmaapAccess dmaapAccess = mapper.readValue(request.getReader(), DmaapAccess.class); + logger.debug("updateDmaapAccess: received object: {} ", dmaapAccess); + + // Use the path-parameter id; don't trust the one in the object + dmaapAccess.setId(id); + // Encrypt password if present + if (dmaapAccess.getPassword() != null) + dmaapAccess.encryptPassword(dmaapAccess.getPassword()); + + // Update the existing row + getDmaapAccessService().saveDmaapAccess(dmaapAccess); + + // Answer "OK" + outboundJson = buildJsonSuccess(200, null); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to update DMaaP access profile", ex); + } + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return outboundJson; + } + + /** + * Deletes a DMaaP access profile if the row user ID matches the requesting + * user ID. Traps errors and + * constructs an appropriate JSON block if an error happens. + * + * @param id + * Path parameter with ID of the DMaaP access profile + * @param request + * HttpServletRequest + * @return Trivial JSON object indicating success or failure (altho this is + * slightly contrary to conventions for a DELETE method) + */ + @RequestMapping(value = { + DMAAP_ACCESS_PATH + "/{id}" }, method = RequestMethod.DELETE, produces = "application/json") + @ResponseBody + public String deleteDmaapAccess(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("deleteDmaapAccess: Failed to get Login ID"); + // Validate that this user owns the row with the specified ID + DmaapAccess domainObj = getDmaapAccessService().getDmaapAccess(id); + if (!appUser.getLoginId().equals(domainObj.getUserId())) + throw new Exception("deleteDmaapAccess: mismatch of appUser and row user ID"); + + getDmaapAccessService().deleteDmaapAccess(id); + + // Answer "OK" + outboundJson = buildJsonSuccess(200, null); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to delete DMaaP access profile", ex); + } + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return outboundJson; + } + + /** + * Gets the selected DMaaP access row for the requesting user. + * + * See {@link #getSelectedDmaapAccess(String)} + * + * @param request + * HttpServletRequest + * @return JSON object with one DmaapAccessProfile, or an error + */ + @RequestMapping(value = { SELECT_DMAAP_ACCESS_PATH }, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public String getSelectedDmaapAccessProfile(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("getSelectedDmaapAccessProfile: Failed to get Login ID"); + DmaapAccess selected = super.getSelectedDmaapAccess(appUser.getLoginId()); + // clone and decrypt + DmaapAccess clear = new DmaapAccess(selected); + try { + clear.setPassword(clear.decryptPassword()); + } catch (Exception ex) { + // Should never happen + throw new RuntimeException("getSelectedDmaapAccessProfile: Failed to decrypt password", ex); + } + outboundJson = buildJsonSuccess(200, clear); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to get selected DMaaP access profile", ex); + } + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return outboundJson; + } + + /** + * Marks the DMaaP access row as selected (first choice) for the requesting + * user if the row user ID matches the requesting user ID. As a side effect, + * removes selected marking from all other user rows. Returns status, + * additionally an error message on failure. Traps errors and + * constructs an appropriate JSON block if an error happens. + * + * Choice of PUT is fairly arbitrary - there is no body, but GET is for + * actions that do not change data. + * + * @param id + * Path parameter with ID of the DMaaP access profile + * @param request + * HttpServletRequest + * @return Trivial JSON object indicating success or failure. + */ + @RequestMapping(value = { + SELECT_DMAAP_ACCESS_PATH + "/{id}" }, method = RequestMethod.PUT, produces = "application/json") + @ResponseBody + public String selectDmaapAccess(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String outboundJson = null; + try { + User appUser = UserUtils.getUserSession(request); + if (appUser == null || appUser.getLoginId() == null || appUser.getLoginId().length() == 0) + throw new Exception("selectDmaapAccess: Failed to get Login UID"); + // A little inefficient in that it requires 3 database accesses; + // probably could be done in 1 with some sophisticated SQL. + List<DmaapAccess> dmaapAccessList = getDmaapAccessService().getDmaapAccessList(appUser.getLoginId()); + for (DmaapAccess dmaap : dmaapAccessList) { + // Only write out the changed rows. + boolean changed = false; + if (id == dmaap.getId()) { + changed = !dmaap.getSelected(); + dmaap.setSelected(true); + } else { + changed = dmaap.getSelected(); + dmaap.setSelected(false); + } + if (changed) + getDmaapAccessService().saveDmaapAccess(dmaap); + } + + // Answer OK + outboundJson = buildJsonSuccess(200, null); + } catch (Exception ex) { + outboundJson = buildJsonError(500, "Failed to select a DMaaP access profile", ex); + } + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return outboundJson; + } + + /** + * Tests the URL in the DMaaP access profile object. Traps errors and + * constructs an appropriate JSON block if an error happens. + * + * @param request + * HttpServletRequest + * @return JSON with a Dmaap object (which has name etc.) on success, error + * on failure. + */ + @RequestMapping(value = { "test_dmaap_access" }, method = RequestMethod.POST, produces = "application/json") + @ResponseBody + public String testDmaapAccess(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String outboundJson = null; + try { + DmaapAccess dmaapAccess = mapper.readValue(request.getReader(), DmaapAccess.class); + logger.debug("testDmaapAccess: received object: {} ", dmaapAccess); + if (dmaapAccess.getDmaapUrl() == null || dmaapAccess.getDmaapUrl().trim().length() == 0) + throw new Exception("Null or empty URL"); + + DmaapBcRestClient restClient = getDmaapBcRestClient(dmaapAccess); + // Get the instance so the page can display its name + DmaapObject dmaap = restClient.getDmaap(); + if (dmaap instanceof Dmaap) { + outboundJson = buildJsonSuccess(200, dmaap); + } else { + // Bad credentials lands here. + ErrorResponse err = (ErrorResponse) dmaap; + outboundJson = buildJsonError(500, "Test failed: " + err.getMessage(), null); + } + } catch (Exception ex) { + // This is entirely likely; e.e., unknown host exception on typo. + outboundJson = buildJsonError(500, "Invalid DMaaP URL", ex); + } + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return outboundJson; + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/HealthCheckController.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/HealthCheckController.java new file mode 100644 index 0000000..820cd5b --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/HealthCheckController.java @@ -0,0 +1,142 @@ +package org.onap.dcae.dmaapbc.dbcapp.controller; + +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.dcae.dmaapbc.dbcapp.service.DmaapAccessService; +import org.openecomp.portalsdk.core.controller.UnRestrictedBaseController; +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.util.SystemProperties; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * This controller responds to probes for application health, returning a JSON + * body to indicate current status. + */ +@RestController +@Configuration +@EnableAspectJAutoProxy +@RequestMapping("/") +public class HealthCheckController extends UnRestrictedBaseController { + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(HealthCheckController.class); + + private static final String HEALTH_CHECK_PATH = "/healthCheck"; + + @Autowired + private DmaapAccessService dmaapAccessService; + + /** + * Model for JSON response with health-check results. + */ + public class HealthStatus { + // Either 200 or 500 + public int statusCode; + // Additional detail in case of error, empty in case of success. + public String message; + + public HealthStatus(int code, String msg) { + this.statusCode = code; + this.message = msg; + } + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int code) { + this.statusCode = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String msg) { + this.message = msg; + } + } + + /** + * Checks application health by making a trivial query to the database. + * + * @param request + * HttpServletRequest + * @return 200 if database access succeeds, 500 if it fails. + */ + @RequestMapping(value = { HEALTH_CHECK_PATH }, method = RequestMethod.GET, produces = "application/json") + public HealthStatus healthCheck(HttpServletRequest request) { + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + HealthStatus healthStatus = null; + try { + logger.debug(EELFLoggerDelegate.debugLogger, "Performing health check"); + dmaapAccessService.getDmaapAccessCount(); + healthStatus = new HealthStatus(200, "health check succeeded"); + } catch (Exception ex) { + logger.error(EELFLoggerDelegate.errorLogger, "Failed to perform health check", ex); + healthStatus = new HealthStatus(500, "health check failed: " + ex.toString()); + } + return healthStatus; + } + + /** + * This implementation does not support suspend/resume. + * + * @param request + * HttpServletRequest + * @return Trivial success + */ + @RequestMapping(value = { + HEALTH_CHECK_PATH + "/suspend" }, method = RequestMethod.GET, produces = "application/json") + public HealthStatus healthCheckSuspend(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + HealthStatus response = new HealthStatus(200, "suspend not implemented"); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * This implementation does not support suspend/resume. + * + * @param request + * HttpServletRequest + * @return Trivial success + */ + @RequestMapping(value = { + HEALTH_CHECK_PATH + "/resume" }, method = RequestMethod.GET, produces = "application/json") + public HealthStatus healthCheckResume(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + HealthStatus response = new HealthStatus(200, "resume not implemented"); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Answers ping request without checking the application health. + * + * @param request + * HttpServletRequest + * @return Trivial success + */ + @RequestMapping(value = { HEALTH_CHECK_PATH + "/ping" }, method = RequestMethod.GET, produces = "application/json") + public HealthStatus ping(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + HealthStatus response = new HealthStatus(200, "ping received"); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/MessageRouterController.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/MessageRouterController.java new file mode 100644 index 0000000..70bc90a --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/controller/MessageRouterController.java @@ -0,0 +1,207 @@ +package org.onap.dcae.dmaapbc.dbcapp.controller; + +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.util.SystemProperties; +import org.slf4j.MDC; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * Message Router controller: serves Ajax requests made by Angular scripts on + * pages that show topics and clients. + */ +@Controller +@RequestMapping("/") +public class MessageRouterController extends DbcappRestrictedBaseController { + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MessageRouterController.class); + + private static final String TOPIC_PATH = "/mr_topic"; + private static final String CLIENT_PATH = "/mr_client"; + + public MessageRouterController() { + } + + /** + * Answers a request for one page of message router topics. See + * {@link #getItemListForPageWrapper(HttpServletRequest, DmaapDataItem)} + * + * @param request + * HttpServletRequest + * @return One page of MR topics + */ + @RequestMapping(value = { TOPIC_PATH }, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public String getMRTopicsByPage(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = getItemListForPageWrapper(request, DmaapDataItem.MR_TOPIC); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Answers a request for one page of message router clients. See + * {@link #getItemListForPageWrapper(HttpServletRequest, DmaapDataItem)} + * + * @param request + * HttpServletRequest + * @return One page of MR clients + */ + @RequestMapping(value = { CLIENT_PATH }, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public String getMRClientsByPage(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = getItemListForPageWrapper(request, DmaapDataItem.MR_CLIENT); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Adds a topic with the specified information. Expects a JSON block in the + * request body - a Topic object. + * + * @param request + * HttpServletRequest + * @return JSON success/failure response + */ + @RequestMapping(value = { TOPIC_PATH }, method = RequestMethod.POST, produces = "application/json") + @ResponseBody + public String addTopic(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = addItem(request, DmaapDataItem.MR_TOPIC, HttpServletResponse.SC_CREATED); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Adds a client with the specified information. Expects a JSON block in the + * request body - a MR_Client object. + * + * @param request + * HttpServletRequest + * @return JSON success/failure response + */ + @RequestMapping(value = { CLIENT_PATH }, method = RequestMethod.POST, produces = "application/json") + @ResponseBody + public String addMRClient(HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = addItem(request, DmaapDataItem.MR_CLIENT, HttpServletResponse.SC_CREATED); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Updates a topic with the specified information. Expects a JSON block in + * the request body - a Topic object. + * + * Writes a JSON object as an HTTP response; on success it has a "status" + * and possibly a "data" item; on failure, also has an "error" item. + * + * @param id + * ID of the topic to update + * @param request + * HttpServletRequest + * @return JSON success/failure response + */ + @RequestMapping(value = { TOPIC_PATH + "/{id}" }, method = RequestMethod.PUT, produces = "application/json") + @ResponseBody + public String updateTopic(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = updateItem(request, DmaapDataItem.MR_TOPIC, Long.toString(id), null); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Updates a client with the specified information. Expects a JSON block in + * the request body - a MR_Client object. + * + * Writes a JSON object as an HTTP response; on success it has a "status" + * and possibly a "data" item; on failure, also has an "error" item. + * + * @param id + * ID of the client to update + * @param request + * HttpServletRequest + * @return JSON success/failure response + */ + @RequestMapping(value = { CLIENT_PATH + "/{id}" }, method = RequestMethod.PUT, produces = "application/json") + @ResponseBody + public String updateMRClient(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = updateItem(request, DmaapDataItem.MR_CLIENT, Long.toString(id), null); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Deletes a topic with the FQTN ID specified as a path parameter. + * + * FQTN is a string of dot-separated names. Spring, in its infinite wisdom, + * truncates extensions on dotted path parameters; e.g., "foo.json" becomes + * "foo". Avoid truncation here with the extra ":.+" incantation at the end. + * + * Writes a JSON object as an HTTP response; on success it only has "status" + * item; on failure, also has an "error" item. + * + * @param id + * Path parameter with object ID + * @param request + * HttpServletRequest + * @return JSON success/failure response + */ + @RequestMapping(value = { "/mr_topic/{id:.+}" }, method = RequestMethod.DELETE, produces = "application/json") + @ResponseBody + public String deleteTopic(@PathVariable("id") String id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = deleteItem(request, DmaapDataItem.MR_TOPIC, id, 204); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + + /** + * Deletes a client with the mrClientId specified as a path parameter. + * + * Writes a JSON object as an HTTP response; on success it only has "status" + * item; on failure, also has an "error" item. + * + * @param id + * Path parameter with object ID + * @param request + * HttpServletRequest + * @return JSON success/failure response + */ + @RequestMapping(value = { "/mr_client/{id}" }, method = RequestMethod.DELETE, produces = "application/json") + @ResponseBody + public String deleteMRClient(@PathVariable("id") long id, HttpServletRequest request) { + MDC.put(SystemProperties.AUDITLOG_BEGIN_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.setRequestBasedDefaultsIntoGlobalLoggingContext(request, DataBusHomeController.APP_NAME); + String response = deleteItem(request, DmaapDataItem.MR_CLIENT, Long.toString(id), null); + MDC.put(SystemProperties.AUDITLOG_END_TIMESTAMP, DataBusHomeController.logDateFormat.format(new Date())); + logger.info(EELFLoggerDelegate.auditLogger, request.getMethod() + request.getRequestURI()); + return response; + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/domain/DmaapAccess.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/domain/DmaapAccess.java new file mode 100644 index 0000000..31b0fdd --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/domain/DmaapAccess.java @@ -0,0 +1,152 @@ +package org.onap.dcae.dmaapbc.dbcapp.domain; + +import org.openecomp.portalsdk.core.domain.support.DomainVo; +import org.openecomp.portalsdk.core.onboarding.util.CipherUtil; + +/** + * Hold an access profile for a DMaaP REST endpoint. Represents one row in the + * DBCA_DMAAP table. + */ +public class DmaapAccess extends DomainVo { + + private static final long serialVersionUID = 6443219375733216340L; + + // parent class defines these fields: + // ID, created, modified, created_id, modified_id + + /** Login ID for user who owns this row */ + private String userId; + /** Nickname for this row */ + private String name; + /** REST API endpoint */ + private String dmaapUrl; + /** Credentials */ + private String mechId; + /** Credentials */ + private String password; + /** User's preferred access profile */ + private boolean selected; + + /** + * Standard POJO no-arg constructor + */ + public DmaapAccess() { + } + + /** + * Copy constructor + * + * @param copy + * Instance to copy + */ + public DmaapAccess(final DmaapAccess copy) { + // Unfortunately DomainVo doesn't provide a copy constructor; + // only the ID field is needed. + this.id = copy.id; + // Our fields + this.userId = copy.userId; + this.name = copy.name; + this.dmaapUrl = copy.dmaapUrl; + this.mechId = copy.mechId; + this.password = copy.password; + this.selected = copy.selected; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDmaapUrl() { + return dmaapUrl; + } + + public void setDmaapUrl(String dmaapUrl) { + this.dmaapUrl = dmaapUrl; + } + + public String getMechId() { + return mechId; + } + + public void setMechId(String mechId) { + this.mechId = mechId; + } + + /** + * Gets the encrypted password. Applications should use + * {@link #decryptPassword()}! + * + * @return The encrypted password + */ + public String getPassword() { + return password; + } + + /** + * Sets the encrypted password. Applications should use + * {@link #encryptPassword(String)}! + * + * @param password + * The encrypted password + */ + public void setPassword(String password) { + this.password = password; + } + + public boolean getSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + /** + * A getter that decrypts the value read from the database and returns the + * clear text. Has no side effects. + * + * @return Clear-text password. + * @throws Exception + * If the password cannot be decrypted + */ + public String decryptPassword() throws Exception { + if (password == null) + return null; + return CipherUtil.decrypt(password); + } + + /** + * A setter that encrypts the clear-text in preparation for storing in the + * database. + * + * @param clearText + * The clear-text password to be encrypted + * @throws Exception + * If the password cannot be encrypted + */ + public void encryptPassword(String clearText) throws Exception { + if (clearText == null) { + password = null; + return; + } + password = CipherUtil.encrypt(clearText); + } + + @Override + public String toString() { + return "DmaapAccess[id=" + id + ", url=" + dmaapUrl + ", ...]"; + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/domain/ManifestTransportModel.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/domain/ManifestTransportModel.java new file mode 100644 index 0000000..24ba1ff --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/domain/ManifestTransportModel.java @@ -0,0 +1,32 @@ +package org.onap.dcae.dmaapbc.dbcapp.domain; + +import java.util.Map; + +/** + * Holds a set of String key-value pairs, the JSON version of a + * java.util.Attributes object read from a jar/war file. + */ +public class ManifestTransportModel { + + private Map<String, String> manifest; + + /** + * Standard POJO no-arg constructor + */ + public ManifestTransportModel() { + } + + public Map<String, String> getManifest() { + return manifest; + } + + public void setManifest(Map<String, String> manifest) { + this.manifest = manifest; + } + + @Override + public String toString() { + return "Manifest[size=" + manifest.size() + "]"; + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/DbcUsvcRestClient.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/DbcUsvcRestClient.java new file mode 100644 index 0000000..b252858 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/DbcUsvcRestClient.java @@ -0,0 +1,182 @@ +package org.onap.dcae.dmaapbc.dbcapp.rest; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.onap.dcae.dmaapbc.dbcapp.domain.DmaapAccess; +import org.onap.dcae.dmaapbc.dbcapp.domain.ManifestTransportModel; +import org.onap.dcae.dmaapbc.dbcapp.service.DmaapAccessService; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +/** + * Provides methods for accessing the DBC microservice via REST using basic HTTP + * authentication. + * + */ +public class DbcUsvcRestClient implements DmaapAccessService { + + public static final String endpointPath = "/dmaap_access"; + private final String baseUrl; + private final RestTemplate restTemplate; + + /** + * Builds a restTemplate that uses basic HTTP authentication for use by all + * methods in this class. + * + * @param webapiUrl + * URL of the web endpoint + * @param user + * user name + * @param pass + * password + */ + public DbcUsvcRestClient(String webapiUrl, String user, String pass) { + if (webapiUrl == null || user == null || pass == null) + throw new IllegalArgumentException("Nulls not permitted"); + + baseUrl = webapiUrl; + URL url = null; + try { + url = new URL(baseUrl); + } catch (MalformedURLException ex) { + throw new RuntimeException("Failed to parse URL", ex); + } + final HttpHost httpHost = new HttpHost(url.getHost(), url.getPort()); + + // Build a client with a credentials provider + CredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials(new AuthScope(httpHost), new UsernamePasswordCredentials(user, pass)); + HttpClientBuilder clientBuilder = HttpClientBuilder.create(); + CloseableHttpClient httpClient = clientBuilder.setDefaultCredentialsProvider(credsProvider).build(); + + // Create request factory with our superpower client + HttpComponentsClientHttpRequestFactoryBasicAuth requestFactory = new HttpComponentsClientHttpRequestFactoryBasicAuth( + httpHost); + requestFactory.setHttpClient(httpClient); + + // Put the factory in the template + this.restTemplate = new RestTemplate(); + restTemplate.setRequestFactory(requestFactory); + } + + /** + * Gets the manifest from the micro service. + */ + @Override + public ManifestTransportModel getManifest() { + String url = baseUrl + "/manifest"; + ResponseEntity<ManifestTransportModel> daResponse = restTemplate.exchange(url, HttpMethod.GET, null, + ManifestTransportModel.class); + ManifestTransportModel response = daResponse.getBody(); + return response; + } + + /** + * Gets the count of DMaaP access profiles. + * + * @return Number of access profiles in the database. + */ + public int getDmaapAccessCount() { + String url = baseUrl + "/count_dmaap_access"; + ResponseEntity<DbcUsvcRestResponse> daResponse = restTemplate.exchange(url, HttpMethod.GET, null, + DbcUsvcRestResponse.class); + DbcUsvcRestResponse response = daResponse.getBody(); + return response.getStatus(); + } + + /** + * Gets the DMaaP access profiles for the specified userId. + * + * @param userId + * User ID + * @return List of access profiles + */ + @Override + public List<DmaapAccess> getDmaapAccessList(final String userId) { + String url = baseUrl + endpointPath + "?userId=" + userId; + ResponseEntity<List<DmaapAccess>> daResponse = restTemplate.exchange(url, HttpMethod.GET, null, + new ParameterizedTypeReference<List<DmaapAccess>>() { + }); + List<DmaapAccess> daList = daResponse.getBody(); + return daList; + } + + /** + * Gets the specified DMaaP access profile. + */ + @Override + public DmaapAccess getDmaapAccess(Long dmaapId) { + String url = baseUrl + endpointPath + "?dmaapId=" + dmaapId; + ResponseEntity<DmaapAccess> daResponse = restTemplate.exchange(url, HttpMethod.GET, null, + new ParameterizedTypeReference<DmaapAccess>() { + }); + DmaapAccess da = daResponse.getBody(); + return da; + } + + /** + * POSTs or PUTs the DMaaP access profile as needed, based on whether the + * object's ID field is set. If not set it creates a new row; if set, it + * updates a row in the remote service table. + * + * @param dmaapAccess + * Access profile + */ + @Override + public void saveDmaapAccess(final DmaapAccess dmaapAccess) { + if (dmaapAccess.getId() == null) { + String url = baseUrl + endpointPath; + restTemplate.postForObject(url, dmaapAccess, String.class); + } else { + String url = baseUrl + endpointPath + "/" + Long.toString(dmaapAccess.getId()); + restTemplate.put(url, dmaapAccess); + } + } + + /** + * Deletes the DMaaP access profile row in the remote service table with the + * specified id. + * + * @param id + * Access profile ID + */ + @Override + public void deleteDmaapAccess(final Long id) { + String url = baseUrl + endpointPath + "/" + Long.toString(id); + restTemplate.delete(url); + } + + /** + * Simple test + * + * @param args + * UserID + * @throws Exception + * On any failure + */ + public static void main(String[] args) throws Exception { + if (args.length != 1) + throw new IllegalArgumentException("Single argument expected: userid"); + DbcUsvcRestClient client = new DbcUsvcRestClient("http://localhost:8081/dbus", "dbus_user", "dbus_pass"); + final String userId = args[0]; + System.out.println("Requesting profiles for user " + userId); + List<DmaapAccess> access = client.getDmaapAccessList(userId); + if (access == null) + System.err.println("Received null"); + else + for (DmaapAccess da : access) + System.out.println(da); + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/DbcUsvcRestResponse.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/DbcUsvcRestResponse.java new file mode 100644 index 0000000..e9284a6 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/DbcUsvcRestResponse.java @@ -0,0 +1,42 @@ +package org.onap.dcae.dmaapbc.dbcapp.rest; + +/** + * Models the responses sent by the micro service in JSON format. + */ +public class DbcUsvcRestResponse { + + private int status; + private String data, error, exception; + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getException() { + return exception; + } + + public void setException(String exception) { + this.exception = exception; + } +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/HttpComponentsClientHttpRequestFactoryBasicAuth.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/HttpComponentsClientHttpRequestFactoryBasicAuth.java new file mode 100644 index 0000000..14ddd93 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/rest/HttpComponentsClientHttpRequestFactoryBasicAuth.java @@ -0,0 +1,46 @@ +package org.onap.dcae.dmaapbc.dbcapp.rest; + +import java.net.URI; + +import org.apache.http.HttpHost; +import org.apache.http.client.AuthCache; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; +import org.springframework.http.HttpMethod; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; + +/** + * Utility class to enable Basic HTTP Authentication with Spring REST templates. + * + * From: + * http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1/ + */ +public class HttpComponentsClientHttpRequestFactoryBasicAuth extends HttpComponentsClientHttpRequestFactory { + + private HttpHost host; + + public HttpComponentsClientHttpRequestFactoryBasicAuth(HttpHost host) { + super(); + this.host = host; + } + + protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) { + return createHttpContext(); + } + + private HttpContext createHttpContext() { + // Create AuthCache instance + AuthCache authCache = new BasicAuthCache(); + // Generate BASIC scheme object and add it to the local auth cache + BasicScheme basicAuth = new BasicScheme(); + authCache.put(host, basicAuth); + + // Add AuthCache to the execution context + BasicHttpContext localcontext = new BasicHttpContext(); + localcontext.setAttribute(HttpClientContext.AUTH_CACHE, authCache); + return localcontext; + } +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/service/DmaapAccessService.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/service/DmaapAccessService.java new file mode 100644 index 0000000..38124a2 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/service/DmaapAccessService.java @@ -0,0 +1,63 @@ +package org.onap.dcae.dmaapbc.dbcapp.service; + +import java.util.List; + +import org.onap.dcae.dmaapbc.dbcapp.domain.DmaapAccess; +import org.onap.dcae.dmaapbc.dbcapp.domain.ManifestTransportModel; + +/** + * Defines methods to manipulate the database table with DmaapAccess domain + * objects. No method throws a checked exception, in keeping with the Spring + * philosophy of throwing unchecked exceptions. + */ +public interface DmaapAccessService { + + /** + * Gets build information. + * + * @return List of key-value pairs; implementations may return null. + */ + ManifestTransportModel getManifest(); + + /** + * Gets the number of Dmaap Access entries. + * + * @return Number of rows in the table. + */ + int getDmaapAccessCount(); + + /** + * Gets all DMaaP access rows in the table for the specified user. + * + * @param userId + * Login ID of the user + * @return List of DMaaP instance objects, which may be empty. + */ + List<DmaapAccess> getDmaapAccessList(String userId); + + /** + * Gets the DMaaP access object with the specified row ID. + * + * @param dmaapId + * Access profile ID + * @return DMaap instance; null if none exists. + */ + DmaapAccess getDmaapAccess(Long dmaapId); + + /** + * Creates a new managed object (a new row in the table). + * + * @param dmaap + * DMaaP instance to create. + */ + void saveDmaapAccess(DmaapAccess dmaap); + + /** + * Deletes the DMaaP access row with the specified ID. + * + * @param dmaapId + * Access profile ID + */ + void deleteDmaapAccess(Long dmaapId); + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/service/DmaapAccessServiceImpl.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/service/DmaapAccessServiceImpl.java new file mode 100644 index 0000000..96fb152 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/service/DmaapAccessServiceImpl.java @@ -0,0 +1,97 @@ +package org.onap.dcae.dmaapbc.dbcapp.service; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.Restrictions; +import org.onap.dcae.dmaapbc.dbcapp.domain.DmaapAccess; +import org.onap.dcae.dmaapbc.dbcapp.domain.ManifestTransportModel; +import org.openecomp.portalsdk.core.service.DataAccessService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * Hibernate-assisted methods to manipulate the DBCA_DMAAP table. + */ +@Service("dmaapAccessService") +@Transactional +public class DmaapAccessServiceImpl implements DmaapAccessService { + + @Autowired + private DataAccessService dataAccessService; + + public DataAccessService getDataAccessService() { + return dataAccessService; + } + + public void setDataAccessService(DataAccessService dataAccessService) { + this.dataAccessService = dataAccessService; + } + + /* + * (non-Javadoc) + * @see org.onap.dmaapbc.dbcapp.service.DmaapAccessService#getManifest() + */ + @Override + public ManifestTransportModel getManifest() { + return null; + } + + /* + * (non-Javadoc) + * @see org.onap.dmaapbc.dbcapp.service.DmaapAccessService#getDmaapAccessCount() + */ + @SuppressWarnings("unchecked") + @Override + public int getDmaapAccessCount() { + List<DmaapAccess> accesses = (List<DmaapAccess>) getDataAccessService().getList(DmaapAccess.class, null); + return accesses.size(); + } + + /* + * (non-Javadoc) + * @see org.onap.dmaapbc.dbcapp.service.DmaapAccessService#getDmaapAccessList(java.lang.String) + */ + @SuppressWarnings("unchecked") + @Override + public List<DmaapAccess> getDmaapAccessList(String userId) { + List<Criterion> restrictionsList = new ArrayList<Criterion>(); + Criterion criterion1 = Restrictions.eq("userId", userId); + restrictionsList.add(criterion1); + List<DmaapAccess> accesses = (List<DmaapAccess>) getDataAccessService().getList(DmaapAccess.class, null, + restrictionsList, null); + return accesses; + } + + /* + * (non-Javadoc) + * @see org.onap.dmaapbc.dbcapp.service.DmaapAccessService#getDmaapAccess(java.lang.Long) + */ + @Override + public DmaapAccess getDmaapAccess(Long dmaapId) { + return (DmaapAccess) getDataAccessService().getDomainObject(DmaapAccess.class, dmaapId, null); + } + + /* + * (non-Javadoc) + * @see org.onap.dmaapbc.dbcapp.service.DmaapAccessService#saveDmaapAccess(org.onap.dmaapbc.dbcapp.domain.DmaapAccess) + */ + @Override + public void saveDmaapAccess(DmaapAccess dmaap) { + getDataAccessService().saveDomainObject(dmaap, null); + } + + /* + * (non-Javadoc) + * @see org.onap.dmaapbc.dbcapp.service.DmaapAccessService#deleteDmaapAccess(java.lang.Long) + */ + @Override + public void deleteDmaapAccess(Long dmaapId) { + DmaapAccess dmaapAccess = getDmaapAccess(dmaapId); + if (dmaapAccess != null) + getDataAccessService().deleteDomainObject(dmaapAccess, null); + } + +} diff --git a/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/util/DbcappProperties.java b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/util/DbcappProperties.java new file mode 100644 index 0000000..c6db620 --- /dev/null +++ b/dcae_dmaapbc_webapp/dbca-common/src/main/java/org/onap/dcae/dmaapbc/dbcapp/util/DbcappProperties.java @@ -0,0 +1,71 @@ +package org.onap.dcae.dmaapbc.dbcapp.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; + +/** + * Publishes a list of constants and methods to access the properties that are + * read by Spring from the specified configuration file(s). + * + * Should be used like this (and never in a constructor): + * + * <pre> + * @Autowired + * DbcappProperties properties; + * </pre> + */ +@Configuration +@PropertySource(value = { "${container.classpath:}/WEB-INF/dbcapp/dbcapp.properties" }) +public class DbcappProperties { + + public static final String DMAAP_REST_URL_LIST = "dmaap.rest.url.list"; + public static final String DMAAP_MECHID_NAME = "dmaap.mechid.name"; + public static final String DMAAP_MECHID_PASSWORD = "dmaap.mechid.password"; + public static final String PROFILE_ACCESS_METHOD = "profile.access.method"; + public static final String PROFILE_USVC_URL = "profile.microservice.url"; + public static final String PROFILE_USVC_USER = "profile.microservice.user.name"; + public static final String PROFILE_USVC_PASS = "profile.microservice.user.password"; + public static final String DMAAP_PII_TYPE_LIST = "dmaap.pii.type.list"; + + private Environment environment; + + public DbcappProperties() { + } + + protected Environment getEnvironment() { + return environment; + } + + @Autowired + public void setEnvironment(final Environment environment) { + this.environment = environment; + } + + public boolean containsProperty(String key) { + return environment.containsProperty(key); + } + + public String getProperty(String key) { + return environment.getRequiredProperty(key); + } + + /** + * Gets the values for a comma-separated list property value as a String + * array. + * + * @param key + * Property key + * @return Array of values with leading and trailing whitespace removed; + * null if key is not found. + */ + public String[] getCsvListProperty(final String key) { + String listVal = getProperty(key); + if (listVal == null) + return null; + String[] vals = listVal.split("\\s*,\\s*"); + return vals; + } + +} |