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