use shutdown to clear handle leak
[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         if (this.shutdown) {
66             throw new PIPException("Engine is shutdown");
67         }
68         logger.debug("getAttributes requesting attribute {} of type {} for issuer {}",
69                 pipRequest.getAttributeId(), pipRequest.getDataTypeId(), pipRequest.getIssuer());
70         //
71         // Determine if the issuer is correct
72         //
73         if (Strings.isNullOrEmpty(pipRequest.getIssuer())) {
74             logger.debug("issuer is null - returning empty response");
75             //
76             // We only respond to ourself as the issuer
77             //
78             return StdPIPResponse.PIP_RESPONSE_EMPTY;
79         }
80         if (! pipRequest.getIssuer().startsWith(ToscaDictionary.GUARD_ISSUER_PREFIX)) {
81             logger.debug("Issuer does not start with guard");
82             //
83             // We only respond to ourself as the issuer
84             //
85             return StdPIPResponse.PIP_RESPONSE_EMPTY;
86         }
87         //
88         // Parse out the issuer which denotes the time window
89         // Eg: any-prefix:tw:10:minute
90         //
91         String[] s1 = pipRequest.getIssuer().split("tw:");
92         String[] s2 = s1[1].split(":");
93         int timeWindowVal = Integer.parseInt(s2[0]);
94         String timeWindowScale = s2[1];
95         //
96         // Grab other attribute values
97         //
98         String actor = getAttribute(pipFinder, PIP_REQUEST_ACTOR);
99         String operation = getAttribute(pipFinder, PIP_REQUEST_RECIPE);
100         String target = getAttribute(pipFinder, PIP_REQUEST_TARGET);
101         String timeWindow = timeWindowVal + " " + timeWindowScale;
102         logger.info("Going to query DB about: actor {} operation {} target {} time window {}",
103                 actor, operation, target, timeWindow);
104         //
105         // Sanity check
106         //
107         if (actor == null || operation == null || target == null) {
108             //
109             // See if we have all the values
110             //
111             logger.error("missing attributes return empty");
112             return StdPIPResponse.PIP_RESPONSE_EMPTY;
113         }
114         //
115         // Ok do the database query
116         //
117         long operationCount = doDatabaseQuery(actor, operation, target, timeWindowVal, timeWindowScale);
118         //
119         // Create and return PipResponse
120         //
121         StdMutablePIPResponse pipResponse    = new StdMutablePIPResponse();
122         this.addLongAttribute(pipResponse,
123                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
124                 ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT,
125                 operationCount,
126                 pipRequest);
127         return new StdPIPResponse(pipResponse);
128     }
129
130     private long doDatabaseQuery(String actor, String operation, String target, int timeWindowVal,
131             String timeWindowScale) {
132         logger.info("Querying operations history for {} {} {} {} {}",
133                 actor, operation, target, timeWindowVal, timeWindowScale);
134         //
135         // Only can query if we have an EntityManager
136         //
137         if (em == null) {
138             logger.error("No EntityManager available");
139             return -1;
140         }
141         //
142         // Do the query
143         //
144         try {
145             //
146             // We are expecting a single result
147             //
148             return em.createQuery("select count(e) from Dbao e"
149                                   + " where e.outcome<>'Failure_Guard'"
150                                   + " and e.actor= ?1"
151                                   + " and e.operation= ?2"
152                                   + " and e.target= ?3"
153                                   + " and e.endtime between"
154                                   + " ?4 and CURRENT_TIMESTAMP",
155                                   Long.class)
156                 .setParameter(1, actor)
157                 .setParameter(2, operation)
158                 .setParameter(3, target)
159                 .setParameter(4, Timestamp.from(Instant.now()
160                                                 .minus(timeWindowVal,
161                                                        stringToChronoUnit(timeWindowScale))))
162                 .getSingleResult();
163         } catch (Exception e) {
164             logger.error("Typed query failed ", e);
165             return -1;
166         }
167     }
168
169     private ChronoUnit stringToChronoUnit(String scale) {
170         //
171         // Compute the time window
172         //
173         switch (scale.toLowerCase()) {
174             case "second":
175                 return ChronoUnit.SECONDS;
176             case "minute":
177                 return ChronoUnit.MINUTES;
178             case "hour":
179                 return ChronoUnit.HOURS;
180             case "day":
181                 return ChronoUnit.DAYS;
182             case "week":
183                 return ChronoUnit.WEEKS;
184             case "month":
185                 return ChronoUnit.MONTHS;
186             case "year":
187                 return ChronoUnit.YEARS;
188             default:
189                 //
190                 // Unsupported
191                 //
192                 logger.error("Unsupported time window scale value {}", scale);
193         }
194         return null;
195     }
196
197 }