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;
25 import java.net.HttpURLConnection;
26 import java.net.MalformedURLException;
27 import java.net.ProtocolException;
29 import java.nio.charset.StandardCharsets;
30 import java.util.ArrayList;
31 import java.util.Base64;
32 import java.util.LinkedList;
33 import java.util.List;
34 import java.util.UUID;
36 import org.onap.policy.common.logging.flexlogger.FlexLogger;
37 import org.onap.policy.common.logging.flexlogger.Logger;
38 import org.onap.policy.rest.XACMLRestProperties;
39 import org.onap.policy.rest.jpa.PolicyDBDaoEntity;
40 import org.onap.policy.utils.PeCryptoUtils;
42 public class NotifyOtherPaps {
44 private static final Logger LOGGER = FlexLogger.getLogger(NotifyOtherPaps.class);
45 private List<PolicyDBDaoEntity> failedPaps = null;
47 public void notifyOthers(long entityId, String entityType) {
48 notifyOthers(entityId, entityType, null);
54 * @param entityId the entity id
55 * @param entityType the entity type
56 * @param newGroupId the new group id
58 public void notifyOthers(long entityId, String entityType, String newGroupId) {
59 LOGGER.debug("notifyOthers(long entityId, String entityType, long newGroupId) as notifyOthers(" + entityId + ","
60 + entityType + "," + newGroupId + ") called");
61 failedPaps = new ArrayList<>();
63 List<?> otherServers = PolicyDBDao.getPolicyDBDaoInstance().getOtherServers();
65 startNotifyThreads(otherServers, entityId, entityType, newGroupId);
66 // Retry for failed paps
67 if (!failedPaps.isEmpty()) {
68 startNotifyThreads(failedPaps, entityId, entityType, newGroupId);
72 private void startNotifyThreads(List<?> otherServers, long entityId, String entityType, String newGroupId) {
73 LinkedList<Thread> notifyThreads = new LinkedList<>();
74 // we're going to run notifications in parallel threads to speed things
76 for (Object obj : otherServers) {
77 Thread newNotifyThread = new Thread(new NotifyOtherThread(obj, entityId, entityType, newGroupId));
78 newNotifyThread.start();
79 notifyThreads.add(newNotifyThread);
81 // we want to wait for all notifications to complete or timeout before
82 // we unlock the interface and allow more changes
83 for (Thread t : notifyThreads) {
86 } catch (Exception e) {
87 LOGGER.warn("Could not join a notifcation thread" + e);
92 private class NotifyOtherThread implements Runnable {
93 public NotifyOtherThread(Object obj, long entityId, String entityType, String newGroupId) {
95 this.entityId = entityId;
96 this.entityType = entityType;
97 this.newGroupId = newGroupId;
101 private long entityId;
102 private String entityType;
103 private String newGroupId;
107 PolicyDBDao dao = new PolicyDBDao();
108 PolicyDBDaoEntity dbdEntity = (PolicyDBDaoEntity) obj;
109 String otherPap = dbdEntity.getPolicyDBDaoUrl();
110 String username = dbdEntity.getUsername();
113 txt = PeCryptoUtils.decrypt(dbdEntity.getPassword());
114 } catch (Exception e) {
116 // if we can't decrypt, might as well try it anyway
117 txt = dbdEntity.getPassword();
120 HttpURLConnection connection = null;
121 UUID requestId = UUID.randomUUID();
125 String[] papUrlUserPass = dao.getPapUrlUserPass();
126 if (papUrlUserPass == null) {
127 papUrl = "undefined";
129 papUrl = papUrlUserPass[0];
131 LOGGER.debug("We are going to try to notify " + otherPap);
132 // is this our own url?
133 String ourUrl = otherPap;
135 ourUrl = dao.splitPapUrlUserPass(otherPap)[0];
136 } catch (Exception e) {
140 if (otherPap == null) {
141 otherPap = "undefined";
143 if (papUrl.equals(ourUrl)) {
144 LOGGER.debug(otherPap + " is our url, skipping notify");
147 if (newGroupId == null) {
148 url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
151 url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
152 + entityType + "&extradata=" + newGroupId);
154 } catch (MalformedURLException e) {
155 LOGGER.warn("Caught MalformedURLException on: new URL()", e);
159 // Open up the connection
161 LOGGER.info("PolicyDBDao: NotifyOtherThread: notifying other PAPs of an update");
162 LOGGER.info("Connecting with url: " + url);
164 connection = (HttpURLConnection) url.openConnection();
165 } catch (Exception e) {
166 LOGGER.warn("Caught exception on: url.openConnection()", e);
170 // Setup our method and headers
173 connection.setRequestMethod("PUT");
174 } catch (ProtocolException e) {
175 // why would this error ever occur?
176 LOGGER.warn("Caught ProtocolException on connection.setRequestMethod(\"PUT\");", e);
179 Base64.Encoder encoder = Base64.getEncoder();
180 String encoding = encoder.encodeToString((username + ":" + txt).getBytes(StandardCharsets.UTF_8));
181 connection.setRequestProperty("Authorization", "Basic " + encoding);
182 connection.setRequestProperty("Accept", "text/x-java-properties");
183 connection.setRequestProperty("Content-Type", "text/x-java-properties");
184 connection.setRequestProperty("requestID", requestId.toString());
188 Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_NOTIFY_TIMEOUT));
189 } catch (Exception e) {
190 LOGGER.error("xacml.rest.pap.notify.timeoutms property not set, using a default.", e);
193 connection.setReadTimeout(readTimeout);
194 connection.setConnectTimeout(readTimeout);
195 connection.setUseCaches(false);
197 // Adding this in. It seems the HttpUrlConnection class does NOT
198 // properly forward our headers for POST re-direction. It does so
199 // for a GET re-direction.
201 // So we need to handle this ourselves.
203 connection.setInstanceFollowRedirects(false);
204 connection.setDoOutput(true);
205 connection.setDoInput(true);
207 connection.connect();
208 } catch (Exception e) {
209 LOGGER.warn("Caught exception on: connection.connect()", e);
213 if (connection.getResponseCode() == 200) {
214 LOGGER.info("PolicyDBDao: NotifyOtherThread received response 200 from pap server on notify");
216 LOGGER.warn("PolicyDBDao: NotifyOtherThread connection response code not 200, received: "
217 + connection.getResponseCode());
218 failedPaps.add(dbdEntity);
220 } catch (Exception e) {
221 LOGGER.warn("Caught Exception on: connection.getResponseCode() ", e);
224 connection.disconnect();