Misc XACML code coverage
[policy/xacml-pdp.git] / applications / common / src / main / java / org / onap / policy / pdp / xacml / application / common / operationshistory / CountRecentOperationsPip.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.pdp.xacml.application.common.operationshistory;
22
23 import com.att.research.xacml.api.XACML3;
24 import com.att.research.xacml.api.pip.PIPException;
25 import com.att.research.xacml.api.pip.PIPFinder;
26 import com.att.research.xacml.api.pip.PIPRequest;
27 import com.att.research.xacml.api.pip.PIPResponse;
28 import com.att.research.xacml.std.pip.StdMutablePIPResponse;
29 import com.att.research.xacml.std.pip.StdPIPResponse;
30 import com.google.common.base.Strings;
31 import java.sql.Timestamp;
32 import java.time.Instant;
33 import java.time.temporal.ChronoUnit;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
37 import org.onap.policy.pdp.xacml.application.common.std.StdOnapPip;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41
42 public class CountRecentOperationsPip extends StdOnapPip {
43     public static final String ISSUER_NAME = "count-recent-operations";
44     private static Logger logger = LoggerFactory.getLogger(CountRecentOperationsPip.class);
45
46     public CountRecentOperationsPip() {
47         super();
48         this.issuer = ISSUER_NAME;
49     }
50
51     @Override
52     public Collection<PIPRequest> attributesRequired() {
53         return Arrays.asList(PIP_REQUEST_ACTOR, PIP_REQUEST_RECIPE, PIP_REQUEST_TARGET);
54     }
55
56     /**
57      * getAttributes.
58      *
59      * @param pipRequest the request
60      * @param pipFinder the pip finder
61      * @return PIPResponse
62      */
63     @Override
64     public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
65         logger.debug("getAttributes requesting attribute {} of type {} for issuer {}",
66                 pipRequest.getAttributeId(), pipRequest.getDataTypeId(), pipRequest.getIssuer());
67         //
68         // Determine if the issuer is correct
69         //
70         if (Strings.isNullOrEmpty(pipRequest.getIssuer())) {
71             logger.debug("issuer is null - returning empty response");
72             //
73             // We only respond to ourself as the issuer
74             //
75             return StdPIPResponse.PIP_RESPONSE_EMPTY;
76         }
77         if (! pipRequest.getIssuer().startsWith(ToscaDictionary.GUARD_ISSUER_PREFIX)) {
78             logger.debug("Issuer does not start with guard");
79             //
80             // We only respond to ourself as the issuer
81             //
82             return StdPIPResponse.PIP_RESPONSE_EMPTY;
83         }
84         //
85         // Parse out the issuer which denotes the time window
86         // Eg: any-prefix:tw:10:minute
87         //
88         String[] s1 = pipRequest.getIssuer().split("tw:");
89         String[] s2 = s1[1].split(":");
90         int timeWindowVal = Integer.parseInt(s2[0]);
91         String timeWindowScale = s2[1];
92         //
93         // Grab other attribute values
94         //
95         String actor = getAttribute(pipFinder, PIP_REQUEST_ACTOR);
96         String operation = getAttribute(pipFinder, PIP_REQUEST_RECIPE);
97         String target = getAttribute(pipFinder, PIP_REQUEST_TARGET);
98         String timeWindow = timeWindowVal + " " + timeWindowScale;
99         logger.info("Going to query DB about: actor {} operation {} target {} time window {}",
100                 actor, operation, target, timeWindow);
101         //
102         // Sanity check
103         //
104         if (actor == null || operation == null || target == null) {
105             //
106             // See if we have all the values
107             //
108             logger.error("missing attributes return empty");
109             return StdPIPResponse.PIP_RESPONSE_EMPTY;
110         }
111         //
112         // Ok do the database query
113         //
114         long operationCount = doDatabaseQuery(actor, operation, target, timeWindowVal, timeWindowScale);
115         //
116         // Create and return PipResponse
117         //
118         StdMutablePIPResponse pipResponse    = new StdMutablePIPResponse();
119         this.addLongAttribute(pipResponse,
120                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
121                 ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT,
122                 operationCount,
123                 pipRequest);
124         return new StdPIPResponse(pipResponse);
125     }
126
127     private long doDatabaseQuery(String actor, String operation, String target, int timeWindowVal,
128             String timeWindowScale) {
129         logger.info("Querying operations history for {} {} {} {} {}",
130                 actor, operation, target, timeWindowVal, timeWindowScale);
131         //
132         // Only can query if we have an EntityManager
133         //
134         if (em == null) {
135             logger.error("No EntityManager available");
136             return -1;
137         }
138         //
139         // Do the query
140         //
141         try {
142             //
143             // We are expecting a single result
144             //
145             return em.createQuery("select count(e) from Dbao e"
146                                   + " where e.outcome<>'Failure_Guard'"
147                                   + " and e.actor= ?1"
148                                   + " and e.operation= ?2"
149                                   + " and e.target= ?3"
150                                   + " and e.endtime between"
151                                   + " ?4 and CURRENT_TIMESTAMP",
152                                   Long.class)
153                 .setParameter(1, actor)
154                 .setParameter(2, operation)
155                 .setParameter(3, target)
156                 .setParameter(4, Timestamp.from(Instant.now()
157                                                 .minus(timeWindowVal,
158                                                        stringToChronoUnit(timeWindowScale))))
159                 .getSingleResult();
160         } catch (Exception e) {
161             logger.error("Typed query failed ", e);
162             return -1;
163         }
164     }
165
166     private ChronoUnit stringToChronoUnit(String scale) {
167         //
168         // Compute the time window
169         //
170         switch (scale.toLowerCase()) {
171             case "second":
172                 return ChronoUnit.SECONDS;
173             case "minute":
174                 return ChronoUnit.MINUTES;
175             case "hour":
176                 return ChronoUnit.HOURS;
177             case "day":
178                 return ChronoUnit.DAYS;
179             case "week":
180                 return ChronoUnit.WEEKS;
181             case "month":
182                 return ChronoUnit.MONTHS;
183             case "year":
184                 return ChronoUnit.YEARS;
185             default:
186                 //
187                 // Unsupported
188                 //
189                 logger.error("Unsupported time window scale value {}", scale);
190         }
191         return null;
192     }
193
194 }