Log thrown exception in PIPEngineGetHistory
[policy/drools-applications.git] / controlloop / common / guard / src / main / java / org / onap / policy / guard / PIPEngineGetHistory.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * guard
4  * ================================================================================
5  * Copyright (C) 2017 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.guard;
22
23 import java.math.BigInteger;
24 import java.sql.Timestamp;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Date;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.Properties;
31 import java.util.Set;
32
33 import javax.persistence.EntityManager;
34 import javax.persistence.NoResultException;
35 import javax.persistence.NonUniqueResultException;
36 import javax.persistence.Persistence;
37 import javax.persistence.Query;
38
39 import org.onap.policy.drools.system.PolicyEngine;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import com.att.research.xacml.api.Attribute;
44 import com.att.research.xacml.api.AttributeValue;
45 import com.att.research.xacml.api.Identifier;
46 import com.att.research.xacml.api.pip.PIPException;
47 import com.att.research.xacml.api.pip.PIPFinder;
48 import com.att.research.xacml.api.pip.PIPRequest;
49 import com.att.research.xacml.api.pip.PIPResponse;
50 import com.att.research.xacml.std.IdentifierImpl;
51 import com.att.research.xacml.std.StdMutableAttribute;
52 import com.att.research.xacml.std.datatypes.DataTypes;
53 import com.att.research.xacml.std.pip.StdMutablePIPResponse;
54 import com.att.research.xacml.std.pip.StdPIPRequest;
55 import com.att.research.xacml.std.pip.StdPIPResponse;
56 import com.att.research.xacml.std.pip.engines.StdConfigurableEngine;
57
58 public class PIPEngineGetHistory extends StdConfigurableEngine{
59         private static final Logger logger = LoggerFactory.getLogger(PIPEngineGetHistory.class);
60
61         //
62         // Base issuer string. The issuer in the policy will also contain time window information
63         // E.g., "com:att:research:xacml:guard:historydb:tw:10:min"
64         //
65         public static final String DEFAULT_ISSUER      = "com:att:research:xacml:guard:historydb";
66         public static final String DEFAULT_DESCRIPTION = "PIP for retrieving Operations History from DB";
67
68         private static final String XML_SCHEMA_STRING = "http://www.w3.org/2001/XMLSchema#string";
69
70         private static final String XACML_SUBJECT_CATEGORY_ACCESS_SUBJECT    = "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject";
71         private static final String XACML_ACTOR_ACTOR_ID                     = "urn:oasis:names:tc:xacml:1.0:actor:actor-id";
72         private static final String XACML_ATTRIBUTE_CATEGORY_ACTION          ="urn:oasis:names:tc:xacml:3.0:attribute-category:action";
73         private static final String XACML_OPERATION_OPERATION_ID             ="urn:oasis:names:tc:xacml:1.0:operation:operation-id";
74         private static final String XACML_ATTRIBUTE_CATEGORY_RESOURCE        ="urn:oasis:names:tc:xacml:3.0:attribute-category:resource";
75         private static final String XACML_TARGET_TARGET_ID                   ="urn:oasis:names:tc:xacml:1.0:target:target-id";
76         private static final String XACML_TEST_SQL_RESOURCE_OPERATIONS_COUNT = "com:att:research:xacml:test:sql:resource:operations:count";
77
78         private static final PIPRequest PIP_REQUEST_ACTOR       = new StdPIPRequest(
79                         new IdentifierImpl(XACML_SUBJECT_CATEGORY_ACCESS_SUBJECT),
80                         new IdentifierImpl(XACML_ACTOR_ACTOR_ID),
81                         new IdentifierImpl(XML_SCHEMA_STRING));
82
83         private static final PIPRequest PIP_REQUEST_RECIPE              = new StdPIPRequest(
84                         new IdentifierImpl(XACML_ATTRIBUTE_CATEGORY_ACTION),
85                         new IdentifierImpl(XACML_OPERATION_OPERATION_ID),
86                         new IdentifierImpl(XML_SCHEMA_STRING));
87
88         private static final PIPRequest PIP_REQUEST_TARGET              = new StdPIPRequest(
89                         new IdentifierImpl(XACML_ATTRIBUTE_CATEGORY_RESOURCE),
90                         new IdentifierImpl(XACML_TARGET_TARGET_ID),
91                         new IdentifierImpl(XML_SCHEMA_STRING));
92
93         public PIPEngineGetHistory() {
94                 super();
95         }
96
97         @Override
98         public Collection<PIPRequest> attributesRequired() {
99                 return Collections.emptySet();
100         }
101
102         @Override
103         public Collection<PIPRequest> attributesProvided() {
104                 return Collections.emptySet();
105         }
106
107         @Override
108         public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
109                 logger.debug("Entering FeqLimiter PIP");
110
111                 /*
112                  * First check to see if the issuer is set and then match it
113                  */
114                 String string;
115                 if ((string = pipRequest.getIssuer()) == null) {
116
117                         logger.debug("No issuer in the request...");
118                         logger.debug("FeqLimiter PIP - No issuer in the request!");
119                         return StdPIPResponse.PIP_RESPONSE_EMPTY;
120                 }
121                 else{
122                         //Notice, we are checking here for the base issuer prefix.
123                         if (!string.contains(this.getIssuer())) {
124                                 logger.debug("Requested issuer '{}' does not match {}", string, getIssuer());
125                                 logger.debug("FeqLimiter PIP - Issuer {}  does not match with: ", string, this.getIssuer());
126                                 return StdPIPResponse.PIP_RESPONSE_EMPTY;
127                         }
128                 }
129
130                 String[] s1 = string.split("tw:");
131                 String[] s2 = s1[1].split(":");
132                 String timeWindowVal = s2[0];// number [of minutes, hours, days...]
133                 String timeWindowScale = s2[1];//e.g., minute, hour, day, week, month, year
134
135                 String actor = null;
136                 String operation = null;
137                 String target = null;
138                 try {
139                         actor = getActor(pipFinder).iterator().next();
140                         operation = getRecipe(pipFinder).iterator().next();
141                         target = getTarget(pipFinder).iterator().next();
142                 } catch (Exception e) {
143                         logger.debug("could not retrieve actor, operation, or target from PIP finder", e);
144                         return StdPIPResponse.PIP_RESPONSE_EMPTY;
145                 }
146
147                 String timeWindow = timeWindowVal + " " + timeWindowScale;
148
149                 logger.debug("Going to query DB about: {} {} {} {}", actor, operation, target, timeWindow);
150                 int countFromDB = getCountFromDB(actor, operation, target, timeWindow);
151
152                 StdMutablePIPResponse stdPIPResponse    = new StdMutablePIPResponse();
153
154                 this.addIntegerAttribute(stdPIPResponse,
155                                 new IdentifierImpl(XACML_ATTRIBUTE_CATEGORY_RESOURCE),
156                                 new IdentifierImpl(XACML_TEST_SQL_RESOURCE_OPERATIONS_COUNT),
157                                 countFromDB,
158                                 pipRequest);
159
160                 return new StdPIPResponse(stdPIPResponse);
161         }
162
163         @Override
164         public void configure(String id, Properties properties) throws PIPException {
165                 super.configure(id, properties);
166
167                 if (this.getDescription() == null) {
168                         this.setDescription(DEFAULT_DESCRIPTION);
169                 }
170                 if (this.getIssuer() == null) {
171                         this.setIssuer(DEFAULT_ISSUER);
172                 }
173         }
174
175         private PIPResponse getAttribute(PIPRequest pipRequest, PIPFinder pipFinder) {
176                 PIPResponse pipResponse = null;
177
178                 try {
179                         pipResponse     = pipFinder.getMatchingAttributes(pipRequest, this);
180                 } catch (PIPException ex) {
181                         logger.error("getAttribute threw:", ex);
182                         return null;
183                 }
184                 if (pipResponse == null) {
185                         return null;
186                 }
187                 if (pipResponse.getStatus() != null && !pipResponse.getStatus().isOk()) {
188                         if (logger.isWarnEnabled()) {
189                                 logger.warn("PIP response error {}: {}", pipRequest.getAttributeId().stringValue(), pipResponse.getStatus().toString());
190                         }
191                         return null;
192                 }
193                 if (pipResponse.getAttributes() != null && pipResponse.getAttributes().isEmpty()) {
194                         if (logger.isWarnEnabled()) {
195                                 logger.warn("No attributes in POP response {}: {}", pipRequest.getAttributeId().stringValue(), pipResponse.getStatus().toString());
196                         }
197                         return null;
198                 }
199                 return pipResponse;
200         }
201
202         private Set<String> getActor(PIPFinder pipFinder) {
203                 /*
204                  * Get the AT&T UID from either the subject id or the attuid property
205                  */
206                 PIPResponse pipResponseATTUID   = this.getAttribute(PIP_REQUEST_ACTOR, pipFinder);
207                 if (pipResponseATTUID == null) {
208                         return new HashSet<>();
209                 }
210
211                 /*
212                  * Iterate over all of the returned results and do the LDAP requests
213                  */
214                 Collection<Attribute> listATTUIDs       = pipResponseATTUID.getAttributes();
215                 Set<String> setATTUIDs                  = new HashSet<>();
216                 for (Attribute attributeATTUID: listATTUIDs) {
217                         Iterator<AttributeValue<String>> iterAttributeValues    = attributeATTUID.findValues(DataTypes.DT_STRING);
218                         if (iterAttributeValues != null) {
219                                 while (iterAttributeValues.hasNext()) {
220                                         String attuid   = iterAttributeValues.next().getValue();
221                                         if (attuid != null) {
222                                                 setATTUIDs.add(attuid);
223                                         }
224                                 }
225                         }
226                 }
227
228                 return setATTUIDs;
229         }
230
231         private Set<String> getRecipe(PIPFinder pipFinder) {
232                 /*
233                  * Get the AT&T UID from either the subject id or the attuid property
234                  */
235                 PIPResponse pipResponseATTUID = this.getAttribute(PIP_REQUEST_RECIPE, pipFinder);
236                 if (pipResponseATTUID == null) {
237                         return new HashSet<>();
238                 }
239
240                 /*
241                  * Iterate over all of the returned results and do the LDAP requests
242                  */
243                 Collection<Attribute> listATTUIDs       = pipResponseATTUID.getAttributes();
244                 Set<String> setATTUIDs                  = new HashSet<>();
245                 for (Attribute attributeATTUID: listATTUIDs) {
246                         Iterator<AttributeValue<String>> iterAttributeValues    = attributeATTUID.findValues(DataTypes.DT_STRING);
247                         if (iterAttributeValues != null) {
248                                 while (iterAttributeValues.hasNext()) {
249                                         String attuid   = iterAttributeValues.next().getValue();
250                                         if (attuid != null) {
251                                                 setATTUIDs.add(attuid);
252                                         }
253                                 }
254                         }
255                 }
256
257                 return setATTUIDs;
258         }
259
260         private void addIntegerAttribute(StdMutablePIPResponse stdPIPResponse, Identifier category, Identifier attributeId, int value, PIPRequest pipRequest) {
261                 AttributeValue<BigInteger> attributeValue       = null;
262                 try {
263                         attributeValue  = DataTypes.DT_INTEGER.createAttributeValue(value);
264                 } catch (Exception ex) {
265                         logger.error("Failed to convert {} to an AttributeValue<Boolean>",value, ex);
266                 }
267                 if (attributeValue != null) {
268                         stdPIPResponse.addAttribute(new StdMutableAttribute(category, attributeId, attributeValue, pipRequest.getIssuer()/*this.getIssuer()*/, false));
269                 }
270         }
271
272         private Set<String> getTarget(PIPFinder pipFinder) {
273                 /*
274                  * Get the AT&T UID from either the subject id or the attuid property
275                  */
276                 PIPResponse pipResponseATTUID   = this.getAttribute(PIP_REQUEST_TARGET, pipFinder);
277                 if (pipResponseATTUID == null) {
278                         return new HashSet<>();
279                 }
280
281                 /*
282                  * Iterate over all of the returned results and do the LDAP requests
283                  */
284                 Collection<Attribute> listATTUIDs       = pipResponseATTUID.getAttributes();
285                 Set<String> setATTUIDs                  = new HashSet<>();
286                 for (Attribute attributeATTUID: listATTUIDs) {
287                         Iterator<AttributeValue<String>> iterAttributeValues    = attributeATTUID.findValues(DataTypes.DT_STRING);
288                         if (iterAttributeValues != null) {
289                                 while (iterAttributeValues.hasNext()) {
290                                         String attuid   = iterAttributeValues.next().getValue();
291                                         if (attuid != null) {
292                                                 setATTUIDs.add(attuid);
293                                         }
294                                 }
295                         }
296                 }
297
298                 return setATTUIDs;
299         }
300
301         private static int getCountFromDB(String actor, String operation, String target, String timeWindow){
302                 // DB Properties
303                 Properties props = new Properties();
304                 props.put(Util.ECLIPSE_LINK_KEY_URL, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL));
305                 props.put(Util.ECLIPSE_LINK_KEY_USER, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER));
306                 props.put(Util.ECLIPSE_LINK_KEY_PASS, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS));
307
308
309                 EntityManager em = null;
310                 String opsHistPU = System.getProperty("OperationsHistoryPU");
311                 if (opsHistPU == null || !opsHistPU.equals("TestOperationsHistoryPU")){
312                         opsHistPU = "OperationsHistoryPU";
313                 }
314                 else {
315                         props.clear();
316                 }
317
318                 try {
319                         em = Persistence.createEntityManagerFactory(opsHistPU, props).createEntityManager();
320                 } catch(Exception ex){
321                         logger.error("PIP thread got Exception. Can't connect to Operations History DB -- {}", opsHistPU);
322                         logger.error("getCountFromDB threw: ", ex);
323                         return -1;
324                 }
325
326                 long now = new Date().getTime();
327                 long diff;
328                 try {
329                         diff = now - getMSFromTimeWindow(timeWindow);
330                 } catch (Exception ex) {
331                         logger.error("PIP thread got Exception " + ex);
332                         return -1;
333                 }
334
335                 StringBuilder sqlBuilder = new StringBuilder();
336                 sqlBuilder.append("select count(*) as count from operationshistory10 where outcome<>'Failure_Guard'");
337                 sqlBuilder.append(" and actor= ?");
338                 sqlBuilder.append(" and operation= ?");
339                 sqlBuilder.append(" and target= ?");
340                 sqlBuilder.append(" and endtime between '");
341                 sqlBuilder.append(new Timestamp(diff));
342                 sqlBuilder.append("' and '");
343                 sqlBuilder.append(new Timestamp(now));
344                 sqlBuilder.append('\'');
345
346                 Query nq = em.createNativeQuery(sqlBuilder.toString());
347                 nq.setParameter(1, actor);
348                 nq.setParameter(2, operation);
349                 nq.setParameter(3, target);
350
351                 int ret = -1;
352                 try {
353                         ret = ((Number)nq.getSingleResult()).intValue();
354                 }
355                 catch(NoResultException | NonUniqueResultException ex){
356                         logger.error("getCountFromDB threw: ", ex);
357                         return -1;
358                 }
359
360                 em.close();
361
362                 return ret;
363         }
364
365         /**
366          * Get the Millisecond time from a time window string
367          * @param timeWindow the time window string to parse
368          * @return the millisecond time from the time window string
369          * @throws PIPException On invalid time window strings
370          */
371         private static long getMSFromTimeWindow(String timeWindowString) throws PIPException {
372                 long ms = 0;
373                 double multiplier = 0;
374
375                 String[] split = timeWindowString.split(" ");
376                 if (split.length != 2) {
377                         throw new PIPException("Invalid Value Unit pair for SQL");
378                 }
379
380                 ms = Long.parseLong(split[0]);
381
382                 if("SECOND".compareToIgnoreCase(split[1]) == 0){
383                         multiplier = 1000;
384                 }
385                 else if("MINUTE".compareToIgnoreCase(split[1]) == 0){
386                         multiplier = 60000;
387                 }
388                 else if("HOUR".compareToIgnoreCase(split[1]) == 0){
389                         multiplier = 3.6e+6;
390                 }
391                 else if("DAY".compareToIgnoreCase(split[1]) == 0){
392                         multiplier = 8.64e+7;
393                 }
394                 else if("WEEK".compareToIgnoreCase(split[1]) == 0){
395                         multiplier = 6.048e+8;
396                 }
397                 else if("MONTH".compareToIgnoreCase(split[1]) == 0){
398                         multiplier = 2.628e+9;
399                 }
400                 else if("QUARTER".compareToIgnoreCase(split[1]) == 0){
401                         multiplier = 2.628e+9 * 3;
402                 }
403                 else if("YEAR".compareToIgnoreCase(split[1]) == 0){
404                         multiplier = 3.154e+10;
405                 }
406                 else{
407                         logger.error("{} not supported", split[1]);
408                 }
409
410                 ms *= multiplier;
411                 return ms;
412         }
413 }