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;
26 import java.net.HttpURLConnection;
27 import java.net.MalformedURLException;
28 import java.net.ProtocolException;
30 import java.nio.charset.StandardCharsets;
31 import java.util.ArrayList;
32 import java.util.Base64;
33 import java.util.LinkedList;
34 import java.util.List;
35 import java.util.UUID;
37 import org.onap.policy.common.logging.flexlogger.FlexLogger;
38 import org.onap.policy.common.logging.flexlogger.Logger;
39 import org.onap.policy.rest.XacmlRestProperties;
40 import org.onap.policy.rest.jpa.PolicyDBDaoEntity;
41 import org.onap.policy.utils.PeCryptoUtils;
43 public class NotifyOtherPaps {
45 private static final Logger LOGGER = FlexLogger.getLogger(NotifyOtherPaps.class);
46 private List<PolicyDBDaoEntity> failedPaps = null;
48 public void notifyOthers(long entityId, String entityType) {
49 notifyOthers(entityId, entityType, null);
55 * @param entityId the entity id
56 * @param entityType the entity type
57 * @param newGroupId the new group id
59 public void notifyOthers(long entityId, String entityType, String newGroupId) {
60 LOGGER.debug("notifyOthers(long entityId, String entityType, long newGroupId) as notifyOthers(" + entityId + ","
61 + entityType + "," + newGroupId + ") called");
62 failedPaps = new ArrayList<>();
64 List<?> otherServers = PolicyDbDao.getPolicyDbDaoInstance().getOtherServers();
66 startNotifyThreads(otherServers, entityId, entityType, newGroupId);
67 // Retry for failed paps
68 if (!failedPaps.isEmpty()) {
69 startNotifyThreads(failedPaps, entityId, entityType, newGroupId);
73 private void startNotifyThreads(List<?> otherServers, long entityId, String entityType, String newGroupId) {
74 LinkedList<Thread> notifyThreads = new LinkedList<>();
75 // we're going to run notifications in parallel threads to speed things
77 for (Object obj : otherServers) {
78 Thread newNotifyThread = new Thread(new NotifyOtherThread(obj, entityId, entityType, newGroupId));
79 newNotifyThread.start();
80 notifyThreads.add(newNotifyThread);
82 // we want to wait for all notifications to complete or timeout before
83 // we unlock the interface and allow more changes
84 for (Thread t : notifyThreads) {
87 } catch (Exception e) {
88 LOGGER.warn("Could not join a notifcation thread" + e);
93 private class NotifyOtherThread implements Runnable {
94 public NotifyOtherThread(Object obj, long entityId, String entityType, String newGroupId) {
96 this.entityId = entityId;
97 this.entityType = entityType;
98 this.newGroupId = newGroupId;
102 private long entityId;
103 private String entityType;
104 private String newGroupId;
108 PolicyDbDao dao = new PolicyDbDao();
109 PolicyDBDaoEntity dbdEntity = (PolicyDBDaoEntity) obj;
110 String otherPap = dbdEntity.getPolicyDBDaoUrl();
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;
124 String[] papUrlUserPass = dao.getPapUrlUserPass();
125 if (papUrlUserPass == null) {
126 papUrl = "undefined";
128 papUrl = papUrlUserPass[0];
130 LOGGER.debug("We are going to try to notify " + otherPap);
131 // is this our own url?
132 String ourUrl = otherPap;
134 ourUrl = dao.splitPapUrlUserPass(otherPap)[0];
135 } catch (Exception e) {
139 if (otherPap == null) {
140 otherPap = "undefined";
142 if (papUrl.equals(ourUrl)) {
143 LOGGER.debug(otherPap + " is our url, skipping notify");
146 if (newGroupId == null) {
147 url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
150 url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
151 + entityType + "&extradata=" + newGroupId);
153 } catch (MalformedURLException e) {
154 LOGGER.warn("Caught MalformedURLException on: new URL()", e);
158 // Open up the connection
160 LOGGER.info("PolicyDBDao: NotifyOtherThread: notifying other PAPs of an update");
161 LOGGER.info("Connecting with url: " + url);
163 connection = (HttpURLConnection) url.openConnection();
164 } catch (Exception e) {
165 LOGGER.warn("Caught exception on: url.openConnection()", e);
169 // Setup our method and headers
172 connection.setRequestMethod("PUT");
173 } catch (ProtocolException e) {
174 // why would this error ever occur?
175 LOGGER.warn("Caught ProtocolException on connection.setRequestMethod(\"PUT\");", e);
179 String username = dbdEntity.getUsername();
180 UUID requestId = UUID.randomUUID();
182 Base64.Encoder encoder = Base64.getEncoder();
183 String encoding = encoder.encodeToString((username + ":" + txt).getBytes(StandardCharsets.UTF_8));
184 connection.setRequestProperty("Authorization", "Basic " + encoding);
185 connection.setRequestProperty("Accept", "text/x-java-properties");
186 connection.setRequestProperty("Content-Type", "text/x-java-properties");
187 connection.setRequestProperty("requestID", requestId.toString());
191 Integer.parseInt(XACMLProperties.getProperty(XacmlRestProperties.PROP_PAP_NOTIFY_TIMEOUT));
192 } catch (Exception e) {
193 LOGGER.error("xacml.rest.pap.notify.timeoutms property not set, using a default.", e);
196 connection.setReadTimeout(readTimeout);
197 connection.setConnectTimeout(readTimeout);
198 connection.setUseCaches(false);
200 // Adding this in. It seems the HttpUrlConnection class does NOT
201 // properly forward our headers for POST re-direction. It does so
202 // for a GET re-direction.
204 // So we need to handle this ourselves.
206 connection.setInstanceFollowRedirects(false);
207 connection.setDoOutput(true);
208 connection.setDoInput(true);
210 connection.connect();
211 } catch (Exception e) {
212 LOGGER.warn("Caught exception on: connection.connect()", e);
216 if (connection.getResponseCode() == 200) {
217 LOGGER.info("PolicyDBDao: NotifyOtherThread received response 200 from pap server on notify");
219 LOGGER.warn("PolicyDBDao: NotifyOtherThread connection response code not 200, received: "
220 + connection.getResponseCode());
221 failedPaps.add(dbdEntity);
223 } catch (Exception e) {
224 LOGGER.warn("Caught Exception on: connection.getResponseCode() ", e);
227 connection.disconnect();