1f73ed3ced519e09317acafbb1d67566c3d436a6
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2019 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.database.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.util.Arrays;
32 import java.util.Collection;
33 import java.util.Properties;
34 import javax.persistence.Persistence;
35 import org.onap.policy.database.ToscaDictionary;
36 import org.onap.policy.database.std.StdOnapPip;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41 public class CountRecentOperationsPip extends StdOnapPip {
42     public static final String ISSUER_NAME = "count-recent-operations";
43     private static Logger logger = LoggerFactory.getLogger(CountRecentOperationsPip.class);
44
45     public CountRecentOperationsPip() {
46         super();
47     }
48
49     @Override
50     public Collection<PIPRequest> attributesRequired() {
51         return Arrays.asList(PIP_REQUEST_ACTOR, PIP_REQUEST_RECIPE, PIP_REQUEST_TARGET);
52     }
53
54     @Override
55     public void configure(String id, Properties properties) throws PIPException {
56         super.configure(id, properties);
57         //
58         // Create our entity manager
59         //
60         em = null;
61         try {
62             //
63             // In case there are any overloaded properties for the JPA
64             //
65             Properties emProperties = new Properties(properties);
66             //
67             // Create the entity manager factory
68             //
69             em = Persistence.createEntityManagerFactory(
70                     properties.getProperty(ISSUER_NAME + ".persistenceunit"),
71                     emProperties).createEntityManager();
72         } catch (Exception e) {
73             logger.error("Persistence failed {} operations history db {}", e.getLocalizedMessage(), e);
74         }
75     }
76
77     /**
78      * getAttributes.
79      *
80      * @param pipRequest the request
81      * @param pipFinder the pip finder
82      * @return PIPResponse
83      */
84     @Override
85     public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
86         logger.debug("getAttributes requesting attribute {} of type {} for issuer {}",
87                 pipRequest.getAttributeId(), pipRequest.getDataTypeId(), pipRequest.getIssuer());
88         //
89         // Determine if the issuer is correct
90         //
91         if (Strings.isNullOrEmpty(pipRequest.getIssuer())) {
92             logger.debug("issuer is null - returning empty response");
93             //
94             // We only respond to ourself as the issuer
95             //
96             return StdPIPResponse.PIP_RESPONSE_EMPTY;
97         }
98         if (! pipRequest.getIssuer().startsWith(ToscaDictionary.GUARD_ISSUER_PREFIX)) {
99             logger.debug("Issuer does not start with guard");
100             //
101             // We only respond to ourself as the issuer
102             //
103             return StdPIPResponse.PIP_RESPONSE_EMPTY;
104         }
105         //
106         // Parse out the issuer which denotes the time window
107         // Eg: any-prefix:tw:10:minute
108         //
109         String[] s1 = pipRequest.getIssuer().split("tw:");
110         String[] s2 = s1[1].split(":");
111         int timeWindowVal = Integer.parseInt(s2[0]);
112         String timeWindowScale = s2[1];
113         //
114         // Grab other attribute values
115         //
116         String actor = getActor(pipFinder);
117         String operation = getRecipe(pipFinder);
118         String target = getTarget(pipFinder);
119         String timeWindow = timeWindowVal + " " + timeWindowScale;
120         logger.info("Going to query DB about: actor {} operation {} target {} time window {}",
121                 actor, operation, target, timeWindow);
122         //
123         // Sanity check
124         //
125         if (actor == null || operation == null || target == null) {
126             //
127             // See if we have all the values
128             //
129             logger.error("missing attributes return empty");
130             return StdPIPResponse.PIP_RESPONSE_EMPTY;
131         }
132         //
133         // Ok do the database query
134         //
135         int operationCount = doDatabaseQuery(actor, operation, target, timeWindowVal, timeWindowScale);
136         //
137         // Create and return PipResponse
138         //
139         StdMutablePIPResponse pipResponse    = new StdMutablePIPResponse();
140         this.addIntegerAttribute(pipResponse,
141                 XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE,
142                 ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT,
143                 operationCount,
144                 pipRequest);
145         return new StdPIPResponse(pipResponse);
146     }
147
148     private int doDatabaseQuery(String actor, String operation, String target, int timeWindowVal,
149             String timeWindowScale) {
150         logger.info("Querying operations history for {} {} {} {} {}",
151                 actor, operation, target, timeWindowVal, timeWindowScale);
152         if (em == null) {
153             logger.error("No EntityManager available");
154             return -1;
155         }
156         //
157         // Compute the time window
158         //
159         if (! "minute".equalsIgnoreCase(timeWindowScale)
160             && ! "hour".equalsIgnoreCase(timeWindowScale)
161             && ! "day".equalsIgnoreCase(timeWindowScale)
162             && ! "week".equalsIgnoreCase(timeWindowScale)
163             && ! "month".equalsIgnoreCase(timeWindowScale)
164             && ! "year".equalsIgnoreCase(timeWindowScale)) {
165             //
166             // Unsupported
167             //
168             logger.error("Unsupported time window scale value {}", timeWindowScale);
169             //
170             // Throw an exception instead?
171             //
172             return -1;
173         }
174         //
175         // Do the query
176         //
177         Object result = null;
178         try {
179             //
180             // Set up query --- operationshistory is magic, should fix sometime
181             //
182             String strQuery = "select count(*) as numops from operationshistory"
183                 + " where outcome<>'Failure_Guard'"
184                 + " and actor=?"
185                 + " and operation=?"
186                 + " and target=?"
187                 + " and endtime between"
188                 + " TIMESTAMPADD(?, ?, CURRENT_TIMESTAMP)"
189                 + " and CURRENT_TIMESTAMP";
190             //
191             // We are expecting a single result
192             //
193             result = em.createNativeQuery(strQuery)
194                 .setParameter(1, actor)
195                 .setParameter(2, operation)
196                 .setParameter(3, target)
197                 .setParameter(4, timeWindowScale)
198                 .setParameter(5, timeWindowVal * -1)
199                 .getSingleResult();
200         } catch (Exception e) {
201             logger.error("Named query failed ", e);
202         }
203         //
204         // Check our query results
205         //
206         if (result != null) {
207             //
208             // Success let's see what JPA returned to us
209             //
210             logger.info("operations query returned {}", result);
211             //
212             // Should get back a long
213             //
214             if (result instanceof Long) {
215                 return ((Long) result).intValue();
216             }
217             //
218             // We shouldn't really get this result, but just
219             // in case we'll do the dirty work of parsing the
220             // string representation of the object.
221             //
222             return Integer.parseInt(result.toString());
223         }
224         //
225         // We get here if we didn't get a result. Should
226         // we propagate back an exception?
227         //
228         return -1;
229     }
230
231 }