- response.setStatus(HttpServletResponse.SC_NO_CONTENT);
- loggingContext.metricStarted();
- notifyAC();
- loggingContext.metricEnded();
- PolicyLogger.metrics("XACMLPapServlet doACPut notifyAC");
- // notify any PDPs in the removed set that their config may have changed
- for (OnapPDP pdp : movedPDPs) {
- pdpChanged(pdp, loggingContext);
- }
- loggingContext.metricStarted();
- removePdpOrGroupTransaction.commitTransaction();
- loggingContext.metricEnded();
- PolicyLogger.metrics("XACMLPapServlet doACPut commitTransaction");
- loggingContext.transactionEnded();
- auditLogger.info("Success");
- PolicyLogger.audit("Transaction Ended Successfully");
- return;
- }
- } catch (PAPException e) {
- removePdpOrGroupTransaction.rollbackTransaction();
- PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "XACMLPapServlet", " AC DELETE exception");
- loggingContext.transactionEnded();
- PolicyLogger.audit("Transaction Failed - See Error.log");
- setResponseError(response,HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
- return;
- }
- }
-
- /**
- * Heartbeat thread - periodically check on PDPs' status
- *
- * Heartbeat with all known PDPs.
- *
- * Implementation note:
- *
- * The PDPs are contacted Sequentially, not in Parallel.
- *
- * If we did this in parallel using multiple threads we would simultaneously use
- * - 1 thread and
- * - 1 connection
- * for EACH PDP.
- * This could become a resource problem since we already use multiple threads and connections for updating the PDPs
- * when user changes occur.
- * Using separate threads can also make it tricky dealing with timeouts on PDPs that are non-responsive.
- *
- * The Sequential operation does a heartbeat request to each PDP one at a time.
- * This has the flaw that any PDPs that do not respond will hold up the entire heartbeat sequence until they timeout.
- * If there are a lot of non-responsive PDPs and the timeout is large-ish (the default is 20 seconds)
- * it could take a long time to cycle through all of the PDPs.
- * That means that this may not notice a PDP being down in a predictable time.
- */
- private class Heartbeat implements Runnable {
- private PAPPolicyEngine papEngine;
- private Set<OnapPDP> pdps = new HashSet<>();
- private int heartbeatInterval;
- private int heartbeatTimeout;
-
- public volatile boolean isRunning = false;
-
- public synchronized boolean isRunning() {
- return this.isRunning;
- }
-
- public synchronized void terminate() {
- this.isRunning = false;
- }
-
- public Heartbeat(PAPPolicyEngine papEngine2) {
- papEngine = papEngine2;
- this.heartbeatInterval = Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_HEARTBEAT_INTERVAL, "10000"));
- this.heartbeatTimeout = Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_HEARTBEAT_TIMEOUT, "10000"));
- }
-
- @Override
- public void run() {
- // Set ourselves as running
- synchronized(this) {
- this.isRunning = true;
- }
- HashMap<String, URL> idToURLMap = new HashMap<>();
- try {
- while (this.isRunning()) {
- // Wait the given time
- Thread.sleep(heartbeatInterval);
- // get the list of PDPs (may have changed since last time)
- pdps.clear();
- synchronized(papEngine) {
- try {
- for (OnapPDPGroup g : papEngine.getOnapPDPGroups()) {
- for (OnapPDP p : g.getOnapPdps()) {
- pdps.add(p);
- }
- }
- } catch (PAPException e) {
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", "Heartbeat unable to read PDPs from PAPEngine");
- }
- }
- // Check for shutdown
- if (this.isRunning() == false) {
- LOGGER.info("isRunning is false, getting out of loop.");
- break;
- }
- // try to get the summary status from each PDP
- boolean changeSeen = false;
- for (OnapPDP pdp : pdps) {
- // Check for shutdown
- if (this.isRunning() == false) {
- LOGGER.info("isRunning is false, getting out of loop.");
- break;
- }
- // the id of the PDP is its url (though we add a query parameter)
- URL pdpURL = idToURLMap.get(pdp.getId());
- if (pdpURL == null) {
- // haven't seen this PDP before
- String fullURLString = null;
- try {
- // Check PDP ID
- if(CheckPDP.validateID(pdp.getId())){
- fullURLString = pdp.getId() + "?type=hb";
- pdpURL = new URL(fullURLString);
- idToURLMap.put(pdp.getId(), pdpURL);
- }
- } catch (MalformedURLException e) {
- PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPapServlet", " PDP id '" + fullURLString + "' is not a valid URL");
- continue;
- }
- }
- // Do a GET with type HeartBeat
- String newStatus = "";
- HttpURLConnection connection = null;
- try {
- // Open up the connection
- if(pdpURL != null){
- connection = (HttpURLConnection)pdpURL.openConnection();
- // Setup our method and headers
- connection.setRequestMethod("GET");
- connection.setConnectTimeout(heartbeatTimeout);
- // Authentication
- String encoding = CheckPDP.getEncoding(pdp.getId());
- if(encoding !=null){
- connection.setRequestProperty("Authorization", "Basic " + encoding);
- }
- // Do the connect
- connection.connect();
- if (connection.getResponseCode() == 204) {
- newStatus = connection.getHeaderField(XACMLRestProperties.PROP_PDP_HTTP_HEADER_HB);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Heartbeat '" + pdp.getId() + "' status='" + newStatus + "'");
- }
- } else {
- // anything else is an unexpected result
- newStatus = PDPStatus.Status.UNKNOWN.toString();
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR + " Heartbeat connect response code " + connection.getResponseCode() + ": " + pdp.getId());
- }
- }
- } catch (UnknownHostException e) {
- newStatus = PDPStatus.Status.NO_SUCH_HOST.toString();
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " Heartbeat '" + pdp.getId() + "' NO_SUCH_HOST");
- } catch (SocketTimeoutException e) {
- newStatus = PDPStatus.Status.CANNOT_CONNECT.toString();
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " Heartbeat '" + pdp.getId() + "' connection timeout");
- } catch (ConnectException e) {
- newStatus = PDPStatus.Status.CANNOT_CONNECT.toString();
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " Heartbeat '" + pdp.getId() + "' cannot connect");
- } catch (Exception e) {
- newStatus = PDPStatus.Status.UNKNOWN.toString();
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", "Heartbeat '" + pdp.getId() + "' connect exception");
- } finally {
- // cleanup the connection
- if(connection != null)
- connection.disconnect();
- }
- if ( ! pdp.getStatus().getStatus().toString().equals(newStatus)) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("previous status='" + pdp.getStatus().getStatus()+"' new Status='" + newStatus + "'");
- }
- try {
- setPDPSummaryStatus(pdp, newStatus);
- } catch (PAPException e) {
- PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "XACMLPapServlet", "Unable to set state for PDP '" + pdp.getId());
- }
- changeSeen = true;
- }
- }
- // Check for shutdown
- if (this.isRunning() == false) {
- LOGGER.info("isRunning is false, getting out of loop.");
- break;
- }
- // if any of the PDPs changed state, tell the ACs to update
- if (changeSeen) {
- notifyAC();
- }
- }
- } catch (InterruptedException e) {
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR + " Heartbeat interrupted. Shutting down");
- this.terminate();
- Thread.currentThread().interrupt();
- }
- }
- }
-
- /*
- * HELPER to change Group status when PDP status is changed
- * (Must NOT be called from a method that is synchronized on the papEngine or it may deadlock)
- */
- private void setPDPSummaryStatus(OnapPDP pdp, PDPStatus.Status newStatus) throws PAPException {
- setPDPSummaryStatus(pdp, newStatus.toString());
- }
-
- private void setPDPSummaryStatus(OnapPDP pdp, String newStatus) throws PAPException {
- synchronized(papEngine) {
- StdPDPStatus status = new StdPDPStatus();
- status.setStatus(PDPStatus.Status.valueOf(newStatus));
- ((StdPDP)pdp).setStatus(status);
- // now adjust the group
- StdPDPGroup group = (StdPDPGroup)papEngine.getPDPGroup((OnapPDP) pdp);
- // if the PDP was just deleted it may transiently exist but not be in a group
- if (group != null) {
- group.resetStatus();
- }
- }
- }
-
- /*
- * Callback methods telling this servlet to notify PDPs of changes made by the PAP StdEngine
- * in the PDP group directories
- */
- @Override
- public void changed() {
- // all PDPs in all groups need to be updated/sync'd
- Set<OnapPDPGroup> groups;
- try {
- groups = papEngine.getOnapPDPGroups();
- } catch (PAPException e) {
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " getPDPGroups failed");
- throw new IllegalAccessError(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Unable to get Groups: " + e);
- }
- for (OnapPDPGroup group : groups) {
- groupChanged(group);
- }
- }
-
- public void changed(ONAPLoggingContext loggingContext) {
- // all PDPs in all groups need to be updated/sync'd
- Set<OnapPDPGroup> groups;
- try {
- groups = papEngine.getOnapPDPGroups();
- } catch (PAPException e) {
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " getPDPGroups failed");
- throw new IllegalAccessError(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Unable to get Groups: " + e);
- }
- for (OnapPDPGroup group : groups) {
- groupChanged(group, loggingContext);
- }
- }
-
- @Override
- public void groupChanged(OnapPDPGroup group) {
- // all PDPs within one group need to be updated/sync'd
- for (OnapPDP pdp : group.getOnapPdps()) {
- pdpChanged(pdp);
- }
- }
-
- public void groupChanged(OnapPDPGroup group, ONAPLoggingContext loggingContext) {
- // all PDPs within one group need to be updated/sync'd
- for (OnapPDP pdp : group.getOnapPdps()) {
- pdpChanged(pdp, loggingContext);
- }
- }
-
- @Override
- public void pdpChanged(OnapPDP pdp) {
- // kick off a thread to do an event notification for each PDP.
- // This needs to be on a separate thread so that PDPs that do not respond (down, non-existent, etc)
- // do not block the PSP response to the AC, which would freeze the GUI until all PDPs sequentially respond or time-out.
- Thread t = new Thread(new UpdatePDPThread(pdp));
- if(CheckPDP.validateID(pdp.getId())){
- t.start();
- }
- }
-
- public void pdpChanged(OnapPDP pdp, ONAPLoggingContext loggingContext) {
- // kick off a thread to do an event notification for each PDP.
- // This needs to be on a separate thread so that PDPs that do not respond (down, non-existent, etc)
- // do not block the PSP response to the AC, which would freeze the GUI until all PDPs sequentially respond or time-out.
- Thread t = new Thread(new UpdatePDPThread(pdp, loggingContext));
- if(CheckPDP.validateID(pdp.getId())){
- t.start();
- }
- }
-
- private class UpdatePDPThread implements Runnable {
- private OnapPDP pdp;
- private String requestId;
- private ONAPLoggingContext loggingContext;
-
- public UpdatePDPThread(OnapPDP pdp) {
- this.pdp = pdp;
- }
-
- public UpdatePDPThread(OnapPDP pdp, ONAPLoggingContext loggingContext) {
- this.pdp = pdp;
- if ((loggingContext != null) && (loggingContext.getRequestID() != null || loggingContext.getRequestID() == "")) {
- this.requestId = loggingContext.getRequestID();
- }
- this.loggingContext = loggingContext;
- }
-
- public void run() {
- // send the current configuration to one PDP
- HttpURLConnection connection = null;
- // get a new logging context for the thread
- try {
- if (this.loggingContext == null) {
- loggingContext = new ONAPLoggingContext(baseLoggingContext);
- }
- } catch (Exception e) {
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " Failed to send property file to " + pdp.getId());
- // Since this is a server-side error, it probably does not reflect a problem on the client,
- // so do not change the PDP status.
- return;
- }
- try {
- loggingContext.setServiceName("PAP:PDP.putConfig");
- // If a requestId was provided, use it, otherwise generate one; post to loggingContext to be used later when calling PDP
- if ((requestId == null) || (requestId == "")) {
- UUID requestID = UUID.randomUUID();
- loggingContext.setRequestID(requestID.toString());
- PolicyLogger.info("requestID not provided in call to XACMLPapSrvlet (UpdatePDPThread) so we generated one: " + loggingContext.getRequestID());
- } else {
- loggingContext.setRequestID(requestId);
- PolicyLogger.info("requestID was provided in call to XACMLPapSrvlet (UpdatePDPThread): " + loggingContext.getRequestID());
- }
- loggingContext.transactionStarted();
- // the Id of the PDP is its URL
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("creating url for id '" + pdp.getId() + "'");
- }
- //TODO - currently always send both policies and pips. Do we care enough to add code to allow sending just one or the other?
- //TODO (need to change "cache=", implying getting some input saying which to change)
- URL url = new URL(pdp.getId() + "?cache=all");
- // Open up the connection
- connection = (HttpURLConnection)url.openConnection();
- // Setup our method and headers
- connection.setRequestMethod("PUT");
- // Authentication
- String encoding = CheckPDP.getEncoding(pdp.getId());
- if(encoding !=null){
- connection.setRequestProperty("Authorization", "Basic " + encoding);
- }
- connection.setRequestProperty("Content-Type", "text/x-java-properties");
- connection.setRequestProperty("X-ECOMP-RequestID", loggingContext.getRequestID());
- connection.setInstanceFollowRedirects(true);
- connection.setDoOutput(true);
- try (OutputStream os = connection.getOutputStream()) {
- OnapPDPGroup group = papEngine.getPDPGroup((OnapPDP) pdp);
- // if the PDP was just deleted, there is no group, but we want to send an update anyway
- if (group == null) {
- // create blank properties files
- Properties policyProperties = new Properties();
- policyProperties.put(XACMLProperties.PROP_ROOTPOLICIES, "");
- policyProperties.put(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
- policyProperties.store(os, "");
- Properties pipProps = new Properties();
- pipProps.setProperty(XACMLProperties.PROP_PIP_ENGINES, "");
- pipProps.store(os, "");
- } else {
- // send properties from the current group
- group.getPolicyProperties().store(os, "");
- Properties policyLocations = new Properties();
- for (PDPPolicy policy : group.getPolicies()) {
- policyLocations.put(policy.getId() + ".url", XACMLPapServlet.papURL + "?id=" + policy.getId());
- }
- policyLocations.store(os, "");
- group.getPipConfigProperties().store(os, "");
- }
- } catch (Exception e) {
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " Failed to send property file to " + pdp.getId());
- // Since this is a server-side error, it probably does not reflect a problem on the client,
- // so do not change the PDP status.
- return;
- }
- // Do the connect
- loggingContext.metricStarted();
- connection.connect();
- loggingContext.metricEnded();
- PolicyLogger.metrics("XACMLPapServlet UpdatePDPThread connection connect");
- if (connection.getResponseCode() == 204) {
- LOGGER.info("Success. We are configured correctly.");
- loggingContext.transactionEnded();
- auditLogger.info("Success. PDP is configured correctly.");
- PolicyLogger.audit("Transaction Success. PDP is configured correctly.");
- setPDPSummaryStatus(pdp, PDPStatus.Status.UP_TO_DATE);
- } else if (connection.getResponseCode() == 200) {
- LOGGER.info("Success. PDP needs to update its configuration.");
- loggingContext.transactionEnded();
- auditLogger.info("Success. PDP needs to update its configuration.");
- PolicyLogger.audit("Transaction Success. PDP is configured correctly.");
- setPDPSummaryStatus(pdp, PDPStatus.Status.OUT_OF_SYNCH);
- } else {
- LOGGER.warn("Failed: " + connection.getResponseCode() + " message: " + connection.getResponseMessage());
- loggingContext.transactionEnded();
- auditLogger.warn("Failed: " + connection.getResponseCode() + " message: " + connection.getResponseMessage());
- PolicyLogger.audit("Transaction Failed: " + connection.getResponseCode() + " message: " + connection.getResponseMessage());
- setPDPSummaryStatus(pdp, PDPStatus.Status.UNKNOWN);
- }
- } catch (Exception e) {
- LOGGER.debug(e);
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " Unable to sync config with PDP '" + pdp.getId() + "'");
- loggingContext.transactionEnded();
- PolicyLogger.audit("Transaction Failed: Unable to sync config with PDP '" + pdp.getId() + "': " + e);
- try {
- setPDPSummaryStatus(pdp, PDPStatus.Status.UNKNOWN);
- } catch (PAPException e1) {
- LOGGER.debug(e1);
- PolicyLogger.audit("Transaction Failed: Unable to set status of PDP " + pdp.getId() + " to UNKNOWN: " + e);
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " Unable to set status of PDP '" + pdp.getId() + "' to UNKNOWN");
- }
- } finally {
- // cleanup the connection
- if(connection != null){
- connection.disconnect();
- }
- // tell the AC to update it's status info
- notifyAC();
- }
- }
- }
-
- /*
- * RESTful Interface from PAP to ACs notifying them of changes
- */
- private void notifyAC() {
- // kick off a thread to do one event notification for all registered ACs
- // This needs to be on a separate thread so that ACs can make calls back to PAP to get the updated Group data
- // as part of processing this message on their end.
- Thread t = new Thread(new NotifyACThread());
- t.start();
- }
-
- private class NotifyACThread implements Runnable {
- public void run() {
- List<String> disconnectedACs = new ArrayList<>();
- // There should be no Concurrent exception here because the list is a CopyOnWriteArrayList.
- // The "for each" loop uses the collection's iterator under the covers, so it should be correct.
- for (String acURL : adminConsoleURLStringList) {
- HttpURLConnection connection = null;
- try {
- acURL += "?PAPNotification=true";
- //TODO - Currently we just tell AC that "Something changed" without being specific. Do we want to tell it which group/pdp changed?
- //TODO - If so, put correct parameters into the Query string here
- acURL += "&objectType=all" + "&action=update";
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("creating url for id '" + acURL + "'");
- }
- //TODO - currently always send both policies and pips. Do we care enough to add code to allow sending just one or the other?
- //TODO (need to change "cache=", implying getting some input saying which to change)
- URL url = new URL(acURL );
- // Open up the connection
- connection = (HttpURLConnection)url.openConnection();
- // Setup our method and headers
- connection.setRequestMethod("PUT");
- connection.setRequestProperty("Content-Type", "text/x-java-properties");
- // Adding this in. It seems the HttpUrlConnection class does NOT
- // properly forward our headers for POST re-direction. It does so
- // for a GET re-direction.
- // So we need to handle this ourselves.
- //TODO - is this needed for a PUT? seems better to leave in for now?
- connection.setInstanceFollowRedirects(false);
- // Do not include any data in the PUT because this is just a
- // notification to the AC.
- // The AC will use GETs back to the PAP to get what it needs
- // to fill in the screens.
- // Do the connect
- connection.connect();
- if (connection.getResponseCode() == 204) {
- LOGGER.info("Success. We updated correctly.");
- } else {
- LOGGER.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Failed: " + connection.getResponseCode() + " message: " + connection.getResponseMessage());
- }
-
- } catch (Exception e) {
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " Unable to sync config AC '" + acURL + "'");
- disconnectedACs.add(acURL);
- } finally {
- // cleanup the connection
- if(connection != null)
- connection.disconnect();
- }
- }
- // remove any ACs that are no longer connected
- if (!disconnectedACs.isEmpty()) {
- adminConsoleURLStringList.removeAll(disconnectedACs);
- }
- }
- }
-
- private void testService(ONAPLoggingContext loggingContext, HttpServletResponse response) throws IOException{
- LOGGER.info("Test request received");
- try {
- im.evaluateSanity();
- //If we make it this far, all is well
- String message = "GET:/pap/test called and PAP " + papResourceName + " is OK";
- LOGGER.info(message);
- loggingContext.transactionEnded();
- PolicyLogger.audit("Transaction Failed - See Error.log");
- response.setStatus(HttpServletResponse.SC_OK);
- return;
- }catch (ForwardProgressException | AdministrativeStateException | StandbyStatusException e){
- String submsg;
- if (e instanceof ForwardProgressException) {
- submsg = " is not making forward progress.";
- } else if (e instanceof AdministrativeStateException) {
- submsg = " Administrative State is LOCKED.";
- } else {
- submsg = " Standby Status is NOT PROVIDING SERVICE.";
- }
-
- String message = "GET:/pap/test called and PAP " + papResourceName + submsg
- + " Exception Message: " + e.getMessage();
- LOGGER.info(message, e);
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR + " " + message);
- loggingContext.transactionEnded();
- PolicyLogger.audit("Transaction Failed - See Error.log");
- setResponseError(response,HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
- return;
- }catch (Exception e) {
- //A subsystem is not making progress, is locked, standby or is not responding
- String eMsg = e.getMessage();
- if(eMsg == null){
- eMsg = "No Exception Message";
- }
- String message = "GET:/pap/test called and PAP " + papResourceName + " has had a subsystem failure."
- + " Exception Message: " + eMsg;
- LOGGER.info(message, e);
- PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR + " " + message);
- loggingContext.transactionEnded();
- PolicyLogger.audit("Transaction Failed - See Error.log");
- //Get the specific list of subsystems that failed
- String ssFailureList = null;
- for(String failedSS : papDependencyGroupsFlatArray){
- if(eMsg.contains(failedSS)){
- if(ssFailureList == null){
- ssFailureList = failedSS;
- }else{
- ssFailureList = ssFailureList.concat(","+failedSS);
- }
- }
- }
- if(ssFailureList == null){
- ssFailureList = "UnknownSubSystem";
- }
- response.addHeader("X-ONAP-SubsystemFailure", ssFailureList);
- setResponseError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
- return;
- }
- }
-
- /*
- * Authorizing the PEP Requests.
- */
- private boolean authorizeRequest(HttpServletRequest request) {
- String clientCredentials = request.getHeader(ENVIRONMENT_HEADER);
- // Check if the Client is Authorized.
- if(clientCredentials!=null && clientCredentials.equalsIgnoreCase(environment)){
- return true;
- }else{
- return false;
- }
- }
-
- private static void loadWebapps() throws PAPException{
- if(actionHome == null || configHome == null){
- Path webappsPath = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_WEBAPPS));
- //Sanity Check
- if (webappsPath == null) {
- PolicyLogger.error("Invalid Webapps Path Location property : " + XACMLRestProperties.PROP_PAP_WEBAPPS);
- throw new PAPException("Invalid Webapps Path Location property : " + XACMLRestProperties.PROP_PAP_WEBAPPS);
- }
- Path webappsPathConfig = Paths.get(webappsPath.toString()+File.separator+"Config");
- Path webappsPathAction = Paths.get(webappsPath.toString()+File.separator+"Action");
- if (Files.notExists(webappsPathConfig)) {
- try {
- Files.createDirectories(webappsPathConfig);
- } catch (IOException e) {
- PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "XACMLPapServlet", "Failed to create config directory: "
- + webappsPathConfig.toAbsolutePath().toString());
- }
- }
- if (Files.notExists(webappsPathAction)) {
- try {
- Files.createDirectories(webappsPathAction);
- } catch (IOException e) {
- LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to create action directory: "
- + webappsPathAction.toAbsolutePath().toString(), e);
- }
- }
- actionHome = webappsPathAction.toString();
- configHome = webappsPathConfig.toString();
- }
- }
-
- public static String getConfigHome(){
- try {
- loadWebapps();
- } catch (PAPException e) {
- LOGGER.debug(e);
- return null;
- }
- return configHome;
- }
-
- private static void setConfigHome(){
- configHome = getConfigHome();
- }
-
- public static String getActionHome(){
- try {
- loadWebapps();
- } catch (PAPException e) {
- LOGGER.debug(e);
- return null;
- }
- return actionHome;
- }
-
- private static void setActionHome(){
- actionHome = getActionHome();
- }
-
- public static EntityManagerFactory getEmf() {
- return emf;
- }
-
- public IntegrityAudit getIa() {
- return ia;
- }
-
- public static String getPDPFile(){
- return XACMLPapServlet.pdpFile;
- }
-
- public static String getPersistenceUnit(){
- return PERSISTENCE_UNIT;
- }
-
- public static PAPPolicyEngine getPAPEngine(){
- return papEngine;
- }
-
- public static PolicyDBDaoTransaction getDbDaoTransaction(){
- return policyDBDao.getNewTransaction();
- }
- public static String getPapDbDriver() {
- return papDbDriver;
- }
-
- public static void setPapDbDriver(String papDbDriver) {
- XACMLPapServlet.papDbDriver = papDbDriver;
- }
-
- public static String getPapDbUrl() {
- return papDbUrl;
- }
-
- public static void setPapDbUrl(String papDbUrl) {
- XACMLPapServlet.papDbUrl = papDbUrl;
- }
-
- public static String getPapDbUser() {
- return papDbUser;
- }
-
- public static void setPapDbUser(String papDbUser) {
- XACMLPapServlet.papDbUser = papDbUser;
- }
-
- public static String getPapDbPassword() {
- return papDbPassword;
- }
-
- public static void setPapDbPassword(String papDbPassword) {
- XACMLPapServlet.papDbPassword = papDbPassword;
- }
-
- public static String getMsOnapName() {
- return msOnapName;
- }
-
- public static void setMsOnapName(String msOnapName) {
- XACMLPapServlet.msOnapName = msOnapName;
- }
-
- public static String getMsPolicyName() {
- return msPolicyName;
- }
-
- public static void setMsPolicyName(String msPolicyName) {
- XACMLPapServlet.msPolicyName = msPolicyName;
- }
-}
+ response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+ loggingContext.metricStarted();
+ notifyAC();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("XACMLPapServlet doACPut notifyAC");
+ // notify any PDPs in the removed set that their config may have changed
+ for (OnapPDP pdp : movedPDPs) {
+ pdpChanged(pdp, loggingContext);
+ }
+ loggingContext.metricStarted();
+ removePdpOrGroupTransaction.commitTransaction();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("XACMLPapServlet doACPut commitTransaction");
+ loggingContext.transactionEnded();
+ auditLogger.info("Success");
+ PolicyLogger.audit("Transaction Ended Successfully");
+ }
+ } catch (PAPException e) {
+ removePdpOrGroupTransaction.rollbackTransaction();
+ PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "XACMLPapServlet", " AC DELETE exception");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ setResponseError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+ }
+ }
+
+ /**
+ * Heartbeat thread - periodically check on PDPs' status
+ * <p>
+ * Heartbeat with all known PDPs.
+ * <p>
+ * Implementation note:
+ * <p>
+ * The PDPs are contacted Sequentially, not in Parallel.
+ * <p>
+ * If we did this in parallel using multiple threads we would simultaneously use
+ * - 1 thread and
+ * - 1 connection
+ * for EACH PDP.
+ * This could become a resource problem since we already use multiple threads and connections for updating the PDPs
+ * when user changes occur.
+ * Using separate threads can also make it tricky dealing with timeouts on PDPs that are non-responsive.
+ * <p>
+ * The Sequential operation does a heartbeat request to each PDP one at a time.
+ * This has the flaw that any PDPs that do not respond will hold up the entire heartbeat sequence until they
+ * timeout.
+ * If there are a lot of non-responsive PDPs and the timeout is large-ish (the default is 20 seconds)
+ * it could take a long time to cycle through all of the PDPs.
+ * That means that this may not notice a PDP being down in a predictable time.
+ */
+ private class Heartbeat implements Runnable {
+ private PAPPolicyEngine papEngine;
+ private Set<OnapPDP> pdps = new HashSet<>();
+ private int heartbeatInterval;
+ private int heartbeatTimeout;
+
+ public volatile boolean isRunning = false;
+
+ public synchronized boolean isRunning() {
+ return this.isRunning;
+ }
+
+ public synchronized void terminate() {
+ this.isRunning = false;
+ }
+
+ public Heartbeat(PAPPolicyEngine papEngine2) {
+ papEngine = papEngine2;
+ this.heartbeatInterval = Integer.parseInt(
+ XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_HEARTBEAT_INTERVAL, "10000"));
+ this.heartbeatTimeout = Integer.parseInt(
+ XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_HEARTBEAT_TIMEOUT, "10000"));
+ }
+
+ @Override
+ public void run() {
+ // Set ourselves as running
+ synchronized (this) {
+ this.isRunning = true;
+ }
+ HashMap<String, URL> idToURLMap = new HashMap<>();
+ try {
+ while (this.isRunning()) {
+ // Wait the given time
+ Thread.sleep(heartbeatInterval);
+ // get the list of PDPs (may have changed since last time)
+ pdps.clear();
+ synchronized (papEngine) {
+ try {
+ for (OnapPDPGroup g : papEngine.getOnapPDPGroups()) {
+ for (OnapPDP p : g.getOnapPdps()) {
+ pdps.add(p);
+ }
+ }
+ } catch (PAPException e) {
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ "Heartbeat unable to read PDPs from PAPEngine");
+ }
+ }
+ // Check for shutdown
+ if (this.isRunning() == false) {
+ LOGGER.info("isRunning is false, getting out of loop.");
+ break;
+ }
+ // try to get the summary status from each PDP
+ boolean changeSeen = false;
+ for (OnapPDP pdp : pdps) {
+ // Check for shutdown
+ if (this.isRunning() == false) {
+ LOGGER.info("isRunning is false, getting out of loop.");
+ break;
+ }
+ // the id of the PDP is its url (though we add a query parameter)
+ URL pdpURL = idToURLMap.get(pdp.getId());
+ if (pdpURL == null) {
+ // haven't seen this PDP before
+ String fullURLString = null;
+ try {
+ // Check PDP ID
+ if (CheckPDP.validateID(pdp.getId())) {
+ fullURLString = pdp.getId() + "?type=hb";
+ pdpURL = new URL(fullURLString);
+ idToURLMap.put(pdp.getId(), pdpURL);
+ }
+ } catch (MalformedURLException e) {
+ PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPapServlet",
+ " PDP id '" + fullURLString + "' is not a valid URL");
+ continue;
+ }
+ }
+ // Do a GET with type HeartBeat
+ String newStatus = "";
+ HttpURLConnection connection = null;
+ try {
+ // Open up the connection
+ if (pdpURL != null) {
+ connection = (HttpURLConnection) pdpURL.openConnection();
+ // Setup our method and headers
+ connection.setRequestMethod("GET");
+ connection.setConnectTimeout(heartbeatTimeout);
+ // Authentication
+ String encoding = CheckPDP.getEncoding(pdp.getId());
+ if (encoding != null) {
+ connection.setRequestProperty("Authorization", "Basic " + encoding);
+ }
+ // Do the connect
+ connection.connect();
+ if (connection.getResponseCode() == 204) {
+ newStatus = connection.getHeaderField(XACMLRestProperties.PROP_PDP_HTTP_HEADER_HB);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Heartbeat '" + pdp.getId() + "' status='" + newStatus + "'");
+ }
+ } else {
+ // anything else is an unexpected result
+ newStatus = PDPStatus.Status.UNKNOWN.toString();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR +
+ " Heartbeat connect response code " + connection.getResponseCode() + ": " +
+ pdp.getId());
+ }
+ }
+ } catch (UnknownHostException e) {
+ newStatus = PDPStatus.Status.NO_SUCH_HOST.toString();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ " Heartbeat '" + pdp.getId() + "' NO_SUCH_HOST");
+ } catch (SocketTimeoutException e) {
+ newStatus = PDPStatus.Status.CANNOT_CONNECT.toString();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ " Heartbeat '" + pdp.getId() + "' connection timeout");
+ } catch (ConnectException e) {
+ newStatus = PDPStatus.Status.CANNOT_CONNECT.toString();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ " Heartbeat '" + pdp.getId() + "' cannot connect");
+ } catch (Exception e) {
+ newStatus = PDPStatus.Status.UNKNOWN.toString();
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ "Heartbeat '" + pdp.getId() + "' connect exception");
+ } finally {
+ // cleanup the connection
+ if (connection != null)
+ connection.disconnect();
+ }
+ if (!pdp.getStatus().getStatus().toString().equals(newStatus)) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("previous status='" + pdp.getStatus().getStatus() + "' new Status='" +
+ newStatus + "'");
+ }
+ try {
+ setPDPSummaryStatus(pdp, newStatus);
+ } catch (PAPException e) {
+ PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "XACMLPapServlet",
+ "Unable to set state for PDP '" + pdp.getId());
+ }
+ changeSeen = true;
+ }
+ }
+ // Check for shutdown
+ if (this.isRunning() == false) {
+ LOGGER.info("isRunning is false, getting out of loop.");
+ break;
+ }
+ // if any of the PDPs changed state, tell the ACs to update
+ if (changeSeen) {
+ notifyAC();
+ }
+ }
+ } catch (InterruptedException e) {
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR + " Heartbeat interrupted. Shutting down");
+ this.terminate();
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /*
+ * HELPER to change Group status when PDP status is changed
+ * (Must NOT be called from a method that is synchronized on the papEngine or it may deadlock)
+ */
+ private void setPDPSummaryStatus(OnapPDP pdp, PDPStatus.Status newStatus) throws PAPException {
+ setPDPSummaryStatus(pdp, newStatus.toString());
+ }
+
+ private void setPDPSummaryStatus(OnapPDP pdp, String newStatus) throws PAPException {
+ synchronized (papEngine) {
+ StdPDPStatus status = new StdPDPStatus();
+ status.setStatus(PDPStatus.Status.valueOf(newStatus));
+ ((StdPDP) pdp).setStatus(status);
+ // now adjust the group
+ StdPDPGroup group = (StdPDPGroup) papEngine.getPDPGroup((OnapPDP) pdp);
+ // if the PDP was just deleted it may transiently exist but not be in a group
+ if (group != null) {
+ group.resetStatus();
+ }
+ }
+ }
+
+ /*
+ * Callback methods telling this servlet to notify PDPs of changes made by the PAP StdEngine
+ * in the PDP group directories
+ */
+ @Override
+ public void changed() {
+ // all PDPs in all groups need to be updated/sync'd
+ Set<OnapPDPGroup> groups;
+ try {
+ groups = papEngine.getOnapPDPGroups();
+ } catch (PAPException e) {
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " getPDPGroups failed");
+ throw new IllegalAccessError(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Unable to get Groups: " + e);
+ }
+ for (OnapPDPGroup group : groups) {
+ groupChanged(group);
+ }
+ }
+
+ public void changed(ONAPLoggingContext loggingContext) {
+ // all PDPs in all groups need to be updated/sync'd
+ Set<OnapPDPGroup> groups;
+ try {
+ groups = papEngine.getOnapPDPGroups();
+ } catch (PAPException e) {
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet", " getPDPGroups failed");
+ throw new IllegalAccessError(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Unable to get Groups: " + e);
+ }
+ for (OnapPDPGroup group : groups) {
+ groupChanged(group, loggingContext);
+ }
+ }
+
+ @Override
+ public void groupChanged(OnapPDPGroup group) {
+ // all PDPs within one group need to be updated/sync'd
+ for (OnapPDP pdp : group.getOnapPdps()) {
+ pdpChanged(pdp);
+ }
+ }
+
+ public void groupChanged(OnapPDPGroup group, ONAPLoggingContext loggingContext) {
+ // all PDPs within one group need to be updated/sync'd
+ for (OnapPDP pdp : group.getOnapPdps()) {
+ pdpChanged(pdp, loggingContext);
+ }
+ }
+
+ @Override
+ public void pdpChanged(OnapPDP pdp) {
+ // kick off a thread to do an event notification for each PDP.
+ // This needs to be on a separate thread so that PDPs that do not respond (down, non-existent, etc)
+ // do not block the PSP response to the AC, which would freeze the GUI until all PDPs sequentially respond or
+ // time-out.
+ Thread t = new Thread(new UpdatePDPThread(pdp));
+ if (CheckPDP.validateID(pdp.getId())) {
+ t.start();
+ }
+ }
+
+ public void pdpChanged(OnapPDP pdp, ONAPLoggingContext loggingContext) {
+ // kick off a thread to do an event notification for each PDP.
+ // This needs to be on a separate thread so that PDPs that do not respond (down, non-existent, etc)
+ // do not block the PSP response to the AC, which would freeze the GUI until all PDPs sequentially respond or
+ // time-out.
+ Thread t = new Thread(new UpdatePDPThread(pdp, loggingContext));
+ if (CheckPDP.validateID(pdp.getId())) {
+ t.start();
+ }
+ }
+
+ private class UpdatePDPThread implements Runnable {
+ private OnapPDP pdp;
+ private String requestId;
+ private ONAPLoggingContext loggingContext;
+
+ public UpdatePDPThread(OnapPDP pdp) {
+ this.pdp = pdp;
+ }
+
+ public UpdatePDPThread(OnapPDP pdp, ONAPLoggingContext loggingContext) {
+ this.pdp = pdp;
+ if ((loggingContext != null) && (loggingContext.getRequestID() != null ||
+ Objects.equals(loggingContext.getRequestID(), ""))) {
+ this.requestId = loggingContext.getRequestID();
+ }
+ this.loggingContext = loggingContext;
+ }
+
+ public void run() {
+ // send the current configuration to one PDP
+ HttpURLConnection connection = null;
+ // get a new logging context for the thread
+ try {
+ if (this.loggingContext == null) {
+ loggingContext = new ONAPLoggingContext(baseLoggingContext);
+ }
+ } catch (Exception e) {
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ " Failed to send property file to " + pdp.getId());
+ // Since this is a server-side error, it probably does not reflect a problem on the client,
+ // so do not change the PDP status.
+ return;
+ }
+ try {
+ loggingContext.setServiceName("PAP:PDP.putConfig");
+ // If a requestId was provided, use it, otherwise generate one; post to loggingContext to be used
+ // later when calling PDP
+ if ((requestId == null) || (Objects.equals(requestId, ""))) {
+ UUID requestID = UUID.randomUUID();
+ loggingContext.setRequestID(requestID.toString());
+ PolicyLogger
+ .info("requestID not provided in call to XACMLPapSrvlet (UpdatePDPThread) so we generated" +
+ " one: " +
+ loggingContext.getRequestID());
+ } else {
+ loggingContext.setRequestID(requestId);
+ PolicyLogger.info("requestID was provided in call to XACMLPapSrvlet (UpdatePDPThread): " +
+ loggingContext.getRequestID());
+ }
+ loggingContext.transactionStarted();
+ // the Id of the PDP is its URL
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("creating url for id '" + pdp.getId() + "'");
+ }
+ //TODO - currently always send both policies and pips. Do we care enough to add code to allow
+ // sending just one or the other?
+ //TODO (need to change "cache=", implying getting some input saying which to change)
+ URL url = new URL(pdp.getId() + "?cache=all");
+ // Open up the connection
+ connection = (HttpURLConnection) url.openConnection();
+ // Setup our method and headers
+ connection.setRequestMethod("PUT");
+ // Authentication
+ String encoding = CheckPDP.getEncoding(pdp.getId());
+ if (encoding != null) {
+ connection.setRequestProperty("Authorization", "Basic " + encoding);
+ }
+ connection.setRequestProperty("Content-Type", "text/x-java-properties");
+ connection.setRequestProperty("X-ECOMP-RequestID", loggingContext.getRequestID());
+ connection.setInstanceFollowRedirects(true);
+ connection.setDoOutput(true);
+ try (OutputStream os = connection.getOutputStream()) {
+ OnapPDPGroup group = papEngine.getPDPGroup((OnapPDP) pdp);
+ // if the PDP was just deleted, there is no group, but we want to send an update anyway
+ if (group == null) {
+ // create blank properties files
+ Properties policyProperties = new Properties();
+ policyProperties.put(XACMLProperties.PROP_ROOTPOLICIES, "");
+ policyProperties.put(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
+ policyProperties.store(os, "");
+ Properties pipProps = new Properties();
+ pipProps.setProperty(XACMLProperties.PROP_PIP_ENGINES, "");
+ pipProps.store(os, "");
+ } else {
+ // send properties from the current group
+ group.getPolicyProperties().store(os, "");
+ Properties policyLocations = new Properties();
+ for (PDPPolicy policy : group.getPolicies()) {
+ policyLocations
+ .put(policy.getId() + ".url", XACMLPapServlet.papURL + "?id=" + policy.getId());
+ }
+ policyLocations.store(os, "");
+ group.getPipConfigProperties().store(os, "");
+ }
+ } catch (Exception e) {
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ " Failed to send property file to " + pdp.getId());
+ // Since this is a server-side error, it probably does not reflect a problem on the client,
+ // so do not change the PDP status.
+ return;
+ }
+ // Do the connect
+ loggingContext.metricStarted();
+ connection.connect();
+ loggingContext.metricEnded();
+ PolicyLogger.metrics("XACMLPapServlet UpdatePDPThread connection connect");
+ if (connection.getResponseCode() == 204) {
+ LOGGER.info("Success. We are configured correctly.");
+ loggingContext.transactionEnded();
+ auditLogger.info("Success. PDP is configured correctly.");
+ PolicyLogger.audit("Transaction Success. PDP is configured correctly.");
+ setPDPSummaryStatus(pdp, PDPStatus.Status.UP_TO_DATE);
+ } else if (connection.getResponseCode() == 200) {
+ LOGGER.info("Success. PDP needs to update its configuration.");
+ loggingContext.transactionEnded();
+ auditLogger.info("Success. PDP needs to update its configuration.");
+ PolicyLogger.audit("Transaction Success. PDP is configured correctly.");
+ setPDPSummaryStatus(pdp, PDPStatus.Status.OUT_OF_SYNCH);
+ } else {
+ LOGGER.warn("Failed: " + connection.getResponseCode() + " message: " +
+ connection.getResponseMessage());
+ loggingContext.transactionEnded();
+ auditLogger.warn("Failed: " + connection.getResponseCode() + " message: " +
+ connection.getResponseMessage());
+ PolicyLogger.audit("Transaction Failed: " + connection.getResponseCode() + " message: " +
+ connection.getResponseMessage());
+ setPDPSummaryStatus(pdp, PDPStatus.Status.UNKNOWN);
+ }
+ } catch (Exception e) {
+ LOGGER.debug(e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ " Unable to sync config with PDP '" + pdp.getId() + "'");
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed: Unable to sync config with PDP '" + pdp.getId() + "': " + e);
+ try {
+ setPDPSummaryStatus(pdp, PDPStatus.Status.UNKNOWN);
+ } catch (PAPException e1) {
+ LOGGER.debug(e1);
+ PolicyLogger
+ .audit("Transaction Failed: Unable to set status of PDP " + pdp.getId() + " to UNKNOWN: " +
+ e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ " Unable to set status of PDP '" + pdp.getId() + "' to UNKNOWN");
+ }
+ } finally {
+ // cleanup the connection
+ if (connection != null) {
+ connection.disconnect();
+ }
+ // tell the AC to update it's status info
+ notifyAC();
+ }
+ }
+ }
+
+ /*
+ * RESTful Interface from PAP to ACs notifying them of changes
+ */
+ private void notifyAC() {
+ // kick off a thread to do one event notification for all registered ACs
+ // This needs to be on a separate thread so that ACs can make calls back to PAP to get the updated Group data
+ // as part of processing this message on their end.
+ Thread t = new Thread(new NotifyACThread());
+ t.start();
+ }
+
+ private class NotifyACThread implements Runnable {
+ public void run() {
+ List<String> disconnectedACs = new ArrayList<>();
+ // There should be no Concurrent exception here because the list is a CopyOnWriteArrayList.
+ // The "for each" loop uses the collection's iterator under the covers, so it should be correct.
+ for (String acURL : adminConsoleURLStringList) {
+ HttpURLConnection connection = null;
+ try {
+ acURL += "?PAPNotification=true";
+ //TODO - Currently we just tell AC that "Something changed" without being specific. Do we want
+ // to tell it which group/pdp changed?
+ //TODO - If so, put correct parameters into the Query string here
+ acURL += "&objectType=all" + "&action=update";
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("creating url for id '" + acURL + "'");
+ }
+ //TODO - currently always send both policies and pips. Do we care enough to add code to allow
+ // sending just one or the other?
+ //TODO (need to change "cache=", implying getting some input saying which to change)
+ URL url = new URL(acURL);
+ // Open up the connection
+ connection = (HttpURLConnection) url.openConnection();
+ // Setup our method and headers
+ connection.setRequestMethod("PUT");
+ connection.setRequestProperty("Content-Type", "text/x-java-properties");
+ // Adding this in. It seems the HttpUrlConnection class does NOT
+ // properly forward our headers for POST re-direction. It does so
+ // for a GET re-direction.
+ // So we need to handle this ourselves.
+ //TODO - is this needed for a PUT? seems better to leave in for now?
+ connection.setInstanceFollowRedirects(false);
+ // Do not include any data in the PUT because this is just a
+ // notification to the AC.
+ // The AC will use GETs back to the PAP to get what it needs
+ // to fill in the screens.
+ // Do the connect
+ connection.connect();
+ if (connection.getResponseCode() == 204) {
+ LOGGER.info("Success. We updated correctly.");
+ } else {
+ LOGGER.warn(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "Failed: " + connection.getResponseCode() +
+ " message: " + connection.getResponseMessage());
+ }
+
+ } catch (Exception e) {
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "XACMLPapServlet",
+ " Unable to sync config AC '" + acURL + "'");
+ disconnectedACs.add(acURL);
+ } finally {
+ // cleanup the connection
+ if (connection != null)
+ connection.disconnect();
+ }
+ }
+ // remove any ACs that are no longer connected
+ if (!disconnectedACs.isEmpty()) {
+ adminConsoleURLStringList.removeAll(disconnectedACs);
+ }
+ }
+ }
+
+ private void testService(ONAPLoggingContext loggingContext, HttpServletResponse response) throws IOException {
+ LOGGER.info("Test request received");
+ try {
+ im.evaluateSanity();
+ //If we make it this far, all is well
+ String message = "GET:/pap/test called and PAP " + papResourceName + " is OK";
+ LOGGER.info(message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ response.setStatus(HttpServletResponse.SC_OK);
+ } catch (ForwardProgressException | AdministrativeStateException | StandbyStatusException e) {
+ String submsg;
+ if (e instanceof ForwardProgressException) {
+ submsg = " is not making forward progress.";
+ } else if (e instanceof AdministrativeStateException) {
+ submsg = " Administrative State is LOCKED.";
+ } else {
+ submsg = " Standby Status is NOT PROVIDING SERVICE.";
+ }
+
+ String message = "GET:/pap/test called and PAP " + papResourceName + submsg
+ + " Exception Message: " + e.getMessage();
+ LOGGER.info(message, e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR + " " + message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ setResponseError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ } catch (Exception e) {
+ //A subsystem is not making progress, is locked, standby or is not responding
+ String eMsg = e.getMessage();
+ if (eMsg == null) {
+ eMsg = "No Exception Message";
+ }
+ String message = "GET:/pap/test called and PAP " + papResourceName + " has had a subsystem failure."
+ + " Exception Message: " + eMsg;
+ LOGGER.info(message, e);
+ PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR + " " + message);
+ loggingContext.transactionEnded();
+ PolicyLogger.audit("Transaction Failed - See Error.log");
+ //Get the specific list of subsystems that failed
+ String ssFailureList = null;
+ for (String failedSS : papDependencyGroupsFlatArray) {
+ if (eMsg.contains(failedSS)) {
+ if (ssFailureList == null) {
+ ssFailureList = failedSS;
+ } else {
+ ssFailureList = ssFailureList.concat("," + failedSS);
+ }
+ }
+ }
+ if (ssFailureList == null) {
+ ssFailureList = "UnknownSubSystem";
+ }
+ response.addHeader("X-ONAP-SubsystemFailure", ssFailureList);
+ setResponseError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ }
+ }
+
+ /*
+ * Authorizing the PEP Requests.
+ */
+ private boolean authorizeRequest(HttpServletRequest request) {
+ String clientCredentials = request.getHeader(ENVIRONMENT_HEADER);
+ // Check if the Client is Authorized.
+ if (clientCredentials != null && clientCredentials.equalsIgnoreCase(environment)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static void loadWebapps() throws PAPException {
+ if (actionHome == null || configHome == null) {
+ Path webappsPath = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_WEBAPPS));
+ //Sanity Check
+ if (webappsPath == null) {
+ PolicyLogger.error("Invalid Webapps Path Location property : " + XACMLRestProperties.PROP_PAP_WEBAPPS);
+ throw new PAPException(
+ "Invalid Webapps Path Location property : " + XACMLRestProperties.PROP_PAP_WEBAPPS);
+ }
+ Path webappsPathConfig = Paths.get(webappsPath.toString() + File.separator + "Config");
+ Path webappsPathAction = Paths.get(webappsPath.toString() + File.separator + "Action");
+ if (Files.notExists(webappsPathConfig)) {
+ try {
+ Files.createDirectories(webappsPathConfig);
+ } catch (IOException e) {
+ PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "XACMLPapServlet",
+ "Failed to create config directory: "
+ + webappsPathConfig.toAbsolutePath().toString());
+ }
+ }
+ if (Files.notExists(webappsPathAction)) {
+ try {
+ Files.createDirectories(webappsPathAction);
+ } catch (IOException e) {
+ LOGGER.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to create action directory: "
+ + webappsPathAction.toAbsolutePath().toString(), e);
+ }
+ }
+ actionHome = webappsPathAction.toString();
+ configHome = webappsPathConfig.toString();
+ }
+ }
+
+ public static String getConfigHome() {
+ try {
+ loadWebapps();
+ } catch (PAPException e) {
+ LOGGER.debug(e);
+ return null;
+ }
+ return configHome;
+ }
+
+ private static void setConfigHome() {
+ configHome = getConfigHome();
+ }
+
+ public static String getActionHome() {
+ try {
+ loadWebapps();
+ } catch (PAPException e) {
+ LOGGER.debug(e);
+ return null;
+ }
+ return actionHome;
+ }
+
+ private static void setActionHome() {
+ actionHome = getActionHome();
+ }
+
+ public static EntityManagerFactory getEmf() {
+ return emf;
+ }
+
+ public IntegrityAudit getIa() {
+ return ia;
+ }
+
+ public static String getPDPFile() {
+ return XACMLPapServlet.pdpFile;
+ }
+
+ public static String getPersistenceUnit() {
+ return PERSISTENCE_UNIT;
+ }
+
+ public static PAPPolicyEngine getPAPEngine() {
+ return papEngine;
+ }
+
+ public static PolicyDBDaoTransaction getDbDaoTransaction() {
+ return policyDBDao.getNewTransaction();
+ }
+
+ public static String getPapDbDriver() {
+ return papDbDriver;
+ }
+
+ public static void setPapDbDriver(String papDbDriver) {
+ XACMLPapServlet.papDbDriver = papDbDriver;
+ }
+
+ public static String getPapDbUrl() {
+ return papDbUrl;
+ }
+
+ public static void setPapDbUrl(String papDbUrl) {
+ XACMLPapServlet.papDbUrl = papDbUrl;
+ }
+
+ public static String getPapDbUser() {
+ return papDbUser;
+ }
+
+ public static void setPapDbUser(String papDbUser) {
+ XACMLPapServlet.papDbUser = papDbUser;
+ }
+
+ public static String getPapDbPassword() {
+ return papDbPassword;
+ }
+
+ public static void setPapDbPassword(String papDbPassword) {
+ XACMLPapServlet.papDbPassword = papDbPassword;
+ }
+
+ public static String getMsOnapName() {
+ return msOnapName;
+ }
+
+ public static void setMsOnapName(String msOnapName) {
+ XACMLPapServlet.msOnapName = msOnapName;
+ }
+
+ public static String getMsPolicyName() {
+ return msPolicyName;
+ }
+
+ public static void setMsPolicyName(String msPolicyName) {
+ XACMLPapServlet.msPolicyName = msPolicyName;
+ }
+}
\ No newline at end of file