Policy TestSuite Enabled
[policy/engine.git] / ECOMP-XACML / src / test / java / org / openecomp / policy / xacml / test / TestPolicy.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ECOMP-XACML
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.openecomp.policy.xacml.test;
22
23 import java.io.IOException;
24 import java.net.MalformedURLException;
25 import java.nio.file.FileVisitResult;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.nio.file.Paths;
29 import java.nio.file.SimpleFileVisitor;
30 import java.nio.file.attribute.BasicFileAttributes;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.regex.Matcher;
39
40 import javax.xml.bind.JAXBContext;
41 import javax.xml.bind.JAXBElement;
42 import javax.xml.bind.Marshaller;
43
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeType;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
46 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributesType;
47 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
48 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
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.RequestType;
51
52 import org.apache.commons.cli.CommandLine;
53 import org.apache.commons.cli.GnuParser;
54 import org.apache.commons.cli.Option;
55 import org.apache.commons.cli.ParseException;
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58
59 import com.att.research.xacml.api.AttributeValue;
60 import com.att.research.xacml.api.DataType;
61 import com.att.research.xacml.api.DataTypeException;
62 import com.att.research.xacml.api.DataTypeFactory;
63 import com.att.research.xacml.api.Identifier;
64 import com.att.research.xacml.api.XACML3;
65 import com.att.research.xacml.std.IdentifierImpl;
66 import com.att.research.xacml.util.FactoryException;
67 import com.att.research.xacml.util.XACMLObjectCopy;
68 import com.att.research.xacml.util.XACMLPolicyAggregator;
69 import com.att.research.xacml.util.XACMLPolicyScanner;
70 import com.att.research.xacml.util.XACMLProperties;
71
72 /**
73  * This class reads the policy in and extracts all the attributes and their values that is contained
74  * in the Policy. It then generates a request every single combination of attributes found.
75  * 
76  * The attributes mostly come from the Target Match elements, since they have both an attribute designator/selector
77  * matched with an attribute value.
78  * 
79  *
80  */
81 public class TestPolicy extends TestBase {
82         private static Log logger       = LogFactory.getLog(TestPolicy.class);
83
84         private boolean skip;
85         private Path policy;
86         private XACMLPolicyAggregator aggregator = new XACMLPolicyAggregator();
87         private long index;
88         
89         //
90         // Our command line parameters
91         //
92         public static final String OPTION_POLICY = "policy";
93         public static final String OPTION_SKIP_GENERATE = "skip";
94
95         static {
96                 options.addOption(new Option(OPTION_POLICY, true, "Path to the policy file."));
97                 options.addOption(new Option(OPTION_SKIP_GENERATE, false, "Skip generating requests."));
98         }
99         
100         public class FlattenerObject {
101                 Identifier category;
102                 Identifier datatype;
103                 Identifier attribute;
104                 Set<AttributeValue<?>> values;
105         }
106         
107         /**
108          * This application exercises a policy by producing ALL the possible request combinations for a policy.
109          * 
110          * -policy Path to a policy file
111          * 
112          * @param args
113          * @throws HelpException 
114          * @throws ParseException 
115          * @throws MalformedURLException 
116          */
117
118         public TestPolicy(String[] args) throws MalformedURLException, ParseException, HelpException {
119                 super(args);
120         }
121
122         /* 
123          * Look for the -policy command line argument. This application needs a pointer to a specific policy
124          * in order to run.
125          * 
126          * 
127          * (non-Javadoc)
128          * @see com.att.research.xacmlatt.pdp.test.TestBase#parseCommands(java.lang.String[])
129          */
130         @Override
131         protected void parseCommands(String[] args) throws ParseException, MalformedURLException, HelpException {
132                 //
133                 // Have our super do its job
134                 //
135                 super.parseCommands(args);
136                 //
137                 // Look for the policy option
138                 //
139                 CommandLine cl;
140                 cl = new GnuParser().parse(options, args);
141                 if (cl.hasOption(OPTION_POLICY)) {
142                         this.policy = Paths.get(cl.getOptionValue(OPTION_POLICY));
143                         //
144                         // Ensure it exists
145                         //
146                         if (Files.notExists(this.policy)) {
147                                 throw new ParseException("Policy file does not exist.");
148                         }
149                 } else {
150                         throw new ParseException("You need to specify the policy file to be used.");
151                 }
152                 if (cl.hasOption(OPTION_SKIP_GENERATE)) {
153                         this.skip = true;
154                 } else {
155                         this.skip = false;
156                 }
157         }
158
159         /* 
160          * We override this method because here is where we want to scan the policy and aggregate all
161          * the attributes that are defined within the policy. This routine will then dump all the possible
162          * requests into the requests sub-directory. Thus, when this method returns the TestBase can proceed
163          * to iterate each generated request and run it against the PDP engine.
164          * 
165          * (non-Javadoc)
166          * @see com.att.research.xacmlatt.pdp.test.TestBase#configure()
167          */
168         @Override
169         protected void configure() throws FactoryException {
170                 //
171                 // Have our base class do its thing
172                 //
173                 super.configure();
174                 //
175                 // Setup where the PDP can find the policy
176                 //
177                 System.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "policy");
178                 System.setProperty("policy.file", this.policy.toString());
179                 //
180                 // Determine if they want us to skip generation. This helps when a huge number of
181                 // requests will get generated for a policy and can take some time to do so. The user
182                 // can generate the requests once and then start testing a policy against the requests. Thus,
183                 // the attributes never changed but the policy logic did (saves time).
184                 //
185                 if (this.skip) {
186                         return;
187                 }
188                 //
189                 // Now we will scan the policy and get all the attributes.
190                 //
191                 XACMLPolicyScanner scanner = new XACMLPolicyScanner(this.policy, this.aggregator);
192                 //
193                 // The scanner returns us a policy object
194                 //
195                 Object policyObject = scanner.scan();
196                 //
197                 // Just dump some info
198                 //
199                 if (policyObject instanceof PolicySetType) {
200                         logger.info("Creating requests for policyset: " + ((PolicySetType)policyObject).getDescription());
201                 } else if (policyObject instanceof PolicyType) {
202                         logger.info("Creating requests for policy: " + ((PolicyType)policyObject).getDescription());
203                 }
204                 //
205                 // Call the function to create the requests
206                 //
207                 if (policyObject != null) {
208                         this.createRequests();
209                 }
210
211                 logger.info("Completed Generating requests.");
212         }
213
214         @SuppressWarnings("unchecked")
215         protected void createRequests() {
216                 //
217                 // Clear out our request directory
218                 //
219                 this.removeRequests();
220                 //
221                 // Get our map
222                 //
223                 Map<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> attributeMap = this.aggregator.getAttributeMap();
224                 //
225                 // We're going to create an initial flat list of requests for each unique attribute ID. Unique being the
226                 // category, datatype and attribute id.
227                 //
228                 // By flattening the list, it makes it easier to then generate all the combinations of possible requests.
229                 //
230                 List<FlattenerObject> attributes = new ArrayList<FlattenerObject>();
231                 //
232                 // Iterate through all the maps, we are going to flatten it
233                 // out into an array list.
234                 //
235                 for (Map.Entry<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> categoryEntry : attributeMap.entrySet()) {
236                         String category = categoryEntry.getKey().toString();
237                         if (logger.isDebugEnabled()) {
238                                 logger.debug("Category: " + category);
239                         }
240                         Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>> datatypeMap = categoryEntry.getValue();
241                         for (Map.Entry<Identifier, Map<Identifier, Set<AttributeValue<?>>>> datatypeEntry : datatypeMap.entrySet()) {
242                                 String datatype = datatypeEntry.getKey().toString();
243                                 if (logger.isDebugEnabled()) {
244                                         logger.debug("\tData Type: " + datatype);
245                                 }
246                                 Map<Identifier, Set<AttributeValue<?>>> attributeIDMap = datatypeEntry.getValue();
247                                 for (Map.Entry<Identifier, Set<AttributeValue<?>>> attributeIDEntry : attributeIDMap.entrySet()) {
248                                         String attributeID = attributeIDEntry.getKey().toString();
249                                         if (logger.isDebugEnabled()) {
250                                                 logger.debug("\t\tAttribute ID: " + attributeID);
251                                         }
252                                         Set<AttributeValue<?>> attributeValueSet = attributeIDEntry.getValue();
253                                         //
254                                         // Sanity check to see if there are any values. Sometimes there isn't if an attribute
255                                         // is a designator that is part of a condition or variable.
256                                         //
257                                         if (attributeValueSet.isEmpty()) {
258                                                 if (logger.isDebugEnabled()) {
259                                                         logger.debug("No values for attribute " + attributeIDEntry.getKey().stringValue());
260                                                 }
261                                                 //
262                                                 // Check for the boolean datatype, in that case we can safely
263                                                 // assume the true/false are ALL the possible values.
264                                                 //
265                                                 if (datatypeEntry.getKey().equals(XACML3.ID_DATATYPE_BOOLEAN) == false) {
266                                                         //
267                                                         // Not boolean, so skip it
268                                                         //
269                                                         continue;
270                                                 }
271                                                 if (logger.isDebugEnabled()) {
272                                                         logger.debug("No values but its a boolean datatype, we will include it anyway.");
273                                                 }
274                                         }
275                                         //
276                                         // Create our flattener object
277                                         //
278                                         FlattenerObject flat = new FlattenerObject();
279                                         flat.category = categoryEntry.getKey();
280                                         flat.datatype = datatypeEntry.getKey();
281                                         flat.attribute = attributeIDEntry.getKey();
282                                         flat.values = new HashSet<AttributeValue<?>>();
283                                         if (datatypeEntry.getKey().equals(XACML3.ID_DATATYPE_BOOLEAN)) {
284                                                 //
285                                                 // There are only 2 possible values, true or false
286                                                 //
287                                                 flat.values.add(this.createAttributeValue(flat.datatype, true));
288                                                 flat.values.add(this.createAttributeValue(flat.datatype, false));
289                                         } else {
290                                                 flat.values.addAll(attributeValueSet);
291                                         }
292                                         attributes.add(flat);
293                                 }
294                         }
295                 }
296                 if (attributes.size() <= 1) {
297                         //
298                         // Only one attribute, why bother
299                         //
300                         logger.info("Not enough attributes in policy: " + attributes.size());
301                         return;
302                 }
303                 /*
304                  * PLD work more on this later. This combinatorial formula is only accurate if each
305                  * attribute has one value.
306                  * 
307                  */
308                 if (logger.isDebugEnabled()) {
309                         //
310                         // This isn't really accurate, if an attribute has more than one value
311                         //
312                         logger.debug(attributes.size() + " will generate " + computePossibleCombinations(attributes.size()));
313                 }
314                 this.index = 1;
315                 for (int i = 0; i < attributes.size(); i++) {
316                         FlattenerObject flat = attributes.get(i);
317                         for (AttributeValue<?> value : flat.values) {
318                                 //
319                                 // Create a basic request object for just that attribute value.
320                                 //
321                                 RequestType request = new RequestType();
322                                 //
323                                 AttributesType attrs = new AttributesType();
324                                 attrs.setCategory(flat.category.stringValue());
325                                 request.getAttributes().add(attrs);
326                                 //
327                                 AttributeType attr = new AttributeType();
328                                 attr.setAttributeId(flat.attribute.stringValue());
329                                 attrs.getAttribute().add(attr);
330                                 //
331                                 AttributeValueType val = new AttributeValueType();
332                                 val.setDataType(flat.datatype.stringValue());
333                                 if (value.getValue() instanceof Collection) {
334                                         val.getContent().addAll((Collection<? extends Object>) value.getValue());
335                                 } else {
336                                         val.getContent().add(value.getValue().toString());
337                                 }
338                                 //
339                                 attr.getAttributeValue().add(val);
340                                 //
341                                 // Dump it out
342                                 //
343                                 this.writeRequest(request);
344                                 //
345                                 // Initiate recursive call to add other attributes to the request
346                                 //
347                                 this.recursivelyGenerateRequests(request, i + 1, attributes);
348                         }
349                 }
350         }
351         
352         protected void recursivelyGenerateRequests(RequestType request, int i, List<FlattenerObject> attributes) {
353                 if (logger.isTraceEnabled()) {
354                         logger.trace("recursiveGenerate index: " + index + " i: " + i);
355                 }
356                 for ( ; i < attributes.size(); i++) {
357                         FlattenerObject flat = attributes.get(i);
358                         for (AttributeValue<?> value : flat.values) {
359                                 //
360                                 // Make a copy of the request
361                                 //
362                                 RequestType copyRequest = XACMLObjectCopy.deepCopy(request);
363                                 //
364                                 // Create the value object
365                                 //
366                                 AttributeValueType newValue = new AttributeValueType();
367                                 newValue.setDataType(flat.datatype.stringValue());
368                                 if (value.getValue() instanceof Collection) {
369                                         for (Object v : (Collection<?>) value.getValue()) {
370                                                 newValue.getContent().add(v.toString());
371                                         }
372                                 } else {
373                                         newValue.getContent().add(value.getValue().toString());
374                                 }
375                                 //
376                                 // Add the value to the request
377                                 //
378                                 this.addAttribute(copyRequest, flat.category.stringValue(), flat.attribute.stringValue(), newValue);
379                                 //
380                                 // Now write it out
381                                 //
382                                 this.writeRequest(copyRequest);
383                                 //
384                                 // Recursively go through the rest of the attributes
385                                 //
386                                 this.recursivelyGenerateRequests(copyRequest, i + 1, attributes);
387                         }
388                 }
389         }
390         
391         public static long      computePossibleCombinations(long numberOfAttributes) {
392                 long num = 0;
393                 for (long i = numberOfAttributes; i > 0; i--) {
394                         num += computeCombinations(numberOfAttributes, i);
395                 }
396                 return num;
397         }
398         
399         public static long      computeFactorial(long n) {
400                 long fact = 1;
401                 for (long i = 1; i <= n; i++) {
402                         fact *= i;
403                 }
404                 return fact;
405         }
406
407         public static long      computePermutationsWithoutRepetition(long n, long r) {
408                 //
409                 //      n!
410                 //      ---------
411                 //   (n - r)!
412                 //
413                 long nPrime = 1;
414                 long n_rPrime = 1;
415                 for (long i = n; i > 1; i--) {
416                         nPrime *= i; 
417                 }
418                 
419                 for (long i = (n - r); i > 1; i--) {
420                         n_rPrime *= i; 
421                 }
422                 return nPrime / n_rPrime;
423         }
424         
425         public static long      computeCombinations(long n, long r) {
426                 //
427                 //               n!
428                 //      -----------
429                 //  r! * (n-r)!
430                 //
431                 long nPrime = 1;
432                 long rPrime = 1;
433                 long n_rPrime = 1;
434                 
435                 for (long i = n; i > 1; i--) {
436                         nPrime *= i; 
437                 }
438                 
439                 for (long i = r; i > 1; i--) {
440                         rPrime *= i; 
441                 }
442                 
443                 for (long i = (n - r); i > 1; i--) {
444                         n_rPrime *= i; 
445                 }
446                 
447                 return nPrime / (rPrime * n_rPrime);
448         }
449
450         protected Set<AttributeValue<?>> getAttributeValues(RequestType request) {
451                 //
452                 // Get our map
453                 //
454                 Map<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> attributeMap = this.aggregator.getAttributeMap();
455                 //
456                 // Find the attribute
457                 //
458                 AttributesType attrs = request.getAttributes().get(0);
459                 Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>> categoryMap = attributeMap.get(new IdentifierImpl(attrs.getCategory()));
460                 if (categoryMap != null) {
461                         AttributeType a = attrs.getAttribute().get(0);
462                         Map<Identifier, Set<AttributeValue<?>>> datatypeMap = categoryMap.get(new IdentifierImpl(a.getAttributeValue().get(0).getDataType()));
463                         if (datatypeMap != null) {
464                                 Set<AttributeValue<?>> values = datatypeMap.get(new IdentifierImpl(a.getAttributeId()));
465                                 if (values != null) {
466                                         return values;
467                                 }
468                         }
469                 }
470                 return Collections.emptySet();
471         }
472         
473         protected AttributeValue<?> createAttributeValue(Identifier datatype, Object value) {
474                 DataTypeFactory dataTypeFactory         = null;
475                 try {
476                         dataTypeFactory = DataTypeFactory.newInstance();
477                         if (dataTypeFactory == null) {
478                                 logger.error("Could not create data type factory");
479                                 return null;
480                         }
481                 } catch (FactoryException e) {
482                         logger.error("Can't get Data type Factory: " + e.getLocalizedMessage());
483                         return null;
484                 }               
485                 DataType<?> dataTypeExtended    = dataTypeFactory.getDataType(datatype);
486                 if (dataTypeExtended == null) {
487                         logger.error("Unknown datatype: " + datatype);
488                         return null;
489                 }
490                 try {
491                         return dataTypeExtended.createAttributeValue(value);
492                 } catch (DataTypeException e) {
493                         logger.error(e);
494                 }
495                 return null;
496         }
497         
498         protected void removeRequests() {
499                 //
500                 // Delete any existing request files that we generate. i.e. Have the Unknown in the file name.
501                 //
502                 try {
503                         Files.walkFileTree(Paths.get(this.directory.toString(), "requests"), new SimpleFileVisitor<Path>() {
504
505                                 @Override
506                                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
507                                         //
508                                         // Sanity check the file name
509                                         //
510                                         Matcher matcher = pattern.matcher(file.getFileName().toString());
511                                         if (matcher.matches()) {
512                                                 try {
513                                                         //
514                                                         // Pull what this request is supposed to be
515                                                         //
516                                                         String group = null;
517                                                         int count = matcher.groupCount();
518                                                         if (count >= 1) {
519                                                                 group = matcher.group(count-1);
520                                                         }
521                                                         //
522                                                         // Send it
523                                                         //
524                                                         if (group.equals("Unknown")) {
525                                                                 //
526                                                                 // Remove the file
527                                                                 //
528                                                                 Files.delete(file);
529                                                         }
530                                                 } catch (Exception e) {
531                                                         logger.error(e);
532                                                         logger.error("Exception Occured"+e);
533                                                 }
534                                         }
535                                         return super.visitFile(file, attrs);
536                                 }                               
537                         });
538                 } catch (IOException e) {
539                         logger.error("Failed to removeRequests from " + this.directory + " " + e);
540                 }
541         }
542
543         protected void addRequests(RequestType request, List<RequestType> requests, int index) {
544                 for (RequestType req : requests) {
545                         //
546                         // There really should only be one attribute
547                         //
548                         for (AttributesType attrs : req.getAttributes()) {
549                                 for (AttributeType attr : attrs.getAttribute()) {
550                                         for (AttributeValueType value : attr.getAttributeValue()) {
551                                                 if (this.addAttribute(request, attrs.getCategory(), attr.getAttributeId(), value)) {
552                                                         this.writeRequest(request);
553                                                 }
554                                         }
555                                 }
556                         }
557                 }
558         }
559
560         /**
561          * Writes the request into the "requests" sub-directory, relative to the value of the "directory" setup
562          * during initialization.
563          * 
564          * Writing the requests out allows one to go back and easily refer to the request when analyzing the responses
565          * generated after the PDP decide() call. Also, one can then use the generated requests into any test tools
566          * they wish to build.
567          * 
568          * @param request - The request to be written.
569          */
570         protected void writeRequest(RequestType request) {
571                 if (logger.isTraceEnabled()) {
572                         logger.trace("writeRequest: " + index);
573                 }
574                 try {
575                         ObjectFactory of = new ObjectFactory();
576                         JAXBElement<RequestType> requestElement = of.createRequest(request);
577                         JAXBContext context = JAXBContext.newInstance(RequestType.class);
578                         Marshaller m = context.createMarshaller();
579                         m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
580                         Path outFile = Paths.get(this.directory, "requests", String.format("Request.%06d.Unknown.xml", this.index));
581                         m.marshal(requestElement, outFile.toFile());
582                 } catch (Exception e) {
583                         logger.error("Failed to write request: " + e.getMessage());
584                 }
585                 this.index++;
586         }
587
588         protected boolean       addAttribute(RequestType request, String category, String id, AttributeValueType value) {
589                 //
590                 // See if the category exists
591                 //
592                 for (AttributesType attrs : request.getAttributes()) {
593                         if (attrs.getCategory().equals(category)) {
594                                 //
595                                 // It does have the category. But does it have the attribute ID?
596                                 //
597                                 for (AttributeType attr : attrs.getAttribute()) {
598                                         if (attr.getAttributeId().equals(id)) {
599                                                 //
600                                                 // Yes, check for the same datatype
601                                                 //
602                                                 for (AttributeValueType val : attr.getAttributeValue()) {
603                                                         if (val.getDataType().equals(value.getDataType())) {
604                                                                 //
605                                                                 // We have something already there
606                                                                 //
607                                                                 return false;
608                                                         }
609                                                 }
610                                                 //
611                                                 // The ID exists, but not the datatype
612                                                 //
613                                                 attr.getAttributeValue().add(value);
614                                                 return true;
615                                         }
616                                 }
617                                 //
618                                 // If we get here, the ID does not exist
619                                 //
620                                 AttributeType attr = new AttributeType();
621                                 attr.setAttributeId(id);
622                                 attr.getAttributeValue().add(value);
623                                 attrs.getAttribute().add(attr);
624                                 return true;
625                         }
626                 }
627                 //
628                 // If we get here, the category does not exist. So add it in.
629                 //
630                 AttributesType attrs = new AttributesType();
631                 attrs.setCategory(category);
632                 AttributeType attr = new AttributeType();
633                 attr.setAttributeId(id);
634                 attr.getAttributeValue().add(value);
635                 attrs.getAttribute().add(attr);
636                 request.getAttributes().add(attrs);
637                 return true;
638         }
639
640         public static void main(String[] args) {
641                 try {
642                         new TestPolicy(args).run();
643                 } catch (ParseException | IOException | FactoryException e) {
644                         logger.error(e);
645                 } catch (HelpException e) {
646                 }
647         }
648
649         /*
650         // Map<CATEGORY, MAP<DATATYPE, MAP<ATTRIBUTEID, SET<VALUES>>>
651         @SuppressWarnings("unchecked")
652         private void generateRequests(Map<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> categoryMap) {
653                 meta = new ArrayList<>();
654                 
655                 for (Map.Entry<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> categoryEntry : categoryMap.entrySet()) {
656                         String category = categoryEntry.getKey().toString();
657                         logger.debug("Category: " + category);
658                         Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>> datatypeMap = categoryEntry.getValue();
659                         for (Map.Entry<Identifier, Map<Identifier, Set<AttributeValue<?>>>> datatypeEntry : datatypeMap.entrySet()) {
660                                 String datatype = datatypeEntry.getKey().toString();
661                                 logger.debug("\tData Type: " + datatype);
662                                 Map<Identifier, Set<AttributeValue<?>>> attributeIDMap = datatypeEntry.getValue();
663                                 for (Map.Entry<Identifier, Set<AttributeValue<?>>> attributeIDEntry : attributeIDMap.entrySet()) {
664                                         String attributeID = attributeIDEntry.getKey().toString();
665                                         logger.debug("\t\tAttribute ID: " + attributeID);
666                                         Set<AttributeValue<?>> attributeValueSet = attributeIDEntry.getValue();
667                                         for (AttributeValue<?> value : attributeValueSet) {
668                                                 logger.debug("\t\t\tAttribute Value: " + value);                                                
669                                         }
670                                         Iterator<AttributeValue<?>> iterator = attributeValueSet.iterator();
671                                         logger.debug("\t\t\t# of Attribute values: " + attributeValueSet.size());
672                                         meta.add(new Object[] {category, datatype, attributeID, iterator.next(), iterator, attributeValueSet});
673                                 }
674                         }
675                 }
676                 
677                 int count = 0;
678                 for (File file : output.toFile().listFiles()) {
679                         file.delete();
680                 }
681                         
682                 do {
683                         RequestType request = new RequestType();
684                         request.setCombinedDecision(false);
685                         request.setReturnPolicyIdList(false);
686                         List<AttributesType> attributesList = request.getAttributes();
687                         
688                         Map<String, AttributesType> category2Attribute= new HashMap<>();
689                         for (int i = 0; i < meta.size(); i++) {
690                                 Object[] record = meta.get(i);
691                                 
692                                 AttributesType attributes = null;
693                                 if (category2Attribute.containsKey(record[0].toString()))
694                                         attributes = category2Attribute.get(record[0].toString());
695                                 else {
696                                         attributes = new AttributesType();
697                                         attributes.setCategory(record[0].toString());
698                                         category2Attribute.put(record[0].toString(), attributes);
699                                         attributesList.add(attributes);                         
700                                 }
701 //                              attributes.setId(record[2].toString());
702                                 List<AttributeType> attrList = attributes.getAttribute();
703                                 
704                                 AttributeType attribute = new AttributeType();
705                                 attribute.setAttributeId(record[2].toString());
706                                 List<AttributeValueType> valueList = attribute.getAttributeValue();
707
708                                 AttributeValue<?> attributeValue = (AttributeValue<?>) record[3];
709
710                                 AttributeValueType value = new AttributeValueType();
711                                 value.setDataType(attributeValue.getDataTypeId().toString());
712                                 List<Object> content = value.getContent();
713                                 content.addAll((Collection<? extends Object>) attributeValue.getValue());
714                                 valueList.add(value);
715
716                                 attrList.add(attribute);
717                         }
718                         
719                         try {
720                                 ObjectFactory of = new ObjectFactory();
721                                 JAXBElement<RequestType> requestElement = of.createRequest(request);
722                                 JAXBContext context = JAXBContext.newInstance(RequestType.class);
723                                 Marshaller m = context.createMarshaller();
724                                 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
725                                 m.marshal(requestElement, output.resolve("request" + count + ".xml").toFile());
726                                 
727 //                              if (count == 0) {//Just send the first request to the engine
728                                         StringWriter sw = new StringWriter();
729                                         m.marshal(requestElement, sw);
730                                         logger.info(sw.toString());
731                                         EngineCaller engine = new LocalEngineCaller();
732                                         if (engine.startEngine("")) {
733                                                 String response = engine.decide(sw.toString(), "xml");
734                                                 FileWriter writer = new FileWriter(output.resolve("response" + count + ".xml").toFile());
735                                                 writer.write(response);
736                                                 writer.close();
737                                                 logger.info("Response received: \n" + response);                                        
738                                         }
739 //                              }
740                         } catch (Exception e) {
741                                 logger.error("Exception Occured"+e);
742                         }
743                         
744                         count++;
745                 } while (hasNextRequest());
746                         
747                 logger.info("# of requests generated: " + count);
748         }
749         
750         private boolean hasNextRequest() {
751                 int i = meta.size() - 1;
752                 Object[] record = meta.get(i);
753                 
754                 @SuppressWarnings("unchecked")
755                 Iterator<AttributeValue<?>> iterator = (Iterator<AttributeValue<?>>) record[4];
756                 if (iterator.hasNext()) {
757                         record[3] = iterator.next();
758                 } else {
759                         return recycleAttributeValue(i);
760                 }
761                 
762                 return true;
763         }
764         
765         @SuppressWarnings("unchecked")
766         private boolean recycleAttributeValue(int position) {
767                 boolean rc = true;
768                 
769                 if (position == 0)
770                         return false;
771                 
772                 Object[] record = meta.get(position);
773                 Set<AttributeValue<?>> attributeValueSet = (Set<AttributeValue<?>>) record[5];
774                 Iterator<AttributeValue<?>> newIt = attributeValueSet.iterator();
775                 record[4] = newIt;
776                 record[3] = newIt.next();
777                 int i = position - 1;
778                 Object[] previous = meta.get(i);
779                 Iterator<AttributeValue<?>> preIt = (Iterator<AttributeValue<?>>) previous[4];
780                 if (preIt.hasNext()) {
781                         previous[3] = preIt.next();
782                 } else {
783                         rc = recycleAttributeValue(i);
784                 }
785                 
786                 return rc;
787         }
788         
789         */
790         
791 }
792