b703917c4143745945a7bc7d479f29ee86de6fea
[policy/engine.git] / ONAP-PAP-REST / src / main / java / org / onap / policy / pap / xacml / rest / components / NotifyOtherPaps.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-PAP-REST
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.pap.xacml.rest.components;
22
23 import com.att.research.xacml.util.XACMLProperties;
24
25 import java.net.HttpURLConnection;
26 import java.net.MalformedURLException;
27 import java.net.ProtocolException;
28 import java.net.URL;
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
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;
41
42 public class NotifyOtherPaps {
43
44     private static final Logger LOGGER = FlexLogger.getLogger(NotifyOtherPaps.class);
45     private List<PolicyDBDaoEntity> failedPaps = null;
46
47     public void notifyOthers(long entityId, String entityType) {
48         notifyOthers(entityId, entityType, null);
49     }
50
51     /**
52      * Notify others.
53      *
54      * @param entityId the entity id
55      * @param entityType the entity type
56      * @param newGroupId the new group id
57      */
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<>();
62
63         List<?> otherServers = PolicyDBDao.getPolicyDBDaoInstance().getOtherServers();
64         // Notify other paps
65         startNotifyThreads(otherServers, entityId, entityType, newGroupId);
66         // Retry for failed paps
67         if (!failedPaps.isEmpty()) {
68             startNotifyThreads(failedPaps, entityId, entityType, newGroupId);
69         }
70     }
71
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
75         // up
76         for (Object obj : otherServers) {
77             Thread newNotifyThread = new Thread(new NotifyOtherThread(obj, entityId, entityType, newGroupId));
78             newNotifyThread.start();
79             notifyThreads.add(newNotifyThread);
80         }
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) {
84             try {
85                 t.join();
86             } catch (Exception e) {
87                 LOGGER.warn("Could not join a notifcation thread" + e);
88             }
89         }
90     }
91
92     private class NotifyOtherThread implements Runnable {
93         public NotifyOtherThread(Object obj, long entityId, String entityType, String newGroupId) {
94             this.obj = obj;
95             this.entityId = entityId;
96             this.entityType = entityType;
97             this.newGroupId = newGroupId;
98         }
99
100         private Object obj;
101         private long entityId;
102         private String entityType;
103         private String newGroupId;
104
105         @Override
106         public void run() {
107             PolicyDBDao dao = new PolicyDBDao();
108             PolicyDBDaoEntity dbdEntity = (PolicyDBDaoEntity) obj;
109             String otherPap = dbdEntity.getPolicyDBDaoUrl();
110             String username = dbdEntity.getUsername();
111             String txt;
112             try {
113                 txt = PeCryptoUtils.decrypt(dbdEntity.getPassword());
114             } catch (Exception e) {
115                 LOGGER.debug(e);
116                 // if we can't decrypt, might as well try it anyway
117                 txt = dbdEntity.getPassword();
118             }
119
120             HttpURLConnection connection = null;
121             UUID requestId = UUID.randomUUID();
122             URL url;
123             String papUrl;
124             try {
125                 String[] papUrlUserPass = dao.getPapUrlUserPass();
126                 if (papUrlUserPass == null) {
127                     papUrl = "undefined";
128                 } else {
129                     papUrl = papUrlUserPass[0];
130                 }
131                 LOGGER.debug("We are going to try to notify " + otherPap);
132                 // is this our own url?
133                 String ourUrl = otherPap;
134                 try {
135                     ourUrl = dao.splitPapUrlUserPass(otherPap)[0];
136                 } catch (Exception e) {
137                     ourUrl = otherPap;
138                     LOGGER.debug(e);
139                 }
140                 if (otherPap == null) {
141                     otherPap = "undefined";
142                 }
143                 if (papUrl.equals(ourUrl)) {
144                     LOGGER.debug(otherPap + " is our url, skipping notify");
145                     return;
146                 }
147                 if (newGroupId == null) {
148                     url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
149                             + entityType);
150                 } else {
151                     url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
152                             + entityType + "&extradata=" + newGroupId);
153                 }
154             } catch (MalformedURLException e) {
155                 LOGGER.warn("Caught MalformedURLException on: new URL()", e);
156                 return;
157             }
158             //
159             // Open up the connection
160             //
161             LOGGER.info("PolicyDBDao: NotifyOtherThread: notifying other PAPs of an update");
162             LOGGER.info("Connecting with url: " + url);
163             try {
164                 connection = (HttpURLConnection) url.openConnection();
165             } catch (Exception e) {
166                 LOGGER.warn("Caught exception on: url.openConnection()", e);
167                 return;
168             }
169             //
170             // Setup our method and headers
171             //
172             try {
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);
177                 return;
178             }
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());
185             int readTimeout;
186             try {
187                 readTimeout =
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);
191                 readTimeout = 10000;
192             }
193             connection.setReadTimeout(readTimeout);
194             connection.setConnectTimeout(readTimeout);
195             connection.setUseCaches(false);
196             //
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.
200             //
201             // So we need to handle this ourselves.
202             //
203             connection.setInstanceFollowRedirects(false);
204             connection.setDoOutput(true);
205             connection.setDoInput(true);
206             try {
207                 connection.connect();
208             } catch (Exception e) {
209                 LOGGER.warn("Caught exception on: connection.connect()", e);
210                 return;
211             }
212             try {
213                 if (connection.getResponseCode() == 200) {
214                     LOGGER.info("PolicyDBDao: NotifyOtherThread received response 200 from pap server on notify");
215                 } else {
216                     LOGGER.warn("PolicyDBDao: NotifyOtherThread connection response code not 200, received: "
217                             + connection.getResponseCode());
218                     failedPaps.add(dbdEntity);
219                 }
220             } catch (Exception e) {
221                 LOGGER.warn("Caught Exception on: connection.getResponseCode() ", e);
222             }
223
224             connection.disconnect();
225         }
226     }
227 }