Merge "Add Control Loop Coordination policy."
[policy/xacml-pdp.git] / applications / guard / src / main / java / org / onap / policy / xacml / pdp / application / guard / LegacyGuardTranslator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019 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  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.xacml.pdp.application.guard;
24
25 import com.att.research.xacml.api.DataTypeException;
26 import com.att.research.xacml.api.Decision;
27 import com.att.research.xacml.api.Identifier;
28 import com.att.research.xacml.api.Request;
29 import com.att.research.xacml.api.Response;
30 import com.att.research.xacml.api.Result;
31 import com.att.research.xacml.api.XACML3;
32 import com.att.research.xacml.std.annotations.RequestParser;
33
34 import java.util.Collection;
35 import java.util.Map;
36
37 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
38 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType;
39 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType;
40 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
41 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
48 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
49 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
50 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
51 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
52
53 import org.onap.policy.models.decisions.concepts.DecisionRequest;
54 import org.onap.policy.models.decisions.concepts.DecisionResponse;
55 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
56 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
57 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
58 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
59 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
60 import org.onap.policy.pdp.xacml.application.common.operationshistory.CountRecentOperationsPip;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 public class LegacyGuardTranslator implements ToscaPolicyTranslator {
65
66     private static final Logger LOGGER = LoggerFactory.getLogger(LegacyGuardTranslator.class);
67
68     private static final String FIELD_GUARD_ACTIVE_START = "guardActiveStart";
69     private static final String FIELD_GUARD_ACTIVE_END = "guardActiveEnd";
70
71     public LegacyGuardTranslator() {
72         super();
73     }
74
75     @Override
76     public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
77         //
78         // Policy name should be at the root
79         //
80         String policyName = toscaPolicy.getMetadata().get("policy-id");
81         //
82         // Set it as the policy ID
83         //
84         PolicyType newPolicyType = new PolicyType();
85         newPolicyType.setPolicyId(policyName);
86         //
87         // Optional description
88         //
89         newPolicyType.setDescription(toscaPolicy.getDescription());
90         //
91         // There should be a metadata section
92         //
93         this.fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
94         //
95         // Set the combining rule
96         //
97         newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue());
98         //
99         // Generate the TargetType
100         //
101         newPolicyType.setTarget(this.generateTargetType(toscaPolicy.getProperties()));
102         //
103         // Now create the Permit Rule
104         //
105         RuleType rule = generatePermitRule(policyName, toscaPolicy.getType(), toscaPolicy.getProperties());
106         //
107         // Check if we were able to create the rule
108         //
109         if (rule == null) {
110             LOGGER.warn("Failed to create rule");
111             return null;
112         }
113         //
114         // Add the rule to the policy
115         //
116         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
117         //
118         // Return our new policy
119         //
120         return newPolicyType;
121     }
122
123     @Override
124     public Request convertRequest(DecisionRequest request) {
125         LOGGER.debug("Converting Request {}", request);
126         try {
127             return RequestParser.parseRequest(LegacyGuardPolicyRequest.createInstance(request));
128         } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
129             LOGGER.error("Failed to convert DecisionRequest: {}", e);
130         }
131         //
132         // TODO throw exception
133         //
134         return null;
135     }
136
137     @Override
138     public DecisionResponse convertResponse(Response xacmlResponse) {
139         LOGGER.debug("Converting Response {}", xacmlResponse);
140         DecisionResponse decisionResponse = new DecisionResponse();
141         //
142         // Iterate through all the results
143         //
144         for (Result xacmlResult : xacmlResponse.getResults()) {
145             //
146             // Check the result
147             //
148             if (xacmlResult.getDecision() == Decision.PERMIT) {
149                 //
150                 // Just simply return a Permit response
151                 //
152                 decisionResponse.setStatus(Decision.PERMIT.toString());
153             }
154             if (xacmlResult.getDecision() == Decision.DENY) {
155                 //
156                 // Just simply return a Deny response
157                 //
158                 decisionResponse.setStatus(Decision.DENY.toString());
159             }
160             if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) {
161                 //
162                 // There is no guard policy, so we return a permit
163                 //
164                 decisionResponse.setStatus(Decision.PERMIT.toString());
165             }
166         }
167
168         return decisionResponse;
169     }
170
171     /**
172      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
173      *
174      * @param policy Policy Object to store the metadata
175      * @param map The Metadata TOSCA Map
176      * @return Same Policy Object
177      * @throws ToscaPolicyConversionException If there is something missing from the metadata
178      */
179     protected PolicyType fillMetadataSection(PolicyType policy,
180             Map<String, String> map) throws ToscaPolicyConversionException {
181         if (! map.containsKey("policy-id")) {
182             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id");
183         } else {
184             //
185             // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field
186             //
187         }
188         if (! map.containsKey("policy-version")) {
189             throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
190         } else {
191             //
192             // Add in the Policy Version
193             //
194             policy.setVersion(map.get("policy-version").toString());
195         }
196         return policy;
197     }
198
199     protected TargetType generateTargetType(Map<String, Object> properties) {
200         //
201         // Go through potential properties
202         //
203         AllOfType allOf = new AllOfType();
204         if (properties.containsKey("actor")) {
205             addMatch(allOf, properties.get("actor"), ToscaDictionary.ID_RESOURCE_GUARD_ACTOR);
206         }
207         if (properties.containsKey("recipe")) {
208             addMatch(allOf, properties.get("recipe"), ToscaDictionary.ID_RESOURCE_GUARD_RECIPE);
209         }
210         if (properties.containsKey("targets")) {
211             addMatch(allOf, properties.get("targets"), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
212         }
213         if (properties.containsKey("clname")) {
214             addMatch(allOf, properties.get("clname"), ToscaDictionary.ID_RESOURCE_GUARD_CLNAME);
215         }
216         if (properties.containsKey("targets")) {
217             addMatch(allOf, properties.get("targets"), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID);
218         }
219         //
220         // Create target
221         //
222         TargetType target = new TargetType();
223         AnyOfType anyOf = new AnyOfType();
224         anyOf.getAllOf().add(allOf);
225         target.getAnyOf().add(anyOf);
226         return target;
227     }
228
229     private static AllOfType addMatch(AllOfType allOf, Object value, Identifier attributeId) {
230         if (value instanceof String) {
231             if (".*".equals(value.toString())) {
232                 //
233                 // There's no point to even have a match
234                 //
235                 return allOf;
236             } else {
237                 //
238                 // Exact match
239                 //
240                 MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
241                     XACML3.ID_FUNCTION_STRING_EQUAL,
242                     value,
243                     XACML3.ID_DATATYPE_STRING,
244                     attributeId,
245                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
246
247                 allOf.getMatch().add(match);
248             }
249             return allOf;
250         }
251         if (value instanceof Collection) {
252             //
253             // TODO support a collection of that attribute
254             //
255         }
256         return allOf;
257     }
258
259     private static RuleType generatePermitRule(String policyName, String policyType, Map<String, Object> properties)
260             throws ToscaPolicyConversionException {
261         //
262         // Now determine which policy type we are generating
263         //
264         if ("onap.policies.controlloop.guard.FrequencyLimiter".equals(policyType)) {
265             return generateFrequencyPermit(policyName, properties);
266         } else if ("onap.policies.controlloop.guard.MinMax".equals(policyType)) {
267             return generateMinMaxPermit(policyName, properties);
268         }
269         LOGGER.error("Missing policy type in the policy");
270         return null;
271     }
272
273     private static RuleType generateFrequencyPermit(String policyName, Map<String, Object> properties)
274             throws ToscaPolicyConversionException {
275         //
276         // See if its possible to generate a count
277         //
278         Integer limit = parseInteger(properties.get("limit").toString());
279         if (limit == null) {
280             LOGGER.debug("Must have a limit value for frequency guard policy to be created");
281             return null;
282         }
283         //
284         // Get the properties that are common among guards
285         //
286         String timeWindow = null;
287         if (properties.containsKey("timeWindow")) {
288             Integer intTimeWindow = parseInteger(properties.get("timeWindow").toString());
289             if (intTimeWindow == null) {
290                 throw new ToscaPolicyConversionException("timeWindow is not an integer");
291             }
292             timeWindow = intTimeWindow.toString();
293         }
294         String timeUnits = null;
295         if (properties.containsKey("timeUnits")) {
296             timeUnits = properties.get("timeUnits").toString();
297         }
298         String guardActiveStart = null;
299         if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) {
300             guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString();
301         }
302         String guardActiveEnd = null;
303         if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) {
304             guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString();
305         }
306         //
307         // Generate the time in range
308         //
309         final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd);
310         //
311         // Generate a count
312         //
313         final ApplyType countCheck = generateCountCheck(limit, timeWindow, timeUnits);
314         //
315         // Now combine into an And
316         //
317         ApplyType applyAnd = new ApplyType();
318         applyAnd.setDescription("return true if time range and count checks are true.");
319         applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
320         applyAnd.getExpression().add(new ObjectFactory().createApply(timeRange));
321         applyAnd.getExpression().add(new ObjectFactory().createApply(countCheck));
322
323         //
324         // Create our condition
325         //
326         final ConditionType condition = new ConditionType();
327         condition.setExpression(new ObjectFactory().createApply(applyAnd));
328
329         //
330         // Now we can create our rule
331         //
332         RuleType permit = new RuleType();
333         permit.setDescription("Default is to PERMIT if the policy matches.");
334         permit.setRuleId(policyName + ":rule");
335         permit.setEffect(EffectType.PERMIT);
336         permit.setTarget(new TargetType());
337         //
338         // Add the condition
339         //
340         permit.setCondition(condition);
341         //
342         // TODO Add the advice - Is the request id needed to be returned?
343         //
344         // permit.setAdviceExpressions(adviceExpressions);
345         //
346         // Done
347         //
348         return permit;
349     }
350
351     private static RuleType generateMinMaxPermit(String policyName, Map<String, Object> properties) {
352         //
353         // Get the properties that are common among guards
354         //
355         String guardActiveStart = null;
356         if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) {
357             guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString();
358         }
359         String guardActiveEnd = null;
360         if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) {
361             guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString();
362         }
363         //
364         // Generate the time in range
365         //
366         final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd);
367         //
368         // See if its possible to generate a count
369         //
370         Integer min = null;
371         if (properties.containsKey("min")) {
372             min = parseInteger(properties.get("min").toString());
373         }
374         Integer max = null;
375         if (properties.containsKey("max")) {
376             max = parseInteger(properties.get("max").toString());
377         }
378         final ApplyType minApply = generateMinCheck(min);
379         final ApplyType maxApply = generateMaxCheck(max);
380         //
381         // Make sure we have at least something to check here,
382         // otherwise there really is no point to this policy.
383         //
384         if (timeRange == null && minApply == null && maxApply == null) {
385             return null;
386         }
387         //
388         // Create our rule
389         //
390         RuleType permit = new RuleType();
391         permit.setDescription("Default is to PERMIT if the policy matches.");
392         permit.setRuleId(policyName + ":rule");
393         permit.setEffect(EffectType.PERMIT);
394         permit.setTarget(new TargetType());
395         //
396         // Create our condition
397         //
398         final ConditionType condition = new ConditionType();
399         //
400         // Check if we have all the fields (this can be a little
401         // ugly) but the ultimate goal is to simplify the policy
402         // condition to only check for necessary attributes.
403         //
404         ObjectFactory factory = new ObjectFactory();
405         if (timeRange != null && minApply != null && maxApply != null) {
406             //
407             // All 3 must apply
408             //
409             ApplyType applyAnd = new ApplyType();
410             applyAnd.setDescription("return true if all the apply's are true.");
411             applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
412             applyAnd.getExpression().add(factory.createApply(timeRange));
413             applyAnd.getExpression().add(factory.createApply(minApply));
414             applyAnd.getExpression().add(factory.createApply(maxApply));
415             //
416             // Add into the condition
417             //
418             condition.setExpression(factory.createApply(applyAnd));
419         } else {
420             //
421             // At least one of these applies is null. We need at least
422             // two to require the And apply. Otherwise there is no need
423             // for an outer And apply as the single condition can work
424             // on its own.
425             //
426             if (timeRange != null && minApply == null && maxApply == null) {
427                 //
428                 // Only the time range check is necessary
429                 //
430                 condition.setExpression(factory.createApply(timeRange));
431             } else if (timeRange == null && minApply != null && maxApply == null) {
432                 //
433                 // Only the min check is necessary
434                 //
435                 condition.setExpression(factory.createApply(minApply));
436             } else if (timeRange == null && minApply == null) {
437                 //
438                 // Only the max check is necessary
439                 //
440                 condition.setExpression(factory.createApply(maxApply));
441             } else {
442                 //
443                 // Ok we will need an outer And and have at least the
444                 // time range and either min or max check
445                 //
446                 ApplyType applyAnd = new ApplyType();
447                 applyAnd.setDescription("return true if all the apply's are true.");
448                 applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue());
449                 if (timeRange != null) {
450                     applyAnd.getExpression().add(factory.createApply(timeRange));
451                 }
452                 if (minApply != null) {
453                     applyAnd.getExpression().add(factory.createApply(minApply));
454                 }
455                 if (maxApply != null) {
456                     applyAnd.getExpression().add(factory.createApply(maxApply));
457                 }
458                 //
459                 // Add into the condition
460                 //
461                 condition.setExpression(factory.createApply(applyAnd));
462             }
463         }
464         //
465         // Add the condition
466         //
467         permit.setCondition(condition);
468         //
469         // TODO Add the advice - Is the request id needed to be returned?
470         //
471         // permit.setAdviceExpressions(adviceExpressions);
472         //
473         // Done
474         //
475         return permit;
476     }
477
478     private static ApplyType generateTimeInRange(String start, String end) {
479         if (start == null || end == null) {
480             LOGGER.warn("Missing time range start {} end {}", start, end);
481             return null;
482         }
483         if (start.isEmpty() || end.isEmpty()) {
484             LOGGER.warn("Empty time range start {} end {}", start, end);
485             return null;
486         }
487
488         AttributeDesignatorType designator = new AttributeDesignatorType();
489         designator.setAttributeId(XACML3.ID_ENVIRONMENT_CURRENT_TIME.stringValue());
490         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_ENVIRONMENT.stringValue());
491         designator.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
492
493         AttributeValueType valueStart = new AttributeValueType();
494         valueStart.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
495         valueStart.getContent().add(start);
496
497         AttributeValueType valueEnd = new AttributeValueType();
498         valueEnd.setDataType(XACML3.ID_DATATYPE_TIME.stringValue());
499         valueEnd.getContent().add(end);
500
501         ObjectFactory factory = new ObjectFactory();
502
503         ApplyType applyOneAndOnly = new ApplyType();
504         applyOneAndOnly.setDescription("Unbag the current time");
505         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_TIME_ONE_AND_ONLY.stringValue());
506         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
507
508         ApplyType applyTimeInRange = new ApplyType();
509         applyTimeInRange.setDescription("return true if current time is in range.");
510         applyTimeInRange.setFunctionId(XACML3.ID_FUNCTION_TIME_IN_RANGE.stringValue());
511         applyTimeInRange.getExpression().add(factory.createApply(applyOneAndOnly));
512         applyTimeInRange.getExpression().add(factory.createAttributeValue(valueStart));
513         applyTimeInRange.getExpression().add(factory.createAttributeValue(valueEnd));
514
515         return applyTimeInRange;
516     }
517
518     private static ApplyType generateCountCheck(Integer limit, String timeWindow, String timeUnits) {
519         AttributeDesignatorType designator = new AttributeDesignatorType();
520         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT.stringValue());
521         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
522         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
523         //
524         // TODO Add this back in when the operational database PIP is configured.
525         // The issuer indicates that the PIP will be providing this attribute during
526         // the decision making.
527         //
528         // Right now I am faking the count value by re-using the request-id field
529         //
530         String issuer = ToscaDictionary.GUARD_ISSUER_PREFIX
531             + CountRecentOperationsPip.ISSUER_NAME
532             + ":tw:" + timeWindow + ":" + timeUnits;
533         designator.setIssuer(issuer);
534
535         AttributeValueType valueLimit = new AttributeValueType();
536         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
537         //
538         // Yes really use toString(), the marshaller will
539         // throw an exception if this is an integer object
540         // and not a string.
541         //
542         valueLimit.getContent().add(limit.toString());
543
544         ObjectFactory factory = new ObjectFactory();
545
546         ApplyType applyOneAndOnly = new ApplyType();
547         applyOneAndOnly.setDescription("Unbag the limit");
548         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
549         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
550
551         ApplyType applyLessThan = new ApplyType();
552         applyLessThan.setDescription("return true if current count is less than.");
553         applyLessThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN.stringValue());
554         applyLessThan.getExpression().add(factory.createApply(applyOneAndOnly));
555         applyLessThan.getExpression().add(factory.createAttributeValue(valueLimit));
556
557         return applyLessThan;
558     }
559
560     private static ApplyType generateMinCheck(Integer min) {
561         if (min == null) {
562             return null;
563         }
564         AttributeDesignatorType designator = new AttributeDesignatorType();
565         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue());
566         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
567         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
568         //
569         //
570         //
571         AttributeValueType valueLimit = new AttributeValueType();
572         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
573         //
574         // Yes really use toString(), the marshaller will
575         // throw an exception if this is an integer object
576         // and not a string.
577         //
578         valueLimit.getContent().add(min.toString());
579         ObjectFactory factory = new ObjectFactory();
580
581         ApplyType applyOneAndOnly = new ApplyType();
582         applyOneAndOnly.setDescription("Unbag the min");
583         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
584         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
585
586         ApplyType applyGreaterThanEqual = new ApplyType();
587         applyGreaterThanEqual.setDescription("return true if current count is greater than or equal.");
588         applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_GREATER_THAN_OR_EQUAL.stringValue());
589         applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly));
590         applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit));
591
592         return applyGreaterThanEqual;
593     }
594
595     private static ApplyType generateMaxCheck(Integer max) {
596         if (max == null) {
597             return null;
598         }
599         AttributeDesignatorType designator = new AttributeDesignatorType();
600         designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue());
601         designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
602         designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
603         //
604         //
605         //
606         AttributeValueType valueLimit = new AttributeValueType();
607         valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
608         //
609         // Yes really use toString(), the marshaller will
610         // throw an exception if this is an integer object
611         // and not a string.
612         //
613         valueLimit.getContent().add(max.toString());
614         ObjectFactory factory = new ObjectFactory();
615
616         ApplyType applyOneAndOnly = new ApplyType();
617         applyOneAndOnly.setDescription("Unbag the min");
618         applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue());
619         applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator));
620
621         ApplyType applyLessThanEqual = new ApplyType();
622         applyLessThanEqual.setDescription("return true if current count is less than or equal.");
623         applyLessThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN_OR_EQUAL.stringValue());
624         applyLessThanEqual.getExpression().add(factory.createApply(applyOneAndOnly));
625         applyLessThanEqual.getExpression().add(factory.createAttributeValue(valueLimit));
626
627         return applyLessThanEqual;
628     }
629
630     private static Integer parseInteger(String strInteger) {
631         Integer theInt = null;
632         try {
633             theInt = Integer.parseInt(strInteger);
634         } catch (NumberFormatException e) {
635             LOGGER.warn("Expecting an integer", e);
636             try {
637                 Double dblLimit = Double.parseDouble(strInteger);
638                 theInt = dblLimit.intValue();
639             } catch (NumberFormatException e1) {
640                 LOGGER.error("Failed to parse expected integer as a double", e);
641                 return null;
642             }
643         }
644         return theInt;
645     }
646
647     private static AdviceExpressionsType generateRequestIdAdvice() {
648         AdviceExpressionType adviceExpression = new AdviceExpressionType();
649         adviceExpression.setAppliesTo(EffectType.PERMIT);
650         adviceExpression.setAdviceId(ToscaDictionary.ID_ADVICE_GUARD.stringValue());
651
652         AttributeDesignatorType designator = new AttributeDesignatorType();
653         designator.setAttributeId(ToscaDictionary.ID_SUBJECT_GUARD_REQUESTID.stringValue());
654         designator.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue());
655         designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
656
657         AttributeAssignmentExpressionType assignment = new AttributeAssignmentExpressionType();
658         assignment.setAttributeId(ToscaDictionary.ID_ADVICE_GUARD_REQUESTID.stringValue());
659         assignment.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue());
660         assignment.setExpression(new ObjectFactory().createAttributeDesignator(designator));
661
662         adviceExpression.getAttributeAssignmentExpression().add(assignment);
663
664         AdviceExpressionsType adviceExpressions = new AdviceExpressionsType();
665         adviceExpressions.getAdviceExpression().add(adviceExpression);
666
667         return adviceExpressions;
668     }
669 }