2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2019 Nordix Foundation.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.pap.xacml.rest.components;
24 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;
35 import org.onap.policy.common.logging.flexlogger.FlexLogger;
36 import org.onap.policy.common.logging.flexlogger.Logger;
37 import org.onap.policy.rest.XacmlRestProperties;
38 import org.onap.policy.rest.jpa.PolicyDBDaoEntity;
39 import org.onap.policy.utils.PeCryptoUtils;
41 public class NotifyOtherPaps {
43 private static final Logger LOGGER = FlexLogger.getLogger(NotifyOtherPaps.class);
44 private List<PolicyDBDaoEntity> failedPaps = null;
46 public void notifyOthers(long entityId, String entityType) {
47 notifyOthers(entityId, entityType, null);
53 * @param entityId the entity id
54 * @param entityType the entity type
55 * @param newGroupId the new group id
57 public void notifyOthers(long entityId, String entityType, String newGroupId) {
58 LOGGER.debug("notifyOthers(long entityId, String entityType, long newGroupId) as notifyOthers(" + entityId + ","
59 + entityType + "," + newGroupId + ") called");
60 failedPaps = new ArrayList<>();
62 List<?> otherServers = PolicyDbDao.getPolicyDbDaoInstance().getOtherServers();
64 startNotifyThreads(otherServers, entityId, entityType, newGroupId);
65 // Retry for failed paps
66 if (!failedPaps.isEmpty()) {
67 startNotifyThreads(failedPaps, entityId, entityType, newGroupId);
71 protected void startNotifyThreads(List<?> otherServers, long entityId, String entityType, String newGroupId) {
72 LinkedList<Thread> notifyThreads = new LinkedList<>();
73 // we're going to run notifications in parallel threads to speed things
75 for (Object obj : otherServers) {
76 Thread newNotifyThread = new Thread(new NotifyOtherThread(obj, entityId, entityType, newGroupId));
77 newNotifyThread.start();
78 notifyThreads.add(newNotifyThread);
80 // we want to wait for all notifications to complete or timeout before
81 // we unlock the interface and allow more changes
82 for (Thread t : notifyThreads) {
85 } catch (Exception e) {
86 LOGGER.warn("Could not join a notifcation thread" + e);
91 private class NotifyOtherThread implements Runnable {
92 public NotifyOtherThread(Object obj, long entityId, String entityType, String newGroupId) {
94 this.entityId = entityId;
95 this.entityType = entityType;
96 this.newGroupId = newGroupId;
100 private long entityId;
101 private String entityType;
102 private String newGroupId;
106 PolicyDbDao dao = new PolicyDbDao();
107 PolicyDBDaoEntity dbdEntity = (PolicyDBDaoEntity) obj;
108 String otherPap = dbdEntity.getPolicyDBDaoUrl();
111 txt = PeCryptoUtils.decrypt(dbdEntity.getPassword());
112 } catch (Exception e) {
114 // if we can't decrypt, might as well try it anyway
115 txt = dbdEntity.getPassword();
118 HttpURLConnection connection = null;
122 String[] papUrlUserPass = dao.getPapUrlUserPass();
123 if (papUrlUserPass == null) {
124 papUrl = "undefined";
126 papUrl = papUrlUserPass[0];
128 LOGGER.debug("We are going to try to notify " + otherPap);
129 // is this our own url?
130 String ourUrl = otherPap;
132 ourUrl = dao.splitPapUrlUserPass(otherPap)[0];
133 } catch (Exception e) {
137 if (otherPap == null) {
138 otherPap = "undefined";
140 if (papUrl.equals(ourUrl)) {
141 LOGGER.debug(otherPap + " is our url, skipping notify");
144 if (newGroupId == null) {
146 otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype=" + entityType);
148 url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
149 + entityType + "&extradata=" + newGroupId);
151 } catch (MalformedURLException e) {
152 LOGGER.warn("Caught MalformedURLException on: new URL()", e);
156 // Open up the connection
158 LOGGER.info("PolicyDBDao: NotifyOtherThread: notifying other PAPs of an update");
159 LOGGER.info("Connecting with url: " + url);
161 connection = (HttpURLConnection) url.openConnection();
162 } catch (Exception e) {
163 LOGGER.warn("Caught exception on: url.openConnection()", e);
167 // Setup our method and headers
170 connection.setRequestMethod("PUT");
171 } catch (ProtocolException e) {
172 // why would this error ever occur?
173 LOGGER.warn("Caught ProtocolException on connection.setRequestMethod(\"PUT\");", e);
177 String username = dbdEntity.getUsername();
178 UUID requestId = UUID.randomUUID();
180 Base64.Encoder encoder = Base64.getEncoder();
181 String encoding = encoder.encodeToString((username + ":" + txt).getBytes(StandardCharsets.UTF_8));
182 connection.setRequestProperty("Authorization", "Basic " + encoding);
183 connection.setRequestProperty("Accept", "text/x-java-properties");
184 connection.setRequestProperty("Content-Type", "text/x-java-properties");
185 connection.setRequestProperty("requestID", requestId.toString());
189 Integer.parseInt(XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_NOTIFY_TIMEOUT));
190 } catch (Exception e) {
191 LOGGER.error("xacml.rest.pap.notify.timeoutms property not set, using a default.", e);
194 connection.setReadTimeout(readTimeout);
195 connection.setConnectTimeout(readTimeout);
196 connection.setUseCaches(false);
198 // Adding this in. It seems the HttpUrlConnection class does NOT
199 // properly forward our headers for POST re-direction. It does so
200 // for a GET re-direction.
202 // So we need to handle this ourselves.
204 connection.setInstanceFollowRedirects(false);
205 connection.setDoOutput(true);
206 connection.setDoInput(true);
208 connection.connect();
209 } catch (Exception e) {
210 LOGGER.warn("Caught exception on: connection.connect()", e);
214 if (connection.getResponseCode() == 200) {
215 LOGGER.info("PolicyDBDao: NotifyOtherThread received response 200 from pap server on notify");
217 LOGGER.warn("PolicyDBDao: NotifyOtherThread connection response code not 200, received: "
218 + connection.getResponseCode());
219 failedPaps.add(dbdEntity);
221 } catch (Exception e) {
222 LOGGER.warn("Caught Exception on: connection.getResponseCode() ", e);
225 connection.disconnect();