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