2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.pap.xacml.rest.components;
23 import com.att.research.xacml.util.XACMLProperties;
24 import java.net.HttpURLConnection;
25 import java.net.MalformedURLException;
26 import java.net.ProtocolException;
28 import java.nio.charset.StandardCharsets;
29 import java.util.ArrayList;
30 import java.util.Base64;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.UUID;
34 import org.onap.policy.common.logging.flexlogger.FlexLogger;
35 import org.onap.policy.common.logging.flexlogger.Logger;
36 import org.onap.policy.rest.XACMLRestProperties;
37 import org.onap.policy.rest.jpa.PolicyDBDaoEntity;
38 import org.onap.policy.utils.CryptoUtils;
40 public class NotifyOtherPaps {
42 private static final Logger LOGGER = FlexLogger.getLogger(NotifyOtherPaps.class);
43 private List<PolicyDBDaoEntity> failedPaps = null;
45 public void notifyOthers(long entityId, String entityType) {
46 notifyOthers(entityId, entityType, null);
52 * @param entityId the entity id
53 * @param entityType the entity type
54 * @param newGroupId the new group id
56 public void notifyOthers(long entityId, String entityType, String newGroupId) {
57 LOGGER.debug("notifyOthers(long entityId, String entityType, long newGroupId) as notifyOthers(" + entityId + ","
58 + entityType + "," + newGroupId + ") called");
59 failedPaps = new ArrayList<>();
61 List<?> otherServers = PolicyDBDao.getPolicyDBDaoInstance().getOtherServers();
63 startNotifyThreads(otherServers, entityId, entityType, newGroupId);
64 // Retry for failed paps
65 if (!failedPaps.isEmpty()) {
66 startNotifyThreads(failedPaps, entityId, entityType, newGroupId);
70 private void startNotifyThreads(List<?> otherServers, long entityId, String entityType, String newGroupId) {
71 LinkedList<Thread> notifyThreads = new LinkedList<>();
72 // we're going to run notifications in parallel threads to speed things
74 for (Object obj : otherServers) {
75 Thread newNotifyThread = new Thread(new NotifyOtherThread(obj, entityId, entityType, newGroupId));
76 newNotifyThread.start();
77 notifyThreads.add(newNotifyThread);
79 // we want to wait for all notifications to complete or timeout before
80 // we unlock the interface and allow more changes
81 for (Thread t : notifyThreads) {
84 } catch (Exception e) {
85 LOGGER.warn("Could not join a notifcation thread" + e);
90 private class NotifyOtherThread implements Runnable {
91 public NotifyOtherThread(Object obj, long entityId, String entityType, String newGroupId) {
93 this.entityId = entityId;
94 this.entityType = entityType;
95 this.newGroupId = newGroupId;
99 private long entityId;
100 private String entityType;
101 private String newGroupId;
105 PolicyDBDao dao = new PolicyDBDao();
106 PolicyDBDaoEntity dbdEntity = (PolicyDBDaoEntity) obj;
107 String otherPap = dbdEntity.getPolicyDBDaoUrl();
108 String username = dbdEntity.getUsername();
111 txt = new String(CryptoUtils.decryptTxt(dbdEntity.getPassword()), StandardCharsets.UTF_8);
112 } catch (Exception e) {
114 // if we can't decrypt, might as well try it anyway
115 txt = dbdEntity.getPassword();
118 HttpURLConnection connection = null;
119 UUID requestId = UUID.randomUUID();
123 String[] papUrlUserPass = dao.getPapUrlUserPass();
124 if (papUrlUserPass == null) {
125 papUrl = "undefined";
127 papUrl = papUrlUserPass[0];
129 LOGGER.debug("We are going to try to notify " + otherPap);
130 // is this our own url?
131 String ourUrl = otherPap;
133 ourUrl = dao.splitPapUrlUserPass(otherPap)[0];
134 } catch (Exception e) {
138 if (otherPap == null) {
139 otherPap = "undefined";
141 if (papUrl.equals(ourUrl)) {
142 LOGGER.debug(otherPap + " is our url, skipping notify");
145 if (newGroupId == null) {
146 url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
149 url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
150 + entityType + "&extradata=" + newGroupId);
152 } catch (MalformedURLException e) {
153 LOGGER.warn("Caught MalformedURLException on: new URL()", e);
157 // Open up the connection
159 LOGGER.info("PolicyDBDao: NotifyOtherThread: notifying other PAPs of an update");
160 LOGGER.info("Connecting with url: " + url);
162 connection = (HttpURLConnection) url.openConnection();
163 } catch (Exception e) {
164 LOGGER.warn("Caught exception on: url.openConnection()", e);
168 // Setup our method and headers
171 connection.setRequestMethod("PUT");
172 } catch (ProtocolException e) {
173 // why would this error ever occur?
174 LOGGER.warn("Caught ProtocolException on connection.setRequestMethod(\"PUT\");", e);
177 Base64.Encoder encoder = Base64.getEncoder();
178 String encoding = encoder.encodeToString((username + ":" + txt).getBytes(StandardCharsets.UTF_8));
179 connection.setRequestProperty("Authorization", "Basic " + encoding);
180 connection.setRequestProperty("Accept", "text/x-java-properties");
181 connection.setRequestProperty("Content-Type", "text/x-java-properties");
182 connection.setRequestProperty("requestID", requestId.toString());
186 Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_NOTIFY_TIMEOUT));
187 } catch (Exception e) {
188 LOGGER.error("xacml.rest.pap.notify.timeoutms property not set, using a default.", e);
191 connection.setReadTimeout(readTimeout);
192 connection.setConnectTimeout(readTimeout);
193 connection.setUseCaches(false);
195 // Adding this in. It seems the HttpUrlConnection class does NOT
196 // properly forward our headers for POST re-direction. It does so
197 // for a GET re-direction.
199 // So we need to handle this ourselves.
201 connection.setInstanceFollowRedirects(false);
202 connection.setDoOutput(true);
203 connection.setDoInput(true);
205 connection.connect();
206 } catch (Exception e) {
207 LOGGER.warn("Caught exception on: connection.connect()", e);
211 if (connection.getResponseCode() == 200) {
212 LOGGER.info("PolicyDBDao: NotifyOtherThread received response 200 from pap server on notify");
214 LOGGER.warn("PolicyDBDao: NotifyOtherThread connection response code not 200, received: "
215 + connection.getResponseCode());
216 failedPaps.add(dbdEntity);
218 } catch (Exception e) {
219 LOGGER.warn("Caught Exception on: connection.getResponseCode() ", e);
222 connection.disconnect();