Initial OpenECOMP policy/engine commit

Change-Id: I7dbff37733b661643dd4d1caefa3d7dccc361b6e
Signed-off-by: Pamela Dragosh <pdragosh@research.att.com>
diff --git a/ECOMP-XACML/.gitignore b/ECOMP-XACML/.gitignore
new file mode 100644
index 0000000..1baade8
--- /dev/null
+++ b/ECOMP-XACML/.gitignore
@@ -0,0 +1,5 @@
+/bin
+/target/
+/target/
+/target/
+/target/
diff --git a/ECOMP-XACML/policyLogger.properties b/ECOMP-XACML/policyLogger.properties
new file mode 100644
index 0000000..7fa1b20
--- /dev/null
+++ b/ECOMP-XACML/policyLogger.properties
@@ -0,0 +1,44 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+################################### Set concurrentHashMap and timer info  #######################
+#Timer initial delay and the delay between in milliseconds before task is to be execute.
+timer.delay.time=1000
+#Timer scheduleAtFixedRate period - time in milliseconds between successive task executions.
+check.interval= 30000
+#Longest time an event info can be stored in the concurrentHashMap for logging - in seconds. 
+event.expired.time=86400
+#Size of the concurrentHashMap which stores the event starting time, etc - when its size reaches this limit, the Timer gets executed 
+#to remove all expired records from this concurrentHashMap.
+concurrentHashMap.limit=5000
+#Size of the concurrentHashMap - when its size drops to this point, stop the Timer
+stop.check.point=2500
+################################### Set logging format #############################################
+# set EELF for EELF logging format, set LOG4J for using log4j, set SYSTEMOUT for using system.out.println
+logger.type=EELF
+#################################### Set level for EELF or SYSTEMOUT logging ##################################
+# Set level for debug file. Set DEBUG to enable .info, .warn and .debug; set INFO for enable .info and .warn; set OFF to disable all 
+debugLogger.level=INFO
+# Set level for metrics file. Set OFF to disable; set ON to enable
+metricsLogger.level=ON
+# Set level for error file. Set OFF to disable; set ON to enable
+error.level=ON
+# Set level for audit file. Set OFF to disable; set ON to enable
+audit.level=ON
diff --git a/ECOMP-XACML/pom.xml b/ECOMP-XACML/pom.xml
new file mode 100644
index 0000000..cb68524
--- /dev/null
+++ b/ECOMP-XACML/pom.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  ECOMP Policy Engine
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+  -->
+
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.openecomp.policy.engine</groupId>
+		<artifactId>PolicyEngineSuite</artifactId>
+		<version>1.0.0-SNAPSHOT</version>
+	</parent>
+	<groupId>org.openecomp.policy.engine</groupId>
+	<artifactId>ECOMP-XACML</artifactId>
+	<packaging>jar</packaging>
+	<dependencies>
+		<dependency>
+			<groupId>org.openecomp.policy.common</groupId>
+			<artifactId>integrity-monitor</artifactId>
+			<version>${common-modules.version}</version> 
+		</dependency>
+		<dependency>
+			<groupId>org.openecomp.policy.engine</groupId>
+			<version>${project.version}</version>
+			<artifactId>PolicyEngineUtils</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.openecomp.policy.common</groupId>
+			<artifactId>integrity-audit</artifactId>
+			<version>${common-modules.version}</version> 
+		</dependency>		
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpcore</artifactId>
+			<version>4.4.4</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.persistence</groupId>
+			<artifactId>eclipselink</artifactId>
+			<version>2.5.2</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>1.5</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-cli</groupId>
+			<artifactId>commons-cli</artifactId>
+			<version>1.2</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.4</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+			<version>3.1</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-logging</groupId>
+			<artifactId>commons-logging</artifactId>
+			<version>1.1.3</version>
+			<exclusions>
+				<exclusion>
+					<groupId>javax.servlet</groupId>
+					<artifactId>servlet-api</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<version>14.0.1</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-databind</artifactId>
+			<version>2.3.0-rc1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.velocity</groupId>
+			<artifactId>velocity</artifactId>
+			<version>1.7</version>
+			<exclusions>
+				<exclusion>
+					<groupId>javax.servlet</groupId>
+					<artifactId>servlet-api</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.opencsv</groupId>
+			<artifactId>opencsv</artifactId>
+			<version>2.3</version>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.11</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-core</artifactId>
+			<version>1.9.5</version>
+		</dependency>     
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-mock</artifactId>
+			<version>2.0.8</version>
+		</dependency>
+		<dependency>
+			<groupId>com.mockrunner</groupId>
+			<artifactId>mockrunner</artifactId>
+			<version>0.3.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.openecomp.policy.common</groupId>
+			<artifactId>ECOMP-Logging</artifactId>
+			<version>${common-modules.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.att.research.xacml</groupId>
+			<artifactId>xacml</artifactId>
+			<version>1.0.0</version>
+		</dependency>
+	</dependencies>
+</project>
diff --git a/ECOMP-XACML/sql/xacmlTest.mv.db b/ECOMP-XACML/sql/xacmlTest.mv.db
new file mode 100644
index 0000000..81e99a9
--- /dev/null
+++ b/ECOMP-XACML/sql/xacmlTest.mv.db
Binary files differ
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/XACMLErrorConstants.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/XACMLErrorConstants.java
new file mode 100644
index 0000000..5a2eac1
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/XACMLErrorConstants.java
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.api;
+
+/**
+ * List of Error Classifications
+ *  PE100 - Permissions
+ *  PE200 - System Error (such as availability, timeout, configuration, etc...)
+ *  PE300 - Data Issue( such as request for REST/JSON )
+ *  PE400 - Schema validation
+ *  PE500 - Process Flow issues
+ *  PE900 - Default/Unknown Errors
+ *  
+ *
+ */
+public class XACMLErrorConstants {
+	//Captures all the errors related to Authentication, Authorizations and Permissions in the PolicyEngine Process
+	public static final String ERROR_PERMISSIONS = "PE100 - Permissions Error: ";
+	
+	//Captures all the errors related to availability, timeout configuration variables, etc... in the PolicyEngine
+	public static final String ERROR_SYSTEM_ERROR = "PE200 - System Error: ";
+	
+	/*
+	 * Captures all the errors related to configuration values from properties files and data from the interfacing System
+	 * like REST/JSON values 
+	*/
+	public static final String ERROR_DATA_ISSUE = "PE300 - Data Issue: ";
+	
+	//Captures all the errors related to the XML schemas and/or REST/JSON structures 
+	public static final String ERROR_SCHEMA_INVALID = "PE400 - Schema validation Error: ";
+	
+	//Captures all the errors related to the Process, when data from one Process to another Process does not flow
+	public static final String ERROR_PROCESS_FLOW = "PE500 - Process Flow Issue: ";
+	
+	//Captures all the errors that not related to the list of above error codes
+	public static final String ERROR_UNKNOWN = "PE900 - Unknown Error: ";
+	
+
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/ECOMPPapEngineFactory.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/ECOMPPapEngineFactory.java
new file mode 100644
index 0000000..d34d033
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/ECOMPPapEngineFactory.java
@@ -0,0 +1,38 @@
+package org.openecomp.policy.xacml.api.pap;
+
+import java.util.Properties;
+
+import com.att.research.xacml.api.pap.PAPException;
+import com.att.research.xacml.util.FactoryException;
+import com.att.research.xacml.util.FactoryFinder;
+
+public abstract class ECOMPPapEngineFactory{
+	
+	/**
+	 * Creates a new <code>PAPEngineFactory</code> instance using the given class name and the default thread class loader.
+	 * 
+	 * @param factoryClassName the <code>String</code> name of the factory class to instantiate
+	 * @return an instance of an object that extends <code>ECOMPPapEngineFactory</code> to use in creating <code>PAPPolicyEngine</code> objects.
+	 */
+	public static ECOMPPapEngineFactory newInstance(String factoryClassName) throws FactoryException {
+		return FactoryFinder.newInstance(factoryClassName, ECOMPPapEngineFactory.class, null, true);
+	}
+
+	/**
+	 * Creates a new <code>PAPPolicyEngine</code> based on the configured <code>ECOMPPapEngineFactory</code>.
+	 * 
+	 * @return a new <code>PAPPolicyEngine</code>
+	 * @throws PAPException 
+	 */
+	public abstract PAPPolicyEngine newEngine() throws FactoryException, PAPException;
+
+	/**
+	 * Creates a new <code>PAPPolicyEngine</code> based on the configured <code>ECOMPPapEngineFactory</code>.
+	 * 
+	 * @return a new <code>PAPPolicyEngine</code>
+	 * @throws PAPException 
+	 */
+	public abstract PAPPolicyEngine newEngine(Properties properties) throws FactoryException, PAPException;
+
+
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPAPPolicy.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPAPPolicy.java
new file mode 100644
index 0000000..c18ad23
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPAPPolicy.java
@@ -0,0 +1,89 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.api.pap;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import org.openecomp.policy.xacml.std.pap.StdPAPPolicy;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+
+/*
+ * The following allows us to use Jackson to convert sub-types of this type into JSON and back to objects.
+ */
+@JsonTypeInfo(  
+	    use = JsonTypeInfo.Id.NAME,  
+	    include = JsonTypeInfo.As.PROPERTY,  
+	    property = "PAPPolicyType")  
+@JsonSubTypes({  
+	    @Type(value = StdPAPPolicy.class, name = "StdPAPPolicy") })  
+public interface EcompPAPPolicy {
+	
+	public String getPolicyName();
+	public String getOldPolicyFileName();
+	public String getPolicyDescription();
+	public String getEcompName();
+	public String getConfigName();
+	public Map<String, String> getDynamicFieldConfigAttributes();
+	public Map<String, String> getDynamicSettingsMap();
+	public List<String> getDynamicRuleAlgorithmLabels();
+	public List<String> getDynamicRuleAlgorithmCombo();
+	public List<String> getDynamicRuleAlgorithmField1();
+	public List<String> getDynamicRuleAlgorithmField2();
+	public List<Object> getDynamicVariableList();
+	public List<String> getDataTypeList();
+	public String getConfigBodyData();
+	public String getPolicyID();
+	public String getRuleID();
+	public String getConfigType();
+	public Boolean isEditPolicy();
+	public Boolean isDraft();
+	public String getVersion();
+	public String getDomainDir();
+	public String getConfigPolicyType();
+	public String getJsonBody();
+	public Integer getHighestVersion();
+	public URI getLocation();
+	public String getActionPerformer();
+	public String getActionAttribute();
+	public String getActionBody();
+	public Map<String, String> getDropDownMap();
+	public String getActionDictHeader();
+	public String getActionDictType();
+	public String getActionDictUrl();
+	public String getActionDictMethod();
+	public String getServiceType();
+	public String getUuid();
+	public String getMsLocation();
+    public String getPriority();	
+    public String getDeleteCondition();
+    public String getDictionaryType();
+    public String getDictionary();
+    public Map<String, String> getDictionaryFields();
+    
+	public String getRiskLevel();
+	public String getGuard();
+	public String getRiskType();
+	public String getTTLDate();
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPDP.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPDP.java
new file mode 100644
index 0000000..f00dd7a
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPDP.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.api.pap;
+
+import java.util.Set;
+
+import org.openecomp.policy.xacml.std.pap.StdPDP;
+
+import com.att.research.xacml.api.pap.PDP;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+
+/*
+ * The following allows us to use Jackson to convert sub-types of this type into JSON and back to objects.
+ */
+@JsonTypeInfo(  
+	    use = JsonTypeInfo.Id.NAME,  
+	    include = JsonTypeInfo.As.PROPERTY,  
+	    property = "PDPType")  
+@JsonSubTypes({  
+	    @Type(value = StdPDP.class, name = "StdPDP") })  
+public interface EcompPDP extends PDP {
+
+	public Integer 						getJmxPort();
+	
+	public void 						setJmxPort(Integer jmxport);
+	
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPDPGroup.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPDPGroup.java
new file mode 100644
index 0000000..a64b4b6
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/EcompPDPGroup.java
@@ -0,0 +1,11 @@
+package org.openecomp.policy.xacml.api.pap;
+
+import java.util.Set;
+
+import com.att.research.xacml.api.pap.PDPGroup;
+
+public interface EcompPDPGroup extends PDPGroup {
+
+	public Set<EcompPDP> getEcompPdps();
+	
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/PAPPolicyEngine.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/PAPPolicyEngine.java
new file mode 100644
index 0000000..0c5c334
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/api/pap/PAPPolicyEngine.java
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.api.pap;
+
+import java.io.InputStream;
+import java.util.Set;
+
+import com.att.research.xacml.api.pap.PAPException;
+import com.att.research.xacml.api.pap.PDPPolicy;
+import com.att.research.xacml.api.pap.PDPStatus;
+
+public interface PAPPolicyEngine{
+	
+	public EcompPDPGroup getDefaultGroup() throws PAPException;
+	
+	public void						SetDefaultGroup(EcompPDPGroup group) throws PAPException;
+	
+	public void		newPDP(String id, EcompPDPGroup group, String name, String description, int jmxport) throws PAPException, NullPointerException;
+	
+	public void						newGroup(String name, String description) throws PAPException, NullPointerException;
+	
+	public EcompPDPGroup getGroup(String id) throws PAPException;
+	
+	public Set<EcompPDPGroup> getEcompPDPGroups() throws PAPException;
+	
+	public EcompPDPGroup getPDPGroup(EcompPDP pdp) throws PAPException;
+	
+	public PDPStatus getStatus(EcompPDP pdp) throws PAPException;
+	
+	public void movePDP(EcompPDP pdp, EcompPDPGroup newGroup) throws PAPException;
+	
+	public void updatePDP(EcompPDP pdp) throws PAPException;
+	
+	public void removePDP(EcompPDP pdp) throws PAPException; 
+	
+	public EcompPDP getPDP(String pdpId) throws PAPException;
+	
+	public void						updateGroup(EcompPDPGroup group) throws PAPException;
+	
+	public void						removeGroup(EcompPDPGroup group, EcompPDPGroup newGroup) throws PAPException, NullPointerException;
+	
+public void						publishPolicy(String id, String name, boolean isRoot, InputStream policy, EcompPDPGroup group) throws PAPException;
+	
+	// copy the given policy file into the group's directory, but do not include the policy in the group's policy set
+	public void						copyPolicy(PDPPolicy policy, EcompPDPGroup group) throws PAPException;
+	
+	public void						removePolicy(PDPPolicy policy, EcompPDPGroup group) throws PAPException;
+	
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngine.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngine.java
new file mode 100644
index 0000000..397f763
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngine.java
@@ -0,0 +1,1087 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openecomp.policy.xacml.api.pap.EcompPDP;
+import org.openecomp.policy.xacml.api.pap.EcompPDPGroup;
+import org.openecomp.policy.xacml.api.pap.PAPPolicyEngine;
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.eelf.PolicyLogger;
+import com.att.research.xacml.api.pap.PAPException;
+import com.att.research.xacml.api.pap.PDP;
+import com.att.research.xacml.api.pap.PDPGroup;
+import com.att.research.xacml.api.pap.PDPPolicy;
+import com.att.research.xacml.api.pap.PDPStatus;
+import com.att.research.xacml.util.XACMLProperties;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Sets;
+
+/**
+ * This is a simple PAP engine that uses some property files and a simple directory
+ * structure in the file system to manage a policy repository and set of PDP nodes.
+ * 
+ *
+ */
+public class StdEngine extends StdPDPItemSetChangeNotifier implements PAPPolicyEngine {
+	private static Log	logger	= LogFactory.getLog(StdEngine.class);
+
+	public static String	PROP_PAP_REPO = "xacml.pap.pdps";
+	public static String	PROP_PAP_GROUPS = "xacml.pap.groups";
+	public static String	PROP_PAP_GROUPS_DEFAULT = "xacml.pap.groups.default";
+	public static String	PROP_PAP_GROUPS_DEFAULT_NAME = "default";
+	//this value will be accessed from XacmlPapServlet so that we know if a default group did not exist
+	//and was just added. This way, we can add the new group to the database.
+	public boolean wasDefaultGroupJustAdded = false;
+
+    protected final Path repository;
+	protected Set<StdPDPGroup> groups;
+		
+	public StdEngine() throws PAPException, IOException {
+		//
+		// Get the location in the file system of our repository
+		//
+		this.repository = Paths.get(XACMLProperties.getProperty(PROP_PAP_REPO));
+		//
+		// Initialize
+		//
+		this.intialize();
+	}
+	
+	public StdEngine(Properties properties) throws PAPException, IOException {
+		//
+		// Get the location in the file system of our repository
+		//
+		this.repository = Paths.get(properties.getProperty(PROP_PAP_REPO));
+		//
+		// Initialize
+		//
+		this.intialize();
+	}
+	
+	public StdEngine(Path repository) throws PAPException, IOException {
+		//
+		// Save our location
+		//
+		this.repository = repository;
+		//
+		// Initialize
+		//
+		this.intialize();
+	}
+	
+	private void intialize() throws PAPException, IOException {
+		//
+		// Sanity check the repository path
+		//
+		if (this.repository == null) {
+			throw new PAPException ("No repository specified.");
+		}
+		if (Files.notExists(this.repository)) {
+			Files.createDirectory(repository);
+		}
+		if (Files.isDirectory(this.repository) == false) {
+			throw new PAPException ("Repository is NOT a directory: " + this.repository.toAbsolutePath());
+		}
+		if (Files.isWritable(this.repository) == false) {
+			throw new PAPException ("Repository is NOT writable: " + this.repository.toAbsolutePath());
+		}
+		//
+		// Load our groups
+		//
+		this.loadGroups();
+	}
+	
+	private void loadGroups() throws PAPException {
+		//
+		// Create a properties object
+		//
+		Properties properties = new Properties();
+		Path file = Paths.get(this.repository.toString(), XACMLProperties.XACML_PROPERTIES_NAME);
+		try {
+			//
+			// Load the properties
+			//
+			try (InputStream is = new FileInputStream(file.toFile())) {
+				properties.load(is);
+			}
+
+			//
+			// Parse it
+			//
+			this.groups = this.readProperties(this.repository, properties);
+		} catch (IOException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to load " + file.toAbsolutePath().toString());
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to load properties file");
+			this.groups = new HashSet<StdPDPGroup>();
+		}
+		//
+		// Initialize the default group
+		//
+		PDPGroup defaultGroup = this.initializeDefaultGroup(file, properties);
+		logger.info("Default group is: " + defaultGroup.getId() + "=" + defaultGroup.getName());
+	}
+	
+	private PDPGroup initializeDefaultGroup(Path file, Properties properties) throws PAPException {
+		wasDefaultGroupJustAdded = false;
+		//
+		// Make sure we have the default group
+		//
+		PDPGroup group = this.getDefaultGroup();
+		if (group != null) {
+			return group;
+		}
+		//
+		// We don't have the default group, create it
+		//
+		String defaultId = properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME);
+		if(defaultId == null){
+			defaultId = PROP_PAP_GROUPS_DEFAULT_NAME;
+		}
+		if(defaultId.equals("")){
+			defaultId = PROP_PAP_GROUPS_DEFAULT_NAME;
+		}
+		//we're going to check one more time in case the PROP_PAP_GROUPS_DEFAULT_NAME doesn't exist
+		if(defaultId == null){
+			defaultId = "default";
+		}
+		if(defaultId.equals("")){
+			defaultId = "default";
+		}
+		logger.warn("Default group does NOT exist, creating " + defaultId);
+		Path defaultPath = Paths.get(this.repository.toString(), defaultId);
+		try {
+			//
+			// Does it exist?
+			//
+			if (Files.notExists(defaultPath)) {
+				//
+				// Create its directory
+				//
+				Files.createDirectory(defaultPath);
+				//
+				// Create property files
+				//
+				{
+					Properties props = new Properties();
+					props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
+					props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
+					Path policyPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.policy.properties");
+					Files.createFile(policyPath);
+					try (OutputStream os = Files.newOutputStream(policyPath)) {
+						props.store(os, "");
+					} catch (IOException e) {
+						//TODO:EELF Cleanup - Remove logger
+						//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to write default policy properties", e);
+						PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to write default policy properties");
+					}
+				}
+				{
+					Properties props = new Properties();
+					props = setPIPProperties(props);
+					Path pipPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.pip.properties");
+					Files.createFile(pipPath);
+					try (OutputStream os = Files.newOutputStream(pipPath)) {
+						props.store(os, "");
+					} catch (IOException e) {
+						//TODO:EELF Cleanup - Remove logger
+						//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to write default pip properties", e);
+						PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to write default pip properties");
+					}					
+				}
+			}
+			//
+			// Create the default group
+			//
+			StdPDPGroup newDefault = new StdPDPGroup(defaultId, true, "default", "The default group where new PDP's are put.", defaultPath);
+			//
+			// Add it to our list
+			//
+			this.groups.add(newDefault);
+			//
+			// Save our properties out since we have
+			// a new default group.
+			//
+			StdEngine.setGroupProperties(newDefault, properties);
+			//
+			// Save it to disk
+			//
+			try {
+				try (OutputStream os = Files.newOutputStream(file)) {
+					properties.store(os, "");
+				}
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error("Failed to save properties with new default group information.", e);
+				PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to save properties with new default group information.");
+			}
+			//
+			// Return it
+			//
+			wasDefaultGroupJustAdded = true;
+			return newDefault;
+		} catch (IOException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error("Failed to create default group: " + defaultId, e);
+			PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to create default group");
+			throw new PAPException("Failed to create default group");
+		}
+	}
+	
+
+    
+    
+	@Override
+	public EcompPDPGroup getDefaultGroup() throws PAPException
+	{
+		for (EcompPDPGroup group : this.groups) {
+			if (group.isDefaultGroup()) {
+				return group;
+			}
+		}
+		//
+		// Default group doesn't exist
+		//
+		return null;
+	}
+
+	/*@Override
+	public void	SetDefaultGroup(PDPGroup group) throws PAPException {
+		
+		boolean changesMade = false;
+		for (PDPGroup aGroup : groups) {
+			if (aGroup.getId().equals(group.getId())) {
+				if ( ! aGroup.isDefaultGroup()) {
+//TODO - since the original code checked for type we do also.
+					if (aGroup instanceof StdPDPGroup) {
+						((StdPDPGroup) aGroup).setDefault(true);
+						changesMade = true;
+					} else {
+						throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'");
+					}
+				}
+			} else {
+				// not the new default group
+				if (aGroup.isDefaultGroup()) {
+//TODO - since the original code checked for type we do also.
+					if (aGroup instanceof StdPDPGroup) {
+						((StdPDPGroup) aGroup).setDefault(false);
+						changesMade = true;
+					} else {
+						throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'");
+					}
+				}
+			}
+		}
+		if (changesMade) {
+			this.doSave();
+		}
+		
+		return;	
+	}*/
+
+	/*@Override
+	public Set<PDPGroup> getPDPGroups() throws PAPException {
+		final Set<PDPGroup> grps = new HashSet<PDPGroup>();
+		for (PDPGroup g : this.groups) {
+			grps.add(g);
+		}
+		return Collections.unmodifiableSet(grps);
+	}*/
+	
+	@Override
+	public EcompPDPGroup getGroup(String id) throws PAPException {
+		for (EcompPDPGroup g: this.groups) {
+			if (g.getId().equals(id)) {
+				return g;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public void	newGroup(String name, String description) throws PAPException, NullPointerException
+	{	
+		//
+		// Null check
+		//
+		if (name == null) {
+			throw new NullPointerException();
+		}
+		//
+		// Do we already have this group?
+		//
+		for (PDPGroup group : this.groups) {
+			if (group.getName().equals(name)) {
+				throw new PAPException("Group with this name=" + name + " already exists.");
+			}
+		}
+		
+		
+		// create an Id that can be used as a file name and a properties file key.
+		// Ids must not contain \/:*?"<>|=,;
+		// The ID must also be unique within the current set of PDPGroups.
+		String id = createNewPDPGroupId(name);
+		
+		
+		//
+		// Construct the directory path
+		//
+		Path groupPath = Paths.get(this.repository.toString(), id);
+		//
+		// If it exists already
+		//
+		if (Files.exists(groupPath)) {
+			logger.warn("addGroup " + id + " directory exists" + groupPath.toString());
+		} else {
+			try {
+				//
+				// Create the directory
+				//
+				Files.createDirectory(groupPath);
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to create " + groupPath);
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to create " + groupPath);
+				throw new PAPException("Failed to create " + id);
+			}
+		}
+		//
+		// Create the Policies
+		//
+
+		Path policyProperties = Paths.get(groupPath.toString(), "xacml.policy.properties");
+		if (Files.exists(policyProperties)) {
+			logger.warn("addGroup " + id + " file exists: " + policyProperties.toString());
+		} else {
+			Properties props = new Properties();
+			props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
+			props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
+			try {
+				Files.createFile(policyProperties);
+				try (OutputStream os = Files.newOutputStream(policyProperties)) {
+					props.store(os, "");
+				}
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error("Failed to create " + policyProperties);
+				PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to create " + policyProperties);
+				throw new PAPException("Failed to create " + id);
+			}
+		}
+		//
+		// Create the PIP config
+		//
+		Path pipProperties = Paths.get(groupPath.toString(), "xacml.pip.properties");
+		if (Files.exists(pipProperties)) {
+			logger.warn("addGroup " + id + " file exists: " + pipProperties.toString());
+		} else {
+			try {
+				Properties props = new Properties();
+				props = setPIPProperties(props);
+				Files.createFile(pipProperties);
+				try (OutputStream os = Files.newOutputStream(pipProperties)) {
+					props.store(os, "");
+				}
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to create " + pipProperties);
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to create " + pipProperties);
+				throw new PAPException("Failed to create " + id);
+			}	
+
+		}
+		//
+		// Ok now add it
+		//
+		StdPDPGroup newGroup = new StdPDPGroup(id, name, description, groupPath);
+		if (this.groups.add(newGroup)) {
+			// save the new group in our properties and notify any listeners of the change
+			groupChanged(newGroup);
+		}
+
+	}
+	
+
+	
+	
+	/**
+	 * Helper to create a new Group ID.
+	 * Use the Name field to create the Id.
+	 * The Name is expected to not be null; if it is then this method throws an exception.
+	 * The name is supposed to be unique within the current set of groups,
+	 * so creating the ID based on the name will create a unique string.
+	 * 
+	 * @param name
+	 * @return
+	 */
+	private String createNewPDPGroupId(String name) {
+		String id = name;
+		// replace "bad" characters with sequences that will be ok for file names and properties keys.
+		id = id.replace(" ", "_sp_");
+		id = id.replace("\t", "_tab_");
+		id = id.replace("\\", "_bksl_");
+		id = id.replace("/", "_sl_");
+		id = id.replace(":", "_col_");
+		id = id.replace("*", "_ast_");
+		id = id.replace("?", "_q_");
+		id = id.replace("\"", "_quo_");
+		id = id.replace("<", "_lt_");
+		id = id.replace(">", "_gt_");
+		id = id.replace("|", "_bar_");
+		id = id.replace("=", "_eq_");
+		id = id.replace(",", "_com_");
+		id = id.replace(";", "_scom_");
+
+		return id;
+	}
+	
+	
+	@Override
+	public EcompPDP	getPDP(String pdpId) throws PAPException {
+		for (EcompPDPGroup group : this.groups) {
+			for (EcompPDP pdp : group.getEcompPdps()) {
+				if (pdp.getId().equals(pdpId)) {
+					return pdp;
+				}
+			}
+		}
+		return null;
+	}
+
+	
+	@Override
+	public void movePDP(EcompPDP pdp, EcompPDPGroup newGroup) throws PAPException {
+		if (newGroup == null) {
+			throw new NullPointerException("You must specify which group the PDP will belong to.");
+		}
+		PDPGroup currentGroup = this.getPDPGroup(pdp);
+		if (currentGroup == null) {
+			throw new PAPException("PDP must already belong to a group.");
+		}
+		if (currentGroup.equals(newGroup)) {
+			logger.warn("Already in that group.");
+			return;
+		}
+		if (currentGroup instanceof StdPDPGroup && newGroup instanceof StdPDPGroup) {
+			if (((StdPDPGroup) currentGroup).removePDP(pdp)) {
+				boolean result = ((StdPDPGroup) newGroup).addPDP(pdp);
+				if (result) {
+					//
+					// Save the configuration
+					//
+					this.doSave();
+				} else {
+					//TODO:EELF Cleanup - Remove logger
+					//logger.error("Failed to add to new group, putting back into original group.");
+					PolicyLogger.error("Failed to add to new group, putting back into original group.");
+					if (((StdPDPGroup) currentGroup).removePDP(pdp) == false) {
+						//TODO:EELF Cleanup - Remove logger
+						//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to put PDP back into original group.");
+						PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Failed to put PDP back into original group.");
+					}
+				}
+			}
+		} else {
+			String message = "Unknown PDP group class: " + newGroup.getClass().getCanonicalName() + " and " + currentGroup.getClass().getCanonicalName();
+			logger.warn(message);
+			throw new PAPException(message);
+		}
+	}
+
+	
+	@Override
+	public void	updatePDP(EcompPDP pdp) throws PAPException {
+		PDP currentPDP = this.getPDP(pdp.getId());
+		if (currentPDP == null) {
+			String message = "Unknown PDP id '" + pdp.getId() + "'";
+			logger.warn(message);
+			throw new PAPException(message);
+		}
+		
+		// the only things that the user can change are name and description
+		currentPDP.setDescription(pdp.getDescription());
+		currentPDP.setName(pdp.getName());
+		if (currentPDP instanceof EcompPDP && pdp instanceof EcompPDP) {
+			((EcompPDP)currentPDP).setJmxPort(((EcompPDP)pdp).getJmxPort());
+		}
+		this.doSave();
+	}
+	
+	@Override
+	public void removePDP(EcompPDP pdp) throws PAPException {
+		PDPGroup group = this.getPDPGroup(pdp);
+		if (group == null) {
+			throw new NullPointerException();
+		}
+		if (group instanceof StdPDPGroup) {
+			boolean result = ((StdPDPGroup) group).removePDP(pdp);
+			if (result) {
+				this.doSave();
+			}
+			return;
+		}
+		String message = "Unknown PDP group class: " + group.getClass().getCanonicalName();
+		logger.warn(message);
+		throw new PAPException(message);
+	}
+
+	
+	@Override
+	/**
+	 * Should never be called - Detailed status is held on the PDP, not the PAP
+	 */
+	public PDPStatus getStatus(EcompPDP pdp) throws PAPException {
+		return getPDP(pdp.getId()).getStatus();
+	}
+	
+	@Override
+	public void publishPolicy(String id, String name, boolean isRoot, InputStream policy, EcompPDPGroup group) throws PAPException {
+		if (group == null) {
+			throw new NullPointerException();
+		}
+		if (group instanceof StdPDPGroup && this.groups.contains(group)) {
+			((StdPDPGroup) group).publishPolicy(id, name, isRoot, policy);
+			return;
+		}
+		logger.warn("unknown PDP Group: " + group);
+		throw new PAPException("Unknown PDP Group: " + group.getId());
+	}
+
+	// Currently not used on the PAP side.  This is done by ((StdPDPGroup) group).copyPolicyToFile
+	@Override
+	public void copyPolicy(PDPPolicy policy, EcompPDPGroup group)
+			throws PAPException {
+	}
+	
+	
+	@Override
+	public void removePolicy(PDPPolicy policy, EcompPDPGroup group) throws PAPException {
+		if (group == null) {
+			throw new NullPointerException();
+		}
+		if (group instanceof StdPDPGroup && this.groups.contains(group)) {
+			((StdPDPGroup) group).removePolicy(policy);
+			return;
+		}
+		logger.warn("unknown PDP Group: " + group);
+		throw new PAPException("Unknown PDP Group: " + group.getId());
+	}
+
+	
+	//
+	// HELPER methods
+	//
+	
+	private Set<StdPDPGroup>	readProperties(Path repository, Properties properties) throws PAPException {
+		Set<StdPDPGroup> groups = new HashSet<StdPDPGroup>();
+		//
+		// See if there is a groups property
+		//
+		String groupList = properties.getProperty(PROP_PAP_GROUPS, "");
+		if (groupList == null) {
+			logger.warn("null group list " + PROP_PAP_GROUPS);
+			groupList = "";
+		}
+		if (logger.isDebugEnabled()) {
+			logger.debug("group list: " + groupList);
+		}
+		//
+		// Iterate the groups, converting to a set ensures we have unique groups.
+		//
+		for (String id : Splitter.on(',').trimResults().omitEmptyStrings().split(groupList)) {
+			//
+			// Add our Group Object
+			//
+			StdPDPGroup g = new StdPDPGroup(id.trim(), 
+								id.equals(properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME)), 
+								properties,
+								Paths.get(repository.toString(), id));
+
+			//
+			// Add it in
+			//
+			groups.add(g);
+		}
+		//
+		// Dump what we got
+		//
+		if (logger.isDebugEnabled()) {
+			logger.debug("PDP Group List: " + groups.toString());
+		}
+		return groups;
+	}
+	
+	private void saveConfiguration() throws PAPException, IOException {
+		//
+		// Create our properties object
+		//
+		Properties properties = new Properties() {
+			private static final long serialVersionUID = 1L;
+			// For Debugging it is helpful for the file to be in a sorted order,
+			// any by returning the keys in the natural Alpha order for strings we get close enough.
+			// TreeSet is sorted, and this just overrides the normal Properties method to get the keys.
+			@Override
+		    public synchronized Enumeration<Object> keys() {
+		        return Collections.enumeration(new TreeSet<Object>(super.keySet()));
+		    }
+	    };
+		//
+		// Iterate our groups
+		//
+		List<String> ids = new ArrayList<String>();
+		for (PDPGroup group : this.groups) {
+			ids.add(group.getId());
+			properties.setProperty(group.getId() + ".name", (group.getName() == null ? "" : group.getName()));
+			properties.setProperty(group.getId() + ".description", (group.getDescription() == null ? "" : group.getDescription()));
+			//
+			// Iterate its PDPs
+			//
+			List<String> pdps = new ArrayList<String>();
+			for (PDP pdp : group.getPdps()) {
+				pdps.add(pdp.getId());
+				properties.setProperty(pdp.getId() + ".name", (pdp.getName() == null ? "" : pdp.getName()));
+				properties.setProperty(pdp.getId() + ".description", (pdp.getDescription() == null ? "" : pdp.getDescription()));
+				if (pdp instanceof EcompPDP) {
+					properties.setProperty(pdp.getId() + ".jmxport", (((EcompPDP)pdp).getJmxPort()==0 ? "" : ((EcompPDP)pdp).getJmxPort()).toString());
+				}
+			}
+			String pdpList = "";
+			if (pdps.size() == 1) {
+				pdpList = pdps.get(0);
+			} else if (pdps.size() > 1) {
+				pdpList = Joiner.on(',').skipNulls().join(pdps);
+			}
+			if (logger.isDebugEnabled()) {
+				logger.debug("Group " + group.getId() + " PDPS: " + pdpList);
+			}
+			properties.setProperty(group.getId() + ".pdps", pdpList);
+		}
+		if (ids.isEmpty()) {
+			throw new PAPException("Inconsistency - we have NO groups. We should have at least one.");
+		}
+		String groupList = "";
+		if (ids.size() == 1) {
+			groupList = ids.get(0);
+		} else if (ids.size() > 1){
+			groupList = Joiner.on(',').skipNulls().join(ids);
+		}
+		logger.info("New Group List: " + groupList);
+		
+		properties.setProperty(PROP_PAP_GROUPS, groupList);
+		//
+		// Get the default group
+		//
+		PDPGroup defaultGroup = this.getDefaultGroup();
+		if (defaultGroup == null) {
+			throw new PAPException("Invalid state - no default group.");
+		}
+		properties.setProperty(PROP_PAP_GROUPS_DEFAULT, defaultGroup.getId());
+		//
+		// Now we can save the file
+		//
+		Path file = Paths.get(this.repository.toString(), "xacml.properties");
+		try (OutputStream os = Files.newOutputStream(file)) {
+			properties.store(os, "");
+		}
+	}
+	
+	public static void	removeGroupProperties(String id, Properties properties) {
+		for (Object key : properties.keySet()) {
+			if (key.toString().startsWith(id + ".")) {
+				properties.remove(key);
+			}
+		}
+	}
+	
+	public static void setGroupProperties(PDPGroup group, Properties properties) {
+		//
+		// make sure its in the list of groups
+		//
+		Iterable<String> groups = Splitter.on(',').trimResults().omitEmptyStrings().split( properties.getProperty(PROP_PAP_GROUPS, ""));
+		boolean inList = false;
+		for (String g : groups) {
+			if (g.equals(group.getId())) {
+				inList = true;
+			}
+		}
+		if (inList == false) {
+			Set<String> grps = Sets.newHashSet(groups);
+			grps.add(group.getId());
+			String newGroupList = "";;
+			if (grps.size() == 1) {
+				newGroupList = grps.iterator().next();
+			} else if (grps.size() > 1) {
+				newGroupList = Joiner.on(',').skipNulls().join(grps);
+			}
+			logger.info("New Group List: " + newGroupList);
+			properties.setProperty(PROP_PAP_GROUPS, newGroupList);
+		}
+		//
+		// Set its properties
+		//
+		properties.setProperty(group.getId() + ".name", group.getName());
+		properties.setProperty(group.getId() + ".description", group.getDescription());
+		//
+		// Set its PDP list
+		//
+		if (group.getPdps().size() > 0) {
+			String pdpList = "";
+			if (group.getPdps().size() == 1) {
+				pdpList = group.getPdps().iterator().next().getId();
+			} else if (group.getPdps().size() > 1) {
+				Set<String> ids = new HashSet<String>();
+				for (PDP pdp : group.getPdps()) {
+					ids.add(pdp.getId());
+				}
+				pdpList = Joiner.on(',').skipNulls().join(ids);
+			}
+			properties.setProperty(group.getId() + ".pdps", pdpList);
+		} else {
+			properties.setProperty(group.getId() + ".pdps", "");
+		}
+	}
+
+	
+	public void changed() {
+		if (logger.isDebugEnabled()) {
+			logger.debug("changed");
+		}
+		this.doSave();
+		this.fireChanged();
+	}
+
+	public void groupChanged(EcompPDPGroup group) {
+		if (logger.isDebugEnabled()) {
+			logger.debug("groupChanged: " + group);
+		}
+		this.doSave();
+		this.firePDPGroupChanged(group);
+	}
+
+
+	public void pdpChanged(EcompPDP pdp) {
+		if (logger.isDebugEnabled()) {
+			logger.debug("pdpChanged: " + pdp);
+		}
+		this.doSave();
+		this.firePDPChanged(pdp);
+	}
+
+	private void doSave() {
+		try {
+			//
+			// Save the configuration
+			//
+			this.saveConfiguration();
+		} catch (IOException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to save configuration", e);
+			PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Failed to save configuration");
+		} catch (PAPException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to save configuration", e);
+			PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Failed to save configuration");
+		}		
+	}
+	
+	// TODO: Adding Default PIP engine(s) while Loading initially. We don't want 
+	//			Programmer intervention with the PIP engines. 
+	private Properties setPIPProperties(Properties props){
+		props.setProperty(XACMLProperties.PROP_PIP_ENGINES, "AAF");
+		props.setProperty("AAF.name", "AAFEngine");
+		props.setProperty("AAF.description", "AAFEngine to communicate with AAF to take decisions");
+		props.setProperty("AAF.classname","org.openecomp.policy.xacml.std.pip.engines.aaf.AAFEngine");
+		return props;
+	}
+
+	
+	@Override
+	public Set<EcompPDPGroup> getEcompPDPGroups() throws PAPException {
+		final Set<EcompPDPGroup> grps = new HashSet<EcompPDPGroup>();
+		for (EcompPDPGroup g : this.groups) {
+			grps.add(g);
+		}
+		return Collections.unmodifiableSet(grps);
+	}
+
+	@Override
+	public EcompPDPGroup getPDPGroup(EcompPDP pdp) throws PAPException {
+		for (EcompPDPGroup group : this.groups) {
+			if (group.getPdps().contains(pdp)) {
+				return group;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public void SetDefaultGroup(EcompPDPGroup group) throws PAPException {
+		boolean changesMade = false;
+		for (EcompPDPGroup aGroup : groups) {
+			if (aGroup.getId().equals(group.getId())) {
+				if ( ! aGroup.isDefaultGroup()) {
+//TODO - since the original code checked for type we do also.
+					if (aGroup instanceof StdPDPGroup) {
+						((StdPDPGroup) aGroup).setDefault(true);
+						changesMade = true;
+					} else {
+						throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'");
+					}
+				}
+			} else {
+				// not the new default group
+				if (aGroup.isDefaultGroup()) {
+//TODO - since the original code checked for type we do also.
+					if (aGroup instanceof StdPDPGroup) {
+						((StdPDPGroup) aGroup).setDefault(false);
+						changesMade = true;
+					} else {
+						throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'");
+					}
+				}
+			}
+		}
+		if (changesMade) {
+			this.doSave();
+		}
+		
+		return;	
+		
+	}
+
+	@Override
+	public void newPDP(String id, EcompPDPGroup group, String name, String description, int jmxport)
+			throws PAPException, NullPointerException {
+		if (group == null) {
+			throw new PAPException("You must specify which group the PDP will belong to.");
+		}
+		if (this.groups.contains(group) == false) {
+			throw new PAPException("Unknown group, not in our list.");
+		}
+		for (EcompPDP p : group.getEcompPdps()) {
+			if (p.getId().equals(id)) {
+				throw new PAPException("A PDP with this ID exists.");
+			}
+		}
+		if (group instanceof StdPDPGroup) {
+			StdPDP pdp = new StdPDP(id, name, description, jmxport);
+			if (((StdPDPGroup) group).addPDP(pdp)) {
+				//
+				// Save the properties and notify any listeners
+				//
+				pdpChanged(pdp);
+				return;
+			}
+		}
+		return;
+		
+	}
+
+	@Override
+	public void updateGroup(EcompPDPGroup group) throws PAPException {
+		if (group == null || group.getId() == null) {
+			throw new PAPException("Group or id is null");
+		}
+		if (group.getName() == null || group.getName().trim().length() == 0) {
+			throw new PAPException("New name for group cannot be null or blank");
+		}
+		StdPDPGroup existingGroup = (StdPDPGroup)getGroup(group.getId());
+		if (existingGroup == null) {
+			throw new PAPException("Update found no existing group with id '" + group.getId() + "'");
+		}
+		
+		
+		// We do dramatically different things when the Name changes
+		// because the Name is essentially the identity of the group (as the User knows it) so when the Identity changes we have to change the group ID.
+		if (group.getName().equals(existingGroup.getName())) {
+
+			// update the disk
+			try {
+				((StdPDPGroup)group).saveGroupConfiguration();
+			} catch (IOException e) {
+				throw new PAPException("Unable to save new configuration for '" + group.getName() + "': " + e.getMessage());
+			}
+			// update the group in the set by simply replacing the old instance with the new one
+			this.groups.remove(existingGroup);
+			this.groups.add((StdPDPGroup)group);
+			
+		} else {
+			// the name/identity of the group has changed
+			// generate the new id
+			String newId = createNewPDPGroupId(group.getName());
+			
+			// make sure no other group uses the new id
+			for (EcompPDPGroup g : groups) {
+				if (g.getId().equals(newId)) {
+					throw new PAPException("Replacement name maps to ID '" + newId + "' which is already in use");
+				}
+			}
+			((StdPDPGroup)group).setId(newId);
+
+			// rename the existing directory to the new id
+			Path oldPath = existingGroup.getDirectory();
+			Path newPath = Paths.get(oldPath.getParent().toString(), newId);
+			((StdPDPGroup)group).setDirectory(newPath);
+			
+			try {
+				boolean success = oldPath.toFile().renameTo(newPath.toFile());
+				if ( ! success) {
+					throw new PAPException("Unable to rename directory; reason unknown");
+				}
+			} catch (Exception e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Move '" + oldPath + "' to '" + newPath + "': " + e.getMessage(), e);
+				PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Unable to rename directory");
+				throw new PAPException("Unable to move directory from '" + oldPath + "' to '" + newPath + "': " + e.getMessage());
+			}
+			// update the disk
+			try {
+				((StdPDPGroup)group).saveGroupConfiguration();
+			} catch (IOException e) {
+				throw new PAPException("Unable to save new configuration for '" + group.getName() + "': " + e.getMessage());
+			}
+			
+			// save the new group into the Set
+			groups.remove(existingGroup);
+			groups.add((StdPDPGroup)group);
+			
+		}
+		
+		// perhaps only the group changed, but if the name/id changed it may look to a listener like more than one group
+		changed();
+
+		
+	}
+
+	@Override
+	public void removeGroup(EcompPDPGroup group, EcompPDPGroup newGroup) throws PAPException, NullPointerException {
+		if (group == null) {
+			throw new NullPointerException();
+		}
+		//
+		// Does this group exist?
+		//
+		if (this.groups.contains(group) == false) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "This group doesn't exist.");
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "This group doesn't exist.");
+			throw new PAPException("The group '" + group.getId() + "' does not exist");
+		}
+		//
+		// Is it the default group?
+		//
+		if (group.isDefaultGroup()) {
+			throw new PAPException("You cannot delete the default group.");
+		}
+		Set<EcompPDP> pdps = group.getEcompPdps();
+		//
+		// Are there PDPs? If so, then we need a target group
+		//
+		if (pdps.isEmpty() == false && newGroup == null) {
+			throw new NullPointerException("Group targeted for deletion has PDPs, you must provide a new group for them.");
+		}
+		//
+		// Move the PDPs
+		//
+		if (pdps.isEmpty() == false) {
+			if (! (newGroup instanceof StdPDPGroup)) {
+				throw new PAPException("Unexpected class for newGroup: " + newGroup.getClass().getCanonicalName());
+			}
+			// The movePDP function will modify the set of PDPs in the group.
+			// To avoid concurrent modification exceptions we need to duplicate the list before calling that function.
+			List<EcompPDP> pdpList = new ArrayList<EcompPDP>();
+			for (EcompPDP pdp : pdps) {
+				pdpList.add(pdp);
+			}
+			// now we can use the PDPs from the list without having ConcurrentAccessExceptions
+			for (EcompPDP pdp : pdpList) {
+				this.movePDP(pdp, newGroup);
+			}
+		}
+		//
+		// remove the directory for the group
+		//
+		String id = group.getId();
+		Path groupPath = Paths.get(this.repository.toString(), id);
+		//
+		// If it exists already
+		//
+		if ( ! Files.exists(groupPath)) {
+			logger.warn("removeGroup " + id + " directory does not exist" + groupPath.toString());
+		} else {
+			try {
+				Files.walkFileTree(groupPath, new SimpleFileVisitor<Path>() {
+
+					@Override
+					public FileVisitResult visitFile(Path file,
+							BasicFileAttributes attrs) throws IOException {
+						Files.delete(file);
+						return super.visitFile(file, attrs);
+					}
+					
+				});
+				//
+				// delete the directory
+				//
+				Files.delete(groupPath);
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to delete " + groupPath + ": " +e);
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to delete " + groupPath);
+				throw new PAPException("Failed to delete " + id);
+			}
+		}
+		
+		// remove the group from the set of all groups
+		groups.remove(group);
+		
+		//
+		// Save changes
+		//
+		changed();
+		this.doSave();
+		return;
+		
+	}
+
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngineFactory.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngineFactory.java
new file mode 100644
index 0000000..b8ca1f2
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngineFactory.java
@@ -0,0 +1,57 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.eelf.PolicyLogger;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import org.openecomp.policy.xacml.api.pap.ECOMPPapEngineFactory;
+import org.openecomp.policy.xacml.api.pap.PAPPolicyEngine;
+
+import com.att.research.xacml.api.pap.PAPException;
+import com.att.research.xacml.util.FactoryException;
+
+public class StdEngineFactory extends ECOMPPapEngineFactory {
+	
+	@Override
+	public PAPPolicyEngine newEngine() throws FactoryException, PAPException {
+		try {
+			return (PAPPolicyEngine) new StdEngine();
+		} catch (IOException e) {
+			PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "StdEngineFactory", "Failed to create engine");
+			return null;
+		}
+	}
+
+	@Override
+	public PAPPolicyEngine newEngine(Properties properties) throws FactoryException,
+			PAPException {
+		try {
+			return (PAPPolicyEngine) new StdEngine(properties);
+		} catch (IOException e) {
+			PolicyLogger.error(MessageCodes.ERROR_SYSTEM_ERROR, e, "StdEngineFactory", "Failed to create engine");
+			return null;
+		}
+	}
+	
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPAPPolicy.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPAPPolicy.java
new file mode 100644
index 0000000..f4817ac
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPAPPolicy.java
@@ -0,0 +1,889 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.openecomp.policy.xacml.api.pap.EcompPAPPolicy;
+
+public class StdPAPPolicy implements EcompPAPPolicy, Serializable{
+	private static final long serialVersionUID = 5260230629397322000L;
+	
+	private String policyName = null;
+	private String oldPolicyFileName = null;
+	private String policyDescription = null;
+	private String ecompName = null;
+	private String configName = null;
+	private Map<String, String> dyanamicFieldConfigAttributes = new HashMap<String, String>();
+	private Map<String, String> dropDownMap = new HashMap<String, String>();
+	private Map<String, String> dynamicSettingsMap = new HashMap<String, String>();
+	private List<String> dynamicRuleAlgorithmLabels;
+	private List<String> dynamicRuleAlgorithmCombo;
+	private List<String> dynamicRuleAlgorithmField1;
+	private List<String> dynamicRuleAlgorithmField2;
+	private List<Object> dynamicVariableList;
+	private List<String> dataTypeList;
+	private String configBodyData = null;
+	private String policyID = null;
+	private String ruleID = null;
+	private String configType = null;
+	private Boolean editPolicy = false;
+	private Boolean draft = false;
+	private String version = null;
+	private String domain = null;
+	private String configPolicyType = null; 
+	private String jsonBody = null;
+	private String serviceType = null;
+	private Integer highestVersion = null;
+	private URI location = null;
+	private String actionPerformer = null;
+	private String actionAttribute = null;
+	private String actionBody = null;
+	private String actionDictHeader = null;
+	private String actionDictType = null;
+	private String actionDictUrl = null;
+	private String actionDictMethod = null;
+	private String uuid = null;
+	private String msLocation = null;
+    private String priority = null;
+	private Map<String,String> drlRuleAndUIParams=null;
+	private String deleteCondition = null;
+	private String dictionaryType = null;
+	private String dictionary = null;
+	private Map<String,String> dictionaryFields = new HashMap<String, String>();
+	private String providerComboBox = null;
+	private String riskType = null;
+	private String guard = null;
+	private String riskLevel;
+	private String ttlDate = null;
+	
+
+	public StdPAPPolicy() {
+		
+	}
+	
+	//Constructor for sending location when pushing policies
+	public StdPAPPolicy(URI location) {
+		this.location = location;
+	}
+	
+	//Constructor for Validating Config Policies
+	public StdPAPPolicy(String policyName, String body, String configType, String configPolicyType) {
+		this.policyName = policyName;
+		this.configBodyData = body;
+		this.configType = configType;
+		this.configPolicyType = configPolicyType;
+	}
+	
+	//convenience constructor
+	public StdPAPPolicy(String configPolicyType, String policyName, String description, String ecompName, String configName, Map<String, String> attributes, String configType, 
+			String body, Boolean editPolicy, String domain, String riskLevel, String riskType, String guard, String ttlDate){
+		this(configPolicyType, policyName, description, ecompName, configName, attributes, configType, 
+				body, editPolicy, domain, 1, riskLevel, riskType, guard, ttlDate);
+	}
+
+	//Constructor for Create/Update Action Policies from API
+	public StdPAPPolicy(String policyName, String description, Map<String, String> attributes, List<String> dynamicRuleAlgorithmLabels, List<String> dynamicRuleAlgorithmCombo, 
+						List<String> dynamicRuleAlgorithmField1, List<String> dynamicRuleAlgorithmField2, String actionPerformer,String actionAttribute, Boolean editPolicy, 
+						String domain, int highestVersion) {
+		
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.dyanamicFieldConfigAttributes = attributes;
+		this.dynamicRuleAlgorithmLabels = dynamicRuleAlgorithmLabels;
+		this.dynamicRuleAlgorithmCombo = dynamicRuleAlgorithmCombo;
+		this.dynamicRuleAlgorithmField1 = dynamicRuleAlgorithmField1;
+		this.dynamicRuleAlgorithmField2 = dynamicRuleAlgorithmField2;
+		this.actionPerformer = actionPerformer;
+		this.actionAttribute = actionAttribute;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.highestVersion = highestVersion;	
+		
+	}
+	
+	//Constructor for Create/Update Decision Policies from Admin Console
+	public StdPAPPolicy(String policyName, String description, String ecompName, String providerComboBox, Map<String, String> attributes, Map<String, String> settings, 
+			List<String> dynamicRuleAlgorithmLabels, List<String> dynamicRuleAlgorithmCombo, List<String> dynamicRuleAlgorithmField1, 
+			List<String> dynamicRuleAlgorithmField2, Map<String, String> dropDownMap, List<Object> dynamicVariableList, 
+			List<String> dataTypeList, Boolean editPolicy, String domain, int highestVersion) {
+		
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.ecompName = ecompName;
+		this.setProviderComboBox(providerComboBox);
+		this.dyanamicFieldConfigAttributes = attributes;
+		this.dynamicSettingsMap = settings;
+		this.dynamicRuleAlgorithmLabels = dynamicRuleAlgorithmLabels;
+		this.dynamicRuleAlgorithmCombo = dynamicRuleAlgorithmCombo;
+		this.dynamicRuleAlgorithmField1 = dynamicRuleAlgorithmField1;
+		this.dynamicRuleAlgorithmField2 = dynamicRuleAlgorithmField2;
+		this.dynamicVariableList = dynamicVariableList;
+		this.dataTypeList = dataTypeList;
+		this.dropDownMap = dropDownMap;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.highestVersion = highestVersion;	
+		
+	}
+	
+	
+	//Constructor for Create Config Policies from API and Admin Console
+	//Constructor for Updating Config Policies from the API
+	public StdPAPPolicy(String configPolicyType, String policyName, String description, String ecompName, String configName, Map<String, String> attributes, String configType, 
+								String body, Boolean editPolicy, String domain, int highestVersion, String riskLevel, String riskType, String guard, String ttlDate) {
+	
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.ecompName = ecompName;
+		this.configName = configName;
+		this.dyanamicFieldConfigAttributes = attributes;
+		this.configType = configType;
+		this.configBodyData = body;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.highestVersion = highestVersion;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+	
+	//convenience constructor
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, String ecompName, String configName, Map<String, String> attributes, String body, String policyID, 
+			String ruleID, String configType, Boolean editPolicy, String version, String domain, String riskLevel, String riskType, String guard, String ttlDate) {
+		this (configPolicyType, policyName, description, ecompName, configName, attributes, body, policyID, 
+				ruleID, configType, editPolicy, version, domain,  1, riskLevel, riskType, guard, ttlDate); 
+		}
+
+	//Constructor for Updating Config Policies from Admin Console
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, String ecompName, String configName, Map<String, String> attributes, String body, String policyID, 
+								String ruleID, String configType, Boolean editPolicy, String version, String domain,  int highestVersion, String riskLevel, String riskType, String guard, String ttlDate) {
+		
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.ecompName = ecompName;
+		this.configName = configName;
+		this.dyanamicFieldConfigAttributes = attributes;
+		this.configBodyData = body;
+		this.policyID = policyID;
+		this.ruleID = ruleID;
+		this.configType = configType;
+		this.editPolicy = editPolicy;
+		this.version = version;
+		this.domain = domain;
+		this.highestVersion = highestVersion;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+	
+
+	//Constructor for Creating Config Firewall Policies
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, String configName, 
+			Boolean editPolicy, String domain, String jsonBody,  Integer highestVersion, String riskLevel, String riskType, String guard, String ttlDate) {
+		
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.configName = configName;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.jsonBody = jsonBody;
+		this.highestVersion = highestVersion;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+
+	}
+	
+	//Constructor for Creating Goc Policies
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, String configName, 
+				Boolean editPolicy, String domain, String jsonBody,  Integer highestVersion, String eCompName, String riskLevel, String riskType, String guard, String ttlDate) {
+			
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.configName = configName;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.jsonBody = jsonBody;
+		this.highestVersion = highestVersion;
+		this.ecompName=eCompName;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+	
+	//Constructor for Creating BRMS Policies from the Admin Console
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, 
+			String configName, Boolean editPolicy, String domain, 
+			Map<String,String> dyanamicFieldConfigAttributes, Integer highestVersion, String eCompName, 
+			String configBodyData, String riskLevel, String riskType, String guard, String ttlDate) {
+		
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.configName = configName;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.dyanamicFieldConfigAttributes = dyanamicFieldConfigAttributes;
+		this.highestVersion = highestVersion;
+		this.ecompName=eCompName;
+		this.configBodyData=configBodyData;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+
+	//Constructor for Creating BRMS Param Policies from the Admin Console
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, 
+			String configName, Boolean editPolicy, String domain, 
+			Map<String,String> dyanamicFieldConfigAttributes, Integer highestVersion, String eCompName, 
+			String configBodyData,Map<String,String> drlRuleAndUIParams, String riskLevel, String riskType, String guard, String ttlDate) {
+		
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.configName = configName;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.dyanamicFieldConfigAttributes = dyanamicFieldConfigAttributes;
+		this.highestVersion = highestVersion;
+		this.ecompName=eCompName;
+		this.configBodyData=configBodyData;
+		this.drlRuleAndUIParams=drlRuleAndUIParams;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+	
+	//Constructor for Creating CloseLoop_Fault and Performance Metric Policies
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, String ecompName, 
+			String jsonBody, Boolean draft, String oldPolicyFileName, String serviceType, Boolean editPolicy, 
+			String domain, Integer highestVersion, String riskLevel, String riskType, String guard, String ttlDate) {
+			
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.ecompName = ecompName;
+		this.jsonBody = jsonBody;
+		this.draft = draft;
+		this.oldPolicyFileName = oldPolicyFileName;
+		this.serviceType = serviceType;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.highestVersion = highestVersion;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+	
+	//Constructor for Updating Config Firewall Policies from the Admin Console
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, String configName, Boolean editPolicy, String domain, String policyID, 
+			String ruleID, String version, String jsonBody,  Integer highestVersion, String riskLevel, String riskType, String guard, String ttlDate) {
+		
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.configName = configName;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.policyID = policyID;
+		this.ruleID = ruleID;
+		this.version = version;
+		this.jsonBody = jsonBody;
+		this.highestVersion = highestVersion;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+	
+    //Constructor for Micro Service Creating/Updating Policies from the Admin Console
+	public StdPAPPolicy(String configPolicyType, String policyName, String description, String ecompName, String configName, String serviceType, String uuid, 
+            String msLocation, String jsonBody, String priority, String version, Boolean editPolicy, String domain, int highestVersion, String riskLevel, 
+            String riskType, String guard, String ttlDate) {
+
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.ecompName = ecompName;
+		this.configName = configName;
+		this.serviceType = serviceType;
+		this.uuid = uuid;
+		this.msLocation = msLocation;
+        this.priority = priority;
+        this.version = version;
+		this.jsonBody = jsonBody;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.highestVersion = highestVersion;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+	
+	//Constructor for Updating Goc Policies from the Admin Console
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, 
+						String configName, Boolean editPolicy, String domain, 
+						String policyID, String ruleID, String version, 
+						String jsonBody,  Integer highestVersion, String eCompName,String riskLevel, String riskType, String guard, String ttlDate) {
+		
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.configName = configName;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.policyID = policyID;
+		this.ruleID = ruleID;
+		this.version = version;
+		this.jsonBody = jsonBody;
+		this.highestVersion = highestVersion;
+		this.ecompName=eCompName;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+		
+	//Constructor for Updating Brms Policies from the Admin Console
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, 
+						String configName, Boolean editPolicy, String domain, 
+						String policyID, String ruleID, String version, 
+						Map<String,String> dyanamicFieldConfigAttributes, Integer highestVersion, String eCompName, 
+						String configBodyData , String riskLevel, String riskType, String guard, String ttlDate
+						) {
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.configName = configName;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.policyID = policyID;
+		this.ruleID = ruleID;
+		this.version = version;
+		this.dyanamicFieldConfigAttributes = dyanamicFieldConfigAttributes;
+		this.highestVersion = highestVersion;
+		this.ecompName=eCompName;
+		this.configBodyData=configBodyData;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+	
+	//Constructor for Updating Brms Param Policies from the Admin Console
+	public StdPAPPolicy (String configPolicyType, String policyName, String description, 
+						String configName, Boolean editPolicy, String domain, 
+						String policyID, String ruleID, String version, 
+						Map<String,String> dyanamicFieldConfigAttributes, Integer highestVersion, String eCompName, 
+						Map<String,String> drlRuleAndUIParams, String riskLevel, String riskType, String guard, String ttlDate
+						) {
+		this.configPolicyType = configPolicyType;
+		this.policyName = policyName;
+		this.policyDescription = description;
+		this.configName = configName;
+		this.editPolicy = editPolicy;
+		this.domain = domain;
+		this.policyID = policyID;
+		this.ruleID = ruleID;
+		this.version = version;
+		this.dyanamicFieldConfigAttributes = dyanamicFieldConfigAttributes;
+		this.highestVersion = highestVersion;
+		this.ecompName=eCompName;
+		this.drlRuleAndUIParams=drlRuleAndUIParams;
+		this.riskLevel = riskLevel;
+		this.riskType = riskType;
+		this.guard = guard;	
+		this.ttlDate = ttlDate;
+	}
+
+	// Constructor for deleting policies from the API
+	public StdPAPPolicy(String policyName, String deleteCondition) {
+		this.policyName = policyName;
+		this.deleteCondition = deleteCondition;
+	}
+	
+	// Constructor for creating dictionary items from the API
+	public StdPAPPolicy(String dictionaryType, String dictionary, Map<String,String> dictionaryFields) {
+		this.dictionaryType = dictionaryType;
+		this.dictionary = dictionary;
+		this.dictionaryFields = dictionaryFields;
+	}
+
+	@Override
+	public String getPolicyName() {
+		return policyName;
+	}
+	
+	@Override
+	public String getPolicyDescription() {
+		return policyDescription;
+	}
+	
+	@Override
+	public String getEcompName() {
+		return ecompName;
+	}
+	
+	@Override
+	public String getConfigName() {
+		return configName;
+	}
+	
+	@Override
+	public Map<String, String> getDynamicFieldConfigAttributes() {
+		return dyanamicFieldConfigAttributes;
+	}
+	
+	@Override
+	public String getConfigBodyData() {
+		return configBodyData;
+	}
+	
+	@Override
+	public String getPolicyID() {
+		return policyID;
+	}
+	
+	@Override
+	public String getRuleID() {
+		return ruleID;
+	}
+	
+	@Override
+	public String getConfigType() {
+		return configType;
+	}
+	
+	@Override
+	public Boolean isEditPolicy() {
+		return editPolicy;
+	}
+	
+	@Override
+	public Boolean isDraft() {
+		return draft;
+	}
+	
+	@Override
+	public String getVersion() {
+		return version;
+	}
+	
+	@Override
+	public String getDomainDir() {
+		return domain;
+	}
+	
+	@Override
+	public String getConfigPolicyType() {
+		return configPolicyType;
+	}
+	
+	@Override
+	public String getJsonBody() {
+		return jsonBody;
+	}
+	
+	@Override
+	public Integer getHighestVersion() {
+		return highestVersion;
+	}
+	
+	@Override
+	public URI getLocation() {
+		return location;
+	}
+	
+	@Override
+	public List<String> getDynamicRuleAlgorithmLabels() {
+		return dynamicRuleAlgorithmLabels;
+	}
+
+	@Override
+	public List<String> getDynamicRuleAlgorithmCombo() {
+		return dynamicRuleAlgorithmCombo;
+	}
+
+	@Override
+	public List<String> getDynamicRuleAlgorithmField1() {
+		return dynamicRuleAlgorithmField1;
+	}
+
+	@Override
+	public List<String> getDynamicRuleAlgorithmField2() {
+		return dynamicRuleAlgorithmField2;
+	}
+
+	@Override
+	public String getActionPerformer() {
+		return actionPerformer;
+	}
+
+	@Override
+	public String getActionAttribute() {
+		return actionAttribute;
+	}
+	
+	@Override
+	public String getActionBody() {
+		return actionBody;
+	}
+	
+	@Override
+	public Map<String, String> getDropDownMap() {
+		return dropDownMap;
+	}
+	
+	@Override
+	public String getActionDictHeader() {
+		return actionDictHeader;
+	}
+	
+	@Override
+	public String getActionDictType() {
+		return actionDictType;
+	}
+	
+	@Override
+	public String getActionDictUrl() {
+		return actionDictUrl;
+	}
+	
+	@Override
+	public String getActionDictMethod() {
+		return actionDictMethod;
+	}
+	
+	@Override
+	public Map<String, String> getDynamicSettingsMap() {
+		return dynamicSettingsMap;
+	}
+	
+	@Override
+	public List<Object> getDynamicVariableList() {
+		return dynamicVariableList;
+	}
+	
+	@Override
+	public List<String> getDataTypeList() {
+		return dataTypeList;
+	}
+	
+	@Override
+	public String getOldPolicyFileName() {
+		return oldPolicyFileName;
+	}
+	
+	@Override
+	public String getServiceType() {
+		return serviceType;
+	}
+	
+	@Override
+	public String getUuid() {
+		return uuid;
+	}
+	
+	@Override
+	public String getMsLocation() {
+		return msLocation;
+	}
+	
+    @Override
+    public String getPriority() {
+        return priority;
+    }
+    
+    @Override
+	public String getDeleteCondition() {
+		return deleteCondition;
+	}
+    
+    @Override
+	public String getDictionaryType() {
+		return dictionaryType;
+	}
+    
+    @Override
+	public String getDictionary() {
+		return dictionary;
+	}
+    
+	@Override
+	public String getTTLDate(){
+		return ttlDate;
+	}
+
+    @Override
+	public Map<String, String> getDictionaryFields() {
+		return dictionaryFields;
+	}
+
+	@Override
+	public String getRiskType() {
+		return riskType;
+	}
+	
+	@Override
+	public String getRiskLevel() {
+		return riskLevel;
+	}
+	
+	@Override
+	public String getGuard() {
+		return guard;
+	}
+	
+	@Override
+	public String toString() {
+		return "StdPAPPolicy [policyName=" + policyName + ", policyDescription=" + policyDescription + ", ecompName="
+				+ ecompName + ", configName=" + configName + ", dyanamicFieldConfigAttributes=" + dyanamicFieldConfigAttributes + ", configBodyData=" + configBodyData
+				+ ", policyID=" + policyID + ", ruleID=" + ruleID + ", configType=" + configType + ", editPolicy=" + ", version=" + ", domain=" + domain  
+				+ ", configPolicyType=" + configPolicyType + ", jsonBody=" + jsonBody + ", highestVersion=" + highestVersion + ", location=" + location 
+				+ ",dynamicRuleAlgorithmLabels=" + dynamicRuleAlgorithmLabels + ",dynamicRuleAlgorithmCombo=" + dynamicRuleAlgorithmCombo 
+				+ ",dynamicRuleAlgorithmField1=" + dynamicRuleAlgorithmField1 + ",dynamicRuleAlgorithmField2=" + dynamicRuleAlgorithmField2 
+				+ ",actionPerformer=" + actionPerformer + ",actionAttribute=" + actionAttribute + ",actionBody=" + actionBody + ",dropDownMap=" + dropDownMap
+				+ ",actionDictHeader=" + actionDictHeader + ",actionDictType=" + actionDictType + ",actionDictUrl=" + actionDictUrl 
+				+ ",actionDictMethod=" + actionDictMethod + ",dynamicSettingsMap=" + dynamicSettingsMap + ",dynamicVariableList=" + dynamicVariableList + ",providerComboBox=" + providerComboBox
+				+ ",dataTypeList=" + dataTypeList + ",draft=" + ",oldPolicyFileName=" + oldPolicyFileName + ",serviceType=" + serviceType
+                + ",uuid=" + uuid + ",msLocation=" + msLocation + ",priority=" + priority + ",deleteCondition=" + deleteCondition + ",dictionaryType=" + dictionaryType 
+                + ",dictionary=" + dictionary + ",dictionaryFields=" + dictionaryFields + ",uuid=" + uuid + ",msLocation=" + msLocation + ",priority=" 
+                + priority + ",deleteCondition=" + deleteCondition + ",riskType="+riskType + ",riskLevel="+riskLevel + ",guard="+ guard + ",ttlDate="+ ttlDate + "]";
+	}
+	
+	// Methods needed for JSON Deserialization
+	public void setPolicyName(String policyName) {
+		this.policyName = policyName;
+	}
+	
+	public void setPolicyDescription(String policyDescription) {
+		this.policyDescription = policyDescription;
+	}
+	
+	public void setEcompName(String ecompName) {
+		this.ecompName = ecompName;
+	}
+	
+	public void setConfigName(String configName) {
+		this.configName = configName;
+	}
+	
+	public void setDyanamicFieldConfigAttributes(
+			Map<String, String> dyanamicFieldConfigAttributes) {
+		this.dyanamicFieldConfigAttributes = dyanamicFieldConfigAttributes;
+	}
+	
+	public void setConfigBodyData(String configBodyData) {
+		this.configBodyData = configBodyData;
+	}
+	
+	public void setPolicyID(String policyID) {
+		this.policyID = policyID;
+	}
+	
+	public void setRuleID(String ruleID) {
+		this.ruleID = ruleID;
+	}
+	
+	public void setConfigType(String configType) {
+		this.configType = configType;
+	}
+
+	public void setEditPolicy(Boolean editPolicy) {
+		this.editPolicy = editPolicy;
+	}
+
+	public void setVersion(String version) {
+		this.version = version;
+	}
+
+	public void setDomainDir(String domain) {
+		this.domain = domain;
+	}
+
+	public void setConfigPolicyType(String configPolicyType) {
+		this.configPolicyType = configPolicyType;
+	}
+
+	public void setJsonBody(String jsonBody) {
+		this.jsonBody = jsonBody;
+	}
+	
+	public void setHighestVersion(Integer highestVersion) {
+		this.highestVersion = highestVersion;
+	}
+	
+	public void setLocation (URI location) {
+		this.location = location;
+	}
+	
+	public void setDynamicRuleAlgorithmLabels(
+			List<String> dynamicRuleAlgorithmLabels) {
+		this.dynamicRuleAlgorithmLabels = dynamicRuleAlgorithmLabels;
+	}
+
+	public void setDynamicRuleAlgorithmCombo(List<String> dynamicRuleAlgorithmCombo) {
+		this.dynamicRuleAlgorithmCombo = dynamicRuleAlgorithmCombo;
+	}
+
+	public void setDynamicRuleAlgorithmField1(
+			List<String> dynamicRuleAlgorithmField1) {
+		this.dynamicRuleAlgorithmField1 = dynamicRuleAlgorithmField1;
+	}
+
+	public void setDynamicRuleAlgorithmField2(
+			List<String> dynamicRuleAlgorithmField2) {
+		this.dynamicRuleAlgorithmField2 = dynamicRuleAlgorithmField2;
+	}
+
+	public void setActionPerformer(String actionPerformer) {
+		this.actionPerformer = actionPerformer;
+	}
+
+	public void setActionAttribute(String actionAttribute) {
+		this.actionAttribute = actionAttribute;
+	}
+
+	public void setActionBody(String actionBody) {
+		this.actionBody = actionBody;
+	}
+
+	public void setDropDownMap(Map<String, String> dropDownMap) {
+		this.dropDownMap = dropDownMap;
+	}
+
+	public void setActionDictHeader(String actionDictHeader) {
+		this.actionDictHeader = actionDictHeader;
+	}
+
+	public void setActionDictType(String actionDictType) {
+		this.actionDictType = actionDictType;
+	}
+
+	public void setActionDictUrl(String actionDictUrl) {
+		this.actionDictUrl = actionDictUrl;
+	}
+
+	public void setActionDictMethod(String actionDictMethod) {
+		this.actionDictMethod = actionDictMethod;
+	}
+
+	public void setDynamicSettingsMap(Map<String, String> dynamicSettingsMap) {
+		this.dynamicSettingsMap = dynamicSettingsMap;
+	}
+
+	public void setDynamicVariableList(List<Object> dynamicVariableList) {
+		this.dynamicVariableList = dynamicVariableList;
+	}
+
+	public void setDataTypeList(List<String> dataTypeList) {
+		this.dataTypeList = dataTypeList;
+	}
+
+	public void setDraft(Boolean draft) {
+		this.draft = draft;
+	}
+
+	public void setOldPolicyFileName(String oldPolicyFileName) {
+		this.oldPolicyFileName = oldPolicyFileName;
+	}
+
+	public void setServiceType(String serviceType) {
+		this.serviceType = serviceType;
+	}
+	
+
+	public Map<String, String> getDrlRuleAndUIParams() {
+		return drlRuleAndUIParams;
+	}
+
+	public void setDrlRuleAndUIParams(Map<String, String> drlRuleAndUIParams) {
+		this.drlRuleAndUIParams = drlRuleAndUIParams;
+	}
+
+	public void setUuid(String uuid) {
+		this.uuid = uuid;
+	}
+
+	public void setMsLocation(String msLocation) {
+		this.msLocation = msLocation;
+	}
+	
+    public void setPriority(String priority) {
+        this.priority = priority;
+    }
+
+	public void setDeleteCondition(String deleteCondition) {
+		this.deleteCondition = deleteCondition;
+	}
+
+	public void setDictionaryType(String dictionaryType) {
+		this.dictionaryType = dictionaryType;
+	}
+
+	public void setDictionary(String dictionary) {
+		this.dictionary = dictionary;
+	}
+
+	public void setDictionaryFields(Map<String, String> dictionaryFields) {
+		this.dictionaryFields = dictionaryFields;
+	}
+
+	public String getProviderComboBox() {
+		return providerComboBox;
+	}
+
+	public void setProviderComboBox(String providerComboBox) {
+		this.providerComboBox = providerComboBox;
+	}
+	
+	public void setRiskType(String riskType){
+		this.riskType = riskType;
+	}
+	
+	public void setRiskLevel(String riskLevel){
+		this.riskLevel = riskLevel;
+	}
+	
+	public void setGuard(String guard){
+		this.guard = guard;
+	}
+	
+	public void setTTLDate(String ttlDate){
+		this.ttlDate = ttlDate;
+	}
+}
+
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDP.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDP.java
new file mode 100644
index 0000000..b8fb59b
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDP.java
@@ -0,0 +1,222 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import org.openecomp.policy.xacml.api.pap.EcompPDP;
+
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger; 
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+import com.att.research.xacml.api.pap.PDPPIPConfig;
+import com.att.research.xacml.api.pap.PDPPolicy;
+import com.att.research.xacml.api.pap.PDPStatus;
+
+public class StdPDP extends StdPDPItemSetChangeNotifier implements EcompPDP, Comparable<StdPDP>, Serializable {
+	private static final long serialVersionUID = 1L;
+	private static Logger	logger	= FlexLogger.getLogger(StdPDP.class);
+	
+	private String id;
+	
+	private String name;
+	
+	private String description;
+	
+	private Integer jmxport = 0;
+	
+	private PDPStatus status = new StdPDPStatus();
+	
+	private Set<PDPPolicy> policies = new HashSet<PDPPolicy>();
+	
+	private Set<PDPPIPConfig> pipConfigs = new HashSet<PDPPIPConfig>();
+	
+	public StdPDP() {
+		
+	}
+	
+	public StdPDP(String id, Integer  jmxport) {
+		this(id, null, null, jmxport);
+	}
+	
+	public StdPDP(String id, String name, Integer  jmxport) {
+		this(id, name, null, jmxport);
+	}
+	
+	public StdPDP(String id, String name, String description, Integer jmxport) {
+		this.id = id;
+		this.name = name;
+		this.description = description;
+		if(jmxport != null){
+			this.jmxport = jmxport;
+		} 
+	}
+	
+	public StdPDP(String id, Properties properties) {
+		this(id, 0);
+		
+		this.initialize(properties);
+	}
+	
+	public void initialize(Properties properties) {
+		for (Object key : properties.keySet()) {
+			if (key.toString().startsWith(this.id + ".")) {
+				if (logger.isDebugEnabled()) {
+					logger.debug("Found: " + key);
+				}
+				if (key.toString().endsWith(".name")) {
+					this.name = properties.getProperty(key.toString());
+				} else if (key.toString().endsWith(".description")) {
+					this.description = properties.getProperty(key.toString());
+				}else if (key.toString().endsWith(".jmxport")) {
+					//todo fix this hackjob
+					if (properties.getProperty(key.toString()) != null && properties.getProperty(key.toString()).trim().length() > 0){
+						logger.debug("initialize before: " + this.jmxport);
+						this.jmxport = Integer.valueOf( properties.getProperty(key.toString()));
+						logger.debug("initialize after: " + this.jmxport);
+					}else{
+						this.jmxport = 0;
+					}
+				}
+			}
+		}
+	}
+
+	@Override
+	public String getId() {
+		return this.id;
+	}
+
+	public void setId(String id) {
+		this.id=id;
+	}
+
+	@Override
+	public String getName() {
+		return this.name;
+	}
+	
+	@Override
+	public void setName(String name) {
+		this.name = name;
+		this.firePDPChanged(this);
+	}
+
+	@Override
+	public String getDescription() {
+		return this.description;
+	}
+	
+	@Override
+	public void setDescription(String description) {
+		this.description = description;
+		this.firePDPChanged(this);
+	}
+
+	@Override
+	public PDPStatus getStatus() {
+		return this.status;
+	}
+
+	public void setStatus(PDPStatus status) {
+		this.status = status;
+	}
+	
+	@Override
+	public Set<PDPPolicy> getPolicies() {
+		return Collections.unmodifiableSet(this.policies);
+	}
+	
+	public void setPolicies(Set<PDPPolicy> policies) {
+		this.policies = policies;
+	}
+
+	@Override
+	public Set<PDPPIPConfig> getPipConfigs() {
+		return Collections.unmodifiableSet(this.pipConfigs);
+	}
+	
+	public void setPipConfigs(Set<PDPPIPConfig> pipConfigs) {
+		this.pipConfigs = pipConfigs;
+	}
+	public void setJmxPort(Integer jmxport) {
+		this.jmxport = jmxport;
+	}
+	@Override
+	public Integer getJmxPort() {
+		return this.jmxport;
+	}
+	
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((id == null) ? 0 : id.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		StdPDP other = (StdPDP) obj;
+		if (id == null) {
+			if (other.id != null)
+				return false;
+		} else if (!id.equals(other.id))
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "StdPDP [id=" + id + ", name=" + name + ", description="
+				+ description + ", jmxport=" + jmxport + ", status=" + status + ", policies=" + policies
+				+ ", pipConfigs=" + pipConfigs + "]";
+	}
+	
+	//
+	// Comparable interface
+	//
+	@Override
+	public int compareTo(StdPDP o) {
+		if (o == null) {
+			return -1;
+		}
+		if ( ! (o instanceof StdPDP)) {
+			return -1;
+		}
+		if (((StdPDP)o).name == null) {
+			return -1;
+		}
+		if (name == null) {
+			return 1;
+		}
+		return name.compareTo(((StdPDP)o).name);
+	}
+	
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPGroup.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPGroup.java
new file mode 100644
index 0000000..ae4a43d
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPGroup.java
@@ -0,0 +1,1031 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.eelf.PolicyLogger;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openecomp.policy.xacml.api.pap.EcompPDP;
+import org.openecomp.policy.xacml.api.pap.EcompPDPGroup;
+import org.openecomp.policy.xacml.std.pap.StdPDPItemSetChangeNotifier.StdItemSetChangeListener;
+
+import com.att.research.xacml.api.pap.PAPException;
+import com.att.research.xacml.api.pap.PDP;
+import com.att.research.xacml.api.pap.PDPGroup;
+//import com.att.research.xacml.api.pap.PDPGroup;
+import com.att.research.xacml.api.pap.PDPGroupStatus;
+import com.att.research.xacml.api.pap.PDPGroupStatus.Status;
+import com.att.research.xacml.api.pap.PDPPIPConfig;
+import com.att.research.xacml.api.pap.PDPPolicy;
+import com.att.research.xacml.util.XACMLProperties;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+import com.google.common.io.ByteStreams;
+
+public class StdPDPGroup extends StdPDPItemSetChangeNotifier implements EcompPDPGroup, StdItemSetChangeListener, Comparable<Object>, Serializable {
+	private static final long serialVersionUID = 1L;
+	private static Log	logger	= LogFactory.getLog(StdPDPGroup.class);
+	
+	private String id;
+	
+	private boolean isDefault = false;
+	
+	private String name;
+	
+	private String description;
+	
+	private StdPDPGroupStatus status = new StdPDPGroupStatus(Status.UNKNOWN);
+	
+	private Set<EcompPDP>	pdps = new HashSet<EcompPDP>();
+	
+	private Set<PDPPolicy> policies = new HashSet<PDPPolicy>();
+	
+	private Set<PDPPIPConfig> pipConfigs = new HashSet<PDPPIPConfig>();
+	
+	@JsonIgnore
+	private  Path directory;
+	
+	@JsonIgnore
+	private Integer jmxport;
+	
+	
+	public StdPDPGroup(String id, Path directory) {
+		this.id = id;
+		this.directory = directory;
+	}
+	
+	public StdPDPGroup(String id, boolean isDefault, Path directory) {
+		this(id, directory);
+		this.isDefault = isDefault;
+	}
+	
+	public StdPDPGroup(String id, boolean isDefault, String name, String description, Path directory) {
+		this(id, isDefault, directory);
+		this.name = name;
+		// force all policies to have a name
+		if (name == null) {
+			this.name = id;
+		}
+		this.description = description;
+	}
+	
+	public StdPDPGroup(String id, String name, String description, Path directory) {
+		this(id, false, name, description, directory);
+		this.resetStatus();
+	}
+	
+	public StdPDPGroup(String id, boolean isDefault, Properties properties, Path directory) throws PAPException {
+		this(id, isDefault, directory);
+		this.initialize(properties, directory);
+		this.resetStatus();
+	}
+	
+	private void initialize(Properties properties, Path directory) throws PAPException {
+		if (this.id == null || this.id.length() == 0) {
+			logger.warn("Cannot initialize with a null or zero length id");
+			return;
+		}
+		//
+		// Pull the group's properties
+		//
+		for (Object key : properties.keySet()) {
+			if (key.toString().startsWith(this.id + ".")) {
+				if (key.toString().endsWith(".name")) {
+					this.name = properties.getProperty(key.toString());
+				} else if (key.toString().endsWith(".description")) {
+					this.description = properties.getProperty(key.toString());
+				} else if (key.toString().endsWith(".pdps")) {
+					String pdpList = properties.getProperty(key.toString());
+					if (pdpList != null && pdpList.length() > 0) {
+						for (String id : Splitter.on(',').omitEmptyStrings().trimResults().split(pdpList)) {
+							StdPDP pdp = new StdPDP(id, properties);
+							pdp.addItemSetChangeListener(this);
+							this.pdps.add(pdp);
+						}
+					}
+				}
+			}
+			// force all policies to have a name
+			if (this.name == null) {
+				this.name = this.id;
+			}
+		}
+		//
+		// Validate our directory
+		//
+		if (Files.notExists(directory)) {
+			logger.warn("Group directory does NOT exist: " + directory.toString());
+			try {
+				Files.createDirectory(directory);
+				this.status.addLoadWarning("Group directory does NOT exist");
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Group directory does NOT exist");
+				this.status.addLoadError("Group directory does NOT exist");
+				this.status.setStatus(PDPGroupStatus.Status.LOAD_ERRORS);
+			}
+		}
+		//
+		// Parse policies
+		//
+		this.loadPolicies(Paths.get(directory.toString(), "xacml.policy.properties"));
+		//
+		// Parse pip config
+		//
+		this.loadPIPConfig(Paths.get(directory.toString(), "xacml.pip.properties"));
+	}
+	
+	public void loadPolicies(Path file) throws PAPException {
+		//
+		// Read the Groups Policies
+		//
+		Properties policyProperties = new Properties();
+		if ( ! file.toFile().exists()) {
+			// need to create the properties file with default values
+			policyProperties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
+			policyProperties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
+			// save properties to file
+			try (OutputStream os = Files.newOutputStream(file)) {
+				policyProperties.store(os, "");
+			} catch (Exception e) {
+				throw new PAPException("Failed to create new default policy properties file '" + file +"'");
+			}
+		} else {
+			// load previously existing file
+			try {
+				//
+				// Load the properties
+				//
+				try (InputStream is = Files.newInputStream(file)) {
+					policyProperties.load(is);
+				}
+				//
+				// Parse the policies
+				//
+				this.readPolicyProperties(directory, policyProperties);
+			} catch (IOException e) {
+				logger.warn("Failed to load group policy properties file: " + file, e);
+				this.status.addLoadError("Not policy properties defined");
+				this.status.setStatus(Status.LOAD_ERRORS);
+				throw new PAPException("Failed to load group policy properties file: " + file);
+			}
+		}
+	}
+	
+	public void loadPIPConfig(Path file) throws PAPException {
+		//
+		// Read the Groups' PIP configuration
+		//
+		Properties pipProperties = new Properties();
+		if ( ! file.toFile().exists()) {
+			// need to create the properties file with no values
+			// TODO: Adding Default PIP engine(s) while Loading initially. We don't want 
+			// Programmer intervention with the PIP engines. 
+			pipProperties = setPIPProperties(pipProperties);
+			// save properties to file
+			try {
+				try (OutputStream os = Files.newOutputStream(file)) {
+					pipProperties.store(os, "");
+				}
+			} catch (Exception e) {
+				throw new PAPException("Failed to create new default pip properties file '" + file +"'");
+			}
+		} else {
+			try {
+				//
+				// Load the properties
+				//
+				try (InputStream is = Files.newInputStream(file)) {
+					pipProperties.load(is);
+				}
+				// For all old PIP config's modify to the new PIP Configuration. 
+				// If PIP is empty add the new values and save it. 
+				if(pipProperties.get(XACMLProperties.PROP_PIP_ENGINES).toString().trim().equals("")){
+					pipProperties = setPIPProperties(pipProperties);
+					try (OutputStream os = Files.newOutputStream(file)) {
+						pipProperties.store(os, "");
+					}
+				}
+				//
+				// Parse the pips
+				//
+				this.readPIPProperties(directory, pipProperties);
+			} catch (IOException e) {
+				logger.warn("Failed to open group PIP Config properties file: " + file, e);
+				this.status.addLoadError("Not PIP config properties defined");
+				this.status.setStatus(Status.LOAD_ERRORS);
+				throw new PAPException("Failed to load group policy properties file: " + file);
+
+			}
+		}
+	}
+	
+	public void resetStatus() {
+//		//
+//		// If we are updating, don't allow reset
+//		//
+//		if (this.status.getStatus() == Status.UPDATING_CONFIGURATION) {
+//			logger.warn("We are updating, chill.");
+//			return;
+//		}
+//		//
+//		// Load errors take precedence
+//		//
+//		if (this.status.getStatus() == Status.LOAD_ERRORS) {
+//			logger.warn("We had load errors.");
+//			return;
+//		}
+		//
+		// Reset our status object
+		//
+		this.status.reset();
+		//
+		// Determine our status
+		//
+		for (PDP pdp : this.pdps) {
+			switch (pdp.getStatus().getStatus()) {
+			case OUT_OF_SYNCH:
+				this.status.addOutOfSynchPDP(pdp);
+				break;
+			case LAST_UPDATE_FAILED:
+				this.status.addLastUpdateFailedPDP(pdp);
+				break;
+			case LOAD_ERRORS:
+				this.status.addFailedPDP(pdp);
+				break;
+			case UPDATING_CONFIGURATION:
+				this.status.addUpdatingPDP(pdp);
+				break;
+			case UP_TO_DATE:
+				this.status.addInSynchPDP(pdp);
+				break;
+			case UNKNOWN:
+			case CANNOT_CONNECT:
+			case NO_SUCH_HOST:
+			default:
+				this.status.addUnknownPDP(pdp);
+				break;
+			}
+		}
+		
+		// priority is worst-cast to best case
+		if (this.status.getUnknownPDPs().size() > 0) {
+			this.status.setStatus(Status.UNKNOWN);
+		} else if (this.status.getFailedPDPs().size() > 0 || this.status.getLastUpdateFailedPDPs().size() > 0) {
+			this.status.setStatus(Status.LOAD_ERRORS);
+		} else if (this.status.getOutOfSynchPDPs().size() > 0) {
+			this.status.setStatus(Status.OUT_OF_SYNCH);
+		} else if (this.status.getUpdatingPDPs().size() > 0) {
+			this.status.setStatus(Status.UPDATING_CONFIGURATION);
+		} else {
+			this.status.setStatus(Status.OK); 
+		}
+	}
+
+	@Override
+	public String getId() {
+		return this.id;
+	}
+	
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	@Override
+	public boolean isDefaultGroup() {
+		return this.isDefault;
+	}
+	
+	public void setDefaultGroup(boolean isDefault) {
+		this.isDefault = isDefault;
+		//
+		// Cannot fire this because 2 operations have
+		// to occur: 1) old default=false (don't want to fire) and
+		// then 2) new default=true (yes fire - but we'll have to do that
+		// elsewhere.
+		//this.firePDPGroupChanged(this);
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public void setName(String groupName) {
+		this.name = groupName;
+		this.firePDPGroupChanged(this);
+	}
+
+	@Override
+	public String getDescription() {
+		return this.description;
+	}
+
+	@Override
+	public void setDescription(String groupDescription) {
+		this.description = groupDescription;
+		this.firePDPGroupChanged(this);
+	}
+	
+	public Path getDirectory() {
+		return this.directory;
+	}
+
+	public void setDirectory(Path groupDirectory) {
+		this.directory = groupDirectory;
+		// this is used only for transmission on the RESTful interface, so no need to fire group changed?
+	}
+
+	@Override
+	public PDPGroupStatus getStatus()
+	{
+		return this.status;
+	}
+	
+	@Override
+	public Set<PDP> getPdps() {
+		return Collections.unmodifiableSet(pdps);
+	}
+
+	public void setEcompPdps(Set<EcompPDP> pdps) {
+		this.pdps = pdps;
+	}
+	
+	public Set<EcompPDP> getEcompPdps(){
+		return Collections.unmodifiableSet(pdps);
+	}
+	
+	public boolean addPDP(EcompPDP pdp) {
+		return this.pdps.add(pdp);
+	}
+	
+	public boolean removePDP(PDP pdp) {
+		return this.pdps.remove(pdp);
+	}
+
+	@Override
+	public Set<PDPPolicy> getPolicies() {
+		return Collections.unmodifiableSet(this.policies);
+	}
+
+	@Override
+	public PDPPolicy getPolicy(String id) {
+		for (PDPPolicy policy : this.policies) {
+			if (policy.getId().equals(id)) {
+				return policy;
+			}
+		}
+		return null;
+	}
+
+	public Properties getPolicyProperties()
+	{
+		Properties properties = new Properties(){
+			private static final long serialVersionUID = 1L;
+			// For Debugging it is helpful for the file to be in a sorted order,
+			// any by returning the keys in the natural Alpha order for strings we get close enough.
+			// TreeSet is sorted, and this just overrides the normal Properties method to get the keys.
+			@Override
+		    public synchronized Enumeration<Object> keys() {
+		        return Collections.enumeration(new TreeSet<Object>(super.keySet()));
+		    }
+	    };;
+		List<String> roots = new ArrayList<String>();
+		List<String> refs = new ArrayList<String>();
+		
+		for (PDPPolicy policy : this.policies) {
+			// for all policies need to tell PDP the "name", which is the base name for the file id
+			if (policy.getName() != null) {
+				properties.setProperty(policy.getId() + ".name", policy.getName());
+			}
+			// put the policy on the correct list
+			if (policy.isRoot()) {
+				roots.add(policy.getId());
+			} else {
+				refs.add(policy.getId());
+			}
+		}
+		
+		properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, Joiner.on(',').join(roots));
+		properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, Joiner.on(',').join(refs));
+	
+		return properties;
+	}
+	
+	public PDPPolicy publishPolicy(String id, String name, boolean isRoot, InputStream policy) throws PAPException {
+		//
+		// Does it exist already?
+		//
+		if (this.getPolicy(id) != null) {
+			throw new PAPException("Policy with id " + id + " already exists - unpublish it first.");
+		}
+		Path tempFile = null;
+		try {
+			//
+			// Copy the policy over
+			//
+			tempFile = Files.createFile(Paths.get(this.directory.toAbsolutePath().toString(), id));
+			long num;
+			try (OutputStream os = Files.newOutputStream(tempFile)) {
+				num = ByteStreams.copy(policy, os);
+			}
+			logger.info("Copied " + num + " bytes for policy " + name);
+			
+			StdPDPPolicy tempRootPolicy = new StdPDPPolicy(id, isRoot, name, tempFile.toUri());
+			if (tempRootPolicy.isValid() == false) {
+				try {
+					Files.delete(tempFile);
+				} catch(Exception ee) {
+					//TODO:EELF Cleanup - Remove logger
+					//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Policy was invalid, could NOT delete it.", ee);
+					PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, ee, "StdPDPGroup", "Policy was invalid, could NOT delete it.");
+				}
+				throw new PAPException("Policy is invalid");
+			}
+			//
+			// Add it in
+			//
+			this.policies.add(tempRootPolicy);
+			//
+			// We are changed
+			//
+			this.firePDPGroupChanged(this);
+			//
+			// Return our new object.
+			//
+			return tempRootPolicy;
+		} catch (IOException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to publishPolicy: ", e);
+			PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdPDPGroup", "Failed to publishPolicy");
+		}
+		return null;
+	}
+	
+	/**
+	 * Copy one policy file into the Group's directory but do not change the configuration.
+	 * This is one part of a multi-step process of publishing policies.
+	 * There may be multiple changes in the group (adding multiple policies, deleting policies, changine root<->referenced)
+	 * that must be done all at once, so we just copy the file in preparation for a later "update whole group" operation.
+	 * 
+	 * @param id
+	 * @param name
+	 * @param isRoot
+	 * @param policy
+	 * @return
+	 * @throws PAPException
+	 */
+	public void copyPolicyToFile(String id,  InputStream policy) throws PAPException {
+		try {
+			//
+			// Copy the policy over
+			//
+			long num;
+			Path policyFilePath = Paths.get(this.directory.toAbsolutePath().toString(), id);
+			
+			//
+			// THERE IS A WEIRD PROBLEM ON WINDOWS...
+			// The file is already "in use" when we try to access it.  
+			// Looking at the file externally while this is halted here does not show the file in use,
+			// so there is no indication what is causing the problem.
+			//
+			// As a way to by-pass the issue, I simply check if the input and the existing file are identical
+			// and generate an exception if they are not.
+			//
+			
+
+			
+//			if (Files.exists(policyFilePath)) {
+//				// compare the 
+//				String incomingPolicyString = null;
+//				try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+//					num = ByteStreams.copy(policy, os);
+//					incomingPolicyString = new String(os.toByteArray(), "UTF-8"); 
+//				}
+//				String existingPolicyString = null;
+//				try {
+//					byte[] bytes =  Files.readAllBytes(policyFilePath);
+//					existingPolicyString = new String(bytes, "UTF-8"); 
+//				} catch (Exception e) {
+//					//TODO:EELF Cleanup - Remove logger
+//					logger.error("Unable to read existing file '" + policyFilePath + "': " + e, e);
+//					PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdPDPGroup", "Unable to read existing policy file");
+//					throw new PAPException("Unable to read policy file for comparison: " + e);
+//				}
+//				if (incomingPolicyString.equals(existingPolicyString)) {
+//					throw new PAPException("Policy '" + policyFilePath + "' does not match existing policy on server");
+//				}
+//				// input is same as existing file
+//				return;
+//			}
+			
+			
+			Path policyFile;
+			if (Files.exists(policyFilePath)) {
+				policyFile = policyFilePath;
+			} else {
+				policyFile = Files.createFile(policyFilePath);
+			}
+
+			try (OutputStream os = Files.newOutputStream(policyFile)) {
+				num = ByteStreams.copy(policy, os);
+			}
+			
+			logger.info("Copied " + num + " bytes for policy " + name);
+
+			for (PDPPolicy p : policies) {
+				if (p.getId().equals(id)) {
+					// we just re-copied/refreshed/updated the policy file for a policy that already exists in this group
+					logger.info("Policy '" + id + "' already exists in group '" + getId() + "'");
+					return;
+				}
+			}
+			
+			// policy is new to this group
+			StdPDPPolicy tempRootPolicy = new StdPDPPolicy(id, true, name, policyFile.toUri());
+			if (tempRootPolicy.isValid() == false) {
+				try {
+					Files.delete(policyFile);
+				} catch(Exception ee) {
+					//TODO:EELF Cleanup - Remove logger
+					//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Policy was invalid, could NOT delete it.", ee);
+					PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, ee, "StdPDPGroup", "Policy was invalid, could NOT delete it.");
+				}
+				throw new PAPException("Policy is invalid");
+			}
+			//
+			// Add it in
+			//
+			this.policies.add(tempRootPolicy);
+			//
+			// We are changed
+			//
+			this.firePDPGroupChanged(this);
+			
+			
+			
+			
+		} catch (IOException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to copyPolicyToFile: ", e);
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Failed to copyPolicyToFile");
+			throw new PAPException("Failed to copy policy to file: " + e);
+		}
+		return;
+	}
+	
+	public boolean removePolicyFromGroup(PDPPolicy policy) {
+		StdPDPPolicy currentPolicy = (StdPDPPolicy) this.getPolicy(policy.getId());
+		if (currentPolicy == null) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Policy " + policy.getId() + " does not exist.");
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Policy " + policy.getId() + " does not exist.");
+			return false;
+		}
+		try {
+			//
+			// Remove it from our list
+			//
+			this.policies.remove(currentPolicy);
+			//
+			// We are changed
+			//
+			this.firePDPGroupChanged(this);
+			return true;
+		} catch (Exception e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to delete policy " + policy);
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Failed to delete policy");
+		}
+		return false;
+	}
+	
+	public boolean removePolicy(PDPPolicy policy) {
+		StdPDPPolicy currentPolicy = (StdPDPPolicy) this.getPolicy(policy.getId());
+		if (currentPolicy == null) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Policy " + policy.getId() + " does not exist.");
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Policy " + policy.getId() + " does not exist.");
+			return false;
+		}
+		try {
+			//
+			// Delete it on disk
+			//
+			Files.delete(Paths.get(currentPolicy.getLocation()));
+			//
+			// Remove it from our list
+			//
+			this.policies.remove(currentPolicy);
+			//
+			// We are changed
+			//
+			this.firePDPGroupChanged(this);
+			return true;
+		} catch (Exception e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to delete policy " + policy);
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Failed to delete policy " + policy);
+		}
+		return false;
+	}
+
+	@Override
+	public Set<PDPPIPConfig> getPipConfigs() {
+		return Collections.unmodifiableSet(this.pipConfigs);
+	}
+
+	@Override
+	public PDPPIPConfig getPipConfig(String id) {
+		for (PDPPIPConfig config : this.pipConfigs) {
+			if (config.getId().equals(id)) {
+				return config;
+			}
+		}
+		return null;
+	}
+	
+	public void setPipConfigs(Set<PDPPIPConfig> pipConfigs) {
+		this.pipConfigs = pipConfigs;
+		this.firePDPGroupChanged(this);
+	}
+	
+	public void removeAllPIPConfigs() {
+		this.pipConfigs.clear();
+		this.firePDPGroupChanged(this);
+	}
+	
+	public Properties getPipConfigProperties() {
+		Properties properties = new Properties();
+		List<String> configs = new ArrayList<String>();
+		
+		for (PDPPIPConfig config : this.pipConfigs) {
+			configs.add(config.getId());
+			properties.putAll(config.getConfiguration());
+		}
+		
+		properties.setProperty(XACMLProperties.PROP_PIP_ENGINES, Joiner.on(',').join(configs));
+
+		return properties;
+	}
+
+	@Override
+	public void repair() {
+		//
+		// Reset the status object
+		//
+		this.status.reset();
+		//
+		// Validate our directory
+		//
+		boolean fire = false;
+		if (Files.notExists(directory)) {
+			logger.warn("Group directory does NOT exist: " + directory.toString());
+			try {
+				Files.createDirectory(directory);
+				fire = true;
+				this.status.addLoadWarning("Created missing group directory");
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Failed to create missing Group directory.");
+				this.status.addLoadError("Failed to create missing Group directory.");
+				this.status.setStatus(PDPGroupStatus.Status.LOAD_ERRORS);
+			}
+		}
+		//
+		// Validate our PIP config file
+		//
+		Path pipPropertiesFile = Paths.get(directory.toString(), "xacml.pip.properties");
+		if (Files.notExists(pipPropertiesFile)) {
+			try {
+				Files.createFile(pipPropertiesFile);
+				fire = true;
+				this.status.addLoadWarning("Created missing PIP properties file");
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Failed to create missing PIP properties file");
+				this.status.addLoadError("Failed to create missing PIP properties file");
+				this.status.setStatus(PDPGroupStatus.Status.LOAD_ERRORS);
+			}
+		}
+		//
+		// Valid our policy properties file
+		//
+		Path policyPropertiesFile = Paths.get(directory.toString(), "xacml.policy.properties");
+		if (Files.notExists(policyPropertiesFile)) {
+			try {
+				Files.createFile(policyPropertiesFile);
+				fire = true;
+				this.status.addLoadWarning("Created missing Policy properties file");
+			} catch (IOException e) {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e);
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Failed to create missing Policy properties file");
+				this.status.addLoadError("Failed to create missing Policy properties file");
+				this.status.setStatus(PDPGroupStatus.Status.LOAD_ERRORS);
+			}
+		}
+		this.resetStatus();
+		if (fire) {
+			this.fireChanged();
+		}
+	}
+
+	private void	readPolicyProperties(Path directory, Properties properties) {
+		//
+		// There are 2 property values that hold policies, root and referenced
+		//
+		String[] lists = new String[2];
+		lists[0] = properties.getProperty(XACMLProperties.PROP_ROOTPOLICIES);
+		lists[1] = properties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES);
+		//
+		// Iterate each policy list
+		//
+		boolean isRoot = true;
+		for (String list : lists) {
+			//
+			// Was there actually a property?
+			//
+			if (list == null || list.length() == 0) {
+				isRoot = false;
+				continue;
+			}
+			//
+			// Parse it out
+			//
+			Iterable<String> policyList = Splitter.on(',').trimResults().omitEmptyStrings().split(list);
+			//
+			// Was there actually a list
+			//
+			if (policyList == null) {
+				isRoot = false;
+				continue;
+			}
+			for (String id : policyList) {
+				//
+				// Construct the policy filename
+				//
+				Path policyPath = Paths.get(directory.toString(), id );
+				//
+				// Create the Policy Object
+				//
+				StdPDPPolicy policy;
+				try {
+					policy = new StdPDPPolicy(id, isRoot, policyPath.toUri(), properties);
+				} catch (IOException e) {
+					//TODO:EELF Cleanup - Remove logger
+					//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to create policy object", e);
+					PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Failed to create policy object");
+					policy = null;
+				}
+				//
+				// Is it valid?
+				//
+				if (policy != null && policy.isValid()) {
+					this.policies.add(policy);
+					this.status.addLoadedPolicy(policy);
+				} else {
+					this.status.addFailedPolicy(policy);
+					this.status.setStatus(Status.LOAD_ERRORS);
+				}
+				// force all policies to have a name
+				if (policy.getName() == null) {
+					policy.setName(policy.getId());
+				}
+			}
+			isRoot = false;
+		}
+	}
+
+	private void	readPIPProperties(Path directory, Properties properties) {
+		String list = properties.getProperty(XACMLProperties.PROP_PIP_ENGINES);
+		if (list == null || list.length() == 0) {
+			return;
+		}
+		for (String id : list.split("[,]")) {
+			StdPDPPIPConfig config = new StdPDPPIPConfig(id, properties);
+			if (config.isConfigured()) {
+				this.pipConfigs.add(config);
+				this.status.addLoadedPipConfig(config);
+			} else {
+				this.status.addFailedPipConfig(config);
+				this.status.setStatus(Status.LOAD_ERRORS);
+			}
+		}
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((id == null) ? 0 : id.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		StdPDPGroup other = (StdPDPGroup) obj;
+		if (id == null) {
+			if (other.id != null)
+				return false;
+		} else if (!id.equals(other.id))
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "StdPDPGroup [id=" + id + ", isDefault=" + isDefault + ", name="
+				+ name + ", description=" + description + ", status=" + status
+				+ ", pdps=" + pdps + ", policies=" + policies + ", pipConfigs="
+				+ pipConfigs + ", directory=" + directory + "]";
+	}
+
+	@Override
+	public void changed() {
+
+		// save the (changed) properties
+		try {
+			saveGroupConfiguration();
+		} catch (PAPException | IOException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Unable to save group configuration change");
+			PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdPDPGroup", "Unable to save group configuration change");
+			// don't notify other things of change if we cannot save it???
+			return;
+		}
+		
+		this.firePDPGroupChanged(this);
+
+	}
+
+	@Override
+	public void groupChanged(EcompPDPGroup group) {
+		this.changed();
+	}
+
+	@Override
+	public void pdpChanged(EcompPDP pdp) {
+		//
+		// If one of the group's PDP's changed, then the group changed
+		//
+		// TODO Really?
+		//
+		this.changed();
+	}
+
+	
+	//
+	// Methods needed for JSON deserialization
+	//
+	public StdPDPGroup() {
+		
+	}
+	
+	public StdPDPGroup(EcompPDPGroup group) {
+		this.id = group.getId();
+		this.name = group.getName();
+		this.description = group.getDescription();
+		this.isDefault = group.isDefaultGroup();
+		this.pdps = group.getEcompPdps();
+		this.policies = group.getPolicies();
+		this.pipConfigs = group.getPipConfigs();
+	}
+
+	public boolean isDefault() {
+		return isDefault;
+	}
+	public void setDefault(boolean isDefault) {
+		this.isDefault = isDefault;
+	}
+	public void setStatus(PDPGroupStatus status) {
+		this.status = new StdPDPGroupStatus(status);
+	}
+	public void setPolicies(Set<PDPPolicy> policies) {
+		this.policies = policies;
+	}
+
+	
+	
+	public void saveGroupConfiguration() throws PAPException, IOException {
+		
+		// First save the Policy properties
+		
+		// save the lists of policies
+		Properties policyProperties = this.getPolicyProperties();
+		
+		// save info about each policy
+		for (PDPPolicy policy : this.policies){
+			policyProperties.put(policy.getId() + ".name", policy.getName());
+		}
+
+		//
+		// Now we can save the file
+		//
+		Path file = Paths.get(this.directory.toString(), "xacml.policy.properties");
+		try (OutputStream os = Files.newOutputStream(file)) {
+			policyProperties.store(os, "");
+		} catch (Exception e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Group Policies Config save failed: " + e, e);
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "STdPDPGroup", "Group Policies Config save failed");
+			throw new PAPException("Failed to save policy properties file '" + file +"'");
+		}
+		
+				
+		// Now save the PIP Config properties
+		Properties pipProperties = this.getPipConfigProperties();
+
+		//
+		// Now we can save the file
+		//
+		file = Paths.get(this.directory.toString(), "xacml.pip.properties");
+		try (OutputStream os = Files.newOutputStream(file)) {
+			pipProperties.store(os, "");
+		} catch (Exception e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Group PIP Config save failed: " + e, e);
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdPDPGroup", "Group PIP Config save failed");
+			throw new PAPException("Failed to save pip properties file '" + file +"'");
+		}
+	}
+
+	//
+	// Comparable Interface
+	//
+	@Override
+	public int compareTo(Object arg0) {
+		if (arg0 == null) {
+			return -1;
+		}
+		if ( ! (arg0 instanceof StdPDPGroup)) {
+			return -1;
+		}
+		if (((StdPDPGroup)arg0).name == null) {
+			return -1;
+		}
+		if (name == null) {
+			return 1;
+		}
+
+		return name.compareTo(((StdPDPGroup)arg0).name);
+	}
+	
+	// TODO: Adding Default PIP engine(s) while Loading initially. We don't want 
+	//			Programmer intervention with the PIP engines. 
+	private Properties setPIPProperties(Properties props){
+		props.setProperty("AAF.name", "AAFEngine");
+		props.setProperty("AAF.description", "AAFEngine to communicate with AAF to take decisions");
+		props.setProperty("AAF.classname","org.openecomp.policy.xacml.std.pip.engines.aaf.AAFEngine");
+		props.setProperty(XACMLProperties.PROP_PIP_ENGINES, "AAF");
+		return props;
+	}
+
+
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPGroupStatus.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPGroupStatus.java
new file mode 100644
index 0000000..dcb1f8f
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPGroupStatus.java
@@ -0,0 +1,405 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.att.research.xacml.api.pap.PDP;
+import com.att.research.xacml.api.pap.PDPGroupStatus;
+import com.att.research.xacml.api.pap.PDPPIPConfig;
+import com.att.research.xacml.api.pap.PDPPolicy;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+public class StdPDPGroupStatus implements PDPGroupStatus {
+	
+	private Status status = Status.UNKNOWN;
+	
+	private Set<String>	loadErrors = new HashSet<String>();
+	
+	private Set<String> loadWarnings = new HashSet<String>();
+	
+	private Set<PDPPolicy> loadedPolicies = new HashSet<PDPPolicy>();
+	
+	private Set<PDPPolicy> failedPolicies = new HashSet<PDPPolicy>();
+	
+	private Set<PDPPIPConfig>	loadedPIPConfigs = new HashSet<PDPPIPConfig>();
+	
+	private Set<PDPPIPConfig>	failedPIPConfigs = new HashSet<PDPPIPConfig>();
+	
+	private Set<PDP>			inSynchPDPs = new HashSet<PDP>();
+	
+	private Set<PDP>			outOfSynchPDPs = new HashSet<PDP>();
+	
+	private Set<PDP>			failedPDPs = new HashSet<PDP>();
+	
+	private Set<PDP>			updatingPDPs = new HashSet<PDP>();
+	
+	private Set<PDP>			lastUpdateFailedPDPs = new HashSet<PDP>();
+	
+	private Set<PDP>			unknownPDPs = new HashSet<PDP>();
+	
+	
+	// Constructor needed for JSON deserialization
+	public StdPDPGroupStatus() {
+		
+	}
+	
+	public StdPDPGroupStatus(Status status) {
+		this.status = status;
+	}
+
+	public StdPDPGroupStatus(PDPGroupStatus stat) {
+		this.status = stat.getStatus();
+		this.failedPDPs.clear(); this.failedPDPs.addAll(stat.getFailedPDPs());
+		this.failedPIPConfigs.clear(); this.failedPIPConfigs.addAll(stat.getFailedPipConfigs());
+		this.failedPolicies.clear(); this.failedPolicies.addAll(stat.getFailedPolicies());
+		this.inSynchPDPs.clear(); this.inSynchPDPs.addAll(stat.getInSynchPDPs());
+		this.lastUpdateFailedPDPs.clear(); this.lastUpdateFailedPDPs.addAll(stat.getLastUpdateFailedPDPs());
+		this.loadedPIPConfigs.clear(); this.loadedPIPConfigs.addAll(stat.getLoadedPipConfigs());
+		this.loadedPolicies.clear(); this.loadedPolicies.addAll(stat.getLoadedPolicies());
+		this.loadErrors.clear(); this.loadErrors.addAll(stat.getLoadErrors());
+		this.loadWarnings.clear(); this.loadWarnings.addAll(stat.getLoadWarnings());
+		this.outOfSynchPDPs.clear(); this.outOfSynchPDPs.addAll(stat.getOutOfSynchPDPs());
+		this.unknownPDPs.clear(); this.unknownPDPs.addAll(stat.getUpdatingPDPs());
+		this.updatingPDPs.clear(); this.updatingPDPs.addAll(stat.getUpdatingPDPs());
+	}
+
+	public Set<PDPPIPConfig> getLoadedPIPConfigs() {
+		return loadedPIPConfigs;
+	}
+	public void setLoadedPIPConfigs(Set<PDPPIPConfig> loadedPIPConfigs) {
+		this.loadedPIPConfigs = loadedPIPConfigs;
+	}
+	public Set<PDPPIPConfig> getFailedPIPConfigs() {
+		return failedPIPConfigs;
+	}
+	public void setFailedPIPConfigs(Set<PDPPIPConfig> failedPIPConfigs) {
+		this.failedPIPConfigs = failedPIPConfigs;
+	}
+	public Set<PDP> getUnknownPDPs() {
+		return unknownPDPs;
+	}
+	public void setUnknownPDPs(Set<PDP> unknownPDPs) {
+		this.unknownPDPs = unknownPDPs;
+	}
+	public void setLoadErrors(Set<String> loadErrors) {
+		this.loadErrors = loadErrors;
+	}
+	public void setLoadWarnings(Set<String> loadWarnings) {
+		this.loadWarnings = loadWarnings;
+	}
+	public void setLoadedPolicies(Set<PDPPolicy> loadedPolicies) {
+		this.loadedPolicies = loadedPolicies;
+	}
+	public void setFailedPolicies(Set<PDPPolicy> failedPolicies) {
+		this.failedPolicies = failedPolicies;
+	}
+	public void setInSynchPDPs(Set<PDP> inSynchPDPs) {
+		this.inSynchPDPs = inSynchPDPs;
+	}
+	public void setOutOfSynchPDPs(Set<PDP> outOfSynchPDPs) {
+		this.outOfSynchPDPs = outOfSynchPDPs;
+	}
+	public void setFailedPDPs(Set<PDP> failedPDPs) {
+		this.failedPDPs = failedPDPs;
+	}
+	public void setUpdatingPDPs(Set<PDP> updatingPDPs) {
+		this.updatingPDPs = updatingPDPs;
+	}
+	public void setLastUpdateFailedPDPs(Set<PDP> lastUpdateFailedPDPs) {
+		this.lastUpdateFailedPDPs = lastUpdateFailedPDPs;
+	}
+	
+
+	@Override
+	public Status getStatus() {
+		return status;
+	}
+
+	public void setStatus(Status status) {
+		this.status = status;
+	}
+
+	@Override
+	public Set<String> getLoadErrors() {
+		return Collections.unmodifiableSet(this.loadErrors);
+	}
+
+	public void addLoadError(String error) {
+		this.loadErrors.add(error);
+	}
+
+	@Override
+	public Set<String> getLoadWarnings() {
+		return Collections.unmodifiableSet(this.loadWarnings);
+	}
+
+	public void addLoadWarning(String warning) {
+		this.loadWarnings.add(warning);
+	}
+
+	@Override
+	public Set<PDPPolicy> getLoadedPolicies() {
+		return Collections.unmodifiableSet(this.loadedPolicies);
+	}
+	
+	public void addLoadedPolicy(PDPPolicy policy) {
+		this.loadedPolicies.add(policy);
+	}
+
+	@Override
+	public Set<PDPPolicy> getFailedPolicies() {
+		return Collections.unmodifiableSet(this.failedPolicies);
+	}
+	
+	public void addFailedPolicy(PDPPolicy policy) {
+		this.failedPolicies.add(policy);
+	}
+
+	@Override
+	public boolean policiesOK() {
+		if (this.failedPolicies.size() > 0) {
+			return false;
+		}
+		return true;
+	}
+
+	@Override
+	public Set<PDPPIPConfig> getLoadedPipConfigs() {
+		return Collections.unmodifiableSet(this.loadedPIPConfigs);
+	}
+	
+	public void addLoadedPipConfig(PDPPIPConfig config) {
+		this.loadedPIPConfigs.add(config);
+	}
+
+	@Override
+	public Set<PDPPIPConfig> getFailedPipConfigs() {
+		return Collections.unmodifiableSet(this.failedPIPConfigs);
+	}
+	
+	public void addFailedPipConfig(PDPPIPConfig config) {
+		this.failedPIPConfigs.add(config);
+	}
+
+	@Override
+	public boolean pipConfigOK() {
+		if (this.failedPIPConfigs.size() > 0) {
+			return false;
+		}
+		return true;
+	}
+
+	@Override
+	public Set<PDP> getInSynchPDPs() {
+		return Collections.unmodifiableSet(this.inSynchPDPs);
+	}
+
+	public void addInSynchPDP(PDP pdp) {
+		this.inSynchPDPs.add(pdp);
+	}
+
+	@Override
+	public Set<PDP> getOutOfSynchPDPs() {
+		return Collections.unmodifiableSet(this.outOfSynchPDPs);
+	}
+
+	public void addOutOfSynchPDP(PDP pdp) {
+		this.outOfSynchPDPs.add(pdp);
+	}
+
+	@Override
+	public Set<PDP> getFailedPDPs() {
+		return Collections.unmodifiableSet(this.failedPDPs);
+	}
+
+	public void addFailedPDP(PDP pdp) {
+		this.failedPDPs.add(pdp);
+	}
+
+	@Override
+	public Set<PDP> getUpdatingPDPs() {
+		return Collections.unmodifiableSet(this.updatingPDPs);
+	}
+
+	public void addUpdatingPDP(PDP pdp) {
+		this.updatingPDPs.add(pdp);
+	}
+
+	@Override
+	public Set<PDP> getLastUpdateFailedPDPs() {
+		return Collections.unmodifiableSet(this.lastUpdateFailedPDPs);
+	}
+
+	public void addLastUpdateFailedPDP(PDP pdp) {
+		this.lastUpdateFailedPDPs.add(pdp);
+	}
+
+	@Override
+	@JsonIgnore
+	public Set<PDP> getUnknownStatusPDPs() {
+		return Collections.unmodifiableSet(this.unknownPDPs);
+	}
+
+	public void addUnknownPDP(PDP pdp) {
+		this.unknownPDPs.add(pdp);
+	}
+
+	@Override
+	public boolean pdpsOK() {
+		if (this.outOfSynchPDPs.size() > 0) {
+			return false;
+		}
+		if (this.failedPDPs.size() > 0) {
+			return false;
+		}
+		if (this.lastUpdateFailedPDPs.size() > 0) {
+			return false;
+		}
+		if (this.unknownPDPs.size() > 0) {
+			return false;
+		}
+		return true;
+	}
+
+	@Override
+	@JsonIgnore
+	public boolean isGroupOk() {
+		if (this.policiesOK() == false) {
+			return false;
+		}
+		if (this.pipConfigOK() == false) {
+			return false;
+		}
+		if (this.pdpsOK() == false) {
+			return false;
+		}
+		if (this.loadErrors.isEmpty() == false) {
+			return false;
+		}
+		return (this.status == Status.OK);
+	}
+	
+	public void reset() {
+		this.status = Status.OK;
+		
+		this.loadErrors.clear();
+		this.loadWarnings.clear();
+		this.loadedPolicies.clear();
+		this.failedPolicies.clear();
+		this.loadedPIPConfigs.clear();
+		this.failedPIPConfigs.clear();
+		this.inSynchPDPs.clear();
+		this.outOfSynchPDPs.clear();
+		this.failedPDPs.clear();
+		this.updatingPDPs.clear();
+		this.lastUpdateFailedPDPs.clear();
+		this.unknownPDPs.clear();
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ (failedPDPs.hashCode());
+		result = prime
+				* result
+				+ (failedPIPConfigs.hashCode());
+		result = prime * result
+				+ (failedPolicies.hashCode());
+		result = prime * result
+				+ (inSynchPDPs.hashCode());
+		result = prime
+				* result
+				+ (lastUpdateFailedPDPs.hashCode());
+		result = prime * result
+				+ (loadErrors.hashCode());
+		result = prime * result
+				+ (loadWarnings.hashCode());
+		result = prime
+				* result
+				+ (loadedPIPConfigs.hashCode());
+		result = prime * result
+				+ (loadedPolicies.hashCode());
+		result = prime * result
+				+ (outOfSynchPDPs.hashCode());
+		result = prime * result + (status.hashCode());
+		result = prime * result
+				+ (unknownPDPs.hashCode());
+		result = prime * result
+				+ (updatingPDPs.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		StdPDPGroupStatus other = (StdPDPGroupStatus) obj;
+		if (!failedPDPs.equals(other.failedPDPs))
+			return false;
+		if (!failedPIPConfigs.equals(other.failedPIPConfigs))
+			return false;
+		if (!failedPolicies.equals(other.failedPolicies))
+			return false;
+		if (!inSynchPDPs.equals(other.inSynchPDPs))
+			return false;
+		if (!lastUpdateFailedPDPs.equals(other.lastUpdateFailedPDPs))
+			return false;
+		if (!loadErrors.equals(other.loadErrors))
+			return false;
+		if (!loadWarnings.equals(other.loadWarnings))
+			return false;
+		if (!loadedPIPConfigs.equals(other.loadedPIPConfigs))
+			return false;
+		if (!loadedPolicies.equals(other.loadedPolicies))
+			return false;
+		if (!outOfSynchPDPs.equals(other.outOfSynchPDPs))
+			return false;
+		if (status != other.status)
+			return false;
+		if (!unknownPDPs.equals(other.unknownPDPs))
+			return false;
+		if (!updatingPDPs.equals(other.updatingPDPs))
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "StdPDPGroupStatus [status=" + status + ", loadErrors="
+				+ loadErrors + ", loadWarnings=" + loadWarnings
+				+ ", loadedPolicies=" + loadedPolicies + ", failedPolicies="
+				+ failedPolicies + ", loadedPIPConfigs=" + loadedPIPConfigs
+				+ ", failedPIPConfigs=" + failedPIPConfigs + ", inSynchPDPs="
+				+ inSynchPDPs + ", outOfSynchPDPs=" + outOfSynchPDPs
+				+ ", failedPDPs=" + failedPDPs + ", updatingPDPs="
+				+ updatingPDPs + ", lastUpdateFailedPDPs="
+				+ lastUpdateFailedPDPs + ", unknownPDPs=" + unknownPDPs + "]";
+	}
+
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPItemSetChangeNotifier.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPItemSetChangeNotifier.java
new file mode 100644
index 0000000..38f8a58
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPItemSetChangeNotifier.java
@@ -0,0 +1,84 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.openecomp.policy.xacml.api.pap.EcompPDP;
+import org.openecomp.policy.xacml.api.pap.EcompPDPGroup;
+
+import com.att.research.xacml.api.pap.PDP;
+import com.att.research.xacml.api.pap.PDPGroup;
+
+public class StdPDPItemSetChangeNotifier {
+	
+	private Collection<StdItemSetChangeListener> listeners = null;
+	
+	public interface StdItemSetChangeListener {
+		
+		public void changed();
+		
+		public void groupChanged(EcompPDPGroup group);
+		
+		public void pdpChanged(EcompPDP pdp);
+
+	}
+	
+	public void addItemSetChangeListener(StdItemSetChangeListener listener) {
+		if (this.listeners == null) {
+			this.listeners = new LinkedList<StdItemSetChangeListener>();
+		}
+		this.listeners.add(listener);
+	}
+	
+	public void removeItemSetChangeListener(StdItemSetChangeListener listener) {
+		if (this.listeners != null) {
+			this.listeners.remove(listener);
+		}
+	}
+
+	public void fireChanged() {
+		if (this.listeners == null) {
+			return;
+		}
+		for (StdItemSetChangeListener l : this.listeners) {
+			l.changed();
+		}		
+	}
+
+	public void firePDPGroupChanged(EcompPDPGroup group) {
+		if (this.listeners == null) {
+			return;
+		}
+		for (StdItemSetChangeListener l : this.listeners) {
+			l.groupChanged(group);
+		}
+	}
+
+	public void firePDPChanged(EcompPDP pdp) {
+		if (this.listeners == null) {
+			return;
+		}
+		for (StdItemSetChangeListener l : this.listeners) {
+			l.pdpChanged(pdp);
+		}
+	}
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPPIPConfig.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPPIPConfig.java
new file mode 100644
index 0000000..814dbe3
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPPIPConfig.java
@@ -0,0 +1,217 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import com.att.research.xacml.api.pap.PDPPIPConfig;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger; 
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+
+public class StdPDPPIPConfig implements PDPPIPConfig, Serializable {
+	private static final long serialVersionUID = 1L;
+	private static Logger	logger	= FlexLogger.getLogger(StdPDPPIPConfig.class);
+	
+	private String id;
+	
+	private String name;
+	
+	private String description;
+	
+	private String classname;
+	
+	private Map<String,String> config = new HashMap<String, String>();
+	
+	public StdPDPPIPConfig() {
+		
+	}
+
+	public StdPDPPIPConfig(String id) {
+		this.id = id;
+	}
+	
+	public StdPDPPIPConfig(String id, String name, String description) {
+		this(id);
+		this.name = name;
+		this.description = description;
+	}
+
+	public StdPDPPIPConfig(String id, Properties properties) {
+		this(id);
+		if ( ! this.initialize(properties) ) {
+			throw new IllegalArgumentException("PIP Engine '" + id + "' has no classname property in config");
+		}
+	}
+	
+	public boolean initialize(Properties properties) {
+		boolean classnameSeen = false;
+		for (Object key : properties.keySet()) {
+			if (key.toString().startsWith(this.id + ".")) {
+				if (logger.isDebugEnabled()) {
+					logger.debug("Found: " + key);
+				}
+				if (key.toString().equals(this.id + ".name")) {
+					this.name = properties.getProperty(key.toString());
+				} else if (key.toString().equals(this.id + ".description")) {
+					this.description = properties.getProperty(key.toString());
+				} else if (key.toString().equals(this.id + ".classname")) {
+					this.classname = properties.getProperty(key.toString());
+					classnameSeen = true;
+				}
+				// all properties, including the special ones located above, are included in the properties list
+				this.config.put(key.toString(), properties.getProperty(key.toString()));
+			}
+		}
+		return classnameSeen;
+	}
+
+	@Override
+	public String getId() {
+		return this.id;
+	}
+	
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	@Override
+	public String getDescription() {
+		return this.description;
+	}
+	
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	@Override
+	public String getClassname() {
+		return classname;
+	}
+
+	public void setClassname(String classname) {
+		this.classname = classname;
+	}
+
+	@Override
+	@JsonIgnore
+	public Map<String,String> getConfiguration() {
+		return Collections.unmodifiableMap(this.config);
+	}
+
+	public void setValues(Map<String,String> config) {
+		this.config = config;
+	}
+
+	@Override
+	@JsonIgnore
+	public boolean isConfigured() {
+		//
+		// TODO
+		// Also include this in the JSON I/O if it is a data field rather than calculated
+		//
+		return true;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((classname == null) ? 0 : classname.hashCode());
+		result = prime * result + ((config == null) ? 0 : config.hashCode());
+		result = prime * result
+				+ ((description == null) ? 0 : description.hashCode());
+		result = prime * result + ((id == null) ? 0 : id.hashCode());
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		StdPDPPIPConfig other = (StdPDPPIPConfig) obj;
+		if (classname == null) {
+			if (other.classname != null)
+				return false;
+		} else if (!classname.equals(other.classname))
+			return false;
+		if (config == null) {
+			if (other.config != null)
+				return false;
+		} else if (!config.equals(other.config))
+			return false;
+		if (description == null) {
+			if (other.description != null)
+				return false;
+		} else if (!description.equals(other.description))
+			return false;
+		if (id == null) {
+			if (other.id != null)
+				return false;
+		} else if (!id.equals(other.id))
+			return false;
+		if (name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!name.equals(other.name))
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "StdPDPPIPConfig [id=" + id + ", name=" + name
+				+ ", description=" + description + ", classname=" + classname
+				+ ", config=" + config + "]";
+	}
+
+	
+	
+	//
+	// Methods needed for JSON serialization/deserialization
+	//
+
+	public Map<String, String> getConfig() {
+		return config;
+	}
+	public void setConfig(Map<String, String> config) {
+		this.config = config;
+	}
+	
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPPolicy.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPPolicy.java
new file mode 100644
index 0000000..06c2498
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPPolicy.java
@@ -0,0 +1,368 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import org.openecomp.policy.common.logging.eelf.PolicyLogger;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Properties;
+
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openecomp.policy.xacml.util.XACMLPolicyScanner;
+
+import com.att.research.xacml.api.pap.PAPException;
+import com.att.research.xacml.api.pap.PDPPolicy;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+
+
+public class StdPDPPolicy implements PDPPolicy, Serializable {
+	private static final long serialVersionUID = 1L;
+	private static Log	logger	= LogFactory.getLog(StdPDPPolicy.class);
+	
+	private String id = null;
+	
+	private String name = null;
+
+	private String policyId = null;
+	
+	private String description = null;
+	
+	private int[]	version = null;
+
+	private boolean isRoot = false;
+	
+	private boolean isValid = false;
+	
+	private URI location = null;
+	
+
+	public StdPDPPolicy(String id, boolean isRoot) {
+		this.id = id;
+		this.isRoot = isRoot;
+	}
+
+	public StdPDPPolicy(String id, boolean isRoot, String name) {
+		this(id, isRoot);
+		this.name = name;
+	}
+
+	
+	public StdPDPPolicy(String id, boolean isRoot, String name, URI location) throws IOException {
+		this(id, isRoot);
+		this.name = name;
+		this.location = location;
+		
+		//
+		// Read the policy data
+		//		
+		String theID = this.readPolicyData();
+
+		if (this.id == null) {
+			logger.debug("id is null so we are calling readPolicyData() to get the policyID");
+			this.id = theID;
+		}
+		
+		logger.debug("The final outcome of the constructor returned the following:  id = " + id + 
+						", location = " + location + ", name = " + name);
+		
+	}
+	
+	public StdPDPPolicy(String id, boolean isRoot, String name, URI location, boolean isValid, String policyId, 
+							String description, String version) throws IOException {
+		this(id, isRoot);
+		this.name = name;
+		this.location = location;
+		this.policyId = policyId;
+		this.description = description;
+		this.version = versionStringToArray(version);
+		this.isValid = isValid;
+		
+		logger.debug("The final outcome of the constructor returned the following:  id = " + id + 
+						", location = " + location + ", name = " + name + ", policyId = " + policyId +
+							", description = " + description + ", Version = " + version);
+		
+	}
+	
+	public StdPDPPolicy(String id, boolean isRoot, String name, URI location, boolean isFromAPI) throws IOException {
+		this(id, isRoot);
+		this.name = name;
+		this.location = location;
+		this.isValid = isFromAPI;
+		
+		logger.debug("The final outcome of the constructor returned the following:  id = " + id + 
+						", location = " + location + ", name = " + name);
+		
+	}
+
+	public StdPDPPolicy(String id, boolean isRoot, URI location, Properties properties) throws IOException {
+		this(id, isRoot);
+		this.location = location;
+		//
+		// Read the policy data
+		//
+		this.readPolicyData();
+		//
+		// See if there's a name
+		//
+		for (Object key : properties.keySet()) {
+			if (key.toString().equals(id + ".name")) {
+				this.name = properties.getProperty(key.toString());
+				break;
+			}
+		}
+	}
+	
+	
+	private String readPolicyData() throws IOException {
+		//
+		// Extract XACML policy information
+		//
+		URL url = this.location.toURL();
+		Object rootElement = XACMLPolicyScanner.readPolicy(url.openStream());
+		if (rootElement == null ||
+			(
+				! (rootElement instanceof PolicySetType) &&
+				! (rootElement instanceof PolicyType)
+			)	) {
+			logger.warn("No root policy element in URI: " + this.location.toString() + " : " + rootElement);
+			this.isValid = false;
+		} else {
+			this.version = versionStringToArray(XACMLPolicyScanner.getVersion(rootElement));
+			if (rootElement instanceof PolicySetType) {
+				this.policyId = ((PolicySetType)rootElement).getPolicySetId();
+				this.description = ((PolicySetType)rootElement).getDescription();
+				this.isValid = true;
+				this.version = versionStringToArray(((PolicySetType)rootElement).getVersion());
+			} else if (rootElement instanceof PolicyType) {
+				this.policyId = ((PolicyType)rootElement).getPolicyId();
+				this.description = ((PolicyType)rootElement).getDescription();
+				this.version = versionStringToArray(((PolicyType)rootElement).getVersion());
+				this.isValid = true;
+			} else {
+				//TODO:EELF Cleanup - Remove logger
+				//logger.error("Unknown root element: " + rootElement.getClass().getCanonicalName());
+				PolicyLogger.error("Unknown root element: " + rootElement.getClass().getCanonicalName());
+			}
+		}
+		if (this.policyId != null) {
+			ArrayList<String> foo = Lists.newArrayList(Splitter.on(':').split(this.policyId));
+			if (foo.isEmpty() == false) {
+				return foo.get(foo.size() - 1);
+			}
+		}
+		return null;
+	}
+	
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	@Override
+	public String getName() {
+		return this.name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	@Override
+	public String getPolicyId() {
+		return this.policyId;
+	}
+	
+	@Override
+	public String getDescription() {
+		return this.description;
+	}
+	
+	@Override
+	public String getVersion() {
+		return versionArrayToString(this.version);
+	}
+	
+	@Override
+	@JsonIgnore
+	public int[] getVersionInts() {
+		return version;
+	}
+
+	@Override
+	public boolean isRoot() {
+		return this.isRoot;
+	}
+
+	@Override
+	public boolean isValid()
+	{
+		return this.isValid;
+	}
+
+	@Override
+	@JsonIgnore
+	public InputStream getStream() throws PAPException, IOException {
+		try {
+			if (this.location != null) {
+				URL url = this.location.toURL();
+				return url.openStream();
+			}
+			return null;
+		} catch (FileNotFoundException e) {
+			throw new PAPException(e);
+		}
+	}
+
+	@Override
+	public URI getLocation() throws PAPException {
+		return this.location;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((id == null) ? 0 : id.hashCode());
+		result = prime * result
+				+ ((policyId == null) ? 0 : policyId.hashCode());
+		result = prime * result;
+		if (version != null) {
+			for (int i = 0; i < version.length; i++) {
+				result += version[i];
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		StdPDPPolicy other = (StdPDPPolicy) obj;
+		if (id == null) {
+			if (other.id != null)
+				return false;
+		} else if (!id.equals(other.id))
+			return false;
+		if (policyId == null) {
+			if (other.policyId != null)
+				return false;
+		} else if (!policyId.equals(other.policyId))
+			return false;
+		if (version != other.version)
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "StdPDPPolicy [id=" + id + ", name=" + name + ", policyId="
+				+ policyId + ", description=" + description + ", version="
+				+ this.getVersion() + ", isRoot=" + isRoot + ", isValid=" + isValid
+				+ ", location=" + location + "]";
+	}
+	
+	
+	/**
+	 * Given a version string consisting of integers with dots between them, convert it into an array of ints.
+	 * 
+	 * @param version
+	 * @return
+	 * @throws NumberFormatException
+	 */
+	public static int[] versionStringToArray(String version) throws NumberFormatException {
+		if (version == null || version.length() == 0) {
+			return new int[0];
+		}
+		String[] stringArray = version.split("\\.");
+		int[] resultArray = new int[stringArray.length];
+		for (int i = 0; i < stringArray.length; i++) {
+			resultArray[i] = Integer.parseInt(stringArray[i]);
+		}
+		return resultArray;
+	}
+	
+	/**
+	 * Given an array representing a version, create the corresponding dot-separated string.
+	 * 
+	 * @param array
+	 * @return
+	 */
+	public static String versionArrayToString(int[] array) {
+		if (array == null || array.length == 0) {
+			return "";
+		}
+		String versionString = "";
+		if (array.length > 0) {
+			versionString = "" + array[0];
+			for (int i = 1; i < array.length; i++) {
+				versionString += "." + array[i];
+			}
+		}
+		return versionString;
+	}
+	
+
+	
+	//
+	// Methods needed for JSON Deserialization
+	//
+	public StdPDPPolicy() {}
+	
+	public void setPolicyId(String policyId) {
+		this.policyId = policyId;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public void setVersion(String version) {
+		this.version = versionStringToArray(version);
+	}
+	public void setRoot(boolean isRoot) {
+		this.isRoot = isRoot;
+	}
+	public void setValid(boolean isValid) {
+		this.isValid = isValid;
+	}
+	public void setLocation(URI location) {
+		this.location = location;
+	}
+	
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPStatus.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPStatus.java
new file mode 100644
index 0000000..dc29765
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdPDPStatus.java
@@ -0,0 +1,265 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pap;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.att.research.xacml.api.pap.PDPPIPConfig;
+import com.att.research.xacml.api.pap.PDPPolicy;
+import com.att.research.xacml.api.pap.PDPStatus;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+public class StdPDPStatus implements Serializable, PDPStatus {
+	private static final long serialVersionUID = 1L;
+	
+	private Status status = Status.UNKNOWN;
+
+	private Set<String>	loadErrors = new HashSet<String>();
+	
+	private Set<String> loadWarnings = new HashSet<String>();
+	
+	private Set<PDPPolicy> loadedPolicies = new HashSet<PDPPolicy>();
+	
+	private Set<PDPPolicy> loadedRootPolicies = new HashSet<PDPPolicy>();
+	
+	private Set<PDPPolicy> failedPolicies = new HashSet<PDPPolicy>();
+	
+	private Set<PDPPIPConfig>	loadedPIPConfigs = new HashSet<PDPPIPConfig>();
+	
+	private Set<PDPPIPConfig>	failedPIPConfigs = new HashSet<PDPPIPConfig>();
+	
+	public StdPDPStatus() {
+	}
+
+	public void set(StdPDPStatus newStatus) {
+		this.status				=	newStatus.status;
+		this.loadErrors.clear();
+		this.loadErrors.addAll(newStatus.getLoadErrors());
+		this.loadWarnings.clear();
+		this.loadWarnings.addAll(newStatus.getLoadWarnings());
+		this.loadedPolicies.clear();
+		this.loadedPolicies.addAll(newStatus.getLoadedPolicies());
+		this.loadedRootPolicies.clear();
+		this.loadedRootPolicies.addAll(newStatus.getLoadedRootPolicies());
+		this.failedPolicies.clear();
+		this.failedPolicies.addAll(newStatus.getFailedPolicies());
+		this.loadedPIPConfigs.clear();
+		this.loadedPIPConfigs.addAll(newStatus.getLoadedPipConfigs());
+		this.failedPIPConfigs.clear();
+		this.failedPIPConfigs.addAll(newStatus.getFailedPipConfigs());
+	}
+	
+	
+
+	@Override
+	public Status getStatus() {
+		return this.status;
+	}
+	
+	public void setStatus(Status status) {
+		this.status = status;
+	}
+	
+	@Override
+	public Set<String> getLoadErrors() {
+		return Collections.unmodifiableSet(this.loadErrors);
+	}
+
+	public void setLoadErrors(Set<String> errors) {
+		this.loadErrors = errors;
+	}
+	
+	public void addLoadError(String error) {
+		this.loadErrors.add(error);
+	}
+
+	@Override
+	public Set<String> getLoadWarnings() {
+		return Collections.unmodifiableSet(this.loadWarnings);
+	}
+
+	public void setLoadWarnings(Set<String> warnings) {
+		this.loadWarnings = warnings;
+	}
+	
+	public void addLoadWarning(String warning) {
+		this.loadWarnings.add(warning);
+	}
+
+	@Override
+	public Set<PDPPolicy> getLoadedPolicies() {
+		return Collections.unmodifiableSet(this.loadedPolicies);
+	}
+	
+	public void setLoadedPolicies(Set<PDPPolicy> policies) {
+		this.loadedPolicies = policies;
+	}
+	
+	public void addLoadedPolicy(PDPPolicy policy) {
+		this.loadedPolicies.add(policy);
+	}
+	
+	@Override
+	public Set<PDPPolicy> getLoadedRootPolicies() {
+		return Collections.unmodifiableSet(this.loadedRootPolicies);
+	}
+	
+	public void setLoadedRootPolicies(Set<PDPPolicy> policies) {
+		this.loadedRootPolicies = policies;
+	}
+	
+	public void addRootPolicy(PDPPolicy policy) {
+		this.loadedRootPolicies.add(policy);
+	}
+	
+	public void addAllLoadedRootPolicies(Set<PDPPolicy> policies) {
+		this.loadedRootPolicies.addAll(policies);
+	}
+	
+	@Override
+	public Set<PDPPolicy> getFailedPolicies() {
+		return Collections.unmodifiableSet(this.failedPolicies);
+	}
+	
+	public void	setFailedPolicies(Set<PDPPolicy> policies) {
+		this.failedPolicies = policies;
+	}
+	
+	public void addFailedPolicy(PDPPolicy policy) {
+		this.failedPolicies.add(policy);
+	}
+
+	@Override
+	public boolean policiesOK() {
+		if (this.failedPolicies.size() > 0) {
+			return false;
+		}
+		return true;
+	}
+
+	@Override
+	public Set<PDPPIPConfig> getLoadedPipConfigs() {
+		return Collections.unmodifiableSet(this.loadedPIPConfigs);
+	}
+	
+	public void setLoadedPipConfigs(Set<PDPPIPConfig> configs) {
+		this.loadedPIPConfigs = configs;
+	}
+	
+	public void addLoadedPipConfig(PDPPIPConfig config) {
+		this.loadedPIPConfigs.add(config);
+	}
+
+	@Override
+	public Set<PDPPIPConfig> getFailedPipConfigs() {
+		return Collections.unmodifiableSet(this.failedPIPConfigs);
+	}
+
+	public void setFailedPipConfigs(Set<PDPPIPConfig> configs) {
+		this.failedPIPConfigs = configs;
+	}
+	
+	public void addFailedPipConfig(PDPPIPConfig config) {
+		this.failedPIPConfigs.add(config);
+	}
+
+	@Override
+	public boolean pipConfigOK() {
+		if (this.failedPIPConfigs.size() > 0) {
+			return false;
+		}
+		return true;
+	}
+
+	@Override
+	@JsonIgnore
+	public boolean isOk() {
+		if (this.policiesOK() == false) {
+			return false;
+		}
+		if (this.pipConfigOK() == false) {
+			return false;
+		}
+		return (this.status == Status.UP_TO_DATE);
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime
+				* result
+				+ (failedPIPConfigs.hashCode());
+		result = prime * result
+				+ (failedPolicies.hashCode());
+		result = prime * result
+				+ (loadErrors.hashCode());
+		result = prime * result
+				+ (loadWarnings.hashCode());
+		result = prime
+				* result
+				+ (loadedPIPConfigs.hashCode());
+		result = prime * result
+				+ (loadedPolicies.hashCode());
+		result = prime * result + (status.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		StdPDPStatus other = (StdPDPStatus) obj;
+		if (!failedPIPConfigs.equals(other.failedPIPConfigs))
+			return false;
+		if (!failedPolicies.equals(other.failedPolicies))
+			return false;
+		if (!loadErrors.equals(other.loadErrors))
+			return false;
+		if (!loadWarnings.equals(other.loadWarnings))
+			return false;
+		if (!loadedPIPConfigs.equals(other.loadedPIPConfigs))
+			return false;
+		if (!loadedPolicies.equals(other.loadedPolicies))
+			return false;
+		if (status != other.status)
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "StdPDPStatus [status=" + status + ", loadErrors=" + loadErrors
+				+ ", loadWarnings=" + loadWarnings + ", loadedPolicies="
+				+ loadedPolicies + ", loadedRootPolicies=" + loadedRootPolicies 
+				+ ", failedPolicies=" + failedPolicies
+				+ ", loadedPIPConfigs=" + loadedPIPConfigs
+				+ ", failedPIPConfigs=" + failedPIPConfigs + "]";
+	}
+
+
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pip/engines/aaf/AAFEngine.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pip/engines/aaf/AAFEngine.java
new file mode 100644
index 0000000..6dea4c2
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pip/engines/aaf/AAFEngine.java
@@ -0,0 +1,276 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.std.pip.engines.aaf;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openecomp.policy.utils.AAFPolicyClient;
+import org.openecomp.policy.utils.AAFPolicyException;
+
+import com.att.research.xacml.api.Attribute;
+import com.att.research.xacml.api.AttributeValue;
+import com.att.research.xacml.api.Identifier;
+import com.att.research.xacml.api.XACML3;
+import com.att.research.xacml.api.pip.PIPException;
+import com.att.research.xacml.api.pip.PIPFinder;
+import com.att.research.xacml.api.pip.PIPRequest;
+import com.att.research.xacml.api.pip.PIPResponse;
+import com.att.research.xacml.std.IdentifierImpl;
+import com.att.research.xacml.std.StdMutableAttribute;
+import com.att.research.xacml.std.datatypes.DataTypes;
+import com.att.research.xacml.std.pip.StdMutablePIPResponse;
+import com.att.research.xacml.std.pip.StdPIPRequest;
+import com.att.research.xacml.std.pip.StdPIPResponse;
+import com.att.research.xacml.std.pip.engines.StdConfigurableEngine;
+
+/**
+ * PIP Engine for Implementing {@link com.att.research.xacml.std.pip.engines.ConfigurableEngine} interface to provide
+ * attribute retrieval from AT&T AAF interface.  
+ * 
+ * @version $Revision$
+ */
+public class AAFEngine extends StdConfigurableEngine {
+	
+	public static final String DEFAULT_DESCRIPTION		= "PIP for authenticating aaf attributes using the AT&T AAF REST interface";
+	public static final String DEFAULT_ISSUER			= "att-aaf";
+	
+	private static final String SUCCESS = "Success";
+	
+	public static final String AAF_RESULT= "AAF_RESULT";
+	public static final String AAF_RESPONSE= "AAF_RESPONSE";
+	// 
+	public static final Identifier AAF_RESPONSE_ID = new IdentifierImpl(AAF_RESPONSE);
+	public static final Identifier AAF_RESULT_ID = new IdentifierImpl(AAF_RESULT);
+	
+	//
+	private static final PIPRequest PIP_REQUEST_UID = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, new IdentifierImpl("AAF_ID"), XACML3.ID_DATATYPE_STRING);
+	private static final PIPRequest PIP_REQUEST_PASS =  new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, new IdentifierImpl("AAF_PASS"), XACML3.ID_DATATYPE_STRING);
+	private static final PIPRequest PIP_REQUEST_TYPE = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, new IdentifierImpl("AAF_TYPE"), XACML3.ID_DATATYPE_STRING);
+	private static final PIPRequest PIP_REQUEST_INSTANCE = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, new IdentifierImpl("AAF_INSTANCE"), XACML3.ID_DATATYPE_STRING);
+	private static final PIPRequest PIP_REQUEST_ACTION = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, new IdentifierImpl("AAF_ACTION"), XACML3.ID_DATATYPE_STRING);
+	private static final PIPRequest PIP_REQUEST_ENV = new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, new IdentifierImpl("AAF_ENVIRONMENT"), XACML3.ID_DATATYPE_STRING);
+	
+	private static final List<PIPRequest> mapRequiredAttributes	= new ArrayList<PIPRequest>();
+	static{ 
+		mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_UID));
+		mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_PASS));
+		mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_TYPE));
+		mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_INSTANCE));
+		mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_ACTION));
+		mapRequiredAttributes.add(new StdPIPRequest(PIP_REQUEST_ENV));
+	}
+	
+	private static final Map<PIPRequest, String> mapSupportedAttributes	= new HashMap<PIPRequest, String>();
+	static{
+		mapSupportedAttributes.put(new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, AAF_RESPONSE_ID, XACML3.ID_DATATYPE_STRING), "response");
+		mapSupportedAttributes.put(new StdPIPRequest(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, AAF_RESULT_ID, XACML3.ID_DATATYPE_BOOLEAN), "result");
+	}
+	
+	protected Log logger	= LogFactory.getLog(this.getClass());
+	
+	public AAFEngine(){
+	}
+	
+	private PIPResponse getAttribute(PIPRequest pipRequest, PIPFinder pipFinder) {
+		PIPResponse pipResponse	= null;
+		try {
+			pipResponse	= pipFinder.getMatchingAttributes(pipRequest, this);
+			if (pipResponse.getStatus() != null && !pipResponse.getStatus().isOk()) {
+				this.logger.warn("Error retrieving " + pipRequest.getAttributeId().stringValue() + ": " + pipResponse.getStatus().toString());
+				pipResponse	= null;
+			}
+			if (pipResponse.getAttributes().size() == 0) {
+				this.logger.warn("No value for " + pipRequest.getAttributeId().stringValue());
+				pipResponse	= null;
+			}
+		} catch (PIPException ex) {
+			this.logger.error("PIPException getting subject-id attribute: " + ex.getMessage(), ex);			
+		}
+		return pipResponse;
+	}
+	
+	private String getValue(PIPResponse pipResponse){
+		String result = null;
+		Collection<Attribute> listAttributes = pipResponse.getAttributes();
+		for(Attribute attribute: listAttributes){
+			Iterator<AttributeValue<String>> iterAttributeValues = attribute.findValues(DataTypes.DT_STRING);
+			if(iterAttributeValues!=null) {
+				while(iterAttributeValues.hasNext()){
+					result = iterAttributeValues.next().getValue();
+					break;
+				}
+			}
+		}
+		return result;
+	}
+	
+	private synchronized String getResult(PIPFinder pipFinder) {
+		PIPResponse pipResponseUID = this.getAttribute(PIP_REQUEST_UID, pipFinder);
+		PIPResponse pipResponsePass = this.getAttribute(PIP_REQUEST_PASS, pipFinder);
+		PIPResponse pipResponseType = this.getAttribute(PIP_REQUEST_TYPE, pipFinder);
+		PIPResponse pipResponseAction = this.getAttribute(PIP_REQUEST_ACTION, pipFinder);
+		PIPResponse pipResponseInstance = this.getAttribute(PIP_REQUEST_INSTANCE, pipFinder);
+		PIPResponse pipResponseEnv = this.getAttribute(PIP_REQUEST_ENV, pipFinder);
+		String response = null;
+		// Evaluate AAF if we have all the required values. 
+		if(pipResponseUID!=null && pipResponsePass!=null && pipResponseType != null && pipResponseAction!= null && pipResponseInstance!=null && pipResponseEnv!=null){
+			// Check the Environment. 
+			String environment = getValue(pipResponseEnv);
+			if(environment == null){
+				response = "Environment Value is not set. ";
+			}
+			String userName = getValue(pipResponseUID);
+			String pass = getValue(pipResponsePass);
+			AAFPolicyClient aafClient = null;
+			Properties properties = new Properties();
+			if(environment.equalsIgnoreCase("PROD")){
+				properties.setProperty("ENVIRONMENT", "PROD");
+			}else if(environment.equalsIgnoreCase("TEST")){
+				properties.setProperty("ENVIRONMENT", "TEST");
+			}else{
+				properties.setProperty("ENVIRONMENT", "DEVL");
+			}
+			logger.debug("environment : " + environment);
+			if(userName!=null && pass!=null){
+				try {
+					aafClient = AAFPolicyClient.getInstance(properties);
+				} catch (AAFPolicyException e) {
+					logger.error("AAF configuration failed. " + e.getMessage());
+				}
+				if(aafClient!=null){
+					if(aafClient.checkAuth(userName, pass)){
+						String type = getValue(pipResponseType);
+						String instance = getValue(pipResponseInstance);
+						String action = getValue(pipResponseAction);
+						if(aafClient.checkPerm(userName, pass, type, instance, action)){
+							response = SUCCESS + "Permissions Validated";
+						}else{
+							response = "No Permissions for "+userName+" to: "+type+", "+instance+", "+action; 
+						}
+					}else{
+						response = "Authentication Failed for the given Values";
+					}
+				}
+			}else{
+				response = "ID and Password are not given";
+			}
+			
+		}else{
+			response = "Insufficient Values to Evaluate AAF";
+		}
+		return response;
+	}
+	
+	private void addStringAttribute(StdMutablePIPResponse stdPIPResponse, Identifier category, Identifier attributeId, String value) {
+		if (value != null) {
+			AttributeValue<String> attributeValue	= null;
+			try {
+				attributeValue	= DataTypes.DT_STRING.createAttributeValue(value);
+			} catch (Exception ex) {
+				this.logger.error("Failed to convert " + value + " to an AttributeValue<String>", ex);
+			}
+			if (attributeValue != null) {
+				stdPIPResponse.addAttribute(new StdMutableAttribute(category, attributeId, attributeValue, this.getIssuer(), false));
+			}
+		}
+	}
+
+	private void addBooleanAttribute(StdMutablePIPResponse stdPIPResponse, Identifier category, Identifier attributeId, boolean value) {
+		AttributeValue<Boolean> attributeValue	= null;
+		try {
+			attributeValue	= DataTypes.DT_BOOLEAN.createAttributeValue(value);
+		} catch (Exception ex) {
+			this.logger.error("Failed to convert " + value + " to an AttributeValue<Boolean>", ex);
+		}
+		if (attributeValue != null) {
+			stdPIPResponse.addAttribute(new StdMutableAttribute(category, attributeId, attributeValue, this.getIssuer(), false));
+		}
+	}
+	
+	@Override
+	public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
+		/*
+		 * First check to see if the issuer is set and then match it
+		 */
+		String string;
+		if ((string = pipRequest.getIssuer()) != null) {
+			if (!string.equals(this.getIssuer())) {
+				this.logger.debug("Requested issuer '" + string + "' does not match " + (this.getIssuer() == null ? "null" : "'" + this.getIssuer() + "'"));
+				return StdPIPResponse.PIP_RESPONSE_EMPTY;
+			}
+		}
+		
+		/*
+		 * Drop the issuer and see if the request matches any of our supported queries
+		 */
+		PIPRequest pipRequestSupported	= (pipRequest.getIssuer() == null ? pipRequest : new StdPIPRequest(pipRequest.getCategory(), pipRequest.getAttributeId(), pipRequest.getDataTypeId()));
+		if (!mapSupportedAttributes.containsKey(pipRequestSupported)) {
+			this.logger.debug("Requested attribute '" + pipRequest.toString() + "' is not supported");
+			return StdPIPResponse.PIP_RESPONSE_EMPTY;
+		}
+		StdMutablePIPResponse stdPIPResponse = new StdMutablePIPResponse();
+		String response = this.getResult(pipFinder);
+		boolean result = false;
+		if(response.contains(SUCCESS)){
+			result = true;
+		}
+		this.addBooleanAttribute(stdPIPResponse, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, AAF_RESULT_ID, result);
+		this.addStringAttribute(stdPIPResponse, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, AAF_RESPONSE_ID, response);
+		return new StdPIPResponse(stdPIPResponse);
+	}
+
+	@Override
+	public void configure(String id, Properties properties) throws PIPException {
+		super.configure(id, properties);
+		if (this.getDescription() == null) {
+			this.setDescription(DEFAULT_DESCRIPTION);
+		}
+		if (this.getIssuer() == null) {
+			this.setIssuer(DEFAULT_ISSUER);
+		}
+	}
+	
+	@Override
+	public Collection<PIPRequest> attributesRequired() {
+		List<PIPRequest> attributes = new ArrayList<PIPRequest>();
+		for (PIPRequest attribute: mapRequiredAttributes) {
+			attributes.add(new StdPIPRequest(attribute));
+		}
+		return attributes;
+	}
+
+	@Override
+	public Collection<PIPRequest> attributesProvided() {
+		List<PIPRequest> attributes = new ArrayList<PIPRequest>();
+		for (PIPRequest attribute : mapSupportedAttributes.keySet()) {
+			attributes.add(new StdPIPRequest(attribute));
+		}
+		return attributes;
+	}
+	
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/MetricsUtil.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/MetricsUtil.java
new file mode 100644
index 0000000..45a51a1
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/MetricsUtil.java
@@ -0,0 +1,80 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.util;
+
+public class MetricsUtil {
+	
+	public static class AvgLatency {
+		private long cumLatency = 0;
+		private long count = 0;
+		
+		public void compute(long latency) {
+			cumLatency += latency;
+			count++;
+		}
+		
+		public long avg() {
+			if (count == 0)
+				return 0;
+			
+			return (cumLatency / count);
+		}
+		
+		public void reset() {
+			cumLatency = 0;
+			count = 0;
+		}
+	}
+
+	public static class MinLatency {
+		private long min = Long.MAX_VALUE;
+		
+		public synchronized void compute(long ts) {
+			if (ts < min)
+				min = ts;
+		}
+		
+		public long min() {
+			return min;
+		}
+		
+		public void reset() {
+			min = Long.MAX_VALUE;
+		}
+	}
+
+	public static class MaxLatency {
+		private long max = Long.MIN_VALUE;
+		
+		public synchronized void compute(long ts) {
+			if (ts > max)
+				max = ts;
+		}
+		
+		public long max() {
+			return max;
+		}
+		
+		public void reset() {
+			max = Long.MIN_VALUE;
+		}
+	}
+
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/XACMLPolicyScanner.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/XACMLPolicyScanner.java
new file mode 100644
index 0000000..7fa2aa4
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/XACMLPolicyScanner.java
@@ -0,0 +1,727 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.eelf.PolicyLogger;
+
+import com.att.research.xacml.api.AttributeAssignment;
+import com.att.research.xacml.std.IdentifierImpl;
+import com.att.research.xacml.std.StdAttribute;
+import com.att.research.xacml.std.StdAttributeAssignment;
+import com.att.research.xacml.std.StdAttributeValue;
+import com.att.research.xacml.std.StdMutableAdvice;
+import com.att.research.xacml.std.StdMutableObligation;
+import com.att.research.xacml.util.XACMLPolicyScanner.Callback;
+import com.att.research.xacml.util.XACMLPolicyScanner.CallbackResult;
+
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeSelectorType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.IdReferenceType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableDefinitionType;
+
+/**
+ * class XACMLPolicyScanner
+ * 
+ * This class traverses the hierarchy of a XACML 3.0 policy. You can optionally pass a Callback class
+ * and override any desired methods to retrieve information from a policy. 
+ * 
+ *
+ */
+public class XACMLPolicyScanner {
+	
+	private static final Log logger				= LogFactory.getLog(XACMLPolicyScanner.class);
+	private Object policyObject = null;
+	private Callback callback = null;
+	
+	public XACMLPolicyScanner(Path filename, Callback callback) {
+		try (InputStream is = Files.newInputStream(filename)) {
+			this.policyObject = XACMLPolicyScanner.readPolicy(is);
+		} catch (IOException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to read policy", e);
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyScanner", "Failed to read policy");
+		}
+		this.callback = callback;
+	}
+	
+	public XACMLPolicyScanner(PolicySetType policySet, Callback callback) {
+		this.policyObject = policySet;
+		this.callback = callback;
+	}
+	
+	public XACMLPolicyScanner(PolicySetType policySet) {
+		this(policySet, null);
+	}
+	
+	public XACMLPolicyScanner(PolicyType policy, Callback callback) {
+		this.policyObject = policy;
+		this.callback = callback;
+	}
+	
+	public XACMLPolicyScanner(PolicyType policy) {
+		this(policy, null);
+	}
+	
+	/**
+	 * Sets the callback interface to be used.
+	 * 
+	 * @param cb
+	 */
+	public void setCallback(Callback cb) {
+		this.callback = cb;
+	}
+	
+	/**
+	 * Saves the given callback object then calls the scan() method.
+	 * 
+	 * @param cb
+	 * @return
+	 */
+	public Object scan(Callback cb) {
+		this.callback = cb;
+		return this.scan();
+	}
+	
+	/**
+	 * 
+	 * This begins the scanning of the contained object.
+	 * 
+	 * @return - The PolicySet/Policy that was scanned.
+	 */
+	public Object scan() {
+		if (this.policyObject == null) {
+			return null;
+		}
+		if (this.callback != null) {
+			if (this.callback.onBeginScan(this.policyObject) == CallbackResult.STOP) {
+				return this.policyObject;
+			}
+		}
+		if (this.policyObject instanceof PolicyType) {
+			this.scanPolicy(null, (PolicyType) this.policyObject);
+		} else if (this.policyObject instanceof PolicySetType) {
+			this.scanPolicySet(null, (PolicySetType) this.policyObject);
+		} else {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Unknown class type: " + this.policyObject.getClass().getCanonicalName());
+			PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW + "Unknown class type: " + this.policyObject.getClass().getCanonicalName());
+		}
+		if (this.callback != null) {
+			this.callback.onFinishScan(this.policyObject);
+		}
+		return this.policyObject;
+	}
+	
+	/**
+	 * This performs the scan of a PolicySet
+	 * 
+	 * @param parent - Its parent PolicySet. Can be null if this is the root.
+	 * @param policySet - The PolicySet object.
+	 * @return CallbackResult - CONTINUE to continue, STOP to terminate scanning.
+	 */
+	/**
+	 * @param parent
+	 * @param policySet
+	 * @return
+	 */
+	protected CallbackResult scanPolicySet(PolicySetType parent, PolicySetType policySet) {
+		if (logger.isTraceEnabled()) {
+			logger.trace("scanning policy set: " + policySet.getPolicySetId() + " " + policySet.getDescription());
+		}
+		if (this.callback != null) {
+			if (this.callback.onPreVisitPolicySet(parent, policySet) == CallbackResult.STOP) {
+				return CallbackResult.STOP;
+			}
+		}
+		//
+		// Scan its info
+		//
+		if (this.scanTarget(policySet, policySet.getTarget()) == CallbackResult.STOP) {
+			return CallbackResult.STOP;
+		}
+		if (this.scanObligations(policySet, policySet.getObligationExpressions()) == CallbackResult.STOP) {
+			return CallbackResult.STOP;
+		}
+		if (this.scanAdvice(policySet, policySet.getAdviceExpressions()) == CallbackResult.STOP) {
+			return CallbackResult.STOP;
+		}
+		//
+		// Iterate the policy sets and/or policies
+		//
+		List<JAXBElement<?>> list = policySet.getPolicySetOrPolicyOrPolicySetIdReference();
+		for (JAXBElement<?> element: list) {
+			if (element.getName().getLocalPart().equals("PolicySet")) {
+				if (this.scanPolicySet(policySet, (PolicySetType)element.getValue()) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+			} else if (element.getName().getLocalPart().equals("Policy")) {
+				if (this.scanPolicy(policySet, (PolicyType)element.getValue()) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+			} else if (element.getValue() instanceof IdReferenceType) {
+				if (element.getName().getLocalPart().equals("PolicySetIdReference")) {
+					
+				} else if (element.getName().getLocalPart().equals("PolicyIdReference")) {
+					
+				}
+			} else {
+				logger.warn("generating policy sets found unsupported element: " + element.getName().getNamespaceURI());
+			}
+		}
+		if (this.callback != null) {
+			if (this.callback.onPostVisitPolicySet(parent, policySet) == CallbackResult.STOP) {
+				return CallbackResult.STOP;
+			}
+		}
+		return CallbackResult.CONTINUE;
+	}
+	
+	/**
+	 * 
+	 * This performs scanning of the Policy object.
+	 * 
+	 * @param parent - The parent PolicySet of the policy. This can be null if this is a root Policy.
+	 * @param policy - The policy being scanned.
+	 * @return CallbackResult - CONTINUE to continue, STOP to terminate scanning.
+	 */
+	protected CallbackResult scanPolicy(PolicySetType parent, PolicyType policy) {
+		if (logger.isTraceEnabled()) {
+			logger.trace("scanning policy: " + policy.getPolicyId() + " " + policy.getDescription());
+		}
+		if (this.callback != null) {
+			if (this.callback.onPreVisitPolicy(parent, policy) == CallbackResult.STOP) {
+				return CallbackResult.STOP;
+			}
+		}
+		//
+		// Scan its info
+		//
+		if (this.scanTarget(policy, policy.getTarget()) == CallbackResult.STOP) {
+			return CallbackResult.STOP;
+		}
+		if (this.scanVariables(policy, policy.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition()) == CallbackResult.STOP) {
+			return CallbackResult.STOP;
+		}
+		if (this.scanObligations(policy, policy.getObligationExpressions()) == CallbackResult.STOP) {
+			return CallbackResult.STOP;
+		}
+		if (this.scanAdvice(policy, policy.getAdviceExpressions()) == CallbackResult.STOP) {
+			return CallbackResult.STOP;
+		}
+		//
+		// Iterate the rules
+		//
+		List<Object> list = policy.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition();
+		for (Object o: list) {
+			if (o instanceof RuleType) {
+				RuleType rule = (RuleType) o;
+				if (logger.isTraceEnabled()) {
+					logger.trace("scanning rule: " + rule.getRuleId() + " " + rule.getDescription());
+				}
+				if (this.callback != null) {
+					if (this.callback.onPreVisitRule(policy, rule) == CallbackResult.STOP) {
+						return CallbackResult.STOP;
+					}
+				}
+				if (this.scanTarget(rule, rule.getTarget()) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+				if (this.scanConditions(rule, rule.getCondition()) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+				if (this.scanObligations(rule, rule.getObligationExpressions()) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+				if (this.scanAdvice(rule, rule.getAdviceExpressions()) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+				if (this.callback != null) {
+					if (this.callback.onPostVisitRule(policy, rule) == CallbackResult.STOP) {
+						return CallbackResult.STOP;
+					}
+				}
+			} else if (o instanceof VariableDefinitionType) {
+				if (this.callback != null) {
+					if (this.callback.onVariable(policy, (VariableDefinitionType) o) == CallbackResult.STOP) {
+						return CallbackResult.STOP;
+					}
+				}
+			} else {
+				if (logger.isDebugEnabled()) {
+					logger.debug("scanning policy rules found unsupported object:" + o.toString());
+				}
+			}
+		}
+		if (this.callback != null) {
+			if (this.callback.onPostVisitPolicy(parent, policy) == CallbackResult.STOP) {
+				return CallbackResult.STOP;
+			}
+		}
+		return CallbackResult.CONTINUE;
+	}
+	
+	/**
+	 * Scans the given target for attributes. Its sole purpose is to return attributes found.
+	 * 
+	 * @param parent - The parent PolicySet/Policy/Rule for the target.
+	 * @param target - The target.
+	 * @return CallbackResult - CONTINUE to continue, STOP to terminate scanning.
+	 */
+	protected CallbackResult scanTarget(Object parent, TargetType target) {
+		if (target == null) {
+			return CallbackResult.CONTINUE;
+		}
+		List<AnyOfType> anyOfList = target.getAnyOf();
+		if (anyOfList != null) {
+			Iterator<AnyOfType> iterAnyOf = anyOfList.iterator();
+			while (iterAnyOf.hasNext()) {
+				AnyOfType anyOf = iterAnyOf.next();
+				List<AllOfType> allOfList = anyOf.getAllOf();
+				if (allOfList != null) {
+					Iterator<AllOfType> iterAllOf = allOfList.iterator();
+					while (iterAllOf.hasNext()) {
+						AllOfType allOf = iterAllOf.next();
+						List<MatchType> matchList = allOf.getMatch();
+						if (matchList != null) {
+							Iterator<MatchType> iterMatch = matchList.iterator();
+							while (iterMatch.hasNext()) {
+								MatchType match = iterMatch.next();
+								//
+								// Finally down to the actual attribute
+								//
+								StdAttribute attribute = null;
+								AttributeValueType value = match.getAttributeValue();
+								if (match.getAttributeDesignator() != null && value != null) {
+									AttributeDesignatorType designator = match.getAttributeDesignator();
+									//
+									// The content may be tricky
+									//
+									attribute = new StdAttribute(new IdentifierImpl(designator.getCategory()),
+																			new IdentifierImpl(designator.getAttributeId()),
+																			new StdAttributeValue<List<?>>(new IdentifierImpl(value.getDataType()), value.getContent()),
+																			designator.getIssuer(),
+																			false);
+								} else if (match.getAttributeSelector() != null && value != null) {
+									AttributeSelectorType selector = match.getAttributeSelector();
+									attribute = new StdAttribute(new IdentifierImpl(selector.getCategory()),
+																			new IdentifierImpl(selector.getContextSelectorId()),
+																			new StdAttributeValue<List<?>>(new IdentifierImpl(value.getDataType()), value.getContent()),
+																			null,
+																			false);
+								} else {
+									logger.warn("NULL designator/selector or value for match.");
+								}
+								if (attribute != null && this.callback != null) {
+									if (this.callback.onAttribute(parent, target, attribute) == CallbackResult.STOP) {
+										return CallbackResult.STOP;
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		return CallbackResult.CONTINUE;
+	}
+	
+	/**
+	 * Scan the list of obligations.
+	 * 
+	 * @param parent - The parent PolicySet/Policy/Rule for the obligation.
+	 * @param obligationExpressionsType - All the obligation expressions.
+	 * @return CallbackResult - CONTINUE to continue, STOP to terminate scanning.
+	 */
+	protected CallbackResult scanObligations(Object parent, ObligationExpressionsType obligationExpressionsType) {
+		if (obligationExpressionsType == null) {
+			return CallbackResult.CONTINUE;
+		}
+		List<ObligationExpressionType> expressions = obligationExpressionsType.getObligationExpression();
+		if (expressions == null || expressions.size() == 0) {
+			return CallbackResult.CONTINUE;
+		}
+		for (ObligationExpressionType expression : expressions) {
+			StdMutableObligation ob = new StdMutableObligation(new IdentifierImpl(expression.getObligationId()));
+			List<AttributeAssignmentExpressionType> assignments = expression.getAttributeAssignmentExpression();
+			if (assignments != null) {
+				for (AttributeAssignmentExpressionType assignment : assignments) {
+					// category is optional and may be null
+					IdentifierImpl categoryId = null;
+					if (assignment.getCategory() != null) {
+						categoryId = new IdentifierImpl(assignment.getCategory());
+					}
+					AttributeAssignment attribute = new StdAttributeAssignment(
+												categoryId,
+												new IdentifierImpl(assignment.getAttributeId()),
+												assignment.getIssuer(),
+												new StdAttributeValue<Object>(null, null)
+												);
+					ob.addAttributeAssignment(attribute);
+				}
+			}
+			if (this.callback != null) {
+				if (this.callback.onObligation(parent, expression, ob) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+			}
+		}
+		return CallbackResult.CONTINUE;
+	}
+
+	/**
+	 * 
+	 * Scans the list of advice expressions returning each individually.
+	 * 
+	 * @param parent - The parent PolicySet/Policy/Rule for the advice.
+	 * @param adviceExpressionstype - The list of advice expressions.
+	 * @return CallbackResult - CONTINUE to continue, STOP to terminate scanning.
+	 */
+	protected CallbackResult scanAdvice(Object parent, AdviceExpressionsType adviceExpressionstype) {
+		if (adviceExpressionstype == null) {
+			return CallbackResult.CONTINUE;
+		}
+		List<AdviceExpressionType> expressions = adviceExpressionstype.getAdviceExpression();
+		if (expressions == null || expressions.size() == 0) {
+			return CallbackResult.CONTINUE;
+		}
+		for (AdviceExpressionType expression : expressions) {
+			StdMutableAdvice ob = new StdMutableAdvice(new IdentifierImpl(expression.getAdviceId()));
+			List<AttributeAssignmentExpressionType> assignments = expression.getAttributeAssignmentExpression();
+			if (assignments != null) {
+				for (AttributeAssignmentExpressionType assignment : assignments) {
+					IdentifierImpl categoryId = null;
+					if (assignment.getCategory() != null) {
+						categoryId = new IdentifierImpl(assignment.getCategory());
+					}
+					AttributeAssignment attribute = new StdAttributeAssignment(
+												categoryId,
+												new IdentifierImpl(assignment.getAttributeId()),
+												assignment.getIssuer(),
+												new StdAttributeValue<Object>(null, null)
+												);
+					ob.addAttributeAssignment(attribute);
+				}
+			}
+			if (this.callback != null) {
+				if (this.callback.onAdvice(parent, expression, ob) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+			}
+		}
+		return CallbackResult.CONTINUE;
+	}
+	
+	/**
+	 * Scans the list of variable definitions.
+	 * 
+	 * @param policy - Policy object containing the variable definition.
+	 * @param list - List of variable definitions.
+	 * @return CallbackResult - CONTINUE to continue, STOP to terminate scanning.
+	 */
+	protected CallbackResult scanVariables(PolicyType policy, List<Object> list) {
+		if (list == null) {
+			return CallbackResult.CONTINUE;
+		}
+		for (Object o : list) {
+			if (o instanceof VariableDefinitionType) {
+				if (this.callback != null) {
+					if (this.callback.onVariable(policy, (VariableDefinitionType) o) == CallbackResult.STOP) {
+						return CallbackResult.STOP;
+					}
+				}
+			}
+		}
+		
+		return CallbackResult.CONTINUE;
+	}
+	
+	/**
+	 * Scans the list of conditions.
+	 * 
+	 * @param rule
+	 * @param condition
+	 * @return
+	 */
+	protected CallbackResult scanConditions(RuleType rule, ConditionType condition) {
+		if (condition != null) {
+			if (this.callback != null) {
+				if (this.callback.onCondition(rule, condition) == CallbackResult.STOP) {
+					return CallbackResult.STOP;
+				}
+			}
+		}
+		return CallbackResult.CONTINUE;
+	}
+	
+	/**
+	 * Reads the XACML XML policy file in and returns the version contained in the root Policy/PolicySet element.
+	 * 
+	 * @param policy - The policy file.
+	 * @return - The version string from the file (uninterpreted)
+	 * @throws IOException 
+	 */
+	public static String	getVersion(Path policy) throws IOException {
+		Object data = null;
+		try (InputStream is = Files.newInputStream(policy)) {
+			data = XACMLPolicyScanner.readPolicy(is);
+		} catch (IOException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to read policy", e);
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyScanner", "Failed to read policy");
+			throw e;
+		}
+		if (data == null) {
+			logger.warn("Version is null.");
+			return null;
+		}
+		return getVersion(data);
+	}
+		
+	/**
+	 * Reads the Policy/PolicySet element object and returns its current version.
+	 * 
+	 * @param data - Either a PolicySet or Policy XACML type object.
+	 * @return - The integer version value. -1 if it doesn't exist or was un-parsable.
+	 */
+	public static String	getVersion(Object data) {
+		String version = null;
+		try {
+			if (data instanceof PolicySetType) {
+				version = ((PolicySetType)data).getVersion();
+			} else if (data instanceof PolicyType) {
+				version = ((PolicyType)data).getVersion();
+			} else {
+				if (data != null) {
+					//TODO:EELF Cleanup - Remove logger
+					//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Expecting a PolicySet/Policy/Rule object. Got: " + data.getClass().getCanonicalName());
+					PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Expecting a PolicySet/Policy/Rule object. Got: " + data.getClass().getCanonicalName());
+				}
+				return null;
+			}
+			if (version != null && version.length() > 0) {
+				return version;
+			} else {
+				logger.warn("No version set in policy");
+			}
+		} catch (NumberFormatException e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Invalid version contained in policy: " + version);
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyScanner", "Invalid version contained in policy: " + version);
+			return null;
+		}
+		return null;
+	}
+	
+	/**
+	 * Returns the Policy or PolicySet ID.
+	 * 
+	 * @param data - A XACML 3.0 Policy or PolicySet element object.
+	 * @return The policy/policyset's policy ID
+	 */
+	public static String getID(Object data) {
+		if (data instanceof PolicySetType) {
+			return ((PolicySetType)data).getPolicySetId();
+		} else if (data instanceof PolicyType) {
+			return ((PolicyType)data).getPolicyId();
+		} else {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Expecting a PolicySet/Policy/Rule object. Got: " + data.getClass().getCanonicalName());
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Expecting a PolicySet/Policy/Rule object. Got: " + data.getClass().getCanonicalName());
+			return null;
+		}
+	}
+	
+	public static List<String> getCreatedByModifiedBy(Path policyPath) throws IOException{
+		String createdBy = "";
+		String modifiedBy= "";
+		String cValue = "@CreatedBy:";
+		String mValue = "@ModifiedBy:";
+		for(String line: Files.readAllLines(policyPath)){
+			line = line.replaceAll("\\s+", "");
+			if(line.isEmpty()){
+				continue;
+			}
+			if(line.contains("<Description>") && line.contains(cValue) && line.contains(mValue)){
+				createdBy = line.substring(line.indexOf(cValue) + cValue.length(), line.lastIndexOf(cValue));
+				modifiedBy = line.substring(line.indexOf(mValue) + mValue.length(), line.lastIndexOf(mValue));
+				break;
+			}
+		}
+		return Arrays.asList(createdBy, modifiedBy);
+	}
+	
+	//get the Created Name of the User on reading the Xml file
+	public static String getCreatedBy(Path policyPath) throws IOException{
+		String userId = "";
+		String value = "@CreatedBy:";
+		for(String line: Files.readAllLines(policyPath)){
+			line = line.replaceAll("\\s+", "");
+			if(line.isEmpty()){
+				continue;
+			}
+			if(line.contains("<Description>") && line.contains(value)){
+				userId = line.substring(line.indexOf(value) + value.length(), line.lastIndexOf(value));
+				break;
+			}
+		}
+		return userId;
+	}
+	
+	//get the Modified Name of the User on reading the Xml file
+	public static String getModifiedBy(Path policyPath) throws IOException{
+		String modifiedBy = "";
+		String value = "@ModifiedBy:";
+		for(String line: Files.readAllLines(policyPath)){
+			line = line.replaceAll("\\s+", "");
+			if(line.isEmpty()){
+				continue;
+			}
+			if(line.contains("<Description>") && line.contains(value)){
+				modifiedBy = line.substring(line.indexOf(value) + value.length(), line.lastIndexOf(value));
+				break;
+			}
+		}
+		return modifiedBy;
+	}
+
+	/**
+	 * readPolicy - does the work to read in policy data from a file.
+	 * 
+	 * @param policy - The path to the policy file.
+	 * @return - The policy data object. This *should* be either a PolicySet or a Policy.
+	 */
+	public static Object readPolicy(InputStream is) {
+		try {
+			//
+			// Create a DOM parser
+			//
+			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+		    dbf.setNamespaceAware(true);
+		    DocumentBuilder db = dbf.newDocumentBuilder();
+		    //
+		    // Parse the policy file
+		    //
+		    Document doc = db.parse(is);
+		    //
+		    // Because there is no root defined in xacml,
+		    // find the first element
+		    //
+			NodeList nodes = doc.getChildNodes();
+			Node node = nodes.item(0);
+			Element e = null;
+			if (node.getNodeType() == Node.ELEMENT_NODE) {
+				e = (Element) node;
+				//
+				// Is it a 3.0 policy?
+				//
+				if (e.getNamespaceURI().equals("urn:oasis:names:tc:xacml:3.0:core:schema:wd-17")) {
+					//
+					// A policyset or policy could be the root
+					//
+					if (e.getNodeName().endsWith("Policy")) {
+						//
+						// Now we can create the context for the policy set
+						// and unmarshall the policy into a class.
+						//
+						JAXBContext context = JAXBContext.newInstance(PolicyType.class);
+						Unmarshaller um = context.createUnmarshaller();
+						JAXBElement<PolicyType> root = um.unmarshal(e, PolicyType.class);
+						//
+						// Here is our policy set class
+						//
+						return root.getValue();
+					} else if (e.getNodeName().endsWith("PolicySet")) {
+						//
+						// Now we can create the context for the policy set
+						// and unmarshall the policy into a class.
+						//
+						JAXBContext context = JAXBContext.newInstance(PolicySetType.class);
+						Unmarshaller um = context.createUnmarshaller();
+						JAXBElement<PolicySetType> root = um.unmarshal(e, PolicySetType.class);
+						//
+						// Here is our policy set class
+						//
+						return root.getValue();
+					} else {
+						if (logger.isDebugEnabled()) {
+							logger.debug("Not supported yet: " + e.getNodeName());
+						}
+					}
+				} else {
+					logger.warn("unsupported namespace: " + e.getNamespaceURI());
+				}
+			} else {
+				if (logger.isDebugEnabled()) {
+					logger.debug("No root element contained in policy " + 
+								" Name: " + node.getNodeName() + " type: " + node.getNodeType() + 
+								" Value: " + node.getNodeValue());
+				}
+			}
+		} catch (Exception e) {
+			//TODO:EELF Cleanup - Remove logger
+			//logger.error(XACMLErrorConstants.ERROR_SCHEMA_INVALID + e.getMessage());
+			PolicyLogger.error(MessageCodes.ERROR_SCHEMA_INVALID, e, "XACMLPolicyScanner", "Exception in readPolicy");
+		}
+		return null;
+	}
+
+	/**
+	 * @return the policyObject
+	 */
+	public Object getPolicyObject() {
+		return policyObject;
+	}
+}
diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/XACMLPolicyWriter.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/XACMLPolicyWriter.java
new file mode 100644
index 0000000..3706bda
--- /dev/null
+++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/util/XACMLPolicyWriter.java
@@ -0,0 +1,344 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.policy.xacml.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.eelf.PolicyLogger;
+
+
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
+
+/**
+ * Helper static class for policy writing.
+ * 
+ *
+ */
+public class XACMLPolicyWriter {
+
+	/**
+	 * Helper static class that does the work to write a policy set to a file on disk.
+	 * 
+	 *
+	 */
+	public static Path writePolicyFile(Path filename, PolicySetType policySet) {
+		JAXBElement<PolicySetType> policySetElement = new ObjectFactory().createPolicySet(policySet);		
+		try {
+			JAXBContext context = JAXBContext.newInstance(PolicySetType.class);
+			Marshaller m = context.createMarshaller();
+			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+			m.marshal(policySetElement, filename.toFile());
+
+			if (Files.exists(filename)) {
+				return filename;
+			} else {
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "File does not exist after marshalling.");
+				return null;
+			}
+
+		} catch (JAXBException e) {
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyWriter", "writePolicyFile failed");
+			return null;
+		}
+	}
+
+	/**
+	 * Helper static class that does the work to write a policy set to an output stream.
+	 * 
+	 *
+	 */
+	public static void writePolicyFile(OutputStream os, PolicySetType policySet) {
+		JAXBElement<PolicySetType> policySetElement = new ObjectFactory().createPolicySet(policySet);
+		try {
+			JAXBContext context = JAXBContext.newInstance(PolicySetType.class);
+			Marshaller m = context.createMarshaller();
+			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+			m.marshal(policySetElement, os);
+		} catch (JAXBException e) {
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyWriter", "writePolicyFile failed");
+		}
+	}
+
+	/**
+	 * Helper static class that does the work to write a policy to a file on disk.
+	 * 
+	 *
+	 */
+	public static Path writePolicyFile(Path filename, PolicyType policy) {
+		JAXBElement<PolicyType> policyElement = new ObjectFactory().createPolicy(policy);		
+		try {
+			JAXBContext context = JAXBContext.newInstance(PolicyType.class);
+			Marshaller m = context.createMarshaller();
+			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+			m.marshal(policyElement, filename.toFile());
+
+			if (Files.exists(filename)) {
+				return filename;
+			} else {
+				PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "File does not exist after marshalling.");
+				return null;
+			}
+
+		} catch (JAXBException e) {
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyWriter", "writePolicyFile failed");
+			return null;
+		}		
+	}
+
+
+	/**
+	 * Helper static class that does the work to write a policy to a file on disk.
+	 * 
+	 *
+	 */
+	public static InputStream getXmlAsInputStream(PolicyType policy) {
+		JAXBElement<PolicyType> policyElement = new ObjectFactory().createPolicy(policy);		
+		try {
+			ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();			
+			JAXBContext context = JAXBContext.newInstance(PolicyType.class);
+			Marshaller m = context.createMarshaller();
+			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+			m.marshal(policyElement, byteArrayOutputStream);
+			ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
+
+			return byteArrayInputStream;
+
+		} catch (JAXBException e) {
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyWriter", "writePolicyFile failed");
+			return null;
+		}		
+	}
+	/**
+	 * Helper static class that does the work to write a policy set to an output stream.
+	 * 
+	 *
+	 */
+	public static void writePolicyFile(OutputStream os, PolicyType policy) {
+		JAXBElement<PolicyType> policySetElement = new ObjectFactory().createPolicy(policy);		
+		try {
+			JAXBContext context = JAXBContext.newInstance(PolicyType.class);
+			Marshaller m = context.createMarshaller();
+			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+			m.marshal(policySetElement, os);
+		} catch (JAXBException e) {
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyWriter", "writePolicyFile failed");
+		}
+	}
+	
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public static String changeFileNameInXmlWhenRenamePolicy(Path filename) {
+
+		PolicyType policyType = null;
+		String extension = "";
+		String domain = null;
+		String repository = "repository";
+		if(filename.toString().contains("Config_")){
+			domain = filename.toString().substring(filename.toString().indexOf(repository) + (repository.toString().length()+1), filename.toString().indexOf("Config_"));		
+		}else if(filename.toString().contains("Action_")){
+			domain = filename.toString().substring(filename.toString().indexOf(repository) + (repository.toString().length()+1), filename.toString().indexOf("Action_"));
+		}else if(filename.toString().contains("Decision_")){
+			domain = filename.toString().substring(filename.toString().indexOf(repository) + (repository.toString().length()+1), filename.toString().indexOf("Decision_"));
+		}
+		if(domain.contains(File.separator)){
+			domain =	domain.replace(File.separator, ".");
+		}
+		try {
+			JAXBContext context = JAXBContext.newInstance(PolicyType.class);
+			Unmarshaller m = context.createUnmarshaller();
+			JAXBElement<PolicyType> policyElement = (JAXBElement<PolicyType>) m.unmarshal(filename.toFile());
+			policyType = policyElement.getValue();
+			if (policyType != null) {
+				TargetType targetType = policyType.getTarget();
+				List<AnyOfType> anyOfTypes = targetType.getAnyOf();
+				for( Iterator anyOfIte = anyOfTypes.iterator(); anyOfIte.hasNext(); ){
+					AnyOfType anyOfType = (AnyOfType) anyOfIte.next();
+					List<AllOfType> allOf = anyOfType.getAllOf();
+					for( Iterator allOfIte = allOf.iterator(); allOfIte.hasNext(); ){
+						AllOfType allOfType = (AllOfType) allOfIte.next();
+						List<MatchType> match = allOfType.getMatch();						
+						for( Iterator matchIte = match.iterator(); matchIte.hasNext();) {							
+							MatchType  matchType = (MatchType) matchIte.next();
+							if(matchType.getAttributeDesignator().getAttributeId().equals("PolicyName")){
+								AttributeValueType attributeValueType = matchType.getAttributeValue();
+								List<Object> contents = attributeValueType.getContent();
+								if (contents != null && contents.size() > 0) {
+									String value = (String) contents.get(0);
+									String version = value;
+									version = version.substring(0, version.lastIndexOf("."));
+									version = version.substring(version.lastIndexOf("."));
+									if(filename.toString().contains("Config_")){
+										value = value.substring(0, value.indexOf("Config_"));
+									}else{
+										value = value.substring(0, value.indexOf("Decision_"));
+									}
+									String tmp = filename.getFileName()+"";
+									String newName = tmp.substring(0, tmp.lastIndexOf("."));
+									attributeValueType.getContent().clear();
+									attributeValueType.getContent().add(domain + newName  + "." + "xml");
+								}	
+							}
+						}
+					}
+				}
+				if(filename.toString().contains("Config_") || filename.toString().contains("Action_")){	
+					List<Object> objects = policyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition();
+					if (objects != null && objects.size() > 0) {
+						for (Iterator ite = objects.iterator(); ite.hasNext();) {
+
+							RuleType  ruleType = (RuleType ) ite.next();
+							AdviceExpressionsType adviceExpressionsType = ruleType.getAdviceExpressions();
+							if (adviceExpressionsType != null) {
+								List<AdviceExpressionType> adviceExpressionTypes = adviceExpressionsType.getAdviceExpression();
+								if (adviceExpressionTypes != null && adviceExpressionTypes.size() > 0) {
+									for (Iterator iterator = adviceExpressionTypes
+											.iterator(); iterator.hasNext();) {
+										AdviceExpressionType adviceExpressionType = (AdviceExpressionType) iterator
+												.next();
+										if (adviceExpressionType.getAdviceId() != null && !adviceExpressionType.getAdviceId().equals("") && (adviceExpressionType.getAdviceId().equals("configID")
+												|| adviceExpressionType.getAdviceId().equals("faultID") || adviceExpressionType.getAdviceId().equals("PMID")||adviceExpressionType.getAdviceId().equals("firewallConfigID") 
+												|| adviceExpressionType.getAdviceId().equals("MSID")) || adviceExpressionType.getAdviceId().equals("GocID")||adviceExpressionType.getAdviceId().equals("GocHPID")||adviceExpressionType.getAdviceId().equals("BRMSRAWID")
+												||adviceExpressionType.getAdviceId().equals("BRMSPARAMID")|| adviceExpressionType.getAdviceId().equals("HPSuppID") || adviceExpressionType.getAdviceId().equals("HPFlapID") || adviceExpressionType.getAdviceId().equals("HPOverID"))
+										{
+											List<AttributeAssignmentExpressionType> attributeAssignmentExpressionTypes = adviceExpressionType.getAttributeAssignmentExpression();
+											if (attributeAssignmentExpressionTypes != null && attributeAssignmentExpressionTypes.size() > 0) {
+												for (Iterator iterator2 = attributeAssignmentExpressionTypes
+														.iterator(); iterator2.hasNext();) {
+													AttributeAssignmentExpressionType attributeAssignmentExpressionType = (AttributeAssignmentExpressionType) iterator2
+															.next();
+													if (attributeAssignmentExpressionType.getAttributeId().equals("URLID")) {
+														JAXBElement<AttributeValueType> attributeValueType = (JAXBElement<AttributeValueType>) attributeAssignmentExpressionType.getExpression();
+														AttributeValueType attributeValueType1 = attributeValueType.getValue();
+														String configUrl = "$URL";
+														String urlVal = (String) attributeValueType1.getContent().get(0);   
+														String origExtension = urlVal.substring(urlVal.lastIndexOf('.')+1).trim();
+														extension = origExtension;
+														attributeValueType1.getContent().clear();
+														String txtFileName = filename.getFileName().toString();
+														txtFileName = txtFileName.substring(0, txtFileName.lastIndexOf(".")+1) + origExtension;
+														txtFileName = configUrl+ File.separator + "Config" + File.separator + domain + txtFileName;
+														attributeValueType1.getContent().add(txtFileName);	
+													} else if (attributeAssignmentExpressionType.getAttributeId().equals("PolicyName")) {
+														JAXBElement<AttributeValueType> attributeValueType = (JAXBElement<AttributeValueType>) attributeAssignmentExpressionType.getExpression();
+														AttributeValueType attributeValueType1 = attributeValueType.getValue();
+														List<Object> contents = attributeValueType1.getContent();
+														if (contents != null && contents.size() > 0) {
+															String value = (String) contents.get(0);
+															String version = value;
+															version = version.substring(0, version.lastIndexOf("."));
+															version = version.substring(version.lastIndexOf("."));
+															value = value.substring(0, value.indexOf("Config_"));
+															String tmp = filename.getFileName()+"";
+															String newName = tmp.substring(0, tmp.lastIndexOf("."));
+															attributeValueType1.getContent().clear();
+															attributeValueType1.getContent().add(domain + newName + "." + "xml");
+														}										
+
+													}
+
+												}
+											}
+										}
+									}
+								}
+							}
+						}
+						if (objects != null && objects.size() > 0) {
+							for (Iterator ite1 = objects.iterator(); ite1.hasNext();) {
+
+								RuleType  ruleType1 = (RuleType ) ite1.next();
+								ObligationExpressionsType obligationExpressionsType = ruleType1.getObligationExpressions();
+								if (obligationExpressionsType != null) {
+									List<ObligationExpressionType> obligationExpressionType = obligationExpressionsType.getObligationExpression();
+									if (obligationExpressionType != null && obligationExpressionType.size() > 0) {
+										for (Iterator iterator = obligationExpressionType
+												.iterator(); iterator.hasNext();) {
+											ObligationExpressionType obligationExpressionTypes = (ObligationExpressionType) iterator
+													.next();
+											if (obligationExpressionTypes.getObligationId() != null && !obligationExpressionTypes.getObligationId().equals("")) {
+												List<AttributeAssignmentExpressionType> attributeAssignmentExpressionTypes = obligationExpressionTypes.getAttributeAssignmentExpression();
+												if (attributeAssignmentExpressionTypes != null && attributeAssignmentExpressionTypes.size() > 0) {
+													for (Iterator iterator2 = attributeAssignmentExpressionTypes
+															.iterator(); iterator2.hasNext();) {
+														AttributeAssignmentExpressionType attributeAssignmentExpressionType = (AttributeAssignmentExpressionType) iterator2
+																.next();
+														if (attributeAssignmentExpressionType.getAttributeId().equals("body")) {
+															JAXBElement<AttributeValueType> attributeValueType = (JAXBElement<AttributeValueType>) attributeAssignmentExpressionType.getExpression();
+															AttributeValueType attributeValueType1 = attributeValueType.getValue();
+															String configUrl = "$URL";
+															String urlVal = (String) attributeValueType1.getContent().get(0);    	
+															String origExtension = urlVal.substring(urlVal.lastIndexOf('.')+1).trim();
+															extension = "json";
+															attributeValueType1.getContent().clear();
+															String txtFileName = filename.getFileName().toString();
+															txtFileName = txtFileName.substring(0, txtFileName.lastIndexOf(".")+1) + origExtension;
+															txtFileName = configUrl+ File.separator + "Action" + File.separator + domain + txtFileName;
+															attributeValueType1.getContent().add(txtFileName);	
+														} 
+
+													}
+												}
+
+											}
+
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+				writePolicyFile(filename, policyType);
+			}
+		}catch (JAXBException e) {
+			PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "XACMLPolicyWriter", "writePolicyFile failed");
+		}	
+
+		return extension;
+	}
+
+}
diff --git a/ECOMP-XACML/src/main/resources/xacml.properties b/ECOMP-XACML/src/main/resources/xacml.properties
new file mode 100644
index 0000000..9cdf680
--- /dev/null
+++ b/ECOMP-XACML/src/main/resources/xacml.properties
@@ -0,0 +1,46 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+# Default XACML Properties File
+# Standard API Factories
+#
+xacml.dataTypeFactory=org.openecomp.policy.xacml.std.StdDataTypeFactory
+xacml.pdpEngineFactory=com.att.research.xacmlatt.pdp.ATTPDPEngineFactory
+xacml.pepEngineFactory=org.openecomp.policy.xacml.std.pep.StdEngineFactory
+xacml.pipFinderFactory=org.openecomp.policy.xacml.std.pip.StdPIPFinderFactory
+
+# If there is a standard set of PIPEngines:
+# xacml.pip.engines=engine1,engine2,...,engineN
+# engine1.classname=com.att.research.xacmlpip.OraclePIP
+# engine1.prop1=foo
+# engine1.prop2=bar
+# ...
+# engine2.classname=com.att.research.xacmlpip.ActiveDirectoryPIP
+# ...
+
+# AT&T PDP Implementation Factories
+#
+xacml.att.evaluationContextFactory=com.att.research.xacmlatt.pdp.std.StdEvaluationContextFactory
+xacml.att.combiningAlgorithmFactory=com.att.research.xacmlatt.pdp.std.StdCombiningAlgorithmFactory
+xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctionDefinitionFactory
+xacml.att.policyFinderFactory=com.att.research.xacmlatt.pdp.std.StdPolicyFinderFactory
+
+# If there is a standard policy for the engine:
+# xacml.att.stdPolicyFinderFactory.rootPolicyFile=/etc/stdpolicyset.xml
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/DOMResponseConformanceTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/DOMResponseConformanceTest.java
new file mode 100644
index 0000000..2083577
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/DOMResponseConformanceTest.java
@@ -0,0 +1,196 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test;
+
+import static org.junit.Assert.fail;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.att.research.xacml.api.Response;
+import com.att.research.xacml.std.dom.DOMResponse;
+
+/**
+ * Tests for handling the XML version of the XACML Response object.
+ * 
+ * TO RUN - use jUnit
+ * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test
+ * 
+ * Normally the Response is generated by the PDP and returned through the RESTful interface as JSON.
+ * Testing of the XML interface is minimal and not complete.
+ * 
+ * 
+ * 
+ *
+ */
+public class DOMResponseConformanceTest {
+	
+	// where to find the conformance test XML files
+	private final String CONFORMANCE_DIRECTORY_PATH = "testsets/conformance/xacml3.0-ct-v.0.4";
+	
+	// The request object output from each test conversion from JSON string
+	Response response;
+
+	
+	
+	// Load the Conformance test responses into Response objects, generate the output XML for that Response and compare with the original files.
+	@Test
+	public void testDOMResponse() {
+		List<File> filesInDirectory = null;
+		
+		File conformanceDirectory = null;
+		
+		File currentFile = null;
+		
+		try {
+			conformanceDirectory = new File(CONFORMANCE_DIRECTORY_PATH);
+			filesInDirectory = getRequestsInDirectory(conformanceDirectory);
+		} catch (Exception e) {
+			fail("Unable to set up Conformance tests for dir '" + conformanceDirectory.getAbsolutePath()+"' e="+ e);
+		}
+		
+		// run through each XML file
+		//	- load the file from XML into an internal Response object
+		//	- generate the XML representation from that Response object
+		// 	- reload the file into a String
+		//	- compare the 2 XML strings
+		Response xmlResponse = null;
+		try {
+			for (File f : filesInDirectory) {
+				currentFile = f;
+
+//// This is a simple way to select just one file for debugging - comment out when not being used
+//if ( ! f.getName().equals("IID302Response.xml")) {   continue;  }
+
+// during debugging it is helpful to know what file it is starting to work on
+//				System.out.println("starting file="+currentFile.getName());
+				
+				
+				BufferedReader br = new BufferedReader(new FileReader(f));
+				StringBuffer sb = new StringBuffer();
+				String line;
+				while ((line = br.readLine()) != null) {
+					sb.append(line + "\n");
+				}
+				br.close();
+				
+				String xmlFromFile = sb.toString();
+				
+				try {
+					// load XML into a Response object
+					xmlResponse = DOMResponse.load(xmlFromFile);
+				} catch (Exception e) {
+					// if XML does not load, just note it and continue with next file
+					System.out.println("XML file did not load: '" + f.getName() + "  e=" + e);
+					continue;
+				}
+//System.out.println(xmlFromFile);				
+				
+				// create String version from the Response object
+				String xmlResponseString = DOMResponse.toString(xmlResponse, false);
+				
+				// Comparing the string directly to the String from the file is difficult.
+				// We can minimize the problems with newlines and whitespace, but we have other issues with how various object values are represented.
+				// For instance, and input double of "23.50" is output as "23.5" which is the same value but not identical strings.
+				// Therefore we take the XML output and use it to create a new Response object, then compare the two objects.
+
+//System.out.println(xmlResponseString);			
+				Response reGeneratedResponse = DOMResponse.load(xmlResponseString);
+				
+				if ( ! xmlResponse.equals(reGeneratedResponse)) {
+					String normalizedFromFile = xmlFromFile.replaceAll("\\r|\\n", "");
+					normalizedFromFile = normalizedFromFile.replaceAll("\\s+", " ");
+					normalizedFromFile = normalizedFromFile.replaceAll(">\\s*<", "><");
+					System.out.println("File="+normalizedFromFile);
+					System.out.println("Gend="+ xmlResponseString);
+					
+					System.out.println(DOMResponse.toString(xmlResponse, true));
+				
+					fail("Output string did not re-generate eqivilent object.");
+				}
+
+//				// Normally whitespace is significant in XML.
+//				// However in this case we are generating an XML string for output and comparing it to a hand-made file.
+//				// The file may contain extra newlines or fewer spaces then our prettyPrinted output version.
+//				// Therefore we do the comparison on the un-prettyPrinted generated string.
+//				// To do this we have to remove the extra whitespace from the version read from the file.
+//				String normalizedFromFile = xmlFromFile.replaceAll("\\r|\\n", "");
+//				normalizedFromFile = normalizedFromFile.replaceAll("\\s+", " ");
+//				normalizedFromFile = normalizedFromFile.replaceAll(">\\s*<", "><");
+//			
+//				if ( ! xmlResponseString.equals(normalizedFromFile)) {
+//					System.out.println("file="+normalizedFromFile+"\ngend="+xmlResponseString);
+//					fail("file not same as generated string: " + f.getName()+ "\nFile="+xmlFromFile + "\nString="+xmlResponseString);
+//				}
+
+
+			}			
+
+		} catch (Exception e) {
+			fail ("Failed test with '" + currentFile.getName() + "', e=" + e);
+		}
+
+		
+	}
+	
+	
+	
+	//
+	// HELPER to get list of all Request files in the given directory
+	//
+	
+	private List<File> getRequestsInDirectory(File directory) {
+		List<File> fileList = new ArrayList<File>();
+		
+		File[] fileArray = directory.listFiles();
+		for (File f : fileArray) {
+			if (f.isDirectory()) {
+				List<File> subDirList = getRequestsInDirectory(f);
+				fileList.addAll(subDirList);
+			}
+			if (f.getName().endsWith("Response.xml")) {
+				fileList.add(f);
+			}
+		}
+		return fileList;
+		
+	}
+	
+	
+}
+
+
+/*
+Place to edit long strings output during tests
+
+
+
+
+
+
+
+
+*/
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/DOMResponseTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/DOMResponseTest.java
new file mode 100644
index 0000000..5c27018
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/DOMResponseTest.java
@@ -0,0 +1,2316 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.att.research.xacml.api.Attribute;
+import com.att.research.xacml.api.AttributeValue;
+import com.att.research.xacml.api.Decision;
+import com.att.research.xacml.api.Identifier;
+import com.att.research.xacml.api.XACML3;
+import com.att.research.xacml.std.IdentifierImpl;
+import com.att.research.xacml.std.StdAttribute;
+import com.att.research.xacml.std.StdAttributeCategory;
+import com.att.research.xacml.std.StdAttributeValue;
+import com.att.research.xacml.std.StdIdReference;
+import com.att.research.xacml.std.StdMutableAdvice;
+import com.att.research.xacml.std.StdMutableAttribute;
+import com.att.research.xacml.std.StdMutableAttributeAssignment;
+import com.att.research.xacml.std.StdMutableMissingAttributeDetail;
+import com.att.research.xacml.std.StdMutableObligation;
+import com.att.research.xacml.std.StdMutableResponse;
+import com.att.research.xacml.std.StdMutableResult;
+import com.att.research.xacml.std.StdMutableStatus;
+import com.att.research.xacml.std.StdMutableStatusDetail;
+import com.att.research.xacml.std.StdStatusCode;
+import com.att.research.xacml.std.StdVersion;
+import com.att.research.xacml.std.datatypes.DataTypes;
+import com.att.research.xacml.std.datatypes.StringNamespaceContext;
+import com.att.research.xacml.std.datatypes.XPathExpressionWrapper;
+import com.att.research.xacml.std.dom.DOMResponse;
+import com.att.research.xacml.std.dom.DOMStructureException;
+
+/**
+ * Test DOM XML Responses
+ * 
+ * TO RUN - use jUnit
+ * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test
+ * 
+ * This class was copied from the JSON tests.  At this time only the first two methods have been revised to work with XML.
+ * The second method includes multiple instances of all possible fields and has been manually verified.
+ * The remaining methods have not been converted because:
+ * 	- "conversion" consists of replacing the JSON strings with XML
+ * 	- the replacement would consist of copying the XML from the JUnit output and doing a String replace
+ * 	- there would be little examination of the (long) XML strings, so their validity would be questionable
+ * so the benefit for the cost of doing that work is not clear.
+ * 
+ *
+ */
+public class DOMResponseTest {
+
+	String xmlResponse;
+	
+	StdMutableResponse response;
+	
+	StdMutableResult result;
+	
+	StdMutableStatus status;
+	
+	
+	// Note: Initially test responses without Obligations, Associated Advice, Attributes, or PolicyIdentifier
+	
+	
+	@Test
+	public void testEmptyAndDecisions() {
+		// null response
+		try {
+			xmlResponse = DOMResponse.toString(null, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// empty response (no Result object)
+		response = new StdMutableResponse();
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		
+		// just decision, no status
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// just status (empty), no decision
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();		
+		result.setStatus(status);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// just status (non-empty), no decision
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_OK);
+		result.setStatus(status);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		
+		// test other decisions without Status
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.DENY);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Deny</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.NOTAPPLICABLE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>NotApplicable</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{D}</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{DP}</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{P}</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+
+		
+		// test Multiple Decisions - success
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		StdMutableResult result2 = new StdMutableResult();
+		result2.setDecision(Decision.DENY);
+		response.add(result2);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision></Result><Result><Decision>Deny</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// test Multiple Decisions - one success and one error
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		result2 = new StdMutableResult();
+		result2.setDecision(Decision.INDETERMINATE);
+		response.add(result2);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision></Result><Result><Decision>Indeterminate</Decision></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+		
+
+	
+	
+	// Test with every field filled in with multiple values where appropriate
+	@Test
+	public void testAllFieldsResponse() {	
+		
+		// fully-loaded multiple response
+		
+		StdMutableResponse response = new StdMutableResponse();
+		// create a Status object
+		StdMutableStatus status = new StdMutableStatus(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		status.setStatusMessage("some status message");
+		StdMutableStatusDetail statusDetailIn = new StdMutableStatusDetail();
+		StdMutableMissingAttributeDetail mad = new StdMutableMissingAttributeDetail();
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "doh"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_INTEGER.getId(), "5432"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		mad.setAttributeId(XACML3.ID_ACTION_PURPOSE);
+		mad.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_ACTION);
+		mad.setDataTypeId(XACML3.ID_DATATYPE_STRING);
+		mad.setIssuer("an Issuer");
+		statusDetailIn.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetailIn);
+		// create a single result object
+		StdMutableResult result = new StdMutableResult(status);
+		// set the decision
+		result.setDecision(Decision.INDETERMINATE);
+		// put the Result into the Response
+		response.add(result);
+
+		
+		// create a new Result with a different Decision
+		status = new StdMutableStatus(StdStatusCode.STATUS_CODE_OK);
+		result = new StdMutableResult(status);
+		result.setDecision(Decision.DENY);
+		
+		StdMutableObligation obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer2", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Ned")));
+		result.addObligation(obligation);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_SUBJECT_CATEGORY_INTERMEDIARY_SUBJECT);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer3", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Maggie")));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer4", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Homer")));
+		result.addObligation(obligation);
+		
+		
+		StdMutableAdvice advice = new StdMutableAdvice();
+		advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu")));
+		advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				null, 
+				XACML3.ID_SUBJECT, 
+				"advice-issuerNoCategory", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Crusty")));
+		result.addAdvice(advice);
+		
+		
+		response.add(result);
+		
+		
+		// create a new Result with a different Decision
+		// add Child/minor status codes within the main status
+		StdStatusCode childChildChildStatusCode = new StdStatusCode(new IdentifierImpl("childChildChildStatusCode"));
+		StdStatusCode childChildStatusCode = new StdStatusCode(new IdentifierImpl("childChildStatusCode"), childChildChildStatusCode);
+		StdStatusCode child1StatusCode = new StdStatusCode(new IdentifierImpl("child1StatusCode"), childChildStatusCode);
+		StdStatusCode statusCode = new StdStatusCode(XACML3.ID_STATUS_OK, child1StatusCode);
+		
+		status = new StdMutableStatus(statusCode);
+		
+		
+		result = new StdMutableResult(status);
+		result.setDecision(Decision.PERMIT);
+		
+		
+		
+		
+		// add attribute list in result
+		Identifier categoryIdentifier = new IdentifierImpl("firstCategory");
+		Attribute[] attrList = {
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent2"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "BIssue", false),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent3"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "CIssue", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent4"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "DIssue", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent5"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), "EIssue", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrNoIssuer"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), null, true) };
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, Arrays.asList(attrList)));
+		categoryIdentifier = new IdentifierImpl("secondCategory");
+		Attribute[] secondAttrList = {
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent12"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu2"), "AIssue2", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent22"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Abc2"), "BIssue2", false),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent32"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Der2"), "CIssue2", true) };
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, Arrays.asList(secondAttrList)));
+		
+		
+		// add PolicyIdentifierList to result
+		StdIdReference policyIdentifier1 = null;
+		StdIdReference policyIdentifier2 = null;
+		StdIdReference policySetIdentifier1 = null;
+		StdIdReference policySetIdentifier2 = null;
+		try {
+			policyIdentifier1 = new StdIdReference(new IdentifierImpl("idRef1"), StdVersion.newInstance("1.2.3"));
+			policyIdentifier2 = new StdIdReference(new IdentifierImpl("idRef2_NoVersion"));
+			policySetIdentifier1 = new StdIdReference(new IdentifierImpl("idSetRef1"), StdVersion.newInstance("4.5.6.7.8.9.0"));
+			policySetIdentifier2 = new StdIdReference(new IdentifierImpl("idSetRef2_NoVersion"));
+		} catch (ParseException e1) {
+			fail("creating policyIds, e="+e1);
+		}
+		
+		result.addPolicyIdentifier(policyIdentifier1);
+		result.addPolicyIdentifier(policyIdentifier2);
+	
+		result.addPolicySetIdentifier(policySetIdentifier1);
+		result.addPolicySetIdentifier(policySetIdentifier2);
+		
+		response.add(result);
+	
+		// convert Response to XML
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+//System.out.println(xmlResponse);
+//System.out.println(DOMResponse.toString(response, true));
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/><StatusMessage>some status message</StatusMessage><StatusDetail><MissingAttributeDetail Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:action\" AttributeId=\"urn:oasis:names:tc:xacml:2.0:action:purpose\" DataTypeId=\"http://www.w3.org/2001/XMLSchema#string\" Issuer=\"an Issuer\"><AttributeValue>doh</AttributeValue><AttributeValue>5432</AttributeValue><AttributeValue>meh</AttributeValue></MissingAttributeDetail></StatusDetail></Status></Result><Result><Decision>Deny</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"/></Status><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Ned</AttributeAssignment></Obligation><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Maggie</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Homer</AttributeAssignment></Obligation></Obligations><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Crusty</AttributeAssignment></Advice></AssociatedAdvice></Result><Result><Decision>Permit</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"><StatusCode Value=\"child1StatusCode\"><StatusCode Value=\"childChildStatusCode\"><StatusCode Value=\"childChildChildStatusCode\"/></StatusCode></StatusCode></StatusCode></Status><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent3\" Issuer=\"CIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#double\">765.432</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent4\" Issuer=\"DIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#boolean\">true</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent5\" Issuer=\"EIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrNoIssuer\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute></Attributes><Attributes Category=\"secondCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent12\" Issuer=\"AIssue2\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu2</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent32\" Issuer=\"CIssue2\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Der2</AttributeValue></Attribute></Attributes><PolicyIdentifierList><PolicyIdReference Version=\"1.2.3\">idRef1</PolicyIdReference><PolicyIdReference>idRef2_NoVersion</PolicyIdReference><PolicySetIdReference Version=\"4.5.6.7.8.9.0\">idSetRef1</PolicySetIdReference><PolicySetIdReference>idSetRef2_NoVersion</PolicySetIdReference></PolicyIdentifierList></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+	
+	
+	
+	
+	// combinations of Status values with Decision values
+	@Test
+	public void testDecisionStatusMatch() {
+		// the tests in this method use different values and do not change structures, so we can re-use the objects
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		result.setStatus(status);
+		response.add(result);
+		
+		// StatusCode = OK
+		status.setStatusCode(StdStatusCode.STATUS_CODE_OK);
+		result.setDecision(Decision.PERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.DENY);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Deny</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.NOTAPPLICABLE);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>NotApplicable</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		
+		
+		
+		
+		
+		// StatusCode = SyntaxError
+		status.setStatusCode(StdStatusCode.STATUS_CODE_SYNTAX_ERROR);
+		result.setDecision(Decision.PERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.DENY);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.NOTAPPLICABLE);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{D}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{DP}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{P}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// StatusCode = ProcessingError
+		status.setStatusCode(StdStatusCode.STATUS_CODE_PROCESSING_ERROR);
+		result.setDecision(Decision.PERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.DENY);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.NOTAPPLICABLE);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{D}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{DP}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{P}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+		// StatusCode = MissingAttribute
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		result.setDecision(Decision.PERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.DENY);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.NOTAPPLICABLE);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{D}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{DP}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate{P}</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+
+	
+	
+
+	// tests related to Status and its components
+	@Test
+	public void testStatus() {
+		// Status with no StatusCode - error
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// Status with StatusMessage when OK
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_OK);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"/><StatusMessage>I'm ok, you're ok</StatusMessage></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with StatusDetail when OK
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_OK);
+		StdMutableStatusDetail statusDetail = new StdMutableStatusDetail();
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// Status with StatusMessage when SyntaxError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_SYNTAX_ERROR);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"/><StatusMessage>I'm ok, you're ok</StatusMessage></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with empty StatusDetail when SyntaxError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_SYNTAX_ERROR);
+		statusDetail = new StdMutableStatusDetail();
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		
+		// Status with StatusMessage when ProcessingError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_PROCESSING_ERROR);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"/><StatusMessage>I'm ok, you're ok</StatusMessage></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with empty StatusDetail when ProcessingError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_PROCESSING_ERROR);
+		statusDetail = new StdMutableStatusDetail();
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+
+		
+		// Status with StatusMessage when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/><StatusMessage>I'm ok, you're ok</StatusMessage></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with empty StatusDetail when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/><StatusDetail></StatusDetail></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+		// Status with StatusDetail with empty detail when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		StdMutableMissingAttributeDetail mad = new StdMutableMissingAttributeDetail();
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// Status with StatusDetail with valid detail with no value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/><StatusDetail><MissingAttributeDetail Category=\"urn:oasis:names:tc:xacml:1.0:action\" AttributeId=\"mad\" DataTypeId=\"http://www.w3.org/2001/XMLSchema#string\"></MissingAttributeDetail></StatusDetail></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with StatusDetail with valid detail with value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/><StatusDetail><MissingAttributeDetail Category=\"urn:oasis:names:tc:xacml:1.0:action\" AttributeId=\"mad\" DataTypeId=\"http://www.w3.org/2001/XMLSchema#string\"><AttributeValue>meh</AttributeValue></MissingAttributeDetail></StatusDetail></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with StatusDetail with array valid detail with value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "nu?"));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/><StatusDetail><MissingAttributeDetail Category=\"urn:oasis:names:tc:xacml:1.0:action\" AttributeId=\"mad\" DataTypeId=\"http://www.w3.org/2001/XMLSchema#string\"><AttributeValue>meh</AttributeValue><AttributeValue>nu?</AttributeValue></MissingAttributeDetail></StatusDetail></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// Status with StatusDetail with valid detail with Integer value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 1111));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/><StatusDetail><MissingAttributeDetail Category=\"urn:oasis:names:tc:xacml:1.0:action\" AttributeId=\"mad\" DataTypeId=\"http://www.w3.org/2001/XMLSchema#string\"><AttributeValue>1111</AttributeValue></MissingAttributeDetail></StatusDetail></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with StatusDetail with array valid detail with Integer value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 1111));
+		mad.addAttributeValue(new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 2222));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Indeterminate</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"/><StatusDetail><MissingAttributeDetail Category=\"urn:oasis:names:tc:xacml:1.0:action\" AttributeId=\"mad\" DataTypeId=\"http://www.w3.org/2001/XMLSchema#string\"><AttributeValue>1111</AttributeValue><AttributeValue>2222</AttributeValue></MissingAttributeDetail></StatusDetail></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+//		StringNamespaceContext snc = new StringNamespaceContext();
+//		try {
+//			snc.add("defaultURI");
+//			snc.add("md", "referenceForMD");
+//		} catch (Exception e) {
+//			fail("unable to create NamespaceContext e="+e);
+//		}
+//		XPathExpressionWrapper xpathExpressionWrapper = new XPathExpressionWrapper(snc, "//md:record");
+//
+//TODO - assume that we will never try to pass back an XPathExpression in a MissingAttributeDetail - it doesn't make sense and is unclear how to put into XML
+//		// Status with StatusDetail with valid detail with XPathExpression value when MissingAttribute
+//		response = new StdMutableResponse();
+//		result = new StdMutableResult();
+//		status = new StdMutableStatus();
+//		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+//		statusDetail = new StdMutableStatusDetail();
+//		mad = new StdMutableMissingAttributeDetail();
+//		mad.setAttributeId(new IdentifierImpl("mad"));
+//		mad.setCategory(XACML3.ID_ACTION);
+//		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+//		mad.addAttributeValue(new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("xpathCategoryId")));
+//		statusDetail.addMissingAttributeDetail(mad);
+//		status.setStatusDetail(statusDetail);
+//		result.setStatus(status);
+//		result.setDecision(Decision.INDETERMINATE);
+//		response.add(result);
+//		try {
+//			xmlResponse = DOMResponse.toString(response, false);
+//			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<MissingAttributeDetail><AttributeValue>1111</AttributeValue><Category>urn:oasis:names:tc:xacml:1.0:action</Category><AttributeId>mad</AttributeId><DataType>http://www.w3.org/2001/XMLSchema#string</DataType></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", xmlResponse);
+//		} catch (Exception e) {
+//			fail("operation failed, e="+e);
+//		}
+//		
+//		// Status with StatusDetail with array valid detail with XPathExpression value when MissingAttribute
+//		response = new StdMutableResponse();
+//		result = new StdMutableResult();
+//		status = new StdMutableStatus();
+//		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+//		statusDetail = new StdMutableStatusDetail();
+//		mad = new StdMutableMissingAttributeDetail();
+//		mad.setAttributeId(new IdentifierImpl("mad"));
+//		mad.setCategory(XACML3.ID_ACTION);
+//		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+//		mad.addAttributeValue(new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("xpathCategoryId1")));
+//		mad.addAttributeValue(new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("xpathCategoryId2")));
+//		statusDetail.addMissingAttributeDetail(mad);
+//		status.setStatusDetail(statusDetail);
+//		result.setStatus(status);
+//		result.setDecision(Decision.INDETERMINATE);
+//		response.add(result);
+//		try {
+//			xmlResponse = DOMResponse.toString(response, false);
+//			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<MissingAttributeDetail><AttributeValue>1111</AttributeValue><AttributeValue>2222</AttributeValue><Category>urn:oasis:names:tc:xacml:1.0:action</Category><AttributeId>mad</AttributeId><DataType>http://www.w3.org/2001/XMLSchema#string</DataType></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", xmlResponse);
+//		} catch (Exception e) {
+//			fail("operation failed, e="+e);
+//		}
+		
+//TODO - try with other data types, esp XPathExpression		
+		
+		// Status with StatusDetail with array valid detail with value when SyntaxError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_SYNTAX_ERROR);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "nu?"));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// Status with StatusDetail with array valid detail with value when ProcessingError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_PROCESSING_ERROR);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "nu?"));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		
+		
+		// Status with nested child StatusCodes (child status containing child status containing...)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		StdStatusCode child1StatusCode = new StdStatusCode(new IdentifierImpl("child1StatusCode"));
+		StdStatusCode statusCode = new StdStatusCode(XACML3.ID_STATUS_OK, child1StatusCode);
+		status = new StdMutableStatus(statusCode);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"><StatusCode Value=\"child1StatusCode\"/></StatusCode><StatusMessage>I'm ok, you're ok</StatusMessage></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		StdStatusCode childChildChildStatusCode = new StdStatusCode(new IdentifierImpl("childChildChildStatusCode"));
+		StdStatusCode childChildStatusCode = new StdStatusCode(new IdentifierImpl("childChildStatusCode"), childChildChildStatusCode);
+		child1StatusCode = new StdStatusCode(new IdentifierImpl("child1StatusCode"), childChildStatusCode);
+		statusCode = new StdStatusCode(XACML3.ID_STATUS_OK, child1StatusCode);
+		status = new StdMutableStatus(statusCode);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"><StatusCode Value=\"child1StatusCode\"><StatusCode Value=\"childChildStatusCode\"><StatusCode Value=\"childChildChildStatusCode\"/></StatusCode></StatusCode></StatusCode><StatusMessage>I'm ok, you're ok</StatusMessage></Status></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+
+	}
+
+
+	
+	@Test
+	public void testObligations() {
+		
+		// create an XPathExpression for use later
+		StringNamespaceContext snc = new StringNamespaceContext();
+		try {
+			snc.add("defaultURI");
+			snc.add("md", "referenceForMD");
+		} catch (Exception e) {
+			fail("unable to create NamespaceContext e="+e);
+		}
+		XPathExpressionWrapper xpathExpressionWrapper = new XPathExpressionWrapper(snc, "//md:record");
+		XPathExpressionWrapper xpathExpressionWrapper2 = new XPathExpressionWrapper(snc, "//md:hospital");
+		
+		StdMutableObligation obligation;
+
+		// test Obligation single decision no attributes
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// obligation missing Id
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		
+		
+		//	AttributeAssignment	- with AttributeId, Value,  Category, DataType, Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		//	AttributeAssignment	- with AttributeId, Value, no Category, DataType, Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				null, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		//	AttributeAssignment	- Missing AttributeId
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				null, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		//	AttributeAssignment	- Missing Value
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				null));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// AttributeAssignment - missing required DataType (Different than JSON where DataType is optional with default String)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(null, "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// AttributeAssignment - missing issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// AttributeAssignment - Integer type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 1111)));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#integer\">1111</AttributeAssignment></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// AttributeAssignment - XPathExpression type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("SimpleXPathCategory"))));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\" xmlns:md=\"referenceForMD\" xmlns=\"defaultURI\">//md:record</AttributeAssignment></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+
+		//
+		// Technically arrays cannot occur in Obligations and Advice elements.  The XML spec boils down to the following definition:
+		//		<Obligation (attributes of the obligation) >
+		//			<AttributeAssignment (attributes of this assignment) >value</AttributeAssignment>
+		//			<AttributeAssignment (attributes of this assignment) >value</AttributeAssignment>
+		//			:
+		//		</Obligation
+		//	which means that there may be multiple AttributeAssignments but each one has only one value.
+		//	This differs from the Attributes section in which each <Attribute> may have multiple <AttributeValue> elements.
+		// For Obligations and Advice we can simulate an array by having multiple AttributeAssignment elements with the same Category, Id and Issuer.
+		//
+
+		
+		//	AttributeAssignment	- Multiple values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Lisa")));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Maggie")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Lisa</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Maggie</AttributeAssignment></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		//	AttributeAssignment	- Multiple Integer values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 1111)));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 2222)));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 3333)));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#integer\">1111</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#integer\">2222</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#integer\">3333</AttributeAssignment></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// Multiple XPathExpression values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("SimpleXPathCategory"))));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper2, new IdentifierImpl("SimpleXPathCategory"))));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Obligations><Obligation ObligationId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\" xmlns:md=\"referenceForMD\" xmlns=\"defaultURI\">//md:record</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\" xmlns:md=\"referenceForMD\" xmlns=\"defaultURI\">//md:hospital</AttributeAssignment></Obligation></Obligations></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}	
+		
+	}
+	
+	
+	
+	
+	@Test
+	public void testAdvice() {
+		
+		// create an XPathExpression for use later
+		StringNamespaceContext snc = new StringNamespaceContext();
+		try {
+			snc.add("defaultURI");
+			snc.add("md", "referenceForMD");
+		} catch (Exception e) {
+			fail("unable to create NamespaceContext e="+e);
+		}
+		XPathExpressionWrapper xpathExpressionWrapper = new XPathExpressionWrapper(snc, "//md:record");
+		XPathExpressionWrapper xpathExpressionWrapper2 = new XPathExpressionWrapper(snc, "//md:hospital");
+		
+		StdMutableAdvice Advice;
+
+		// test Advice single decision no attributes
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Advice missing Id
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		
+		
+		//	AttributeAssignment	- with AttributeId, Value,  Category, DataType, Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		//	AttributeAssignment	- with AttributeId, Value, no Category, DataType, Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				null, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		//	AttributeAssignment	- Missing AttributeId
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				null, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		//	AttributeAssignment	- Missing Value
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				null));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// AttributeAssignment - missing Required DataType (Different than JSON where DataType is optional with default String)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(null, "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// AttributeAssignment - missing issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// AttributeAssignment - Integer type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 1111)));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#integer\">1111</AttributeAssignment></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// AttributeAssignment - XPathExpression type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("SimpleXPathCategory"))));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\" xmlns:md=\"referenceForMD\" xmlns=\"defaultURI\">//md:record</AttributeAssignment></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+
+		//
+		// Technically arrays cannot occur in Obligations and Advice elements.  The XML spec boils down to the following definition:
+		//		<Obligation (attributes of the obligation) >
+		//			<AttributeAssignment (attributes of this assignment) >value</AttributeAssignment>
+		//			<AttributeAssignment (attributes of this assignment) >value</AttributeAssignment>
+		//			:
+		//		</Obligation
+		//	which means that there may be multiple AttributeAssignments but each one has only one value.
+		//	This differs from the Attributes section in which each <Attribute> may have multiple <AttributeValue> elements.
+		// For Obligations and Advice we can simulate an array by having multiple AttributeAssignment elements with the same Category, Id and Issuer.
+		//
+		
+		//	AttributeAssignment	- Multiple values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Lisa")));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Maggie")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Lisa</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">Maggie</AttributeAssignment></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		//	AttributeAssignment	- Multiple Integer values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 1111)));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 2222)));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 3333)));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#integer\">1111</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#integer\">2222</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"http://www.w3.org/2001/XMLSchema#integer\">3333</AttributeAssignment></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// Multiple XPathExpression values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("SimpleXPathCategory"))));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper2, new IdentifierImpl("SimpleXPathCategory"))));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><AssociatedAdvice><Advice AdviceId=\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\" xmlns:md=\"referenceForMD\" xmlns=\"defaultURI\">//md:record</AttributeAssignment><AttributeAssignment AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject\" DataType=\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\" xmlns:md=\"referenceForMD\" xmlns=\"defaultURI\">//md:hospital</AttributeAssignment></Advice></AssociatedAdvice></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+	
+	
+	
+	
+	
+
+	
+	
+
+	
+	// Attributes tests
+	@Test
+	public void testAttributes() {
+		
+		// create an XPathExpression for use later
+		StringNamespaceContext snc = new StringNamespaceContext();
+		try {
+			snc.add("defaultURI");
+			snc.add("md", "referenceForMD");
+		} catch (Exception e) {
+			fail("unable to create NamespaceContext e="+e);
+		}
+		XPathExpressionWrapper xpathExpressionWrapper = new XPathExpressionWrapper(snc, "//md:record");
+		
+		
+		Identifier categoryIdentifier;
+		List<Attribute> attrList = new ArrayList<Attribute>();
+		StdMutableAttribute mutableAttribute;
+		
+		// Attr list with no entries
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// one Attribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// multiple attributes
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent2"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "BIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent3"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "CIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent4"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "DIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent5"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), "EIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent2\" Issuer=\"BIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\">P10Y4M</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent3\" Issuer=\"CIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#double\">765.432</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent4\" Issuer=\"DIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#boolean\">true</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent5\" Issuer=\"EIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// IncludeInResult=false/true
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", false));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Missing AttributeId (mandatory)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, null, new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// Missing mandatory Value
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), null), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// Missing optional Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), null, true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// missing required DataType (different from JSON where DataType is optional and assumed to be String)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(null, "Apu"), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// same id, same type different issuer
+		// (This is not an array of values because Issuer is different)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart"), "BIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Simpson"), "CIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"BIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"CIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Simpson</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// same id, same type same issuer
+		// (This is an array of values)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Simpson"), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Simpson</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// same Id, different types, same issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\">P10Y4M</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#double\">765.432</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#boolean\">true</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// same Id, different types, different issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "BIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "CIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "DIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), "EIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), null, true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"BIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\">P10Y4M</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"CIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#double\">765.432</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"DIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#boolean\">true</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"EIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+
+		// different Id, different types, same issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent2"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "AIssue"), "BIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent3"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent4"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent5"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent2\" Issuer=\"BIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\">AIssue</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent3\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#double\">765.432</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent4\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#boolean\">true</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent5\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// one Attribute of type XPathExpression (the only complex data type)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("xpathCategory")), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\" XPathCategory=\"xpathCategory\">//md:record</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// multiple sets of values
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent2"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "BIssue", false));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent3"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "CIssue", true));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent4"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "DIssue", true));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent5"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), "EIssue", true));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrNoIssuer"), new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567), null, true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		categoryIdentifier = new IdentifierImpl("secondCategory");
+		Attribute[] secondAttrList = {
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent12"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu2"), "AIssue2", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent22"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Abc2"), "BIssue2", false),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent32"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Der2"), "CIssue2", true) };
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, Arrays.asList(secondAttrList)));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent3\" Issuer=\"CIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#double\">765.432</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent4\" Issuer=\"DIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#boolean\">true</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent5\" Issuer=\"EIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrNoIssuer\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute></Attributes><Attributes Category=\"secondCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent12\" Issuer=\"AIssue2\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu2</AttributeValue></Attribute><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent32\" Issuer=\"CIssue2\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Der2</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// array of values - same type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		attrList.clear();
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		mutableAttribute = new StdMutableAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), (Collection<AttributeValue<?>>)null, "AIssue", true);
+
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"));
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart"));
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Homer"));
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Ned"));
+			
+		attrList.add(mutableAttribute);
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Bart</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Homer</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Ned</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// array of values - compatible different types
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		attrList.clear();
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		mutableAttribute = new StdMutableAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), (Collection<AttributeValue<?>>)null, "AIssue", true);
+
+			mutableAttribute.addValue(new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567));
+			mutableAttribute.addValue(new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432));
+			mutableAttribute.addValue(new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567));
+		attrList.add(mutableAttribute);
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#double\">765.432</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// array of values - incompatible different types (Different from JSON because these are not part of an array in XML, just separate values)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		attrList.clear();
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		mutableAttribute = new StdMutableAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), (Collection<AttributeValue<?>>)null, "AIssue", true);
+
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"));
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"));
+			mutableAttribute.addValue(new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432));
+			mutableAttribute.addValue(new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true));
+			mutableAttribute.addValue(new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567));
+			mutableAttribute.addValue(new StdAttributeValue<Integer>(DataTypes.DT_INTEGER.getId(), 4567));
+		attrList.add(mutableAttribute);
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><Attributes Category=\"firstCategory\"><Attribute IncludeInResult=\"true\" AttributeId=\"attrIdent1\" Issuer=\"AIssue\"><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">Apu</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\">P10Y4M</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#double\">765.432</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#boolean\">true</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue><AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#integer\">4567</AttributeValue></Attribute></Attributes></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+	}
+	
+	
+	
+	
+	
+	// PolicyIdentifier tests
+	@Test
+	public void testPolicyIdentifier() {
+		
+		StdIdReference policyIdentifier1 = null;
+		StdIdReference policyIdentifier2 = null;
+		StdIdReference policySetIdentifier1 = null;
+		StdIdReference policySetIdentifier2 = null;
+		
+		// multiple PolicyIdentifiers of both types
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		try {
+			policyIdentifier1 = new StdIdReference(new IdentifierImpl("idRef1"), StdVersion.newInstance("1.2.3"));
+			policyIdentifier2 = new StdIdReference(new IdentifierImpl("idRef2_NoVersion"));
+			policySetIdentifier1 = new StdIdReference(new IdentifierImpl("idSetRef1"), StdVersion.newInstance("4.5.6.7.8.9.0"));
+			policySetIdentifier2 = new StdIdReference(new IdentifierImpl("idSetRef2_NoVersion"));
+		} catch (ParseException e1) {
+			fail("creating policyIds, e="+e1);
+		}
+		result.addPolicyIdentifier(policyIdentifier1);
+		result.addPolicyIdentifier(policyIdentifier2);
+		result.addPolicySetIdentifier(policySetIdentifier1);
+		result.addPolicySetIdentifier(policySetIdentifier2);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><PolicyIdentifierList><PolicyIdReference Version=\"1.2.3\">idRef1</PolicyIdReference><PolicyIdReference>idRef2_NoVersion</PolicyIdReference><PolicySetIdReference Version=\"4.5.6.7.8.9.0\">idSetRef1</PolicySetIdReference><PolicySetIdReference>idSetRef2_NoVersion</PolicySetIdReference></PolicyIdentifierList></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// PolicyIdentifier exists but has no IdReferences
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		policyIdentifier1 = null;
+		result.addPolicyIdentifier(policyIdentifier1);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// PolicySetIdentifier exists but has not IdReferences
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		policySetIdentifier1 = null;
+		result.addPolicyIdentifier(policySetIdentifier1);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (DOMStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from object to XML: " + e);
+		}
+		
+		// PolicyIdentifier with PolicyIdReference and no PolicySetIdReference
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		try {
+			policyIdentifier1 = new StdIdReference(new IdentifierImpl("idRef1"), StdVersion.newInstance("1.2.3"));
+		} catch (ParseException e1) {
+			fail("creating policyIds, e="+e1);
+		}
+		result.addPolicyIdentifier(policyIdentifier1);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><PolicyIdentifierList><PolicyIdReference Version=\"1.2.3\">idRef1</PolicyIdReference></PolicyIdentifierList></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+		// PolicyIdentifier with no PolicyIdReference and with PolicySetIdReference
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		try {
+			policySetIdentifier1 = new StdIdReference(new IdentifierImpl("idSetRef1"), StdVersion.newInstance("4.5.6.7.8.9.0"));
+		} catch (ParseException e1) {
+			fail("creating policyIds, e="+e1);
+		}
+		result.addPolicySetIdentifier(policySetIdentifier1);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><PolicyIdentifierList><PolicySetIdReference Version=\"4.5.6.7.8.9.0\">idSetRef1</PolicySetIdReference></PolicyIdentifierList></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// IdReferences without version
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+
+			policyIdentifier1 = new StdIdReference(new IdentifierImpl("idRef1"), null);
+			policyIdentifier2 = new StdIdReference(new IdentifierImpl("idRef2_NoVersion"));
+			policySetIdentifier1 = new StdIdReference(new IdentifierImpl("idSetRef1"));
+			policySetIdentifier2 = new StdIdReference(new IdentifierImpl("idSetRef2_NoVersion"));
+
+		result.addPolicyIdentifier(policyIdentifier1);
+		result.addPolicyIdentifier(policyIdentifier2);
+		result.addPolicySetIdentifier(policySetIdentifier1);
+		result.addPolicySetIdentifier(policySetIdentifier2);
+		response.add(result);
+		try {
+			xmlResponse = DOMResponse.toString(response, false);
+			assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd\"><Result><Decision>Permit</Decision><PolicyIdentifierList><PolicyIdReference>idRef1</PolicyIdReference><PolicyIdReference>idRef2_NoVersion</PolicyIdReference><PolicySetIdReference>idSetRef1</PolicySetIdReference><PolicySetIdReference>idSetRef2_NoVersion</PolicySetIdReference></PolicyIdentifierList></Result></Response>", xmlResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+
+
+//TODO - the XML spec implies that the Result Attributes may include the Content (It is part of the UML)
+	
+	
+	// test indentation???
+	
+	
+}
+
+
+/*
+Place to edit long strings ouput from tests
+
+
+Expected
+<?xml version="1.0" encoding="UTF-8"?><Response xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd"><Result><Decision>Permit</Decision></Result></Response>
+<?xml version="1.0" encoding="UTF-8"?><Response xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17 http://docs.oasis-open.org/xacml/3.0/xacml-core-v3-schema-wd-17.xsd"><Result><Decision>Permit</Decision></Result></Response>
+Actual
+
+
+
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestAnnotation.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestAnnotation.java
new file mode 100644
index 0000000..c5dda8a
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestAnnotation.java
@@ -0,0 +1,239 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.att.research.xacml.api.DataTypeException;
+import com.att.research.xacml.api.Response;
+import com.att.research.xacml.std.annotations.RequestParser;
+import com.att.research.xacml.std.annotations.XACMLAction;
+import com.att.research.xacml.std.annotations.XACMLAttribute;
+import com.att.research.xacml.std.annotations.XACMLEnvironment;
+import com.att.research.xacml.std.annotations.XACMLMultiRequest;
+import com.att.research.xacml.std.annotations.XACMLRequest;
+import com.att.research.xacml.std.annotations.XACMLRequestReference;
+import com.att.research.xacml.std.annotations.XACMLResource;
+import com.att.research.xacml.std.annotations.XACMLSubject;
+import com.att.research.xacml.std.datatypes.HexBinary;
+import com.att.research.xacml.std.datatypes.IPAddress;
+import com.att.research.xacml.std.datatypes.IPv4Address;
+import com.att.research.xacml.std.datatypes.ISO8601DateTime;
+import com.att.research.xacml.std.datatypes.ISO8601Time;
+import com.att.research.xacml.util.FactoryException;
+
+/**
+ * This example application shows how to use annotations for Java classes to create requests to send to the
+ * engine.
+ * 
+ *
+ */
+public class TestAnnotation extends TestBase {
+	private static final Log logger	= LogFactory.getLog(TestAnnotation.class);
+	
+	private int	num;
+	
+	/**
+	 * This is a sample class that uses annotations. In addition to demonstrating how to use XACML annotations,
+	 * it also demonstrates the various Java objects that can be used and how the request parser will
+	 * resolve each object's datatype.
+	 * 
+	 *
+	 */
+	@XACMLRequest(ReturnPolicyIdList=true)
+	public class MyRequestAttributes {
+		
+		public MyRequestAttributes(String user, String action, String resource) {
+			this.userID = user;
+			this.action = action;
+			this.resource = resource;
+			this.today = new Date();
+			this.yesterday = Calendar.getInstance();
+			this.yesterday.add(Calendar.DAY_OF_MONTH, -1);
+		}
+
+		@XACMLSubject(includeInResults=true)
+		String	userID;
+		
+		@XACMLSubject(attributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id-qualifier")
+		boolean admin = false;
+		
+		@XACMLSubject(attributeId="urn:oasis:names:tc:xacml:1.0:subject:key-info", issuer="com:foo:security")
+		HexBinary publicKey = new HexBinary(new byte[] {'1', '0'});
+		
+		@XACMLSubject(attributeId="urn:oasis:names:tc:xacml:1.0:subject:authentication-time")
+		ISO8601Time	authenticationTime = new ISO8601Time(8, 0, 0, 0);
+		
+		/**
+		 * Here our base object is "Object", but it is reflected as a Java "String". The parser
+		 * will then use the XACML http://www.w3.org/2001/XMLSchema#string as the datatype.
+		 */
+		@XACMLSubject(attributeId="urn:oasis:names:tc:xacml:1.0:subject:authentication-method")
+		Object authenticationMethod = new String("RSA Public Key");
+		
+		/**
+		 * Here our base object is "String", but we use the annotation for datatype to clarify
+		 * that the real XACML data type is http://www.w3.org/2001/XMLSchema#time. The parser will
+		 * use the data type factory to convert the "String" to a "ISO8601Time" Java object.
+		 */
+		@XACMLSubject(attributeId="urn:oasis:names:tc:xacml:1.0:subject:request-time", datatype="http://www.w3.org/2001/XMLSchema#time")
+		String requestTime = new String("13:20:00-05:00");
+		
+		@XACMLSubject(attributeId="urn:oasis:names:tc:xacml:1.0:subject:session-start-time")
+		ISO8601DateTime sessionStart = new ISO8601DateTime(TimeZone.getDefault().getID(), 2014, 1, 1, 10, 0, 0, 0);
+		
+		@XACMLSubject(attributeId="urn:oasis:names:tc:xacml:3.0:subject:authn-locality:ip-address")
+		IPAddress ip = new IPv4Address(new short[] {123, 134, 156, 255 }, null, null);
+		
+		@XACMLSubject(attributeId="urn:oasis:names:tc:xacml:3.0:subject:authn-locality:dns-name")
+		String dnsName = "localhost";
+		
+		@XACMLAction()
+		String	action;
+		
+		@XACMLAction(attributeId="urn:oasis:names:tc:xacml:1.0:action:implied-action")
+		long	impliedAction;
+		
+		@XACMLResource()
+		String	resource;
+		
+		@XACMLEnvironment()
+		Date		today;
+		
+		@XACMLEnvironment()
+		Calendar	yesterday;
+		
+		/**
+		 * This field demonstrates how the parser can detect collections and build a bag of values.
+		 */
+		@XACMLAttribute(attributeId="foo:bar:attribute")
+		Collection<Double>		fooBar = Arrays.asList(2.5, 3.5);
+		
+		/**
+		 * The XACMLAttribute annotation allows one to specify all the 
+		 */
+		@XACMLAttribute(category="foo:bar:category", attributeId="foo:bar:attribute2")
+		double		fooBar2 = 3.999;
+		
+		/**
+		 * This field demonstrates how the parser can detect arrays and build a bag of values.
+		 */
+		@XACMLAttribute(category="foo:bar:category", attributeId="foo:bar:attribute:many")
+		URI[]		fooBarMany = new URI[] {URI.create("file://opt/app/test"), URI.create("https://localhost:8443/")};
+		
+	};
+
+	@XACMLRequest(
+		Defaults="http://www.w3.org/TR/1999/Rec-xpath-19991116",
+		multiRequest=@XACMLMultiRequest(values={
+			@XACMLRequestReference(values={"subject1", "action", "resource"}),
+			@XACMLRequestReference(values={"subject2", "action", "resource"})})
+	)
+	public class MyMultiRequestAttributes {
+		
+		@XACMLSubject(id="subject1")
+		String	userID1 = "John";
+		
+		@XACMLSubject(id="subject2")
+		String	userID2 = "Ringo";
+
+		@XACMLAction(id="action")
+		String	action = "access";
+
+		@XACMLResource(id="resource")
+		String	resource = "www.mywebsite.com";
+	}
+
+	public TestAnnotation(String[] args) throws MalformedURLException, ParseException, HelpException {
+		super(args);
+	}
+
+	@Override
+	public void run() throws IOException, FactoryException {
+		//
+		// We are not going to iterate any existing request files. So we will override
+		// any TestBase code that assumes there are request files present.
+		//
+		//
+		// Configure ourselves
+		//
+		this.configure();
+		//
+		// Cycle through creating a few objects
+		//
+		this.num = 0;
+		this.doRequest(new MyRequestAttributes("John", "access", "www.mywebsite.com"));
+		this.num++;
+		this.doRequest(new MyRequestAttributes("Ringo", "access", "www.mywebsite.com"));
+		this.num++;
+		this.doRequest(new MyMultiRequestAttributes());
+		this.num++;
+	}
+
+	private void doRequest(Object info) {
+		try {
+			Response response = this.callPDP(RequestParser.parseRequest(info));
+			Path resultFile;
+			if (this.output != null) {
+				resultFile = Paths.get(this.output.toString(), "Response." + String.format("%03d", this.num) + ".json");
+			} else {
+				resultFile = Paths.get(this.directory, "results", "Response." + String.format("%03d", this.num) + ".json");
+			}
+			//
+			// Write the response to the result file
+			//
+			logger.info("Response is: " + response.toString());
+			if (resultFile != null) {
+				Files.write(resultFile, response.toString().getBytes());
+			}
+		} catch (IllegalArgumentException | IllegalAccessException | DataTypeException | IOException e) {
+			logger.error(e);
+			e.printStackTrace();
+		}
+	}
+	
+	public static void main(String[] args) {
+		try {
+			new TestAnnotation(args).run();
+		} catch (ParseException | IOException | FactoryException e) {
+			logger.error(e);
+		} catch (HelpException e) {
+			//
+			// ignore this, its thrown just to exit the application
+			// after dumping help to stdout.
+			//
+		}		
+	}
+}
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestBase.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestBase.java
new file mode 100644
index 0000000..8f757ab
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestBase.java
@@ -0,0 +1,1082 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.entity.ContentType;
+
+import com.att.research.xacml.api.AttributeValue;
+import com.att.research.xacml.api.DataType;
+import com.att.research.xacml.api.DataTypeException;
+import com.att.research.xacml.api.DataTypeFactory;
+import com.att.research.xacml.api.Decision;
+import com.att.research.xacml.api.Identifier;
+import com.att.research.xacml.api.Request;
+import com.att.research.xacml.api.RequestAttributes;
+import com.att.research.xacml.api.Response;
+import com.att.research.xacml.api.Result;
+import com.att.research.xacml.api.pdp.PDPEngine;
+import com.att.research.xacml.api.pdp.PDPEngineFactory;
+import com.att.research.xacml.api.pdp.PDPException;
+import com.att.research.xacml.api.pep.PEPException;
+import com.att.research.xacml.std.IdentifierImpl;
+import com.att.research.xacml.std.StdAttributeValue;
+import com.att.research.xacml.std.StdMutableAttribute;
+import com.att.research.xacml.std.StdMutableRequest;
+import com.att.research.xacml.std.StdMutableRequestAttributes;
+import com.att.research.xacml.std.dom.DOMRequest;
+import com.att.research.xacml.std.dom.DOMResponse;
+import com.att.research.xacml.std.dom.DOMStructureException;
+import com.att.research.xacml.std.json.JSONRequest;
+import com.att.research.xacml.std.json.JSONResponse;
+import com.att.research.xacml.std.json.JSONStructureException;
+import com.att.research.xacml.util.FactoryException;
+import com.att.research.xacml.util.XACMLProperties;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+
+/**
+ * This is a base class for setting up a test environment. Using properties files, it contains the
+ * necessary information for 
+ * 1. defining and providing attributes
+ * 2. defining and instantiating the PDP engine
+ * 3. creating PEP requests and calling the PDP engine
+ * 
+ *
+ */
+public class TestBase extends SimpleFileVisitor<Path> {
+	private static final Log logger	= LogFactory.getLog(TestBase.class);
+	
+	public class HelpException extends Exception {
+		private static final long serialVersionUID = 1L;
+		
+	}
+	
+	/**
+	 * This private class holds information for properties defined for attribute
+	 * generation. The user can configure the properties file such that attributes
+	 * can be automatically generated and added into each request.
+	 * 
+	 *
+	 */
+	class Generator {
+		Path file;
+		InputStream is;
+		BufferedReader reader;
+		List<StdMutableAttribute> attributes = new ArrayList<StdMutableAttribute>();
+		
+		public Generator(Path path) {
+			this.file = path;
+		}
+
+		/**
+		 * read - reads in the next line of data
+		 * 
+		 * @return	String - a line from the csv containing attribute data
+		 */
+		public String	read() {
+			String str = null;
+			if (is == null) {
+				try {
+					is = Files.newInputStream(file);
+				} catch (IOException e) {
+					logger.error(e);
+					return null;
+				}
+			}
+			if (reader == null) {
+				reader = new BufferedReader(new InputStreamReader(this.is));
+			}
+			try {
+				str = reader.readLine();
+				if (str == null) {
+					//
+					// No more strings, close up
+					//
+					this.close();
+				}
+				if (logger.isDebugEnabled()) {
+					logger.debug(str);
+				}
+			} catch (IOException e) {
+				logger.error(e);
+			}
+			return str;
+		}
+		
+		public void 	close() {
+			if (this.reader != null) {
+				try {
+					this.reader.close();
+				} catch (IOException idontcare) {
+				} finally {
+					this.reader = null;
+					this.is = null;
+				}
+			}
+		}
+		
+	}
+	
+	public static final String PROP_GENERATOR = "xacml.attribute.generator";
+	
+	public static final String OPTION_HELP = "help";
+	public static final String OPTION_TESTDIR = "dir";
+	public static final String OPTION_TESTREST = "rest";
+	public static final String OPTION_TESTURL = "url";
+	public static final String OPTION_TESTOUTPUT = "output";
+	public static final String OPTION_LOOP = "loop";
+	public static final String OPTION_TESTNUMBERS = "testNumbers";
+
+	public static final String DEFAULT_RESTURL = "https://localhost:8080/pdp/";	// Modified for test purpose. Port no. 8443 to 8080
+	
+	public static Options options = new Options();
+	static {
+		options.addOption(new Option(OPTION_HELP, false, "Prints help."));
+		options.addOption(new Option(OPTION_TESTDIR, true, "Directory path where all the test properties and data are located."));
+		options.addOption(new Option(OPTION_TESTREST, false, "Test against RESTful PDP."));
+		options.addOption(new Option(OPTION_TESTURL, true, "URL to the RESTful PDP. Default is " + DEFAULT_RESTURL));
+		options.addOption(new Option(OPTION_TESTOUTPUT, true, "Specify a different location for dumping responses."));
+		options.addOption(new Option(OPTION_LOOP, true, "Number of times to loop through the tests. Default is 1. A value of -1 runs indefinitely."));
+		options.addOption(new Option(OPTION_TESTNUMBERS, true, "Comma-separated list of numbers found in the names of the test files to be run.  Numbers must exactly match the file name, e.g. '02'.  Used to limit testing to specific set of tests."));
+	}
+	
+	protected String directory = null;
+	protected Path output = null;
+	protected boolean isREST;
+	protected URL restURL = null;
+	protected int loop = 1;
+	protected PDPEngine engine = null;
+	protected List<Generator> generators = new ArrayList<Generator>();
+	protected static DataTypeFactory dataTypeFactory		= null;
+	
+	private long	permits = 0;
+	private long	denies = 0;
+	private long	notapplicables = 0;
+	private long	indeterminates = 0;
+	
+	private long	expectedPermits = 0;
+	private long	expectedDenies = 0;
+	private long	expectedNotApplicables = 0;
+	private long	expectedIndeterminates = 0;
+	
+	private long	generatedpermits = 0;
+	private long	generateddenies = 0;
+	private long	generatednotapplicables = 0;
+	private long	generatedindeterminates = 0;
+	
+	private long	responseMatches = 0;
+	private long	responseNotMatches = 0;
+	
+	private String[]	testNumbersArray = null;
+	
+	protected final Pattern pattern = Pattern.compile("Request[.]\\d+[.](Permit|Deny|NA|Indeterminate|Generate|Unknown)\\.(json|xml)");
+	
+	public static boolean isJSON(Path file) {
+		return file.toString().endsWith(".json");
+	}
+	
+	public static boolean isXML(Path file) {
+		return file.toString().endsWith(".xml");
+	}
+	
+	public TestBase(String[] args) throws ParseException, MalformedURLException, HelpException {
+		//
+		// Finish Initialization
+		//
+		this.restURL = new URL(DEFAULT_RESTURL);
+		//
+		// Parse arguments
+		//
+		this.parseCommands(args);
+	}
+	
+	/**
+	 * Parse in the command line arguments that the following parameters:
+	 * 
+	 * @param args - command line arguments
+	 * @throws ParseException 
+	 * @throws MalformedURLException 
+	 * @throws HelpException 
+	 */
+	protected void parseCommands(String[] args) throws ParseException, MalformedURLException, HelpException {
+		//
+		// Parse the command line options
+		//
+		CommandLine cl;
+		cl = new GnuParser().parse(options, args);
+		//
+		// Check for what we have
+		//
+		if (cl.hasOption(OPTION_HELP)) {
+    		new HelpFormatter().printHelp("Usage: -dir testdirectory OPTIONS",
+    				options);
+    		throw new HelpException();
+		}
+		if (cl.hasOption(OPTION_TESTDIR)) {
+			this.directory = cl.getOptionValue(OPTION_TESTDIR);
+		} else {
+			throw new IllegalArgumentException("You must specify a test directory. -dir path/to/some/where");
+		}
+		if (cl.hasOption(OPTION_TESTREST)) {
+			this.isREST = true;
+		} else {
+			this.isREST = false;
+		}
+		if (cl.hasOption(OPTION_TESTURL)) {
+			this.restURL = new URL(cl.getOptionValue(OPTION_TESTURL));
+		}
+		if (cl.hasOption(OPTION_TESTOUTPUT)) {
+			this.output = Paths.get(cl.getOptionValue(OPTION_TESTOUTPUT));
+		} else {
+			this.output = Paths.get(this.directory, "results");
+		}
+		if (cl.hasOption(OPTION_LOOP)) {
+			this.loop = Integer.parseInt(cl.getOptionValue(OPTION_LOOP));
+		}
+		if (cl.hasOption(OPTION_TESTNUMBERS)) {
+			String testNumberString = cl.getOptionValue(OPTION_TESTNUMBERS);
+			testNumbersArray = testNumberString.split(",");
+			//
+			// reset strings to include dots so they exactly match pattern in file name
+			//
+			for (int i = 0; i < testNumbersArray.length; i++) {
+				testNumbersArray[i] = "." + testNumbersArray[i] + ".";
+			}
+		}
+	}
+	
+	/**
+	 * Using the command line options that were parsed, configures our test instance.
+	 * 
+	 * @throws FactoryException
+	 */
+	protected void configure() throws FactoryException {
+		//
+		// Setup the xacml.properties file
+		//
+		if (this.directory == null) {
+			throw new IllegalArgumentException("Must supply a path to a test directory.");
+		}
+		Path pathDir = Paths.get(this.directory, "xacml.properties");
+		if (Files.notExists(pathDir)) {
+			throw new IllegalArgumentException(pathDir.toString() + " does not exist.");
+		}
+		//
+		// Set it as the System variable so the XACML factories know where the properties are
+		// loaded from.
+		//
+		System.setProperty(XACMLProperties.XACML_PROPERTIES_NAME, pathDir.toString());
+		//
+		// Now we can create the data type factory
+		//
+		dataTypeFactory	= DataTypeFactory.newInstance();
+		//
+		// Load in what generators we are to create
+		//
+		String generators = XACMLProperties.getProperty(PROP_GENERATOR);
+		if (generators != null) {
+			//
+			// Parse the generators
+			//
+			for (String generator : Splitter.on(',').trimResults().omitEmptyStrings().split(generators)) {
+				this.configureGenerator(generator);
+			}
+		}
+		//
+		// If we are embedded, create our engine
+		//
+		if (this.isREST == false) {
+			PDPEngineFactory factory = PDPEngineFactory.newInstance();
+			this.engine = factory.newEngine();
+		}
+		//
+		// Remove all the responses from the results directory
+		//
+		this.removeResults();
+	}
+	
+	/**
+	 * Removes all the Response* files from the results directory.
+	 * 
+	 */
+	public void	removeResults() {
+		try {
+			//
+			// Determine where the results are supposed to be written to
+			//
+			Path resultsPath;
+			if (this.output != null) {
+				resultsPath = this.output;
+			} else {
+				resultsPath = Paths.get(this.directory.toString(), "results");
+			}
+			//
+			// Walk the files
+			//
+			Files.walkFileTree(resultsPath, new SimpleFileVisitor<Path>() {
+
+				@Override
+				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+					if (file.getFileName().toString().startsWith("Response")) {
+						Files.delete(file);
+					}
+					return super.visitFile(file, attrs);
+				}				
+			});
+		} catch (IOException e) {
+			logger.error("Failed to removeRequests from " + this.directory + " " + e);
+		}
+	}
+	
+	/**
+	 * Configure's a specific generator instance from the properties file.
+	 * 
+	 * @param generator
+	 */
+	protected void configureGenerator(String generator) {
+		String prefix = PROP_GENERATOR + "." + generator;
+		String file = XACMLProperties.getProperty(prefix + ".file");
+		//
+		// Create a generator object
+		//
+		Generator gen = new Generator(Paths.get(this.directory, file));
+		this.generators.add(gen);
+		//
+		// Grab attributes
+		//
+		String attributes = XACMLProperties.getProperty(prefix + ".attributes");
+		for (String attribute : Splitter.on(',').trimResults().omitEmptyStrings().split(attributes)) {
+			String attributePrefix = prefix + ".attributes." + attribute;
+			//
+			// Create an attribute value. It is simply a placeholder for the field within
+			// the CSV that contains the actual attribute value. It mainly holds the data type
+			//
+			Identifier datatype = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".datatype"));
+			Integer field = Integer.parseInt(XACMLProperties.getProperty(attributePrefix + ".field"));
+			StdAttributeValue<?> value = new StdAttributeValue<>(datatype, field);
+			//
+			// Get the rest of the attribute properties
+			//
+			Identifier category = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".category"));
+			Identifier id = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".id"));
+			String issuer = XACMLProperties.getProperty(attributePrefix + ".issuer");
+			boolean include = Boolean.parseBoolean(XACMLProperties.getProperty(attributePrefix + ".include", "false"));
+			//
+			// Now we have a skeleton attribute
+			//
+			gen.attributes.add(new StdMutableAttribute(category, id, value, issuer, include));
+		}
+	}
+	
+	/**
+	 * This runs() the test instance. It first configure's itself and then walks the
+	 * requests directory issue each request to the PDP engine.
+	 * 
+	 * @throws IOException
+	 * @throws FactoryException 
+	 * 
+	 */
+	public void run() throws IOException, FactoryException {
+		//
+		// Configure ourselves
+		//
+		this.configure();
+		//
+		// Loop and run
+		//
+		int runs = 1;
+		do {
+			long lTimeStart = System.currentTimeMillis();
+			logger.info("Run number: " + runs);
+			//
+			// Walk the request directory
+			//
+			Files.walkFileTree(Paths.get(this.directory.toString(), "requests"), this);
+			long lTimeEnd = System.currentTimeMillis();
+			logger.info("Run elapsed time: " + (lTimeEnd - lTimeStart) + "ms");
+			//
+			// Dump the stats
+			//
+			this.dumpStats();
+			this.resetStats();
+			//
+			// Increment
+			//
+			runs++;
+		} while ((this.loop == -1 ? true : runs <= this.loop));
+	}
+	
+	@Override
+	public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+		//
+		// Sanity check the file name
+		//
+		Matcher matcher = this.pattern.matcher(file.getFileName().toString());
+		if (matcher.matches()) {
+			//
+			// if user has limited which files to use, check that here
+			//
+			if (testNumbersArray != null) {
+				String fileNameString = file.getFileName().toString();
+				boolean found = false;
+				for (String numberString : testNumbersArray) {
+					if (fileNameString.contains(numberString)) {
+						found = true;
+						break;
+					}
+				}
+				if (found == false) {
+					//
+					// this test is not in the list to be run, so skip it
+					//
+					return super.visitFile(file, attrs);
+				}
+			}
+			try {
+				//
+				// Pull what this request is supposed to be
+				//
+				String group = null;
+				int count = matcher.groupCount();
+				if (count >= 1) {
+					group = matcher.group(count-1);
+				}
+				//
+				// Send it
+				//
+				this.sendRequest(file, group);
+			} catch (Exception e) {
+				logger.error(e);
+				e.printStackTrace();
+			}
+		}
+		return super.visitFile(file, attrs);
+	}
+	
+	/**
+	 * When a request file is encountered, this method is called send the request to the PDP engine. It will also dump
+	 * the response object. If the group equals "Generate", then it will loop and send the request with generated attributes
+	 * until that list is empty.
+	 * 
+	 * @param file - Request file. Eg. Request-01-Permit.json
+	 * @param group - This is the parsed out string of the request file that defines if it is a Permit/Deny/Generate etc.
+	 * @throws Exception
+	 */
+	protected void sendRequest(Path file, String group) throws Exception {
+		logger.info(file.toString());
+		int requestCount = 0;
+		do {
+			//
+			// Generate the request
+			//
+			Request request = this.generateRequest(file, group);
+			//
+			// Was something generated?
+			//
+			if (request == null) {
+				//
+				// Get out of the loop
+				//
+				logger.info("NULL request generated.");
+				break;
+			}
+			logger.info(request);
+			//
+			// Call the PDP
+			//
+			Response response = this.callPDP(request);
+			//
+			// Process the response
+			//
+			this.processResponse(file, request, response, group, requestCount);
+			//
+			// Is this a generated request?
+			//
+			if (group.equals("Generate")) {
+				//
+				// Yes, increment counter and move
+				// on to the next generated request.
+				//
+				requestCount++;
+			} else {
+				//
+				// Nope, exit the loop
+				//
+				break;
+			}
+		} while (group.equals("Generate"));
+	}
+	
+	/**
+	 * Sends the request object to the PDP engine. Either the embedded engine or the RESTful engine.
+	 * 
+	 * @param request - XACML request object
+	 * @return Response - returns the XACML response object
+	 */
+	protected Response callPDP(Request request) {
+		//
+		// Send it to the PDP
+		//
+		Response response = null;
+		if (this.isREST) {
+			try {
+				String jsonString = JSONRequest.toString(request, false);
+				//
+				// Call RESTful PDP
+				//
+				response = this.callRESTfulPDP(new ByteArrayInputStream(jsonString.getBytes()));
+			} catch (Exception e) {
+				logger.error("Error in sending RESTful request: " + e, e);
+			}
+		} else {
+			//
+			// Embedded call to PDP
+			//
+			long lTimeStart = System.currentTimeMillis();
+			try {
+				response = this.engine.decide(request);
+			} catch (PDPException e) {
+				logger.error(e);
+			}
+			long lTimeEnd = System.currentTimeMillis();
+			logger.info("Elapsed Time: " + (lTimeEnd - lTimeStart) + "ms");
+		}
+		return response;
+	}
+	
+	/**
+	 * Reads the request file into a Request object based on its type.
+	 * 
+	 * If the request has "Generate" in its filename, then this function will add
+	 * generated attributes into the request.
+	 * 
+	 * @param file - Request file. Eg. Request-01-Permit.json
+	 * @param group - This is the parsed out string of the request file that defines if it is a Permit/Deny/Generate etc.
+	 * @return
+	 * @throws JSONStructureException
+	 * @throws DOMStructureException
+	 * @throws PEPException
+	 */
+	protected Request generateRequest(Path file, String group) throws JSONStructureException, DOMStructureException, PEPException {
+		//
+		// Convert to a XACML Request Object
+		//
+		Request request = null;
+		if (TestBase.isJSON(file)) {
+			request = JSONRequest.load(file.toFile());
+		} else if (TestBase.isXML(file)) {
+			request = DOMRequest.load(file.toFile());
+		}
+		if (request == null) {
+			throw new PEPException("Invalid Request File: " + file.toString());
+		}
+		//
+		// Only if this request has "Generate"
+		// Request.XX.Generate.[json|xml]
+		//
+		if (group.equals("Generate")) {
+			//
+			// Add attributes to it
+			//
+			request = this.onNextRequest(request);
+		}
+		//
+		// Done
+		//
+		return request;
+	}
+
+	/**
+	 * Called to add in generated attributes into the request.
+	 * 
+	 * @param request
+	 * @return
+	 */
+	protected Request onNextRequest(Request request) {
+		//
+		// If we have no generators, just return
+		//
+		if (this.generators.isEmpty()) {
+			return request;
+		}
+		//
+		// Copy the request attributes
+		//
+		List<StdMutableRequestAttributes> attributes = new ArrayList<StdMutableRequestAttributes>();
+		for (RequestAttributes a : request.getRequestAttributes()) {
+			attributes.add(new StdMutableRequestAttributes(a));
+		}
+		//
+		// Iterate the generators
+		//
+		for (Generator generator : this.generators) {
+			//
+			// Read a row in
+			//
+			String line = generator.read();
+			//
+			// Was something read?
+			//
+			if (line == null) {
+				//
+				// No more rows to read, return null
+				//
+				return null;
+			}
+			//
+			// Split the line
+			//
+			List<String> fields = Lists.newArrayList(Splitter.on(',').trimResults().split(line));
+			//
+			// Now work on the attributes
+			//
+			for (StdMutableAttribute attribute : generator.attributes) {
+				//
+				// Grab the attribute holder, which holds the datatype and field. There should
+				// be only ONE object in the collection.
+				//
+				AttributeValue<?> value = attribute.getValues().iterator().next();
+				Integer field = (Integer) value.getValue();
+				//
+				// Is the field number valid?
+				//
+				if (field >= fields.size()) {
+					logger.error("Not enough fields: " + field + "(" + fields.size() + ")");
+					return null;
+				}
+				//
+				// Determine what datatype it is
+				//
+				DataType<?> dataTypeExtended	= dataTypeFactory.getDataType(value.getDataTypeId());
+				if (dataTypeExtended == null) {
+					logger.error("Failed to determine datatype");
+					return null;
+				}
+				//
+				// Create the attribute value
+				//
+				try {
+					AttributeValue<?> attributeValue = dataTypeExtended.createAttributeValue(fields.get(field));					
+					//
+					// Create the attribute
+					//
+					StdMutableAttribute newAttribute = new StdMutableAttribute(attribute.getCategory(),
+																				attribute.getAttributeId(),
+																				attributeValue,
+																				attribute.getIssuer(),
+																				attribute.getIncludeInResults());
+					boolean added = false;
+					for (StdMutableRequestAttributes a : attributes) {
+						//
+						// Does the category exist?
+						//
+						if (a.getCategory().equals(attribute.getCategory())) {
+							//
+							// Yes - add in the new attribute value
+							//
+							a.add(newAttribute);
+							added = true;
+							break;
+						}
+					}
+					if (added == false) {
+						//
+						// New category - create it and add it in
+						//
+						StdMutableRequestAttributes a = new StdMutableRequestAttributes(); 
+						a.setCategory(newAttribute.getCategory());
+						a.add(newAttribute);
+						attributes.add(a);
+					}
+				} catch (DataTypeException e) {
+					logger.error(e);
+					return null;
+				}
+			}
+		}
+		//
+		// Now form our final request
+		//
+		StdMutableRequest newRequest = new StdMutableRequest();
+		newRequest.setCombinedDecision(request.getCombinedDecision());
+		newRequest.setRequestDefaults(request.getRequestDefaults());
+		newRequest.setReturnPolicyIdList(request.getReturnPolicyIdList());
+		newRequest.setStatus(request.getStatus());
+		for (StdMutableRequestAttributes a : attributes) {
+			newRequest.add(a);
+		}
+		return newRequest;
+	}
+
+	/**
+	 * This makes an HTTP POST call to a running PDP RESTful servlet to get a decision.
+	 * 
+	 * @param file
+	 * @return
+	 */
+	protected Response callRESTfulPDP(InputStream is) {
+		Response response = null;
+		HttpURLConnection connection = null;
+		try {
+
+			//
+			// Open up the connection
+			//
+			connection = (HttpURLConnection) this.restURL.openConnection();
+			connection.setRequestProperty("Content-Type", "application/json");
+			//
+			// Setup our method and headers
+			//
+            connection.setRequestMethod("POST");
+            connection.setUseCaches(false);
+            //
+            // Adding this in. It seems the HttpUrlConnection class does NOT
+            // properly forward our headers for POST re-direction. It does so
+            // for a GET re-direction.
+            //
+            // So we need to handle this ourselves.
+            //
+            connection.setInstanceFollowRedirects(false);
+			connection.setDoOutput(true);
+			connection.setDoInput(true);
+			//
+			// Send the request
+			//
+			try (OutputStream os = connection.getOutputStream()) {
+				IOUtils.copy(is, os);
+			}
+            //
+            // Do the connect
+            //
+            connection.connect();
+            if (connection.getResponseCode() == 200) {
+            	//
+            	// Read the response
+            	//
+        		ContentType contentType = null;
+        		try {
+        			contentType = ContentType.parse(connection.getContentType());
+        			
+        			if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType())) {
+                		response = JSONResponse.load(connection.getInputStream());
+        			} else if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
+        					contentType.getMimeType().equalsIgnoreCase("application/xacml+xml") ) {
+                		response = DOMResponse.load(connection.getInputStream());
+        			} else {
+                		logger.error("unknown content-type: " + contentType);
+                	}
+
+                } catch (Exception e) {
+        			String message = "Parsing Content-Type: " + connection.getContentType() + ", error=" + e.getMessage();
+        			logger.error(message, e);
+        		}
+
+            } else {
+            	logger.error(connection.getResponseCode() + " " + connection.getResponseMessage());
+            }
+		} catch (Exception e) {
+			logger.error(e);
+		}
+		
+		return response;
+	}
+	
+	/**
+	 * This processes a response. Saves the response out to disk. If there is a corresponding response file for the request located
+	 * in the "responses" sub-directory, then this method will compare that response file with what the engine returned to see if it
+	 * matched.
+	 * 
+	 * @param requestFile
+	 * @param request
+	 * @param response
+	 * @param group
+	 * @param count
+	 * @throws Exception
+	 */
+	protected void processResponse(Path requestFile, Request request, Response response, String group, int count) throws Exception {
+		//
+		// Construct the output filename
+		//
+		Path responseFile = null;
+		Path resultFile = null;
+		int num = requestFile.getNameCount();
+		if (num < 2) {
+			logger.error("Too few dir's in request filename.");
+			throw new Exception("Too few dir's in request filename. Format should be Request.[0-9]+.{Permit|Deny|NA|Indeterminate}.{json|xml}");
+		}
+		String filename = requestFile.getFileName().toString();
+		if (group.equals("Generate")) {
+			//
+			// Using count variable, construct a filename
+			//
+			//		i.e. Response.03.Generate.{count}.json
+			//
+			filename = "Response" + filename.substring(filename.indexOf('.'), filename.lastIndexOf('.')) + String.format("%03d", count) + filename.substring(filename.lastIndexOf('.'));
+		} else {
+			//
+			// Construct filename
+			//
+			filename = "Response" + filename.substring(filename.indexOf('.'));
+		}
+		//
+		// Determine equivalent response file path
+		//
+		responseFile = Paths.get(requestFile.subpath(0, num - 2).toString(), "responses");
+		if (Files.notExists(responseFile)) {
+			//
+			// Create it
+			//
+			logger.warn(responseFile.toString() + " does NOT exist, creating...");
+			try {
+				Files.createDirectories(responseFile);
+			} catch (IOException e) {
+				logger.error(e);
+				throw new Exception("Cannot proceed without an output directory.");
+			}
+		}
+		responseFile = Paths.get(responseFile.toString(), filename);
+		//
+		// Determine path to write result file
+		//
+		if (this.output != null) {
+			//
+			// User specified an output path
+			//
+			resultFile = this.output;
+		} else {
+			//
+			// Default path
+			//
+			resultFile = Paths.get(requestFile.subpath(0, num - 2).toString(), "results");
+		}
+		//
+		// Check if the path exists
+		//
+		if (Files.notExists(resultFile)) {
+			//
+			// Create it
+			//
+			logger.warn(resultFile.toString() + " does NOT exist, creating...");
+			try {
+				Files.createDirectories(resultFile);
+			} catch (IOException e) {
+				logger.error(e);
+				throw new Exception("Cannot proceed without an output directory.");
+			}
+		}
+		//
+		// Add the filename to the path
+		//
+		resultFile = Paths.get(resultFile.toString(), filename);
+		//
+		// Check if there is an equivalent response in the response
+		// directory. If so, compare our response result with that one.
+		//
+		boolean succeeded = true;
+		if (responseFile != null && Files.exists(responseFile)) {
+			//
+			// Do comparison
+			//
+			Response expectedResponse = null;
+			if (TestBase.isJSON(responseFile)) {
+				expectedResponse = JSONResponse.load(responseFile);
+			} else if (TestBase.isXML(responseFile)) {
+				expectedResponse = DOMResponse.load(responseFile);
+			}
+			if (expectedResponse != null) {
+				//
+				// Do the compare
+				//
+				if (response == null) {
+					logger.error("NULL response returned.");
+					this.responseNotMatches++;
+					succeeded = false;
+				} else {
+					if (response.equals(expectedResponse)) {
+						logger.info("Response matches expected response.");
+						this.responseMatches++;
+					} else {
+						logger.error("Response does not match expected response.");
+						logger.error("Expected: ");
+						logger.error(expectedResponse.toString());
+						this.responseNotMatches++;
+						succeeded = false;
+					}
+				}
+			}
+		}
+		//
+		// Write the response to the result file
+		//
+		logger.info("Request: " + requestFile.getFileName() + " response is: " + (response == null ? "null" : response.toString()));
+		if (resultFile != null && response != null) {
+			if (TestBase.isJSON(resultFile)) {
+				Files.write(resultFile, JSONResponse.toString(response, true).getBytes());
+			} else if (TestBase.isXML(resultFile)) {
+				Files.write(resultFile, DOMResponse.toString(response, true).getBytes());
+			}
+		}
+		//
+		// Stats
+		//		
+		if (group.equals("Permit")) {
+			this.expectedPermits++;
+		} else if (group.equals("Deny")) {
+			this.expectedDenies++;
+		} else if (group.equals("NA")) {
+			this.expectedNotApplicables++;
+		} else if (group.equals("Indeterminate")) {
+			this.expectedIndeterminates++;
+		}
+		if (response != null) {
+			for (Result result : response.getResults()) {
+				Decision decision = result.getDecision();
+				if (group.equals("Generate")) {
+					if (decision.equals(Decision.PERMIT)) {
+						this.generatedpermits++;
+					} else if (decision.equals(Decision.DENY)) {
+						this.generateddenies++;
+					} else if (decision.equals(Decision.NOTAPPLICABLE)) {
+						this.generatednotapplicables++;
+					} else if (decision.equals(Decision.INDETERMINATE)) {
+						this.generatedindeterminates++;
+					}
+					continue;
+				}
+				if (decision.equals(Decision.PERMIT)) {
+					this.permits++;
+					if (group.equals("Permit") == false) {
+						succeeded = false;
+						logger.error("Expected " + group + " got " + decision);
+					}
+				} else if (decision.equals(Decision.DENY)) {
+					this.denies++;
+					if (group.equals("Deny") == false) {
+						succeeded = false;
+						logger.error("Expected " + group + " got " + decision);
+					}
+				} else if (decision.equals(Decision.NOTAPPLICABLE)) {
+					this.notapplicables++;
+					if (group.equals("NA") == false) {
+						succeeded = false;
+						logger.error("Expected " + group + " got " + decision);
+					}
+				} else if (decision.equals(Decision.INDETERMINATE)) {
+					this.indeterminates++;
+					if (group.equals("Indeterminate") == false) {
+						succeeded = false;
+						logger.error("Expected " + group + " got " + decision);
+					}
+				}
+			}
+		}
+		if (succeeded) {
+			logger.info("REQUEST SUCCEEDED");
+		} else {
+			logger.info("REQUEST FAILED");
+		}
+	}
+
+	protected void	dumpStats() {
+		StringBuilder dump = new StringBuilder();
+		dump.append(System.lineSeparator());
+		dump.append("Permits: " + this.permits + " Expected: " + this.expectedPermits);
+		dump.append(System.lineSeparator());
+		dump.append("Denies: " + this.denies + " Expected: " + this.expectedDenies);
+		dump.append(System.lineSeparator());
+		dump.append("NA: " + this.notapplicables + " Expected: " + this.expectedNotApplicables);
+		dump.append(System.lineSeparator());
+		dump.append("Indeterminates: " + this.indeterminates + " Expected: " + this.expectedIndeterminates);
+		dump.append(System.lineSeparator());
+		dump.append("Generated Permits: " + this.generatedpermits);
+		dump.append(System.lineSeparator());
+		dump.append("Generated Denies: " + this.generateddenies);
+		dump.append(System.lineSeparator());
+		dump.append("Generated NA: " + this.generatednotapplicables);
+		dump.append(System.lineSeparator());
+		dump.append("Generated Indeterminates: " + this.generatedindeterminates);
+		dump.append(System.lineSeparator());
+		dump.append("Responses Matched: " + this.responseMatches);
+		dump.append(System.lineSeparator());
+		dump.append("Responses NOT Matched: " + this.responseNotMatches);
+		
+		if (this.permits != this.expectedPermits ||
+			this.denies != this.expectedDenies ||
+			this.notapplicables != this.expectedNotApplicables ||
+			this.indeterminates != this.expectedIndeterminates ||
+			this.responseNotMatches > 0) {
+			logger.fatal(dump.toString());
+		} else {
+			logger.info(dump.toString());
+		}
+	}
+	
+	protected void	resetStats() {
+		this.permits = 0;
+		this.denies = 0;
+		this.notapplicables = 0;
+		this.indeterminates = 0;
+		this.generatedpermits = 0;
+		this.generateddenies = 0;
+		this.generatednotapplicables = 0;
+		this.generatedindeterminates = 0;
+		this.responseMatches = 0;
+		this.responseNotMatches = 0;
+	}
+
+	public static void main(String[] args) {
+		try {
+			new TestBase(args).run();
+		} catch (ParseException | IOException | FactoryException e) {
+			logger.error(e);
+		} catch (HelpException e) {
+		}		
+	}
+}
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestPolicy.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestPolicy.java
new file mode 100644
index 0000000..9838559
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/TestPolicy.java
@@ -0,0 +1,792 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Marshaller;
+
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributesType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.RequestType;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.att.research.xacml.api.AttributeValue;
+import com.att.research.xacml.api.DataType;
+import com.att.research.xacml.api.DataTypeException;
+import com.att.research.xacml.api.DataTypeFactory;
+import com.att.research.xacml.api.Identifier;
+import com.att.research.xacml.api.XACML3;
+import com.att.research.xacml.std.IdentifierImpl;
+import com.att.research.xacml.util.FactoryException;
+import com.att.research.xacml.util.XACMLObjectCopy;
+import com.att.research.xacml.util.XACMLPolicyAggregator;
+import com.att.research.xacml.util.XACMLPolicyScanner;
+import com.att.research.xacml.util.XACMLProperties;
+
+/**
+ * This class reads the policy in and extracts all the attributes and their values that is contained
+ * in the Policy. It then generates a request every single combination of attributes found.
+ * 
+ * The attributes mostly come from the Target Match elements, since they have both an attribute designator/selector
+ * matched with an attribute value.
+ * 
+ *
+ */
+public class TestPolicy extends TestBase {
+	private static Log logger	= LogFactory.getLog(TestPolicy.class);
+
+	private boolean skip;
+	private Path policy;
+	private XACMLPolicyAggregator aggregator = new XACMLPolicyAggregator();
+	private long index;
+	
+	//
+	// Our command line parameters
+	//
+	public static final String OPTION_POLICY = "policy";
+	public static final String OPTION_SKIP_GENERATE = "skip";
+
+	static {
+		options.addOption(new Option(OPTION_POLICY, true, "Path to the policy file."));
+		options.addOption(new Option(OPTION_SKIP_GENERATE, false, "Skip generating requests."));
+	}
+	
+	public class FlattenerObject {
+		Identifier category;
+		Identifier datatype;
+		Identifier attribute;
+		Set<AttributeValue<?>> values;
+	}
+	
+	/**
+	 * This application exercises a policy by producing ALL the possible request combinations for a policy.
+	 * 
+	 * -policy Path to a policy file
+	 * 
+	 * @param args
+	 * @throws HelpException 
+	 * @throws ParseException 
+	 * @throws MalformedURLException 
+	 */
+
+	public TestPolicy(String[] args) throws MalformedURLException, ParseException, HelpException {
+		super(args);
+	}
+
+	/* 
+	 * Look for the -policy command line argument. This application needs a pointer to a specific policy
+	 * in order to run.
+	 * 
+	 * 
+	 * (non-Javadoc)
+	 * @see com.att.research.xacmlatt.pdp.test.TestBase#parseCommands(java.lang.String[])
+	 */
+	@Override
+	protected void parseCommands(String[] args) throws ParseException, MalformedURLException, HelpException {
+		//
+		// Have our super do its job
+		//
+		super.parseCommands(args);
+		//
+		// Look for the policy option
+		//
+		CommandLine cl;
+		cl = new GnuParser().parse(options, args);
+		if (cl.hasOption(OPTION_POLICY)) {
+			this.policy = Paths.get(cl.getOptionValue(OPTION_POLICY));
+			//
+			// Ensure it exists
+			//
+			if (Files.notExists(this.policy)) {
+				throw new ParseException("Policy file does not exist.");
+			}
+		} else {
+			throw new ParseException("You need to specify the policy file to be used.");
+		}
+		if (cl.hasOption(OPTION_SKIP_GENERATE)) {
+			this.skip = true;
+		} else {
+			this.skip = false;
+		}
+	}
+
+	/* 
+	 * We override this method because here is where we want to scan the policy and aggregate all
+	 * the attributes that are defined within the policy. This routine will then dump all the possible
+	 * requests into the requests sub-directory. Thus, when this method returns the TestBase can proceed
+	 * to iterate each generated request and run it against the PDP engine.
+	 * 
+	 * (non-Javadoc)
+	 * @see com.att.research.xacmlatt.pdp.test.TestBase#configure()
+	 */
+	@Override
+	protected void configure() throws FactoryException {
+		//
+		// Have our base class do its thing
+		//
+		super.configure();
+		//
+		// Setup where the PDP can find the policy
+		//
+		System.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "policy");
+		System.setProperty("policy.file", this.policy.toString());
+		//
+		// Determine if they want us to skip generation. This helps when a huge number of
+		// requests will get generated for a policy and can take some time to do so. The user
+		// can generate the requests once and then start testing a policy against the requests. Thus,
+		// the attributes never changed but the policy logic did (saves time).
+		//
+		if (this.skip) {
+			return;
+		}
+		//
+		// Now we will scan the policy and get all the attributes.
+		//
+		XACMLPolicyScanner scanner = new XACMLPolicyScanner(this.policy, this.aggregator);
+		//
+		// The scanner returns us a policy object
+		//
+		Object policyObject = scanner.scan();
+		//
+		// Just dump some info
+		//
+		if (policyObject instanceof PolicySetType) {
+			logger.info("Creating requests for policyset: " + ((PolicySetType)policyObject).getDescription());
+		} else if (policyObject instanceof PolicyType) {
+			logger.info("Creating requests for policy: " + ((PolicyType)policyObject).getDescription());
+		}
+		//
+		// Call the function to create the requests
+		//
+		if (policyObject != null) {
+			this.createRequests();
+		}
+
+		logger.info("Completed Generating requests.");
+	}
+
+	@SuppressWarnings("unchecked")
+	protected void createRequests() {
+		//
+		// Clear out our request directory
+		//
+		this.removeRequests();
+		//
+		// Get our map
+		//
+		Map<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> attributeMap = this.aggregator.getAttributeMap();
+		//
+		// We're going to create an initial flat list of requests for each unique attribute ID. Unique being the
+		// category, datatype and attribute id.
+		//
+		// By flattening the list, it makes it easier to then generate all the combinations of possible requests.
+		//
+		List<FlattenerObject> attributes = new ArrayList<FlattenerObject>();
+		//
+		// Iterate through all the maps, we are going to flatten it
+		// out into an array list.
+		//
+		for (Map.Entry<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> categoryEntry : attributeMap.entrySet()) {
+			String category = categoryEntry.getKey().toString();
+			if (logger.isDebugEnabled()) {
+				logger.debug("Category: " + category);
+			}
+			Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>> datatypeMap = categoryEntry.getValue();
+			for (Map.Entry<Identifier, Map<Identifier, Set<AttributeValue<?>>>> datatypeEntry : datatypeMap.entrySet()) {
+				String datatype = datatypeEntry.getKey().toString();
+				if (logger.isDebugEnabled()) {
+					logger.debug("\tData Type: " + datatype);
+				}
+				Map<Identifier, Set<AttributeValue<?>>> attributeIDMap = datatypeEntry.getValue();
+				for (Map.Entry<Identifier, Set<AttributeValue<?>>> attributeIDEntry : attributeIDMap.entrySet()) {
+					String attributeID = attributeIDEntry.getKey().toString();
+					if (logger.isDebugEnabled()) {
+						logger.debug("\t\tAttribute ID: " + attributeID);
+					}
+					Set<AttributeValue<?>> attributeValueSet = attributeIDEntry.getValue();
+					//
+					// Sanity check to see if there are any values. Sometimes there isn't if an attribute
+					// is a designator that is part of a condition or variable.
+					//
+					if (attributeValueSet.isEmpty()) {
+						if (logger.isDebugEnabled()) {
+							logger.debug("No values for attribute " + attributeIDEntry.getKey().stringValue());
+						}
+						//
+						// Check for the boolean datatype, in that case we can safely
+						// assume the true/false are ALL the possible values.
+						//
+						if (datatypeEntry.getKey().equals(XACML3.ID_DATATYPE_BOOLEAN) == false) {
+							//
+							// Not boolean, so skip it
+							//
+							continue;
+						}
+						if (logger.isDebugEnabled()) {
+							logger.debug("No values but its a boolean datatype, we will include it anyway.");
+						}
+					}
+					//
+					// Create our flattener object
+					//
+					FlattenerObject flat = new FlattenerObject();
+					flat.category = categoryEntry.getKey();
+					flat.datatype = datatypeEntry.getKey();
+					flat.attribute = attributeIDEntry.getKey();
+					flat.values = new HashSet<AttributeValue<?>>();
+					if (datatypeEntry.getKey().equals(XACML3.ID_DATATYPE_BOOLEAN)) {
+						//
+						// There are only 2 possible values, true or false
+						//
+						flat.values.add(this.createAttributeValue(flat.datatype, true));
+						flat.values.add(this.createAttributeValue(flat.datatype, false));
+					} else {
+						flat.values.addAll(attributeValueSet);
+					}
+					attributes.add(flat);
+				}
+			}
+		}
+		if (attributes.size() <= 1) {
+			//
+			// Only one attribute, why bother
+			//
+			logger.info("Not enough attributes in policy: " + attributes.size());
+			return;
+		}
+		/*
+		 * PLD work more on this later. This combinatorial formula is only accurate if each
+		 * attribute has one value.
+		 * 
+		 */
+		if (logger.isDebugEnabled()) {
+			//
+			// This isn't really accurate, if an attribute has more than one value
+			//
+			logger.debug(attributes.size() + " will generate " + computePossibleCombinations(attributes.size()));
+		}
+		this.index = 1;
+		for (int i = 0; i < attributes.size(); i++) {
+			FlattenerObject flat = attributes.get(i);
+			for (AttributeValue<?> value : flat.values) {
+				//
+				// Create a basic request object for just that attribute value.
+				//
+				RequestType request = new RequestType();
+				//
+				AttributesType attrs = new AttributesType();
+				attrs.setCategory(flat.category.stringValue());
+				request.getAttributes().add(attrs);
+				//
+				AttributeType attr = new AttributeType();
+				attr.setAttributeId(flat.attribute.stringValue());
+				attrs.getAttribute().add(attr);
+				//
+				AttributeValueType val = new AttributeValueType();
+				val.setDataType(flat.datatype.stringValue());
+				if (value.getValue() instanceof Collection) {
+					val.getContent().addAll((Collection<? extends Object>) value.getValue());
+				} else {
+					val.getContent().add(value.getValue().toString());
+				}
+				//
+				attr.getAttributeValue().add(val);
+				//
+				// Dump it out
+				//
+				this.writeRequest(request);
+				//
+				// Initiate recursive call to add other attributes to the request
+				//
+				this.recursivelyGenerateRequests(request, i + 1, attributes);
+			}
+		}
+	}
+	
+	protected void recursivelyGenerateRequests(RequestType request, int i, List<FlattenerObject> attributes) {
+		if (logger.isTraceEnabled()) {
+			logger.trace("recursiveGenerate index: " + index + " i: " + i);
+		}
+		for ( ; i < attributes.size(); i++) {
+			FlattenerObject flat = attributes.get(i);
+			for (AttributeValue<?> value : flat.values) {
+				//
+				// Make a copy of the request
+				//
+				RequestType copyRequest = XACMLObjectCopy.deepCopy(request);
+				//
+				// Create the value object
+				//
+				AttributeValueType newValue = new AttributeValueType();
+				newValue.setDataType(flat.datatype.stringValue());
+				if (value.getValue() instanceof Collection) {
+					for (Object v : (Collection<?>) value.getValue()) {
+						newValue.getContent().add(v.toString());
+					}
+				} else {
+					newValue.getContent().add(value.getValue().toString());
+				}
+				//
+				// Add the value to the request
+				//
+				this.addAttribute(copyRequest, flat.category.stringValue(), flat.attribute.stringValue(), newValue);
+				//
+				// Now write it out
+				//
+				this.writeRequest(copyRequest);
+				//
+				// Recursively go through the rest of the attributes
+				//
+				this.recursivelyGenerateRequests(copyRequest, i + 1, attributes);
+			}
+		}
+	}
+	
+	public static long	computePossibleCombinations(long numberOfAttributes) {
+		long num = 0;
+		for (long i = numberOfAttributes; i > 0; i--) {
+			num += computeCombinations(numberOfAttributes, i);
+		}
+		return num;
+	}
+	
+	public static long	computeFactorial(long n) {
+		long fact = 1;
+		for (long i = 1; i <= n; i++) {
+			fact *= i;
+		}
+		return fact;
+	}
+
+	public static long	computePermutationsWithoutRepetition(long n, long r) {
+		//
+		//      n!
+		//	---------
+		//   (n - r)!
+		//
+		long nPrime = 1;
+		long n_rPrime = 1;
+		for (long i = n; i > 1; i--) {
+			nPrime *= i; 
+		}
+		
+		for (long i = (n - r); i > 1; i--) {
+			n_rPrime *= i; 
+		}
+		return nPrime / n_rPrime;
+	}
+	
+	public static long	computeCombinations(long n, long r) {
+		//
+		//		 n!
+		//	-----------
+		//  r! * (n-r)!
+		//
+		long nPrime = 1;
+		long rPrime = 1;
+		long n_rPrime = 1;
+		
+		for (long i = n; i > 1; i--) {
+			nPrime *= i; 
+		}
+		
+		for (long i = r; i > 1; i--) {
+			rPrime *= i; 
+		}
+		
+		for (long i = (n - r); i > 1; i--) {
+			n_rPrime *= i; 
+		}
+		
+		return nPrime / (rPrime * n_rPrime);
+	}
+
+	protected Set<AttributeValue<?>> getAttributeValues(RequestType request) {
+		//
+		// Get our map
+		//
+		Map<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> attributeMap = this.aggregator.getAttributeMap();
+		//
+		// Find the attribute
+		//
+		AttributesType attrs = request.getAttributes().get(0);
+		Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>> categoryMap = attributeMap.get(new IdentifierImpl(attrs.getCategory()));
+		if (categoryMap != null) {
+			AttributeType a = attrs.getAttribute().get(0);
+			Map<Identifier, Set<AttributeValue<?>>> datatypeMap = categoryMap.get(new IdentifierImpl(a.getAttributeValue().get(0).getDataType()));
+			if (datatypeMap != null) {
+				Set<AttributeValue<?>> values = datatypeMap.get(new IdentifierImpl(a.getAttributeId()));
+				if (values != null) {
+					return values;
+				}
+			}
+		}
+		return Collections.emptySet();
+	}
+	
+	protected AttributeValue<?> createAttributeValue(Identifier datatype, Object value) {
+		DataTypeFactory dataTypeFactory		= null;
+		try {
+			dataTypeFactory	= DataTypeFactory.newInstance();
+			if (dataTypeFactory == null) {
+				logger.error("Could not create data type factory");
+				return null;
+			}
+		} catch (FactoryException e) {
+			logger.error("Can't get Data type Factory: " + e.getLocalizedMessage());
+			return null;
+		}		
+		DataType<?> dataTypeExtended	= dataTypeFactory.getDataType(datatype);
+		if (dataTypeExtended == null) {
+			logger.error("Unknown datatype: " + datatype);
+			return null;
+		}
+		try {
+			return dataTypeExtended.createAttributeValue(value);
+		} catch (DataTypeException e) {
+			logger.error(e);
+		}
+		return null;
+	}
+	
+	protected void removeRequests() {
+		//
+		// Delete any existing request files that we generate. i.e. Have the Unknown in the file name.
+		//
+		try {
+			Files.walkFileTree(Paths.get(this.directory.toString(), "requests"), new SimpleFileVisitor<Path>() {
+
+				@Override
+				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+					//
+					// Sanity check the file name
+					//
+					Matcher matcher = pattern.matcher(file.getFileName().toString());
+					if (matcher.matches()) {
+						try {
+							//
+							// Pull what this request is supposed to be
+							//
+							String group = null;
+							int count = matcher.groupCount();
+							if (count >= 1) {
+								group = matcher.group(count-1);
+							}
+							//
+							// Send it
+							//
+							if (group.equals("Unknown")) {
+								//
+								// Remove the file
+								//
+								Files.delete(file);
+							}
+						} catch (Exception e) {
+							logger.error(e);
+							e.printStackTrace();
+						}
+					}
+					return super.visitFile(file, attrs);
+				}				
+			});
+		} catch (IOException e) {
+			logger.error("Failed to removeRequests from " + this.directory + " " + e);
+		}
+	}
+
+	protected void addRequests(RequestType request, List<RequestType> requests, int index) {
+		for (RequestType req : requests) {
+			//
+			// There really should only be one attribute
+			//
+			for (AttributesType attrs : req.getAttributes()) {
+				for (AttributeType attr : attrs.getAttribute()) {
+					for (AttributeValueType value : attr.getAttributeValue()) {
+						if (this.addAttribute(request, attrs.getCategory(), attr.getAttributeId(), value)) {
+							this.writeRequest(request);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Writes the request into the "requests" sub-directory, relative to the value of the "directory" setup
+	 * during initialization.
+	 * 
+	 * Writing the requests out allows one to go back and easily refer to the request when analyzing the responses
+	 * generated after the PDP decide() call. Also, one can then use the generated requests into any test tools
+	 * they wish to build.
+	 * 
+	 * @param request - The request to be written.
+	 */
+	protected void writeRequest(RequestType request) {
+		if (logger.isTraceEnabled()) {
+			logger.trace("writeRequest: " + index);
+		}
+		try {
+			ObjectFactory of = new ObjectFactory();
+			JAXBElement<RequestType> requestElement = of.createRequest(request);
+			JAXBContext context = JAXBContext.newInstance(RequestType.class);
+			Marshaller m = context.createMarshaller();
+			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+			Path outFile = Paths.get(this.directory, "requests", String.format("Request.%06d.Unknown.xml", this.index));
+			m.marshal(requestElement, outFile.toFile());
+		} catch (Exception e) {
+			logger.error("Failed to write request: " + e.getMessage());
+		}
+		this.index++;
+	}
+
+	protected boolean	addAttribute(RequestType request, String category, String id, AttributeValueType value) {
+		//
+		// See if the category exists
+		//
+		for (AttributesType attrs : request.getAttributes()) {
+			if (attrs.getCategory().equals(category)) {
+				//
+				// It does have the category. But does it have the attribute ID?
+				//
+				for (AttributeType attr : attrs.getAttribute()) {
+					if (attr.getAttributeId().equals(id)) {
+						//
+						// Yes, check for the same datatype
+						//
+						for (AttributeValueType val : attr.getAttributeValue()) {
+							if (val.getDataType().equals(value.getDataType())) {
+								//
+								// We have something already there
+								//
+								return false;
+							}
+						}
+						//
+						// The ID exists, but not the datatype
+						//
+						attr.getAttributeValue().add(value);
+						return true;
+					}
+				}
+				//
+				// If we get here, the ID does not exist
+				//
+				AttributeType attr = new AttributeType();
+				attr.setAttributeId(id);
+				attr.getAttributeValue().add(value);
+				attrs.getAttribute().add(attr);
+				return true;
+			}
+		}
+		//
+		// If we get here, the category does not exist. So add it in.
+		//
+		AttributesType attrs = new AttributesType();
+		attrs.setCategory(category);
+		AttributeType attr = new AttributeType();
+		attr.setAttributeId(id);
+		attr.getAttributeValue().add(value);
+		attrs.getAttribute().add(attr);
+		request.getAttributes().add(attrs);
+		return true;
+	}
+
+	public static void main(String[] args) {
+		try {
+			new TestPolicy(args).run();
+		} catch (ParseException | IOException | FactoryException e) {
+			logger.error(e);
+		} catch (HelpException e) {
+		}
+	}
+
+	/*
+	// Map<CATEGORY, MAP<DATATYPE, MAP<ATTRIBUTEID, SET<VALUES>>>
+	@SuppressWarnings("unchecked")
+	private void generateRequests(Map<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> categoryMap) {
+		meta = new ArrayList<>();
+		
+		for (Map.Entry<Identifier, Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>>> categoryEntry : categoryMap.entrySet()) {
+			String category = categoryEntry.getKey().toString();
+			logger.debug("Category: " + category);
+			Map<Identifier, Map<Identifier, Set<AttributeValue<?>>>> datatypeMap = categoryEntry.getValue();
+			for (Map.Entry<Identifier, Map<Identifier, Set<AttributeValue<?>>>> datatypeEntry : datatypeMap.entrySet()) {
+				String datatype = datatypeEntry.getKey().toString();
+				logger.debug("\tData Type: " + datatype);
+				Map<Identifier, Set<AttributeValue<?>>> attributeIDMap = datatypeEntry.getValue();
+				for (Map.Entry<Identifier, Set<AttributeValue<?>>> attributeIDEntry : attributeIDMap.entrySet()) {
+					String attributeID = attributeIDEntry.getKey().toString();
+					logger.debug("\t\tAttribute ID: " + attributeID);
+					Set<AttributeValue<?>> attributeValueSet = attributeIDEntry.getValue();
+					for (AttributeValue<?> value : attributeValueSet) {
+						logger.debug("\t\t\tAttribute Value: " + value);						
+					}
+					Iterator<AttributeValue<?>> iterator = attributeValueSet.iterator();
+					logger.debug("\t\t\t# of Attribute values: " + attributeValueSet.size());
+					meta.add(new Object[] {category, datatype, attributeID, iterator.next(), iterator, attributeValueSet});
+				}
+			}
+		}
+		
+		int count = 0;
+		for (File file : output.toFile().listFiles()) {
+			file.delete();
+		}
+			
+		do {
+			RequestType request = new RequestType();
+			request.setCombinedDecision(false);
+			request.setReturnPolicyIdList(false);
+			List<AttributesType> attributesList = request.getAttributes();
+			
+			Map<String, AttributesType> category2Attribute= new HashMap<>();
+			for (int i = 0; i < meta.size(); i++) {
+				Object[] record = meta.get(i);
+				
+				AttributesType attributes = null;
+				if (category2Attribute.containsKey(record[0].toString()))
+					attributes = category2Attribute.get(record[0].toString());
+				else {
+					attributes = new AttributesType();
+					attributes.setCategory(record[0].toString());
+					category2Attribute.put(record[0].toString(), attributes);
+					attributesList.add(attributes);				
+				}
+//				attributes.setId(record[2].toString());
+				List<AttributeType> attrList = attributes.getAttribute();
+				
+				AttributeType attribute = new AttributeType();
+				attribute.setAttributeId(record[2].toString());
+				List<AttributeValueType> valueList = attribute.getAttributeValue();
+
+				AttributeValue<?> attributeValue = (AttributeValue<?>) record[3];
+
+				AttributeValueType value = new AttributeValueType();
+				value.setDataType(attributeValue.getDataTypeId().toString());
+				List<Object> content = value.getContent();
+				content.addAll((Collection<? extends Object>) attributeValue.getValue());
+				valueList.add(value);
+
+				attrList.add(attribute);
+			}
+			
+			try {
+				ObjectFactory of = new ObjectFactory();
+				JAXBElement<RequestType> requestElement = of.createRequest(request);
+				JAXBContext context = JAXBContext.newInstance(RequestType.class);
+				Marshaller m = context.createMarshaller();
+				m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+				m.marshal(requestElement, output.resolve("request" + count + ".xml").toFile());
+				
+//				if (count == 0) {//Just send the first request to the engine
+					StringWriter sw = new StringWriter();
+					m.marshal(requestElement, sw);
+					logger.info(sw.toString());
+					EngineCaller engine = new LocalEngineCaller();
+					if (engine.startEngine("")) {
+						String response = engine.decide(sw.toString(), "xml");
+						FileWriter writer = new FileWriter(output.resolve("response" + count + ".xml").toFile());
+						writer.write(response);
+						writer.close();
+						logger.info("Response received: \n" + response);					
+					}
+//				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+			
+			count++;
+		} while (hasNextRequest());
+			
+		logger.info("# of requests generated: " + count);
+	}
+	
+	private boolean hasNextRequest() {
+		int i = meta.size() - 1;
+		Object[] record = meta.get(i);
+		
+		@SuppressWarnings("unchecked")
+		Iterator<AttributeValue<?>> iterator = (Iterator<AttributeValue<?>>) record[4];
+		if (iterator.hasNext()) {
+			record[3] = iterator.next();
+		} else {
+			return recycleAttributeValue(i);
+		}
+		
+		return true;
+	}
+	
+	@SuppressWarnings("unchecked")
+	private boolean recycleAttributeValue(int position) {
+		boolean rc = true;
+		
+		if (position == 0)
+			return false;
+		
+		Object[] record = meta.get(position);
+		Set<AttributeValue<?>> attributeValueSet = (Set<AttributeValue<?>>) record[5];
+		Iterator<AttributeValue<?>> newIt = attributeValueSet.iterator();
+		record[4] = newIt;
+		record[3] = newIt.next();
+		int i = position - 1;
+		Object[] previous = meta.get(i);
+		Iterator<AttributeValue<?>> preIt = (Iterator<AttributeValue<?>>) previous[4];
+		if (preIt.hasNext()) {
+			previous[3] = preIt.next();
+		} else {
+			rc = recycleAttributeValue(i);
+		}
+		
+		return rc;
+	}
+	
+	*/
+	
+}
+	
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/XACMLEngineTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/XACMLEngineTest.java
new file mode 100644
index 0000000..660180b
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/XACMLEngineTest.java
@@ -0,0 +1,84 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletConfig;
+
+public class XACMLEngineTest extends TestCase{
+	
+	private List<String> headers = new ArrayList<String>();
+	
+	private HttpServletRequest httpServletRequest;
+	private HttpServletResponse httpServletResponse;
+	private ServletOutputStream mockOutput;
+	private ServletConfig servletConfig; 
+
+    @Before
+   
+    public void setUp() throws IOException {
+    	httpServletRequest = Mockito.mock(HttpServletRequest.class);
+    	Mockito.when(httpServletRequest.getMethod()).thenReturn("POST");
+    	Mockito.when(httpServletRequest.getParameter("groupId")).thenReturn(null);
+    	Mockito.when(httpServletRequest.getHeaderNames()).thenReturn(Collections.enumeration(headers));
+    	Mockito.when(httpServletRequest.getAttributeNames()).thenReturn(Collections.enumeration(headers));
+    	
+    	
+    	mockOutput = Mockito.mock(ServletOutputStream.class);
+    	
+    	httpServletResponse = Mockito.mock(MockHttpServletResponse.class);
+    	
+    	Mockito.when(httpServletResponse.getOutputStream()).thenReturn(mockOutput);
+
+    	servletConfig = Mockito.mock(MockServletConfig.class);
+
+    	Mockito.when(servletConfig.getInitParameterNames()).thenReturn(Collections.enumeration(headers));
+    	
+    	
+    	      
+    }
+	
+    @Test
+	public void testDummy() throws Exception{
+		try {	
+			assertTrue(true);
+		} catch (Exception e) {
+			fail();
+		}
+
+	}
+	
+}
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/components/XACMLPDPPolicyTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/components/XACMLPDPPolicyTest.java
new file mode 100644
index 0000000..96163b2
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/components/XACMLPDPPolicyTest.java
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test.components;
+
+import org.junit.Test;
+import org.junit.Before;
+import org.junit.After;
+
+import org.junit.Assert;
+
+public class XACMLPDPPolicyTest {
+
+	
+	@Before
+	public void init(){
+		
+	}
+	
+	@After
+	public void cleanUp(){
+		
+	}
+	
+	@Test
+	public void testDummy(){
+
+		Assert.assertTrue(true);
+		
+	}
+	
+}
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestCategoryTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestCategoryTest.java
new file mode 100644
index 0000000..e4ef4be
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestCategoryTest.java
@@ -0,0 +1,4174 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import com.att.research.xacml.api.Request;
+import com.att.research.xacml.std.json.JSONRequest;
+import com.att.research.xacml.std.json.JSONStructureException;
+
+/**
+ * Test JSON Request convert to object - Category sub-component.  Does not include "Default" Categories (Subject, Action, Resource, Environment).
+ * Basic existance/absence of Category is tested in RequestMainTest.
+ * 
+ * TO RUN - use jUnit
+ * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test
+ * 
+ * NOTE:
+ * The "correct" way to verify that each JSON string gets translated into our internal Objects correctly is to look explicitly at each of the child objects
+ * and verify that they are correct.  This would involve a lot of coding to get child of child of child and individually verify each property of each element.
+ * To simplify testing we assume that request.toString() correctly includes a complete text representation of every sub-component of the Request object
+ * and we compare the resulting String to our expected String.
+ * This has two possible sources of error:
+ * 	- toString might not include some sub-component, and
+ * 	- the initial verification of the resulting string is done by hand and may have been incorrect.
+ * 
+ *
+ */
+public class RequestCategoryTest {
+	
+	// The request object output from each test conversion from JSON string
+	Request request;
+
+	
+	/*
+	 * Request that uses all fields with both single and multiple  entries
+	 */
+	String allFieldsRequest = 
+			"{\"Request\": {" +
+					"\"ReturnPolicyIdList\" : true ," +
+					"\"CombinedDecision\" : true ," +
+					"\"XPathVersion\" : \"http://www.w3.org/TR/1999/REC-xpath-19991116\"," +
+					"\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar1\"]" +
+			                "}]" +   
+			          "}," +
+
+					"\"Category\": [" +
+						"{ " +
+					    	"\"CategoryId\": \"custom-category\", " +
+					    	"\"Id\" : \"customId\", " +
+					    	"\"Attribute\" : [" +
+					    		"{" +
+					    			"\"AttributeId\"		: \"document-id\", " +
+					    			"\"DataType\"	: \"integer\", " +
+					    			"\"Value\"	: 123 " +
+								"}, " +
+								"{" +
+				    				"\"AttributeId\"		: \"document-url\", " +
+				    				"\"DataType\"	: \"anyURI\", " +
+				    				"\"Value\"	: \"http://somewhere.over.the.com/rainbow\" " +
+				    			"}, " +
+								"{" +
+				    				"\"AttributeId\"		: \"page-list\", " +
+				    				"\"Value\"	: [1, 2, 3, 4.5, 3, 2, 1] " +
+							"} " +
+					    	"]" +
+					    "}, " +
+					    "{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"], " +
+					    
+					"\"AccessSubject\":{ " +
+						"\"Content\" : \"<?xml version=\\\"1.0\\\"?><catalog>" + 
+							"<book id=\\\"bk101\\\"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre>" +
+							"<price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description>"+
+							"</book></catalog>\"," +
+						"\"Attribute\" : []" +
+					"}, " +
+					
+					"\"Resource\" : {" +
+						"\"Content\" : \"PD94bWwgdmVyc2lvbj0iMS4wIj8+PGNhdGFsb2c+PGJvb2sgaWQ9ImJrMTAxIj48YXV0aG9yPkdhbWJhcmRlbGxhLCBNYXR0aGV3PC9hdXRob3I+PHRpdGxlPlhNT" +
+							"CBEZXZlbG9wZXIncyBHdWlkZTwvdGl0bGU+PGdlbnJlPkNvbXB1dGVyPC9nZW5yZT48cHJpY2U+NDQuOTU8L3ByaWNlPjxwdWJsaXNoX2RhdGU+MjAwMC0xMC0wMTwvcHVibGlzaF"+
+							"9kYXRlPjxkZXNjcmlwdGlvbj5BbiBpbi1kZXB0aCBsb29rIGF0IGNyZWF0aW5nIGFwcGxpY2F0aW9ucyB3aXRoIFhNTC48L2Rlc2NyaXB0aW9uPjwvYm9vaz48L2NhdGFsb2c+\"" +
+
+
+					"} " +
+
+			          
+			"}}";
+	
+	/*
+	 * The following example comes directly from the JSON Profile Spec
+	 */
+	String exampleFromSpec = "{ " +
+			"\"Request\" : { " +
+				"\"AccessSubject\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Andreas\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Gamla Stan\" " +
+						"} " +
+					"] " +
+				"}, " +
+				"\"Action\" : { " +
+					"\"Attribute\":  " +
+						"{ " +
+							"\"Id\" : \"action-id\", " +
+							"\"Value\" : \"http://www.xacml.eu/buy\", " +
+							"\"DataType\" : \"anyURI\" " +
+						"} " +
+				"}, " +
+				"\"Resource\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"book-title\", " +
+							"\"Value\" : \"Learn German in 90 days\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"currency\", " +
+							"\"Value\" : \"SEK\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"price\", " +
+							"\"Value\" : 123.34 " +
+						"} " +
+						"] " +
+					"} " +
+				"} " +
+			"} ";
+
+	
+	/*
+	 * The following example comes directly from the JSON Profile Spec (modified to include a "</Catalog>" missing from both examples).
+	 * It shows the two ways of handling XPath content, as escaped XML and as Base64 encoding.
+	 */
+	String xPathExampleFromSpec = "{ " +
+			"\"Request\" : { " +
+				"\"Resource\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+						 	"\"Id\" : \"urn:oasis:names:tc:xacml:3.0:content-selector\", " +
+				            "\"DataType\" : \"xpathExpression\", " +
+				            "\"Value\" : { " +
+				                "\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\", " +
+				                "\"Namespaces\" : [{ " +
+				                    	"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+				                    	"}, " +
+				                    "{ " +
+				                    	"\"Prefix\" : \"md\", " +
+				                    	"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+				                    "} " +
+				                "], " +
+				                "\"XPath\" : \"md:record/md:patient/md:patientDoB\" " +
+				            "} " +
+				        "} " +
+					"] " +
+				"} " +
+			"} " +
+		"} ";
+
+
+	
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	// Top-level of Category
+	@Test
+	public void testCategoryTopLevel() {	
+		
+		// empty Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Missing value
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\" }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\" : }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category without CategoryId
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{}] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category with CategoryId value missing or =""
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\"] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"\" ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// CategoryId wrong type
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : true } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : 123 } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category with Id
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Id\" : \"customId\" } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category},xmlId=customId}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category with Id - wrong type
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Id\" : true } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Id\" : 123 } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Category without Id	
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\" } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Category with standard CategoryId
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\" } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category with extra unknown field
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", unknown } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"unknown\" : 123 } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category with multiple sub-Category objects using same CategoryId
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"category1\" }, {\"CategoryId\" : \"category1\" } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=category1}}{super={category=category1}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+	}
+
+	
+	
+	// Tests related to Attributes
+	@Test
+	public void testCategoryAttributes() {	
+	
+		// Category with Attribute but none given ("Attribute" : [] )		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+		// Category Attribute with empty attribute (missing both AttributeId and Id)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with AttributeId and no Value
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"AttributeId\" : \"document-id\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute missing AttributeId but with Id		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"AttributeId\" : \"document-id\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute missing AttributeId but with Id
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute including both AttributeId and Id with same value
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"AttributeId\" : \"document-id\", " +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute missing both AttributeId and Id
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute AttributeId not string
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"AttributeId\" : true, " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"AttributeId\" : 123, " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute Id not string
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : true, " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : 123, " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Category Attribute with DataType
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"integer\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with DataType not string (e.g. "DataType" : 55.5 )
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: true, " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with unknown DataType
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"no such data type\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: 321, " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with multiple value array
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dayTimeDuration\", " +
+	    			"\"Value\"	: [\"P3D\", \"P2DT12H34M\", \"PT15M\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=3hours=0minutes=0seconds=0millis=0},factionalSeconds=0.0}}{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=2hours=12minutes=34seconds=0millis=0},factionalSeconds=0.0}}{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=0hours=0minutes=15seconds=0millis=0},factionalSeconds=0.0}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute multiple value with null in array
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dayTimeDuration\", " +
+	    			"\"Value\"	: [\"P3D\", , \"P15M\"] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with array value with no values ("Attribute": [ {"AttributeId" :"a", Value:[] } ] }  )
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dayTimeDuration\", " +
+	    			"\"Value\"	: [ ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with no DataType and array with no values
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with Issuer
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+					"\"Issuer\" : \"University Press\", " +
+	    			"\"DataType\"	: \"integer\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],issuer=University Press,includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with Issuer not string
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+					"\"Issuer\" : true, " +
+	    			"\"DataType\"	: \"integer\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+					"\"Issuer\" : 4.56, " +
+	    			"\"DataType\"	: \"integer\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with includeInResult=true
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: 123, " +
+	    			"\"IncludeInResult\" : true " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=true}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with includeInResult = false
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: 123, " +
+	    			"\"IncludeInResult\" : false " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with includeInResult not boolean
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: 123, " +
+	    			"\"IncludeInResult\" : \"abc\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: 123, " +
+	    			"\"IncludeInResult\" : 123.45 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+	}
+
+	
+	
+	// Tests related to DataTypes within Attributes
+	@Test
+	public void testCategoryAttributesDataTypesSimple() {	
+		
+		// Category Attribute using full Identifier for each data type
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: \"abc\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#boolean\", " +
+	    			"\"Value\"	: true " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#double\", " +
+	    			"\"Value\"	: 123.34 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#time\", " +
+	    			"\"Value\"	: \"12:00:00Z\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#time,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#date\", " +
+	    			"\"Value\"	: \"2002-10-10\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#date,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dateTime\", " +
+	    			"\"Value\"	: \"2002-10-10T12:00:00Z\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dateTime,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dayTimeDuration\", " +
+	    			"\"Value\"	: \"P23DT7H12M54S\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=23hours=7minutes=12seconds=54millis=0},factionalSeconds=54.0}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#yearMonthDuration\", " +
+	    			"\"Value\"	: \"P165Y8M\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#yearMonthDuration,value={super={durationSign=1years=165months=8days=0hours=0minutes=0seconds=0millis=0},monthsDuration=1988}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#anyURI\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#hexBinary\", " +
+	    			"\"Value\"	: \"FA027B7D12CC34DDD20012AEEF\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#hexBinary,value={data=[-6,2,123,125,18,-52,52,-35,-46,0,18,-82,-17]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#base64Binary\", " +
+	    			"\"Value\"	: \"lvbj0iMS4wIj8+PGNhdGFsb2c+PGJvb2sgaWQ9ImJrMTAxIj48YXV0aG9y\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,-46,35,18,-29,2,35,-13,-29,-58,54,23,70,22,-58,-10,115,-29,-58,38,-10,-10,-78,6,-106,67,-46,38,38,-77,19,3,18,35,-29,-58,23,87,70,-122,-9]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name\", " +
+	    			"\"Value\"	: \"someone.else@A.COMPANY.com\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name,value={localName=someone.else,domainName=A.COMPANY.com}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:x500Name\", " +
+	    			"\"Value\"	: \"cn=Julius Hibbert, o=Medi Corporation, c=US\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:ipAddress\", " +
+	    			"\"Value\"	: \"10.221.43.58:12345\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:ipAddress,value=10.221.43.58:12345-12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:dnsName\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    					+ "{ "+
+    							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+    							"}," +
+    							"{" +
+    								"\"Prefix\" : \"md\", " +
+    								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+    							"}], "+
+    					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace={[{md,urn:example:med:schemas:record}{urn:oasis:names:tc:xacml:3.0:core:schema:wd-17}]},status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}],includeInResults=false}]}}]}", request.toString());
+
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+		
+		// Category Attribute shorthand notation for each data type
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"string\", " +
+	    			"\"Value\"	: \"abc\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"boolean\", " +
+	    			"\"Value\"	: true " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"integer\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"double\", " +
+	    			"\"Value\"	: 123.34 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"time\", " +
+	    			"\"Value\"	: \"12:00:00Z\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#time,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"date\", " +
+	    			"\"Value\"	: \"2002-10-10\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#date,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dateTime\", " +
+	    			"\"Value\"	: \"2002-10-10T12:00:00Z\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dateTime,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dayTimeDuration\", " +
+	    			"\"Value\"	: \"P23DT7H12M54S\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=23hours=7minutes=12seconds=54millis=0},factionalSeconds=54.0}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"yearMonthDuration\", " +
+	    			"\"Value\"	: \"P165Y8M\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#yearMonthDuration,value={super={durationSign=1years=165months=8days=0hours=0minutes=0seconds=0millis=0},monthsDuration=1988}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"anyURI\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"hexBinary\", " +
+	    			"\"Value\"	: \"FA027B7D12CC34DDD20012AEEF\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#hexBinary,value={data=[-6,2,123,125,18,-52,52,-35,-46,0,18,-82,-17]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"base64Binary\", " +
+	    			"\"Value\"	: \"lvbj0iMS4wIj8+PGNhdGFsb2c+PGJvb2sgaWQ9ImJrMTAxIj48YXV0aG9y\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,-46,35,18,-29,2,35,-13,-29,-58,54,23,70,22,-58,-10,115,-29,-58,38,-10,-10,-78,6,-106,67,-46,38,38,-77,19,3,18,35,-29,-58,23,87,70,-122,-9]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"rfc822Name\", " +
+	    			"\"Value\"	: \"someone.else@A.COMPANY.com\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name,value={localName=someone.else,domainName=A.COMPANY.com}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"x500Name\", " +
+	    			"\"Value\"	: \"cn=Julius Hibbert, o=Medi Corporation, c=US\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"ipAddress\", " +
+	    			"\"Value\"	: \"10.221.43.58:12345\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:ipAddress,value=10.221.43.58:12345-12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dnsName\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    					+ "{ "+
+    							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+    							"}," +
+    							"{" +
+    								"\"Prefix\" : \"md\", " +
+    								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+    							"}], "+
+    					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace={[{md,urn:example:med:schemas:record}{urn:oasis:names:tc:xacml:3.0:core:schema:wd-17}]},status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}],includeInResults=false}]}}]}", request.toString());
+
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+		
+		
+		// infer data type - only integer, boolean and double are distinguishable from strings; everything else is treated as a string
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"abc\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: true " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: 123.34 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"12:00:00Z\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"2002-10-10\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"2002-10-10T12:00:00Z\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"P23DT7H12M54S\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"P165Y8M\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"FA027B7D12CC34DDD20012AEEF\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=FA027B7D12CC34DDD20012AEEF}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"lvbj0iMS4wIj8+PGNhdGFsb2c+PGJvb2sgaWQ9ImJrMTAxIj48YXV0aG9y\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lvbj0iMS4wIj8+PGNhdGFsb2c+PGJvb2sgaWQ9ImJrMTAxIj48YXV0aG9y}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"someone.else@A.COMPANY.com\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=someone.else@A.COMPANY.com}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:x500Name\", " +
+	    			"\"Value\"	: \"cn=Julius Hibbert, o=Medi Corporation, c=US\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"10.221.43.58:12345\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    					+ "{ "+
+    							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+    							"}," +
+    							"{" +
+    								"\"Prefix\" : \"md\", " +
+    								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+    							"}], "+
+    					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			// gets inferred to a String containing the whole structure under Value as a String
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value={XPathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource, Namespaces=[{Namespace=urn:oasis:names:tc:xacml:3.0:core:schema:wd-17}, {Prefix=md, Namespace=urn:example:med:schemas:record}], XPath=md:record/md:patient/md:patientDoB}}],includeInResults=false}]}}]}", request.toString());
+
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+	}
+	
+	
+	
+	@Test
+	public void testCategoryAttributesDataTypesNotMatchValue() {	
+
+		// Category Attribute with DataType not matching value type (JSON type derived from syntax)
+		// AUTO-CONVERSION from Boolean to String!
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: true " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: 123.34 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123.34}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#boolean\", " +
+	    			"\"Value\"	: \"abc\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#boolean\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#boolean\", " +
+	    			"\"Value\"	: 123.45 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: \"123\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: true " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: 123.45 " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#double\", " +
+	    			"\"Value\"	: \"123.34\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#double\", " +
+	    			"\"Value\"	: true " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// allow integer to auto-convert to double when DataType is given
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#double\", " +
+	    			"\"Value\"	: 123 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.0}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// special JavaScript values not allowed except for -0 (inappropriate requirement in spec - check it anyway)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: \"NaN\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: \"INF\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: \"-INF\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// JavaScript 0 and -0 are ok
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: 0 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=0}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: -0 " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=0}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// All other data types are checked when we convert internally, so value must be syntactically correct
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#time\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#date\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dateTime\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dayTimeDuration\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#yearMonthDuration\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#anyURI\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#hexBinary\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Base64 convert does not throw an exception if the contents are not Base64, so cannot test for this.
+		// Any problem with the data will have to be discovered later when the data is used.
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:x500Name\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:ipAddress\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:dnsName\", " +
+	    			"\"Value\"	: \"syntactically incorrect value\" " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+
+		// Cannot test XPathExpressions here.  The XPathExpression gets converted into a simple String value within the XPathExpression object,
+		// but it is not evaluated or compiled at that time.  Therefore we do not know whether or not the value is valid until it is used in a computation.
+
+	}
+	
+	
+	@Test
+	public void testArrayDataTypes() {
+		
+		// array of size 0
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: [] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Category Attribute value array DataType given (repeat for all data types)
+		// Category Attribute using full Identifier for each data type
+		// Category Attribute shorthand notation for each data type
+		// Also tests for mixes of different JSON types (trying incorrect strings for XACML data types whenever possible)
+		// string
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: [\"abc\", \"def\", \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=def}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"string\", " +
+	    			"\"Value\"	: [\"abc\", \"def\", \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=def}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT to DataType
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: [\"abc\", true, \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: [\"abc\",123, \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: [\"abc\", 34.34, \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=34.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// boolean
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#boolean\", " +
+	    			"\"Value\"	: [true, true, false, true, false ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=false}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=false}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"boolean\", " +
+	    			"\"Value\"	: [true, true, false, true, false ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=false}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=false}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#boolean\", " +
+	    			"\"Value\"	: [true, \"abc\", false, true, false ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#boolean\", " +
+	    			"\"Value\"	: [true, 123, false, true, false ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#boolean\", " +
+	    			"\"Value\"	: [true, 12.34, false, true, false ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		
+		// integer
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: [123, 456, 765, 234] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=456}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=765}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=234}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"integer\", " +
+	    			"\"Value\"	: [123, 456, 765, 234] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=456}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=765}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=234}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: [123, \"abc\", 765, 234] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: [123, true, 765, 234] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#integer\", " +
+	    			"\"Value\"	: [123, 34.56, 765, 234] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// double
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#double\", " +
+	    			"\"Value\"	: [ 123.34, 543.54, 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=543.54}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=3445.455}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=4543.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=543.0}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"double\", " +
+	    			"\"Value\"	: [ 123.34, 543.54, 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=543.54}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=3445.455}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=4543.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=543.0}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// special case - auto-convert integer to boolean
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#double\", " +
+	    			"\"Value\"	: [ 123.34, 111122, 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=111122.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=3445.455}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=4543.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=543.0}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#double\", " +
+	    			"\"Value\"	: [ 123.34, true, 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#double\", " +
+	    			"\"Value\"	: [ 123.34, \"abb\", 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// time
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#time\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", \"12:00:00Z\", \"12:00:00Z\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#time,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#time,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#time,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"time\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", \"12:00:00Z\", \"12:00:00Z\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#time,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#time,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#time,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#time\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", \"not a time\", \"12:00:00Z\"] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#time\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", true, \"12:00:00Z\"] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#time\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", 123, \"12:00:00Z\"] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#time\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", 12.34, \"12:00:00Z\"] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// date
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#date\", " +
+	    			"\"Value\"	: [\"2002-10-10\",\"2002-10-10\",\"2002-10-10\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#date,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#date,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#date,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"date\", " +
+	    			"\"Value\"	: [\"2002-10-10\",\"2002-10-10\",\"2002-10-10\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#date,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#date,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#date,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#date\", " +
+	    			"\"Value\"	: [\"2002-10-10\",\"not a date\",\"2002-10-10\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#date\", " +
+	    			"\"Value\"	: [\"2002-10-10\",true,\"2002-10-10\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#date\", " +
+	    			"\"Value\"	: [\"2002-10-10\",123,\"2002-10-10\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#date\", " +
+	    			"\"Value\"	: [\"2002-10-10\",123.45,\"2002-10-10\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// dateTime
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dateTime\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",\"2002-10-10T12:00:00Z\",\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dateTime,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#dateTime,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#dateTime,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dateTime\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",\"2002-10-10T12:00:00Z\",\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dateTime,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#dateTime,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#dateTime,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dateTime\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",\"not a dateTime\",\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dateTime\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",true,\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dateTime\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",123,\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dateTime\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",12.34,\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// dayTimeDuration
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dayTimeDuration\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",\"P23DT7H12M54S\",\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=23hours=7minutes=12seconds=54millis=0},factionalSeconds=54.0}}{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=23hours=7minutes=12seconds=54millis=0},factionalSeconds=54.0}}{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=23hours=7minutes=12seconds=54millis=0},factionalSeconds=54.0}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dayTimeDuration\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",\"P23DT7H12M54S\",\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=23hours=7minutes=12seconds=54millis=0},factionalSeconds=54.0}}{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=23hours=7minutes=12seconds=54millis=0},factionalSeconds=54.0}}{dataTypeId=http://www.w3.org/2001/XMLSchema#dayTimeDuration,value={super={durationSign=1years=0months=0days=23hours=7minutes=12seconds=54millis=0},factionalSeconds=54.0}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dayTimeDuration\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",\"not a duration\",\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dayTimeDuration\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",true,\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dayTimeDuration\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",123,\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#dayTimeDuration\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",11.22,\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// yearMonth duration
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#yearMonthDuration\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",\"P165Y8M\",\"P165Y8M\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#yearMonthDuration,value={super={durationSign=1years=165months=8days=0hours=0minutes=0seconds=0millis=0},monthsDuration=1988}}{dataTypeId=http://www.w3.org/2001/XMLSchema#yearMonthDuration,value={super={durationSign=1years=165months=8days=0hours=0minutes=0seconds=0millis=0},monthsDuration=1988}}{dataTypeId=http://www.w3.org/2001/XMLSchema#yearMonthDuration,value={super={durationSign=1years=165months=8days=0hours=0minutes=0seconds=0millis=0},monthsDuration=1988}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"yearMonthDuration\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",\"P165Y8M\",\"P165Y8M\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#yearMonthDuration,value={super={durationSign=1years=165months=8days=0hours=0minutes=0seconds=0millis=0},monthsDuration=1988}}{dataTypeId=http://www.w3.org/2001/XMLSchema#yearMonthDuration,value={super={durationSign=1years=165months=8days=0hours=0minutes=0seconds=0millis=0},monthsDuration=1988}}{dataTypeId=http://www.w3.org/2001/XMLSchema#yearMonthDuration,value={super={durationSign=1years=165months=8days=0hours=0minutes=0seconds=0millis=0},monthsDuration=1988}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#yearMonthDuration\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",\"not a duration\",\"P165Y8M\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#yearMonthDuration\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",true,\"P165Y8M\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#yearMonthDuration\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",123,\"P165Y8M\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#yearMonthDuration\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",11.22,\"P165Y8M\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// anyURI
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#anyURI\", " +
+	    			"\"Value\"	: [ \"aValue\",\"aValue\",\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"anyURI\", " +
+	    			"\"Value\"	: [ \"aValue\",\"aValue\",\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#anyURI\", " +
+	    			"\"Value\"	: [ \"aValue\",true,\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#anyURI\", " +
+	    			"\"Value\"	: [ \"aValue\",123,\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#anyURI\", " +
+	    			"\"Value\"	: [ \"aValue\",11.111,\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=11.111}{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// hexBinary
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#hexBinary\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",\"FA027B7D12CC34DDD20012AEEF\",\"FA027B7D12CC34DDD20012AEEF\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#hexBinary,value={data=[-6,2,123,125,18,-52,52,-35,-46,0,18,-82,-17]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#hexBinary,value={data=[-6,2,123,125,18,-52,52,-35,-46,0,18,-82,-17]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#hexBinary,value={data=[-6,2,123,125,18,-52,52,-35,-46,0,18,-82,-17]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"hexBinary\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",\"FA027B7D12CC34DDD20012AEEF\",\"FA027B7D12CC34DDD20012AEEF\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#hexBinary,value={data=[-6,2,123,125,18,-52,52,-35,-46,0,18,-82,-17]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#hexBinary,value={data=[-6,2,123,125,18,-52,52,-35,-46,0,18,-82,-17]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#hexBinary,value={data=[-6,2,123,125,18,-52,52,-35,-46,0,18,-82,-17]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#hexBinary\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",true,\"012AEEF\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#hexBinary\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",123,\"012AEEF\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#hexBinary\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",11.44,\"012AEEF\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// base64Binary
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#base64Binary\", " +
+	    			"\"Value\"	: [ \"aG9y\",\"lvbj0iMS4xIj48YXV0aG9y\",\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[104,111,114]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,-46,35,18,-29,18,35,-29,-58,23,87,70,-122,-9]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,34,62,60,97,117,116,104,111,114]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"base64Binary\", " +
+	    			"\"Value\"	: [ \"aG9y\",\"lvbj0iMS4xIj48YXV0aG9y\",\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[104,111,114]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,-46,35,18,-29,18,35,-29,-58,23,87,70,-122,-9]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,34,62,60,97,117,116,104,111,114]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#base64Binary\", " +
+	    			"\"Value\"	: [ \"aG9y\",true,\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[104,111,114]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-74,-69,-98]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,34,62,60,97,117,116,104,111,114]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#base64Binary\", " +
+	    			"\"Value\"	: [ \"aG9y\",1123,\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[104,111,114]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-41,93,-73]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,34,62,60,97,117,116,104,111,114]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#base64Binary\", " +
+	    			"\"Value\"	: [ \"aG9y\",11.22,\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[104,111,114]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-41,93,-74]}}{dataTypeId=http://www.w3.org/2001/XMLSchema#base64Binary,value={data=[-106,-10,-29,34,62,60,97,117,116,104,111,114]}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// RFC822 name
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",\"one.else@A.COMPANY.com\",\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name,value={localName=sne.else,domainName=A.COMPANY.com}}{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name,value={localName=one.else,domainName=A.COMPANY.com}}{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name,value={localName=someone.else,domainName=A.CONY.com}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"rfc822Name\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",\"one.else@A.COMPANY.com\",\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name,value={localName=sne.else,domainName=A.COMPANY.com}}{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name,value={localName=one.else,domainName=A.COMPANY.com}}{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name,value={localName=someone.else,domainName=A.CONY.com}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",\"not a dns\",\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",true,\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",111,\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",11.22,\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// x500
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:x500Name\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", \"cn=Julius Hibbert, o=Medi Corporation, c=US\", \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"x500Name\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", \"cn=Julius Hibbert, o=Medi Corporation, c=US\", \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}{dataTypeId=urn:oasis:names:tc:xacml:1.0:data-type:x500Name,value=CN=Julius Hibbert, O=Medi Corporation, C=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:x500Name\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", \"non-x500 string\", \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:x500Name\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", true, \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:x500Name\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", 1111, \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:1.0:data-type:x500Name\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", 11.22, \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// ipAddress
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:ipAddress\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",\"10.221.43.58:12345\",\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:ipAddress,value=10.221.43.58:12345-12345}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:ipAddress,value=10.221.43.58:12345-12345}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:ipAddress,value=10.221.43.58:12345-12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"ipAddress\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",\"10.221.43.58:12345\",\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:ipAddress,value=10.221.43.58:12345-12345}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:ipAddress,value=10.221.43.58:12345-12345}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:ipAddress,value=10.221.43.58:12345-12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:ipAddress\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",\"not an ip address\",\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:ipAddress\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",true,\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:ipAddress\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",1111,\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:ipAddress\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",11.22,\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// dnsName
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:dnsName\", " +
+	    			"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"dnsName\", " +
+	    			"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:dnsName\", " +
+	    			"\"Value\"	: [ \"aValue\", true, \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=true}}{dataTypeId=urn:oasis:names:tc:xacml:2.0:data-type:dnsName,value={domainName=aValue}}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:dnsName\", " +
+	    			"\"Value\"	: [ \"aValue\", 1111, \"aValue\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:2.0:data-type:dnsName\", " +
+	    			"\"Value\"	: [ \"aValue\", 11.22, \"aValue\" ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// xPathExpression
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\", " +
+	    			"\"Value\"	: [ "
+	    			+ "{" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    					+ "{ "+
+    							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+    							"}," +
+    							"{" +
+    								"\"Prefix\" : \"md\", " +
+    								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+    							"}], "+
+    					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}," +
+            		"{" +
+    	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+    	    				"\"Namespaces\" : ["
+    	    					+ "{ "+
+        							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+        							"}," +
+        							"{" +
+        								"\"Prefix\" : \"md\", " +
+        								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+        							"}], "+
+        					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+                		"}," +
+                		"{" +
+        	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+        	    				"\"Namespaces\" : ["
+        	    					+ "{ "+
+            							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+            							"}," +
+            							"{" +
+            								"\"Prefix\" : \"md\", " +
+            								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+            							"}], "+
+            					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+                    		"}"
+	    			+ "] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace={[{md,urn:example:med:schemas:record}{urn:oasis:names:tc:xacml:3.0:core:schema:wd-17}]},status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace={[{md,urn:example:med:schemas:record}{urn:oasis:names:tc:xacml:3.0:core:schema:wd-17}]},status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace={[{md,urn:example:med:schemas:record}{urn:oasis:names:tc:xacml:3.0:core:schema:wd-17}]},status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\", " +
+	    			"\"Value\"	: [ "
+	    			+ "{" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    					+ "{ "+
+    							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+    							"}," +
+    							"{" +
+    								"\"Prefix\" : \"md\", " +
+    								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+    							"}], "+
+    					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}," +
+            		"\"simpleString\"," +
+                		"{" +
+        	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+        	    				"\"Namespaces\" : ["
+        	    					+ "{ "+
+            							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+            							"}," +
+            							"{" +
+            								"\"Prefix\" : \"md\", " +
+            								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+            							"}], "+
+            					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+                    		"}"
+	    			+ "] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\", " +
+	    			"\"Value\"	: [ "
+	    			+ "{" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    					+ "{ "+
+    							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+    							"}," +
+    							"{" +
+    								"\"Prefix\" : \"md\", " +
+    								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+    							"}], "+
+    					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}," +
+            		"true," +
+                		"{" +
+        	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+        	    				"\"Namespaces\" : ["
+        	    					+ "{ "+
+            							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+            							"}," +
+            							"{" +
+            								"\"Prefix\" : \"md\", " +
+            								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+            							"}], "+
+            					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+                    		"}"
+	    			+ "] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\", " +
+	    			"\"Value\"	: [ "
+	    			+ "{" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    					+ "{ "+
+    							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+    							"}," +
+    							"{" +
+    								"\"Prefix\" : \"md\", " +
+    								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+    							"}], "+
+    					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}," +
+            		"123," +
+                		"{" +
+        	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+        	    				"\"Namespaces\" : ["
+        	    					+ "{ "+
+            							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+            							"}," +
+            							"{" +
+            								"\"Prefix\" : \"md\", " +
+            								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+            							"}], "+
+            					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+                    		"}"
+	    			+ "] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\", " +
+	    			"\"Value\"	: [ "
+	    			+ "{" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    					+ "{ "+
+    							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+    							"}," +
+    							"{" +
+    								"\"Prefix\" : \"md\", " +
+    								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+    							"}], "+
+    					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}," +
+            		"12.34," +
+                		"{" +
+        	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+        	    				"\"Namespaces\" : ["
+        	    					+ "{ "+
+            							"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+            							"}," +
+            							"{" +
+            								"\"Prefix\" : \"md\", " +
+            								"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+            							"}], "+
+            					"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+                    		"}"
+	    			+ "] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+
+	}
+	
+
+	
+	
+	
+	
+	
+	@Test
+	public void testArrayNoDataTypes() {
+		
+		// array of size 0
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Category Attribute value array DataType Not given (repeat for all data types)
+		// Also tests for mixes of different JSON types (trying incorrect strings for XACML data types whenever possible)
+		// string
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [\"abc\", \"def\", \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=def}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT to DataType
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [\"abc\", true, \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [\"abc\",123, \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [\"abc\", 34.34, \"hig\", \"lmn\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=34.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=hig}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lmn}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// boolean
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [true, true, false, true, false ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=false}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#boolean,value=false}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [true, \"abc\", false, true, false ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [true, 123, false, true, false ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [true, 12.34, false, true, false ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		
+		// integer
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [123, 456, 765, 234] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=456}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=765}{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=234}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [123, \"abc\", 765, 234] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [123, true, 765, 234] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+		
+		
+		// double
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ 123.34, 543.54, 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=543.54}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=3445.455}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=4543.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=543.0}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// special case - auto-convert integer to boolean
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ 123.34, 111122, 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=111122.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=3445.455}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=4543.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=543.0}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ 123.34, true, 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ 123.34, \"abb\", 3445.455, 4543,543 ] " +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// time - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", \"12:00:00Z\", \"12:00:00Z\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", true, \"12:00:00Z\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// SUCCESSFUL AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", 123, \"12:00:00Z\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"12:00:00Z\", 12.34, \"12:00:00Z\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// date - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [\"2002-10-10\",\"2002-10-10\",\"2002-10-10\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [\"2002-10-10\",true,\"2002-10-10\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [\"2002-10-10\",123,\"2002-10-10\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [\"2002-10-10\",123.45,\"2002-10-10\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123.45}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// dateTime - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",\"2002-10-10T12:00:00Z\",\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",true,\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",123,\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"2002-10-10T12:00:00Z\",12.34,\"2002-10-10T12:00:00Z\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=12.34}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=2002-10-10T12:00:00Z}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// dayTimeDuration - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",\"P23DT7H12M54S\",\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		//AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",true,\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",123,\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"P23DT7H12M54S\",11.22,\"P23DT7H12M54S\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.22}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P23DT7H12M54S}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// yearMonth duration - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",\"P165Y8M\",\"P165Y8M\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",true,\"P165Y8M\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",123,\"P165Y8M\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"P165Y8M\",11.22,\"P165Y8M\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.22}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=P165Y8M}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// anyURI - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\",\"aValue\",\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\",true,\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\",123,\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\",11.111,\"aValue\"] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.111}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// hexBinary - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",\"FA027B7D12CC34DDD20012AEEF\",\"FA027B7D12CC34DDD20012AEEF\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=FA027B7D12CC34DDD20012AEEF}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=FA027B7D12CC34DDD20012AEEF}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=FA027B7D12CC34DDD20012AEEF}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",true,\"012AEEF\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=FA027B7D12CC34DDD20012AEEF}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=012AEEF}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",123,\"012AEEF\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=FA027B7D12CC34DDD20012AEEF}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=012AEEF}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"FA027B7D12CC34DDD20012AEEF\",11.44,\"012AEEF\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=FA027B7D12CC34DDD20012AEEF}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.44}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=012AEEF}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// base64Binary - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aG9y\",\"lvbj0iMS4xIj48YXV0aG9y\",\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aG9y}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lvbj0iMS4xIj48YXV0aG9y}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lvbjIj48YXV0aG9y}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aG9y\",true,\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aG9y}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lvbjIj48YXV0aG9y}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aG9y\",1123,\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aG9y}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=1123}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lvbjIj48YXV0aG9y}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aG9y\",11.22,\"lvbjIj48YXV0aG9y\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aG9y}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.22}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=lvbjIj48YXV0aG9y}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// RFC822 name - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",\"one.else@A.COMPANY.com\",\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=sne.else@A.COMPANY.com}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=one.else@A.COMPANY.com}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=someone.else@A.CONY.com}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",true,\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=sne.else@A.COMPANY.com}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=someone.else@A.CONY.com}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",111,\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=sne.else@A.COMPANY.com}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=111}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=someone.else@A.CONY.com}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"sne.else@A.COMPANY.com\",11.22,\"someone.else@A.CONY.com\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=sne.else@A.COMPANY.com}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.22}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=someone.else@A.CONY.com}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// x500 - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", \"cn=Julius Hibbert, o=Medi Corporation, c=US\", \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", true, \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", 1111, \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=1111}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"cn=Julius Hibbert, o=Medi Corporation, c=US\", 11.22, \"cn=Julius Hibbert, o=Medi Corporation, c=US\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.22}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=cn=Julius Hibbert, o=Medi Corporation, c=US}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// ipAddress - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",\"10.221.43.58:12345\",\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",true,\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",1111,\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=1111}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"10.221.43.58:12345\",11.22,\"10.221.43.58:12345\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.22}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=10.221.43.58:12345}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// dnsName - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", true, \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", 1111, \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=1111}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", 11.22, \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.22}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// xPathExpression - defaults to String
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", true, \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=true}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", 1111, \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=1111}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		// AUTO-CONVERT
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", 11.22, \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=11.22}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+	}
+	
+	
+
+	
+	@Test
+	public void testXPathExpression() {
+		// Category Attribute with XPathExpression including XPathCategory and XPath
+		// Category Attribute with XPathExpression with Namespaces with/without Prefix
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : ["
+	    				  + "{ "+
+	    						"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+	    					"}," +
+	    					"{ "+
+    							"\"Prefix\" : \"lab\", " +
+    							"\"Namespace\" : \"http://somewhere/uri.html\" " +
+    						"}," +
+	    					"{" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace={[{md,urn:example:med:schemas:record}{lab,http://somewhere/uri.html}{urn:oasis:names:tc:xacml:3.0:core:schema:wd-17}]},status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with XPathExpression missing XPathCategory
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"Namespaces\" : [{ "+
+	    						"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+	    					"}," +
+	    					"{" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with XPathExpression missing XPath
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [{ "+
+	    						"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+	    					"}," +
+	    					"{" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}] "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with XPathExpression without Namespaces
+		// (path does not contain namespace references)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"XPath\" : \"record/patient/patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=record/patient/patientDoB,Namespace=null,status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with XPathExpression with 0 Namespaces
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace=null,status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Category Attribute with XPathExpression with Namespaces without mandatory Namespace
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [{ "+
+	    						"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+	    					"}," +
+	    					"{" +
+	    						"\"Prefix\" : \"md\", " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [{ "+
+	    					"}," +
+	    					"{" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+				
+		// Category Attribute with XPathExpression with Namespaces with 2 namespaces using same prefix
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [{ "+
+							"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+	    					"}," +
+	    					"{" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with XPathExpression without Namespaces which are used within the XPathExpression (NOTE: Error is not syntactic and is not found by converter)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace=null,status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with XPathExpression containing simple value (must be object)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: \"simple Value\"" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with Namespaces containing simple value (must be object)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [ \"simpleValue\"," +
+	    					"{" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Category Attribute with Namespaces non-string Namespace
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [ {" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : 123 " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with Namespaces non-string prefix
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [ {" +
+	    						"\"Prefix\" : 123, " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with Namespaces non-string XPathCategory
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : 123," +
+	    				"\"Namespaces\" : [ {" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}], "+
+	    				"\"XPath\" : \"md:record/md:patient/md:patientDoB\" "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category Attribute with Namespaces non-string XPath
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"xpathExpression\", " +
+	    			"\"Value\"	: {" +
+	    				"\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\"," +
+	    				"\"Namespaces\" : [ {" +
+	    						"\"Prefix\" : \"md\", " +
+	    						"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+	    					"}], "+
+	    				"\"XPath\" : 123 "+
+            		"}" +
+					"}] } ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+	}
+
+
+	
+	@Test
+	public void testContent() {
+
+		// Category with Content in XML, escaped properly
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\",\"aValue\",\"aValue\"] " +
+	    			"}]," +
+					"\"Content\" : \"<?xml version=\\\"1.0\\\"?><catalog>" + 
+						"<book id=\\\"bk101\\\"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre>" +
+						"<price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description>"+
+						"</book></catalog>\"" +
+					"} ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]},contentRoot=[catalog: null]}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category with Content in XML, double quotes and back-slashes NOT escaped properly?
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\",\"aValue\",\"aValue\"] " +
+	    			"}]," +
+					"\"Content\" : \"<?xml version=\\\"1.0\\\"?><catalog>" + 
+						"<book id=\"bk101\\\"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre>" +
+						"<price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description>"+
+						"</book></catalog>\"" +
+					"} ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category with Content in Base64
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\",\"aValue\",\"aValue\"] " +
+	    			"}]," +
+					"\"Content\" :  \"PD94bWwgdmVyc2lvbj0iMS4wIj8+PGNhdGFsb2c+PGJvb2sgaWQ9ImJrMTAxIj48YXV0aG9yPkdhbWJhcmRlbGxhLCBNYXR0aGV3PC9hdXRob3I+PHRpdGxlPlhNT" +
+							"CBEZXZlbG9wZXIncyBHdWlkZTwvdGl0bGU+PGdlbnJlPkNvbXB1dGVyPC9nZW5yZT48cHJpY2U+NDQuOTU8L3ByaWNlPjxwdWJsaXNoX2RhdGU+MjAwMC0xMC0wMTwvcHVibGlzaF"+
+							"9kYXRlPjxkZXNjcmlwdGlvbj5BbiBpbi1kZXB0aCBsb29rIGF0IGNyZWF0aW5nIGFwcGxpY2F0aW9ucyB3aXRoIFhNTC48L2Rlc2NyaXB0aW9uPjwvYm9vaz48L2NhdGFsb2c+\"" +
+					"} ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]},contentRoot=[catalog: null]}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Category with Bad Content in Base64
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\",\"aValue\",\"aValue\"] " +
+	    			"}]," +
+					"\"Content\" :  \"PD94bWwgdmV\"" +
+					"} ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+	}
+	
+
+	
+	
+	@Test
+	public void testDuplicates() {
+		// duplicate of same element within Category array is ok
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: \"abc\" " +
+					"}] }, " +
+					"{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+			    			"\"Id\" : \"document-id\", " +
+			    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+			    			"\"Value\"	: \"abc\" " +
+							"}] } "
+					+ "] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}],includeInResults=false}]}}{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=abc}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// duplicate Attribute
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [" +
+					"{\"CategoryId\" : \"custom-category\","
+					+ " \"Attribute\" : [{" +
+			    			"\"Id\" : \"document-id\", " +
+			    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+			    			"\"Value\"	: \"abc\" " +
+							"}], "
+					+ " \"Attribute\" : [{" +
+			    			"\"Id\" : \"document-id\", " +
+			    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+			    			"\"Value\"	: \"abc\" " +
+							"}] "
+							+ "} "
+					+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// dup id
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: \"abc\" " +
+					"}] } " 
+					+ "] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// dup DataType
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: \"abc\" " +
+					"}] } " 
+					+ "] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// dup Value
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"DataType\"	: \"http://www.w3.org/2001/XMLSchema#string\", " +
+	    			"\"Value\"	: \"abc\" " +
+	    			"\"Value\"	: \"abc\" " +
+					"}] } " 
+					+ "] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// duplicate Content
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{"
+					+ "\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: [ \"aValue\",\"aValue\",\"aValue\"] " +
+	    				"}]," +
+	    				"\"Content\" : \"<?xml version=\\\"1.0\\\"?><catalog>" + 
+							"<book id=\\\"bk101\\\"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre>" +
+							"<price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description>"+
+							"</book></catalog>\" , " +
+						"\"Content\" : \"<?xml version=\\\"1.0\\\"?><catalog>" + 
+							"<book id=\\\"bk101\\\"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre>" +
+							"<price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description>"+
+							"</book></catalog>\"" +
+					"} ] }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+	}
+	
+
+	
+//TODO - Shorthand for CategoryId ????
+	
+	
+}
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestConformanceTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestConformanceTest.java
new file mode 100644
index 0000000..6c30cb4
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestConformanceTest.java
@@ -0,0 +1,253 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Test;
+
+import com.att.research.xacml.api.Request;
+import com.att.research.xacml.api.RequestAttributes;
+import com.att.research.xacml.api.RequestReference;
+import com.att.research.xacml.std.dom.DOMRequest;
+import com.att.research.xacml.std.json.JSONRequest;
+import com.att.research.xacml.std.json.JSONStructureException;
+/**
+ * Test JSON Request convert to object - Conformance tests
+ * 
+ * TO RUN - use jUnit
+ * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test
+ * 
+ * NOTE:
+ * The "correct" way to verify that each JSON string gets translated into our internal Objects correctly is to look explicitly at each of the child objects
+ * and verify that they are correct.  This would involve a lot of coding to get child of child of child and individually verify each property of each element.
+ * To simplify testing we assume that request.toString() correctly includes a complete text representation of every sub-component of the Request object
+ * and we compare the resulting String to our expected String.
+ * This has two possible sources of error:
+ * 	- toString might not include some sub-component, and
+ * 	- the initial verification of the resulting string is done by hand and may have been incorrect.
+ * 
+ *
+ */
+public class RequestConformanceTest {
+	
+	// where to find the conformance test XML files
+	private final String CONFORMANCE_DIRECTORY_PATH = "testsets/conformance/xacml3.0-ct-v.0.4";
+	
+	// The request object output from each test conversion from JSON string
+	Request request;
+
+
+	
+	
+	
+	// test just one of each top-level element.
+	// For simple elements also test for incorrect type
+	@Test
+	public void testConformanceRequests() {
+		
+		List<File> filesInDirectory = null;
+		
+		File conformanceDirectory = null;
+		
+		File currentFile = null;
+		
+		try {
+			conformanceDirectory = new File(CONFORMANCE_DIRECTORY_PATH);
+			filesInDirectory = getRequestsInDirectory(conformanceDirectory);
+		} catch (Exception e) {
+			fail("Unable to set up Conformance tests for dir '" + conformanceDirectory.getAbsolutePath()+"' e="+ e);
+		}
+		
+		// run through each XML file
+		//	- load the file from XML into an internal Request object
+		//	- generate the JSON representation of that Request object
+		//	- load that JSON representation into a new Request object
+		//	- compare the 2 Request objects
+		Request xmlRequest = null;
+		Request jsonRequest = null;
+		try {
+			for (File f : filesInDirectory) {
+				currentFile = f;
+
+//// This is a simple way to select just one file for debugging - comment out when not being used
+//if ( ! f.getName().equals("IIA023Request.xml")) {   continue;  }
+
+// during debugging it is helpful to know what file it is starting to work on
+//				System.out.println("starting file="+currentFile.getName());
+				
+				try {
+					// load XML into a Request object
+					xmlRequest = DOMRequest.load(f);
+					xmlRequest.getStatus();
+				} catch (Exception e) {
+					// if XML does not load, just note it and continue with next file
+					System.out.println("XML file did not load: '" + f.getName() + "  e=" + e);
+					continue;
+				}
+				
+//System.out.println(JSONRequest.toString(xmlRequest, false));
+
+				// generate JSON from the Request
+				String jsonString = JSONRequest.toString(xmlRequest, false);		
+				
+				// load JSON into a Request
+				jsonRequest = JSONRequest.load(jsonString);
+				
+				// compare the two Request objects
+				
+				// check simple things first
+				assertEquals("File '" + currentFile.getName() + "' CombinedDecision", xmlRequest.getCombinedDecision(), jsonRequest.getCombinedDecision());
+				assertEquals("File '" + currentFile.getName() + "' getReturnPolicyIdList", xmlRequest.getReturnPolicyIdList(), jsonRequest.getReturnPolicyIdList());
+				assertEquals("File '" + currentFile.getName() + "' requestDefaults", xmlRequest.getRequestDefaults(), jsonRequest.getRequestDefaults());
+
+				// multiRequests (guaranteed to not be null)
+				// We do NOT care about ordering, so compare the two collections inefficiently
+				Collection<RequestReference> xmlCollection = xmlRequest.getMultiRequests();
+				Collection<RequestReference> jsonCollection = jsonRequest.getMultiRequests();
+				String errorMessage = null;
+				if (jsonCollection.size() != xmlCollection.size()) {
+					errorMessage = "File '" + currentFile.getName() + "' MultiRequests not same size.  ";
+				} else if (! jsonCollection.containsAll(xmlCollection)) {
+					errorMessage = "File '" + currentFile.getName() + "' MultiRequests have different contents.  ";
+				}
+				if (errorMessage != null) {
+					String xmlContents = "";
+					String jsonContents = "";
+					Iterator<RequestReference> rrIt = xmlCollection.iterator();
+					while (rrIt.hasNext()) {
+						xmlContents += "\n   " + rrIt.next().toString(); 
+					}
+					rrIt = jsonCollection.iterator();
+					while (rrIt.hasNext()) { 
+						jsonContents += "\n  " + rrIt.next().toString(); 
+					}
+					fail(errorMessage + "\nXML(" + xmlCollection.size() + ")='" + xmlContents + 
+							"'  \nJSON(" + jsonCollection.size() + ")='" + jsonContents +
+							"'" +
+							"\njson='" + jsonString + "'");
+				}
+				
+				// attributes (guaranteed to not be null)
+				// We do NOT care about ordering, so compare the two collections inefficiently
+				Collection<RequestAttributes> xmlAttrCollection = xmlRequest.getRequestAttributes();
+				Collection<RequestAttributes> jsonAttrCollection = jsonRequest.getRequestAttributes();
+				errorMessage = null;
+				if (jsonAttrCollection.size() != xmlAttrCollection.size()) {
+					errorMessage = "File '" + currentFile.getName() + "' RequestAttributes not same size.  ";
+				} else if (! jsonAttrCollection.containsAll(xmlAttrCollection)) {
+					String attrName = "";
+					Iterator<RequestAttributes> rait = xmlAttrCollection.iterator();
+					while (rait.hasNext()) {
+						RequestAttributes ra = rait.next();
+						if (jsonAttrCollection.contains(ra) == false) {
+							attrName = ra.toString();
+						}
+					}
+					errorMessage = "File '" + currentFile.getName() + "' RequestAttributes have different contents.  JSON is missing attr=" + attrName;
+				}
+				if (errorMessage != null) {
+					String xmlContents = "";
+					String jsonContents = "";
+					Iterator<RequestAttributes> rrIt = xmlAttrCollection.iterator();
+					while (rrIt.hasNext()) {
+						RequestAttributes ras = rrIt.next();
+						xmlContents += "\n   " + ras.toString();
+						if (ras.getContentRoot() != null) {
+							StringWriter writer = new StringWriter();
+							Transformer transformer = null;
+							try {
+								transformer = TransformerFactory.newInstance().newTransformer();
+								transformer.transform(new DOMSource(ras.getContentRoot()), new StreamResult(writer));
+							} catch (Exception e) {
+								throw new JSONStructureException("Unable to Content node to string; e="+e);
+							}
+
+							xmlContents += "\n        Content: " + writer.toString();
+						}
+					}
+					rrIt = jsonAttrCollection.iterator();
+					while (rrIt.hasNext()) { 
+						RequestAttributes ras = rrIt.next();
+						jsonContents += "\n   " + ras.toString();	
+						if (ras.getContentRoot() != null) {
+							StringWriter writer = new StringWriter();
+							Transformer transformer = null;
+							try {
+								transformer = TransformerFactory.newInstance().newTransformer();
+								transformer.transform(new DOMSource(ras.getContentRoot()), new StreamResult(writer));
+							} catch (Exception e) {
+								throw new JSONStructureException("Unable to Content node to string; e="+e);
+							}
+
+							jsonContents += "\n        Content: " + writer.toString();
+						}
+					}
+					fail(errorMessage + "\nXML(" + xmlAttrCollection.size() + ")='" + xmlContents + 
+							"'  \nJSON(" + jsonAttrCollection.size() + ")='" + jsonContents +
+							"\njson='" + jsonString + "'");
+				}
+				
+
+			}			
+
+		} catch (Exception e) {
+			fail ("Failed test with '" + currentFile.getName() + "', e=" + e);
+		}
+
+		
+	}
+	
+	//
+	// HELPER to get list of all Request files in the given directory
+	//
+	
+	private List<File> getRequestsInDirectory(File directory) {
+		List<File> fileList = new ArrayList<File>();
+		
+		File[] fileArray = directory.listFiles();
+		for (File f : fileArray) {
+			if (f.isDirectory()) {
+				List<File> subDirList = getRequestsInDirectory(f);
+				fileList.addAll(subDirList);
+			}
+			if (f.getName().endsWith("Request.xml")) {
+				fileList.add(f);
+			}
+		}
+		return fileList;
+		
+	}
+	
+}
\ No newline at end of file
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestDefaultCategoryTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestDefaultCategoryTest.java
new file mode 100644
index 0000000..a5929a4
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestDefaultCategoryTest.java
@@ -0,0 +1,1427 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import com.att.research.xacml.api.Request;
+import com.att.research.xacml.std.json.JSONRequest;
+import com.att.research.xacml.std.json.JSONStructureException;
+/**
+ * Test JSON Request convert to object - Default Category object tests
+ * 
+ * TO RUN - use jUnit
+ * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test
+ * 
+ * NOTE:
+ * The "correct" way to verify that each JSON string gets translated into our internal Objects correctly is to look explicitly at each of the child objects
+ * and verify that they are correct.  This would involve a lot of coding to get child of child of child and individually verify each property of each element.
+ * To simplify testing we assume that request.toString() correctly includes a complete text representation of every sub-component of the Request object
+ * and we compare the resulting String to our expected String.
+ * This has two possible sources of error:
+ * 	- toString might not include some sub-component, and
+ * 	- the initial verification of the resulting string is done by hand and may have been incorrect.
+ * 
+ *
+ */
+public class RequestDefaultCategoryTest {
+	
+	// The request object output from each test conversion from JSON string
+	Request request;
+
+	
+	/*
+	 * Request that uses all fields with both single and multiple  entries
+	 */
+	String allFieldsRequest = 
+			"{\"Request\": {" +
+					"\"ReturnPolicyIdList\" : true ," +
+					"\"CombinedDecision\" : true ," +
+					"\"XPathVersion\" : \"http://www.w3.org/TR/1999/REC-xpath-19991116\"," +
+					"\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar1\"]" +
+			                "}]" +   
+			          "}," +
+
+					"\"Category\": [" +
+						"{ " +
+					    	"\"CategoryId\": \"custom-category\", " +
+					    	"\"Id\" : \"customId\", " +
+					    	"\"Attribute\" : [" +
+					    		"{" +
+					    			"\"AttributeId\"		: \"document-id\", " +
+					    			"\"DataType\"	: \"integer\", " +
+					    			"\"Value\"	: 123 " +
+								"}, " +
+								"{" +
+				    				"\"AttributeId\"		: \"document-url\", " +
+				    				"\"DataType\"	: \"anyURI\", " +
+				    				"\"Value\"	: \"http://somewhere.over.the.com/rainbow\" " +
+				    			"}, " +
+								"{" +
+				    				"\"AttributeId\"		: \"page-list\", " +
+				    				"\"Value\"	: [1, 2, 3, 4.5, 3, 2, 1] " +
+							"} " +
+					    	"]" +
+					    "}, " +
+					    "{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"], " +
+					    
+					"\"AccessSubject\":{ " +
+						"\"Content\" : \"<?xml version=\\\"1.0\\\"?><catalog>" + 
+							"<book id=\\\"bk101\\\"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre>" +
+							"<price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description>"+
+							"</book></catalog>\"," +
+						"\"Attribute\" : []" +
+					"}, " +
+					
+					"\"Resource\" : {" +
+						"\"Content\" : \"PD94bWwgdmVyc2lvbj0iMS4wIj8+PGNhdGFsb2c+PGJvb2sgaWQ9ImJrMTAxIj48YXV0aG9yPkdhbWJhcmRlbGxhLCBNYXR0aGV3PC9hdXRob3I+PHRpdGxlPlhNT" +
+							"CBEZXZlbG9wZXIncyBHdWlkZTwvdGl0bGU+PGdlbnJlPkNvbXB1dGVyPC9nZW5yZT48cHJpY2U+NDQuOTU8L3ByaWNlPjxwdWJsaXNoX2RhdGU+MjAwMC0xMC0wMTwvcHVibGlzaF"+
+							"9kYXRlPjxkZXNjcmlwdGlvbj5BbiBpbi1kZXB0aCBsb29rIGF0IGNyZWF0aW5nIGFwcGxpY2F0aW9ucyB3aXRoIFhNTC48L2Rlc2NyaXB0aW9uPjwvYm9vaz48L2NhdGFsb2c+\"" +
+
+
+					"} " +
+
+			          
+			"}}";
+	
+	/*
+	 * The following example comes directly from the JSON Profile Spec
+	 */
+	String exampleFromSpec = "{ " +
+			"\"Request\" : { " +
+				"\"AccessSubject\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Andreas\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Gamla Stan\" " +
+						"} " +
+					"] " +
+				"}, " +
+				"\"Action\" : { " +
+					"\"Attribute\":  " +
+						"{ " +
+							"\"Id\" : \"action-id\", " +
+							"\"Value\" : \"http://www.xacml.eu/buy\", " +
+							"\"DataType\" : \"anyURI\" " +
+						"} " +
+				"}, " +
+				"\"Resource\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"book-title\", " +
+							"\"Value\" : \"Learn German in 90 days\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"currency\", " +
+							"\"Value\" : \"SEK\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"price\", " +
+							"\"Value\" : 123.34 " +
+						"} " +
+						"] " +
+					"} " +
+				"} " +
+			"} ";
+
+	
+	/*
+	 * The following example comes directly from the JSON Profile Spec (modified to include a "</Catalog>" missing from both examples).
+	 * It shows the two ways of handling XPath content, as escaped XML and as Base64 encoding.
+	 */
+	String xPathExampleFromSpec = "{ " +
+			"\"Request\" : { " +
+				"\"Resource\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+						 	"\"Id\" : \"urn:oasis:names:tc:xacml:3.0:content-selector\", " +
+				            "\"DataType\" : \"xpathExpression\", " +
+				            "\"Value\" : { " +
+				                "\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\", " +
+				                "\"Namespaces\" : [{ " +
+				                    	"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+				                    	"}, " +
+				                    "{ " +
+				                    	"\"Prefix\" : \"md\", " +
+				                    	"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+				                    "} " +
+				                "], " +
+				                "\"XPath\" : \"md:record/md:patient/md:patientDoB\" " +
+				            "} " +
+				        "} " +
+					"] " +
+				"} " +
+			"} " +
+		"} ";
+
+	
+	// test Shorthand Category notation for elements not tested in their own section below.
+	// Categories that are more commonly used are fully tested. 
+	// Given that the functions within the categories are the same irrespective of the name of the category, 
+	// we assume that the contents of the category will work ok once the Shorthand notation is recognized, so all we need to test is the shorthand
+	// The ones that are tested in their own sections are:
+	//		AccessSubject
+	//		Action
+	//		Resource
+	//		Environment 
+	// test Subject
+	@Test
+	public void testCategoryShorthand() {
+	
+		// RecipientSubject present both as element within Category and as separate RecipientSubject element at same level as Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+						"}] }, "
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"RecipientSubject\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// IntermediarySubject present both as element within Category and as separate IntermediarySubject element at same level as Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+						"}] }, "
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"IntermediarySubject\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Codebase present both as element within Category and as separate Codebase element at same level as Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:codebase\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+						"}] }, "
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:codebase\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"Codebase\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:codebase,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:codebase,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:codebase,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:codebase,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:codebase,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:codebase,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:codebase,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		
+		// RequestingMachine present both as element within Category and as separate RequestingMachine element at same level as Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+						"}] }, "
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"RequestingMachine\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+	}
+
+
+
+
+
+	
+
+
+	
+
+
+	
+	
+	
+	
+	
+	// test AccessSubject
+	// Include test for backward compatibility with "Subject"
+	@Test
+	public void testAccessSubjectRequest() {
+		
+		// AccessSubject absent
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// AccessSubject as normal element under Category (with CategoryId==subject category id)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// multiple AccessSubjects under Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": ["
+					+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] }, "
+					+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: \"aValue\"" +
+					"}] } "
+					+ "] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// AccessSubject present both as element within Category and as separate AccessSubject element at same level as Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+						"}] }, "
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"AccessSubject\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// AccessSubject present, no other Category element
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"AccessSubject\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Subject present, no other Category element (Backward Compatibility
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Subject\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// AccessSubject present, 1/multiple other Category element also present
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"AccessSubject\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// 2 AccessSubjects - duplicates fail
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"AccessSubject\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+					+ 
+					"\"AccessSubject\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// AccessSubject with correct Category value
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"AccessSubject\" : { " +
+						"\"CategoryId\" : \"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\" ," +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// AccessSubject with wrong Category value
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"AccessSubject\" : { " +
+						"\"CategoryId\" : \"notthesubject\" ," +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// AccessSubject with array of sub-object AccessSubjects (Multi Decision)
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"AccessSubject\" : ["
+					+ "{ " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"}, "
+					+ "{ " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Arless\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Somewhere\" " +
+						"} " +
+					"] " +
+					"}, "
+					+ "{ " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Barry\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Elsewhere\" " +
+						"} " +
+					"] " +
+					"} "
+				+ "]"
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Arless}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Somewhere}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Barry}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Elsewhere}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+	}
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	// Action ... duplicate all AccessSubject tests...
+	// test Action
+	@Test
+	public void testActionRequest() {
+		
+		// Action absent
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action as normal element under Category (with CategoryId==subject category id)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// multiple Actions under Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": ["
+					+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] }, "
+					+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: \"aValue\"" +
+					"}] } "
+					+ "] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action present both as element within Category and as separate Action element at same level as Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+						"}] }, "
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"Action\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action present, no other Category element
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Action\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action present, 1/multiple other Category element also present
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"Action\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// 2 Actions - duplicates fail
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Action\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+					+ 
+					"\"Action\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action with correct Category value
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Action\" : { " +
+						"\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:action\" ," +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action with wrong Category value
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Action\" : { " +
+						"\"CategoryId\" : \"notthesubject\" ," +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action with array of sub-object Actions (Multi Decision)
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Action\" : ["
+					+ "{ " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"}, "
+					+ "{ " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Arless\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Somewhere\" " +
+						"} " +
+					"] " +
+					"}, "
+					+ "{ " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Barry\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Elsewhere\" " +
+						"} " +
+					"] " +
+					"} "
+				+ "]"
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Arless}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Somewhere}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Barry}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Elsewhere}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+	}
+	
+	
+	
+	
+	// Resource ... duplicate all AccessSubject tests...
+	// test Resource
+	@Test
+	public void testResourceRequest() {
+		
+		// Resource absent
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource as normal element under Category (with CategoryId==subject category id)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// multiple Resources under Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": ["
+					+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] }, "
+					+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: \"aValue\"" +
+					"}] } "
+					+ "] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource present both as element within Category and as separate Resource element at same level as Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+						"}] }, "
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"Resource\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource present, no other Category element
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Resource\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource present, 1/multiple other Category element also present
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"Resource\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// 2 Resources - duplicates fail
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Resource\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+					+ 
+					"\"Resource\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource with correct Category value
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Resource\" : { " +
+						"\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\" ," +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource with wrong Category value
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Resource\" : { " +
+						"\"CategoryId\" : \"notthesubject\" ," +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource with array of sub-object Resources (Multi Decision)
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Resource\" : ["
+					+ "{ " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"}, "
+					+ "{ " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Arless\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Somewhere\" " +
+						"} " +
+					"] " +
+					"}, "
+					+ "{ " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Barry\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Elsewhere\" " +
+						"} " +
+					"] " +
+					"} "
+				+ "]"
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Arless}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Somewhere}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Barry}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Elsewhere}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+	}
+	
+	
+	
+	
+	
+	
+	// Environment ... duplicate all AccessSubject tests ...
+	// test Environment
+	@Test
+	public void testEnvironmentRequest() {
+		
+		// Environment absent
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment as normal element under Category (with CategoryId==subject category id)
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": [{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    			"\"Id\" : \"document-id\", " +
+	    			"\"Value\"	: \"aValue\" " +
+					"}] } ] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// multiple Environments under Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {\"Category\": ["
+					+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+					"}] }, "
+					+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+	    				"\"Id\" : \"document-id\", " +
+	    				"\"Value\"	: \"aValue\"" +
+					"}] } "
+					+ "] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment present both as element within Category and as separate Environment element at same level as Category
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: [ \"aValue\", \"aValue\", \"aValue\" ] " +
+						"}] }, "
+						+ "{\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"Environment\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=document-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment present, no other Category element
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Environment\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment present, 1/multiple other Category element also present
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ "\"Category\": ["
+						+ "{\"CategoryId\" : \"custom-category\", \"Attribute\" : [{" +
+		    				"\"Id\" : \"document-id\", " +
+		    				"\"Value\"	: \"aValue\"" +
+						"}] } "
+						+ "]," +
+					"\"Environment\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=aValue}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// 2 Environments - duplicates fail
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Environment\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+					+ 
+					"\"Environment\" : { " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment with correct Category value
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Environment\" : { " +
+						"\"CategoryId\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\" ," +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment with wrong Category value
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Environment\" : { " +
+						"\"CategoryId\" : \"notthesubject\" ," +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"} " 
+				+ " }}");
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment with array of sub-object Environments (Multi Decision)
+		try {
+			request = JSONRequest.load("{\"Request\" : {"
+					+ 
+					"\"Environment\" : ["
+					+ "{ " +
+						"\"Attribute\": [ " +
+							"{ " +
+								"\"Id\" : \"subject-id\", " +
+								"\"Value\" : \"Andreas\" " +
+							"}, " +
+							"{ " +
+								"\"Id\" : \"location\", " +
+								"\"Value\" : \"Gamla Stan\" " +
+							"} " +
+						"] " +
+					"}, "
+					+ "{ " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Arless\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Somewhere\" " +
+						"} " +
+					"] " +
+					"}, "
+					+ "{ " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Barry\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Elsewhere\" " +
+						"} " +
+					"] " +
+					"} "
+				+ "]"
+				+ " }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Arless}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Somewhere}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Barry}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Elsewhere}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+	}
+
+	
+}
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestMainTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestMainTest.java
new file mode 100644
index 0000000..198ba3a
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/RequestMainTest.java
@@ -0,0 +1,1076 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import com.att.research.xacml.api.Request;
+import com.att.research.xacml.std.json.JSONRequest;
+import com.att.research.xacml.std.json.JSONStructureException;
+/**
+ * Test JSON Request convert to object - High-level Request-as-a-whole tests including test that fills in all fields with multiple values (where appropriate)
+ * 
+ * TO RUN - use jUnit
+ * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test
+ * 
+ * NOTE:
+ * The "correct" way to verify that each JSON string gets translated into our internal Objects correctly is to look explicitly at each of the child objects
+ * and verify that they are correct.  This would involve a lot of coding to get child of child of child and individually verify each property of each element.
+ * To simplify testing we assume that request.toString() correctly includes a complete text representation of every sub-component of the Request object
+ * and we compare the resulting String to our expected String.
+ * This has two possible sources of error:
+ * 	- toString might not include some sub-component, and
+ * 	- the initial verification of the resulting string is done by hand and may have been incorrect.
+ * 
+ *
+ */
+public class RequestMainTest {
+	
+	// The request object output from each test conversion from JSON string
+	Request request;
+
+	
+	/*
+	 * Request that uses all fields with both single and multiple  entries
+	 */
+	String allFieldsRequest = 
+			"{\"Request\": {" +
+					"\"ReturnPolicyIdList\" : true ," +
+					"\"CombinedDecision\" : true ," +
+					"\"XPathVersion\" : \"http://www.w3.org/TR/1999/REC-xpath-19991116\"," +
+					"\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar1\"]" +
+			                "}]" +   
+			          "}," +
+
+					"\"Category\": [" +
+						"{ " +
+					    	"\"CategoryId\": \"custom-category\", " +
+					    	"\"Id\" : \"customId\", " +
+					    	"\"Attribute\" : [" +
+					    		"{" +
+					    			"\"AttributeId\"		: \"document-id\", " +
+					    			"\"DataType\"	: \"integer\", " +
+					    			"\"Value\"	: 123 " +
+								"}, " +
+								"{" +
+				    				"\"AttributeId\"		: \"document-url\", " +
+				    				"\"DataType\"	: \"anyURI\", " +
+				    				"\"Value\"	: \"http://somewhere.over.the.com/rainbow\" " +
+				    			"}, " +
+								"{" +
+				    				"\"AttributeId\"		: \"page-list\", " +
+				    				"\"Value\"	: [1, 2, 3, 4.5, 3, 2, 1] " +
+							"} " +
+					    	"]" +
+					    "}, " +
+					    "{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"], " +
+					    
+					"\"AccessSubject\":{ " +
+						"\"Content\" : \"<?xml version=\\\"1.0\\\"?><catalog>" + 
+							"<book id=\\\"bk101\\\"><author>Gambardella, Matthew</author><title>XML Developer's Guide</title><genre>Computer</genre>" +
+							"<price>44.95</price><publish_date>2000-10-01</publish_date><description>An in-depth look at creating applications with XML.</description>"+
+							"</book></catalog>\"," +
+						"\"Attribute\" : []" +
+					"}, " +
+					
+					"\"Resource\" : {" +
+						"\"Content\" : \"PD94bWwgdmVyc2lvbj0iMS4wIj8+PGNhdGFsb2c+PGJvb2sgaWQ9ImJrMTAxIj48YXV0aG9yPkdhbWJhcmRlbGxhLCBNYXR0aGV3PC9hdXRob3I+PHRpdGxlPlhNT" +
+							"CBEZXZlbG9wZXIncyBHdWlkZTwvdGl0bGU+PGdlbnJlPkNvbXB1dGVyPC9nZW5yZT48cHJpY2U+NDQuOTU8L3ByaWNlPjxwdWJsaXNoX2RhdGU+MjAwMC0xMC0wMTwvcHVibGlzaF"+
+							"9kYXRlPjxkZXNjcmlwdGlvbj5BbiBpbi1kZXB0aCBsb29rIGF0IGNyZWF0aW5nIGFwcGxpY2F0aW9ucyB3aXRoIFhNTC48L2Rlc2NyaXB0aW9uPjwvYm9vaz48L2NhdGFsb2c+\"" +
+
+
+					"} " +
+
+			          
+			"}}";
+	
+	/*
+	 * The following example comes directly from the JSON Profile Spec
+	 */
+	String exampleFromSpec = "{ " +
+			"\"Request\" : { " +
+				"\"AccessSubject\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"subject-id\", " +
+							"\"Value\" : \"Andreas\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"location\", " +
+							"\"Value\" : \"Gamla Stan\" " +
+						"} " +
+					"] " +
+				"}, " +
+				"\"Action\" : { " +
+					"\"Attribute\":  " +
+						"{ " +
+							"\"Id\" : \"action-id\", " +
+							"\"Value\" : \"http://www.xacml.eu/buy\", " +
+							"\"DataType\" : \"anyURI\" " +
+						"} " +
+				"}, " +
+				"\"Resource\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+							"\"Id\" : \"book-title\", " +
+							"\"Value\" : \"Learn German in 90 days\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"currency\", " +
+							"\"Value\" : \"SEK\" " +
+						"}, " +
+						"{ " +
+							"\"Id\" : \"price\", " +
+							"\"Value\" : 123.34 " +
+						"} " +
+						"] " +
+					"} " +
+				"} " +
+			"} ";
+
+	
+	/*
+	 * The following example comes directly from the JSON Profile Spec (modified to include a "</Catalog>" missing from both examples).
+	 * It shows the two ways of handling XPath content, as escaped XML and as Base64 encoding.
+	 */
+	String xPathExampleFromSpec = "{ " +
+			"\"Request\" : { " +
+				"\"Resource\" : { " +
+					"\"Attribute\": [ " +
+						"{ " +
+						 	"\"Id\" : \"urn:oasis:names:tc:xacml:3.0:content-selector\", " +
+				            "\"DataType\" : \"xpathExpression\", " +
+				            "\"Value\" : { " +
+				                "\"XPathCategory\" : \"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\", " +
+				                "\"Namespaces\" : [{ " +
+				                    	"\"Namespace\" : \"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" " +
+				                    	"}, " +
+				                    "{ " +
+				                    	"\"Prefix\" : \"md\", " +
+				                    	"\"Namespace\" : \"urn:example:med:schemas:record\" " +
+				                    "} " +
+				                "], " +
+				                "\"XPath\" : \"md:record/md:patient/md:patientDoB\" " +
+				            "} " +
+				        "} " +
+					"] " +
+				"} " +
+			"} " +
+		"} ";
+
+	
+	
+	// test various ways that request might be empty
+	@Test
+	public void testEmptyRequest() {
+		// null request
+		try {
+			request = JSONRequest.load((String)null);
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// empty request
+		try {
+			request = JSONRequest.load((String)"");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)" ");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// empty JSON request
+		try {
+			request = JSONRequest.load((String)"{}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{{}}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// garbage input
+		try {
+			request = JSONRequest.load((String)"Some non-JSON string");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{something non-JSON}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// bad syntax (Request with no content)
+		try {
+			request = JSONRequest.load((String)"{\"Request\"}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// bad syntax (no :field after Request)
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// bad syntax (no " around Request)
+		try {
+			request = JSONRequest.load((String)"{Request}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// empty content in Request
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : \"\"}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// content is not an object
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : \"CombinedDecision\" : true }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// too many } at end
+		// Jackson parser does not treat this as an error
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : \"http://www.w3.org/TR/1999/REC-xpath-19991116\"}}}}}");
+			assertEquals("{requestDefaults={xpatherVersion=http://www.w3.org/TR/1999/REC-xpath-19991116},returnPolicyIdList=false,combinedDecision=false}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// too few } at end
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : \"http://www.w3.org/TR/1999/REC-xpath-19991116\" }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// misplaced } in middle
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : } \"http://www.w3.org/TR/1999/REC-xpath-19991116\"}}}}}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+
+	}
+	
+
+	
+	// Test double braces around request
+	@Test
+	public void testDoubleBraces() {
+		
+		try {
+			request = JSONRequest.load((String)"{{\"Request\" }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{{\"Request\" : }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{{\"Request\" : {\"CombinedDecision\" : true }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+	}
+	
+	
+	
+	// test elements missing from top-level Request and arrays where single elements should be
+	@Test
+	public void testMissingFields() {
+		
+		// Request containing empty array
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : []}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// array of one element
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : [{\"CombinedDecision\" : true }]}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// correctly formatted empty request gives request with defaults set
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : { }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// space in front of name (inside quotes)
+		try {
+			request = JSONRequest.load((String)"{\" Request\" : {\"XPathVersion\" : \"http://some/other/default/uri\" }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// space at end of name (inside quotes)
+		try {
+			request = JSONRequest.load((String)"{\"Request \" : {\"XPathVersion\" : \"http://some/other/default/uri\" }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// space in front of value (inside quotes) - valid String but not valid URI
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : \" http://some/other/default/uri\" }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// space at end of value (inside quotes) - valid String but not valid URI
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : \"http://some/other/default/uri \" }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+	}
+	
+	
+	
+	// test just one of each top-level element.
+	// For simple elements also test for incorrect type
+	@Test
+	public void testTopLevelElements() {
+		
+		// empty request
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {}}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+
+		
+		// ReturnPolicyIdList
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"ReturnPolicyIdList\" : true  }}");
+			assertEquals("{returnPolicyIdList=true,combinedDecision=false}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"ReturnPolicyIdList\" : \"abc\"  }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"ReturnPolicyIdList\" : 123  }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// CombinedDecision
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : { \"CombinedDecision\" : true }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=true}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"CombinedDecision\" : \"abc\"  }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"CombinedDecision\" : 123  }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// XPathVersion
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : \"http://some/other/default/uri\" }}");
+			assertEquals("{requestDefaults={xpatherVersion=http://some/other/default/uri},returnPolicyIdList=false,combinedDecision=false}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : true  }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : 123  }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : \"not a uri\" }}");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Category
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Category\": [{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=another-custom-cat},xmlId=anotherXmlId}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// AccessSubject
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : { \"AccessSubject\":{ }}}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : { \"Action\":{ }}}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Resource\":{ }}}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Environment\":{ } }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:environment}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequests
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]" +   
+			          "} } }");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,multiRequests=[{requestAttributesReferences=[{referenceId=foo1}{referenceId=bar1}]}{requestAttributesReferences=[{referenceId=foo2}{referenceId=bar2}]}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequest with 1
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			                "{" +
+			                	"\"ReferenceId\" : [\"bar2\"]" +
+			                "}]" +   
+			          "} } }");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,multiRequests=[{requestAttributesReferences=[{referenceId=bar2}]}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequest with RequestReferences with no ReferenceId
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			                "{" +
+			                	"\"ReferenceId\" : []" +
+			                "}]" +   
+			          "} } }");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+
+		// MultiRequests with no RequestReference
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": []" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequests with something other than RequestReference
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"SomeOtherAttribute\": 123" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequests with single RequestReference rather than array
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": " +
+			                "{" +
+			                	"\"ReferenceId\" : []" +
+			                "}" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequests with RequestReference containing single element instead of array
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			                "{" +
+			                	"\"ReferenceId\" : \"foo1\"" +
+			                "}]" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			                "{" +
+			                	"\"ReferenceId\" : {\"foo1\"}" +
+			                "}]" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequests with component that is not a RequestReference
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"SomeOtherAttribute\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequests with component that is not a RequestReference
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+		                		"\"ReferenceId\" : [\"foo2\",\"bar2\"]," +
+			                	"\"SomeOtherAttribute\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequest with unknown elements (in addition to RequestReference)
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+		            	"\"SomeOtherAttribute\": 123," +   
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequest with RequestReferences with  ReferenceId NOT a string
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			                "{" +
+			                	"\"ReferenceId\" : [ true ]" +
+			                "}]" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			                "{" +
+			                	"\"ReferenceId\" : [ 123 ]" +
+			                "}]" +   
+			          "} } }");
+			fail("Request should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Cannot test with ReferenceId that is NOT referring to a Category object Id property because we may not have read the Category objects yet.
+		// Need to leave this up to the PDP.
+
+		
+		// extra elements in top-level
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {}, \"unknownElement\" : false, \"unk2\" : \"abc\", \"unk3\" : 123 }}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// extra elements in Request
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"XPathVersion\" : \"http://www.w3.org/TR/1999/REC-xpath-19991116\", \"unknownElement\" : false }}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+	}
+	
+	
+	// Test with every field filled in with multiple values where appropriate
+	@Test
+	public void testAllFieldsRequest() {	
+	
+		// convert Response to JSON
+		try {
+			request = JSONRequest.load(allFieldsRequest);
+			assertEquals("{requestDefaults={xpatherVersion=http://www.w3.org/TR/1999/REC-xpath-19991116},returnPolicyIdList=true,combinedDecision=true,requestAttributes=[{super={category=custom-category,attributes=[{attributeId=document-id,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#integer,value=123}],includeInResults=false}{attributeId=document-url,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=http://somewhere.over.the.com/rainbow}],includeInResults=false}{attributeId=page-list,category=custom-category,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=1.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=2.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=3.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=4.5}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=3.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=2.0}{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=1.0}],includeInResults=false}]},xmlId=customId}{super={category=another-custom-cat},xmlId=anotherXmlId}{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject},contentRoot=[catalog: null]}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource},contentRoot=[catalog: null]}],multiRequests=[{requestAttributesReferences=[{referenceId=foo1}{referenceId=bar1}]}{requestAttributesReferences=[{referenceId=foo2}{referenceId=bar1}]}]}"
+					, request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// convert example request from spec
+		try {
+			request = JSONRequest.load(exampleFromSpec);
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,attributes=[{attributeId=subject-id,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Andreas}],includeInResults=false}{attributeId=location,category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Gamla Stan}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,attributes=[{attributeId=action-id,category=urn:oasis:names:tc:xacml:3.0:attribute-category:action,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#anyURI,value=http://www.xacml.eu/buy}],includeInResults=false}]}}{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=book-title,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=Learn German in 90 days}],includeInResults=false}{attributeId=currency,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#string,value=SEK}],includeInResults=false}{attributeId=price,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=http://www.w3.org/2001/XMLSchema#double,value=123.34}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// convert example request from spec containing XPAthExpression
+		try {
+			request = JSONRequest.load(xPathExampleFromSpec);
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,attributes=[{attributeId=urn:oasis:names:tc:xacml:3.0:content-selector,category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource,values=[{dataTypeId=urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression,value={path=md:record/md:patient/md:patientDoB,Namespace={[{md,urn:example:med:schemas:record}{urn:oasis:names:tc:xacml:3.0:core:schema:wd-17}]},status=null,xpathExpressionWrapped=null},xpathCategory=urn:oasis:names:tc:xacml:3.0:attribute-category:resource}],includeInResults=false}]}}]}", request.toString());
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+	
+	}
+	
+	
+	
+	// Duplicates - Each element duplicated
+	@Test
+	public void testDuplicates() {
+		// duplicate Request
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {}, \"Request\" : {}}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"ReturnPolicyIdList\" : true, \"ReturnPolicyIdList\" : true   }}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : { \"CombinedDecision\" : true, \"CombinedDecision\" : true }}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Category\": [{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"],"
+					+ "\"Category\": [{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"] }}");
+			assertEquals("{returnPolicyIdList=false,combinedDecision=false,requestAttributes=[{super={category=another-custom-cat},xmlId=anotherXmlId}]}", request.toString());
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Category\": [{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"] }}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Category\": [{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"] }}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Category\": [{ " +
+					    	"\"CategoryId\": \"another-custom-cat\", " +
+					    	"\"Id\" : \"anotherXmlId\", " +
+					    	"\"Attribute\" : []" +
+					    	"\"Attribute\" : []" +
+					    "} " +
+					"] }}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// AccessSubject
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : { \"AccessSubject\":{ }, \"AccessSubject\":{ }}}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Action
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : { \"Action\":{ }, \"Action\":{ }}}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Resource
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Resource\":{ }, \"Resource\":{ }}}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Environment
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"Environment\":{ }, \"Environment\":{ } }}");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// MultiRequests
+
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]" +   
+			          "},"
+			          + "\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]" +   
+			          "}  } }");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]," + 
+			                "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]" +
+			          "} } }");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		try {
+			request = JSONRequest.load((String)"{\"Request\" : {\"MultiRequests\" : {" +
+			            "\"RequestReference\": [" +
+			            	"{ " +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                	"\"ReferenceId\" : [\"foo1\",\"bar1\"]" +
+			                "}," +
+			                "{" +
+			                	"\"ReferenceId\" : [\"foo2\",\"bar2\"]" +
+			                "}]" +   
+			          "} } }");
+			fail("Unknown element should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+	}
+	
+
+}
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/ResponseConformanceTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/ResponseConformanceTest.java
new file mode 100644
index 0000000..601a462
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/ResponseConformanceTest.java
@@ -0,0 +1,370 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.att.research.xacml.api.Advice;
+import com.att.research.xacml.api.Attribute;
+import com.att.research.xacml.api.AttributeCategory;
+import com.att.research.xacml.api.IdReference;
+import com.att.research.xacml.api.Obligation;
+import com.att.research.xacml.api.Response;
+import com.att.research.xacml.api.Result;
+import com.att.research.xacml.std.dom.DOMResponse;
+import com.att.research.xacml.std.json.JSONResponse;
+import com.att.research.xacml.util.ListUtil;
+/**
+ * Test JSON Response convert to object - Conformance tests
+ * 
+ * TO RUN - use jUnit
+ * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test
+ * 
+ * Note: some of the validation tests comparing the XML-derived Results to the JSON-derived Results are high-level comparisons of Collections.
+ *		When this class was first created that was sufficient to pass all Conformance tests.
+ *		However if this sees a failure in a Conformance test, those validations may need to be upgraded to look at the individual data elements to see what is wrong.
+ * 
+ *
+ */
+public class ResponseConformanceTest {
+	
+	// where to find the conformance test XML files
+	private final String CONFORMANCE_DIRECTORY_PATH = "testsets/conformance/xacml3.0-ct-v.0.4";
+	
+	// The request object output from each test conversion from JSON string
+	Response response;
+
+
+	
+	
+	
+	// test just one of each top-level element.
+	// For simple elements also test for incorrect type
+	@Test
+	public void testConformanceResponses() {
+		
+		List<File> filesInDirectory = null;
+		
+		File conformanceDirectory = null;
+		
+		File currentFile = null;
+		
+		try {
+			conformanceDirectory = new File(CONFORMANCE_DIRECTORY_PATH);
+			filesInDirectory = getRequestsInDirectory(conformanceDirectory);
+		} catch (Exception e) {
+			fail("Unable to set up Conformance tests for dir '" + conformanceDirectory.getAbsolutePath()+"' e="+ e);
+		}
+		
+		// run through each XML file
+		//	- load the file from XML into an internal Response object
+		//	- generate the JSON representation of that Response object
+		//	- load that JSON representation into a new Response object
+		//	- compare the 2 Request objects
+		Response xmlResponse = null;
+		Response jsonResponse = null;
+		try {
+			for (File f : filesInDirectory) {
+				currentFile = f;
+
+//// This is a simple way to select just one file for debugging - comment out when not being used
+//if ( ! f.getName().equals("IIIA030Response.xml") && ! f.getName().equals("IIIA330Response.xml")) {   continue;  }
+
+// during debugging it is helpful to know what file it is starting to work on
+//				System.out.println("starting file="+currentFile.getName());
+				
+				try {
+					// load XML into a Response object
+					xmlResponse = DOMResponse.load(f);
+				} catch (Exception e) {
+					// if XML does not load, just note it and continue with next file
+					System.out.println("XML file did not load: '" + f.getName() + "  e=" + e);
+					continue;
+				}
+				
+				// some tests have JSON response files to load, most do not
+				String jsonFileName = f.getName().replace(".xml", ".json");
+				File jsonFile = new File(conformanceDirectory, jsonFileName);
+				
+				if (jsonFile.exists()) {
+//System.out.println("found file "+jsonFile.getName());
+					// json version exists in file, so load it
+					jsonResponse = JSONResponse.load(jsonFile);
+				} else {
+					// json does not exist in file, so create it from the XML response using a String intermediate version
+					String jsonResponseString = JSONResponse.toString(xmlResponse, false);
+//System.out.println(jsonResponseString);	
+//System.out.println(JSONResponse.toString(xmlResponse, true));
+					
+					jsonResponse = JSONResponse.load(jsonResponseString);
+				}			
+				
+				
+//System.out.println(JSONResponse.toString(xmlResponse, true));
+
+
+
+				
+				// compare the two Response objects
+				
+				// compare results
+				assertEquals(xmlResponse.getResults().size(), jsonResponse.getResults().size());
+				
+				if (xmlResponse.getResults().size() == 0) {
+					fail("neither XML nor JSON response have any Results");
+				}
+				
+				
+				// Results are an un-ordered Collection.
+				// There is no identifying information that is unique to a specific Result.
+				// If there are more than one we cannot be sure which one corresponds with which.
+				// The best we can do is say that one or more in the first list do not match any in the second list
+				if (xmlResponse.getResults().size() > 1) {
+					for (Result xmlResult : xmlResponse.getResults()) {
+						boolean found = false;
+						for (Result jsonResult : jsonResponse.getResults()) {
+							if (xmlResult.equals(jsonResult)) {
+								found = true;
+								break;
+							}
+						}
+						if (found) {
+							continue;
+						}
+						// no match found
+						System.out.println("No match for XML in " + f.getName());
+						System.out.println("XML =" + xmlResult.toString());
+						for (Result jsonResult : jsonResponse.getResults()) {
+							System.out.println("JSON="+ jsonResult.toString());
+						}
+						fail("JSON Response has no match for XML Result: " + xmlResult.toString());
+					}
+					// we've done the best we can for multiple decisions, so go to next file
+					continue;
+				}
+				
+				// single Result in each
+				Result xmlResult = xmlResponse.getResults().iterator().next();
+				Result jsonResult = jsonResponse.getResults().iterator().next();
+				
+				// The following sections have not given us trouble, so checking is very high-level.
+				// If we see a problem in one of these elements, the single line will need to be replaced with detailed examination of the objects.
+				assertEquals(f.getName() + " Decision", xmlResult.getDecision(), jsonResult.getDecision());
+				assertEquals(f.getName() + " Status", xmlResult.getStatus(), jsonResult.getStatus());
+				
+				// Obligations
+				if (xmlResult.getObligations() != jsonResult.getObligations()) {
+					Collection<Obligation> xmlObligations = xmlResult.getObligations();
+					Collection<Obligation> jsonObligations = jsonResult.getObligations();
+					// if both are null we do not get here
+					if (xmlObligations == null || jsonObligations == null) {
+						fail(f.getName() + " Obligations has null \nXML="+xmlObligations + "\nJSON="+jsonObligations);
+					}
+					if (ListUtil.equalsAllowNulls(xmlObligations, jsonObligations) == false) {
+						// collections are not equal, so need to examine further
+fail(f.getName() + " Obligation collections not equal\nXML="+xmlObligations + "\nJSON="+jsonObligations);
+					}
+				}
+				
+				// AssociatedAdvice
+				if (xmlResult.getAssociatedAdvice() != jsonResult.getAssociatedAdvice()) {
+					Collection<Advice> xmlAdvice = xmlResult.getAssociatedAdvice();
+					Collection<Advice> jsonAdvice = jsonResult.getAssociatedAdvice();
+					// if both are null we do not get here
+					if (xmlAdvice == null || jsonAdvice == null) {
+						fail(f.getName() + " Advice has null \nXML="+xmlAdvice + "\nJSON="+jsonAdvice);
+					}
+					if (ListUtil.equalsAllowNulls(xmlAdvice, jsonAdvice) == false) {
+						// collections are not equal, so need to examine further
+fail(f.getName() + " Advice collections not equal\nXML="+xmlAdvice + "\nJSON="+jsonAdvice);
+					}
+				}
+				
+				
+				
+				// check Attributes in more detail
+				Collection<AttributeCategory> xmlAttributes = xmlResult.getAttributes();
+				Collection<AttributeCategory> jsonAttributes = jsonResult.getAttributes();
+				if (xmlAttributes == null && jsonAttributes != null || 
+						xmlAttributes != null && jsonAttributes == null) {
+					fail(f.getName() + " XML Attributes="+xmlAttributes + "  but JSON Attributes=" + jsonAttributes);
+				}
+				if (xmlAttributes != null) {
+					// both are non-null
+					if (xmlAttributes.size() != jsonAttributes.size()) {
+						String xmlAttributesString = "XML categorys=";
+						for (AttributeCategory ac : xmlAttributes) {
+							xmlAttributesString += " " + ac.getCategory().stringValue();
+						}
+						String jsonAttributesString = "JSON categorys=";
+						for (AttributeCategory ac : jsonAttributes) {
+							jsonAttributesString += " " + ac.getCategory().stringValue();
+						}
+						fail(f.getName() + " XML and JSON have different number of Category elements: " + xmlAttributesString + ", " + jsonAttributesString);
+					}
+					
+					// Attribute collections are the same size but may be in different orders.
+					// for each XML category try to find the corresponding JSON category.
+					// ASSUME that each category only shows up once!!!!
+					for (AttributeCategory xmlAttributeCategory : xmlAttributes) {
+						boolean attributeCategoryFound = false;
+						for (AttributeCategory jsonAttributeCategory : jsonAttributes) {
+							if (xmlAttributeCategory.equals(jsonAttributeCategory)) {
+								attributeCategoryFound = true;
+								break;
+							}
+							// not an exact match, but if same CategoryId then need to check individual Attribute objects
+							if (xmlAttributeCategory.getCategory().equals(jsonAttributeCategory.getCategory())) {
+								// same category
+								if (xmlAttributeCategory.getAttributes().size() != jsonAttributeCategory.getAttributes().size()) {
+									System.out.println("XML =" + xmlAttributeCategory.getAttributes());
+									System.out.println("JSON=" + jsonAttributeCategory.getAttributes());
+									fail(f.getName() + " Attributes Category '" + xmlAttributeCategory.getCategory().stringValue() + "' size mismatch; XML="+
+											xmlAttributeCategory.getAttributes().size() +", JSON=" + jsonAttributeCategory.getAttributes().size());
+								}
+								for (Attribute xmlAttr : xmlAttributeCategory.getAttributes()) {
+									boolean attributeFound = false;
+									for (Attribute jsonAttr : jsonAttributeCategory.getAttributes()) {
+										if (xmlAttr.equals(jsonAttr)) {
+											attributeFound = true;
+											break;
+										}
+									}
+
+									if (attributeFound) {
+										// check next XML attribute
+										continue;
+									}
+									System.out.println("Attribute not found in JSON, Category="+xmlAttributeCategory.getCategory());
+									System.out.println("XML Attribute ="+ xmlAttr);
+									System.out.println("JSON Attributes=" + jsonAttributeCategory.toString());
+									fail(f.getName() + " Attribute not found in JSON, Category=" + xmlAttributeCategory.getCategory() +
+											"/nXML Attribute="+xmlAttr+
+											"\nJSON Category Attributes="+jsonAttributeCategory.toString());
+								}
+								
+
+
+							}
+						}
+						if (attributeCategoryFound) {
+							continue;
+						}
+						fail("XML Category not found in JSON; xml="+xmlAttributeCategory.toString());
+					}
+					
+				}
+				
+				// PolicyIdentifiers
+				if (xmlResult.getPolicyIdentifiers() != jsonResult.getPolicyIdentifiers()) {
+					Collection<IdReference> xmlIdReferences = xmlResult.getPolicyIdentifiers();
+					Collection<IdReference> jsonIdReferences = jsonResult.getPolicyIdentifiers();
+					// if both are null we do not get here
+					if (xmlIdReferences == null || jsonIdReferences == null) {
+						fail(f.getName() + " PolicyIdentifiers has null \nXML="+xmlIdReferences + "\nJSON="+jsonIdReferences);
+					}
+					if (ListUtil.equalsAllowNulls(xmlIdReferences, jsonIdReferences) == false) {
+						// collections are not equal, so need to examine further
+fail(f.getName() + " PolicyIdentifiers collections not equal\nXML="+xmlIdReferences+ "\nJSON="+jsonIdReferences);
+					}
+				}
+				
+				// PolicySetIdentifiers
+				if (xmlResult.getPolicySetIdentifiers() != jsonResult.getPolicySetIdentifiers()) {
+					Collection<IdReference> xmlIdReferences = xmlResult.getPolicySetIdentifiers();
+					Collection<IdReference> jsonIdReferences = jsonResult.getPolicySetIdentifiers();
+					// if both are null we do not get here
+					if (xmlIdReferences == null || jsonIdReferences == null) {
+						fail(f.getName() + " PolicySetIdentifiers has null \nXML="+xmlIdReferences + "\nJSON="+jsonIdReferences);
+					}
+					if (ListUtil.equalsAllowNulls(xmlIdReferences, jsonIdReferences) == false) {
+						// collections are not equal, so need to examine further
+fail(f.getName() + " PolicySetIdentifiers collections not equal\nXML="+xmlIdReferences + "\nJSON="+jsonIdReferences);
+					}
+				}
+								
+
+			}			
+
+		} catch (Exception e) {
+			fail ("Failed test with '" + currentFile.getName() + "', e=" + e);
+		}
+
+		
+	}
+	
+	//
+	// HELPER to get list of all Request files in the given directory
+	//
+	
+	private List<File> getRequestsInDirectory(File directory) {
+		List<File> fileList = new ArrayList<File>();
+		
+		File[] fileArray = directory.listFiles();
+		for (File f : fileArray) {
+			if (f.isDirectory()) {
+				List<File> subDirList = getRequestsInDirectory(f);
+				fileList.addAll(subDirList);
+			}
+			if (f.getName().endsWith("Response.xml")) {
+				fileList.add(f);
+			}
+		}
+		return fileList;
+		
+	}
+	
+}
+
+
+
+
+
+/*
+ * 
+This is a place to copy the really long output from test rigs that need to be manually edited for readability....
+
+
+
+{"Response":[{"Status":{"StatusCode":{"Value":"urn:oasis:names:tc:xacml:1.0:status:ok"}},"Obligations":[{"Id":"urn:oasis:names:tc:xacml:2.0:conformance-test:IIIA030:obligation-1","AttributeAssignment":[
+{"Value":"assignment1","DataType":"string","AttributeId":"urn:oasis:names:tc:xacml:2.0:conformance-test:IIIA030:assignment1"},
+{"Value":{"Namespaces":[{"Namespace":"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"},{"Namespace":"http://www.w3.org/2001/XMLSchema-instance","Prefix":"xsi"}],
+		"XPathCategory":"urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
+		"XPath":"//md:records/md:record"},
+	"DataType":"xpathExpression",
+	"AttributeId":"urn:oasis:names:tc:xacml:2.0:conformance-test:IIIA030:assignment2"}]}],"Decision":"Permit"}]}
+
+
+
+*/
+
+
+
+
+
diff --git a/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/ResponseTest.java b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/ResponseTest.java
new file mode 100644
index 0000000..12da12c
--- /dev/null
+++ b/ECOMP-XACML/src/test/java/org/openecomp/policy/xacml/test/json/ResponseTest.java
@@ -0,0 +1,2297 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ECOMP-XACML
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.xacml.test.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.math.BigInteger;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.att.research.xacml.api.Attribute;
+import com.att.research.xacml.api.AttributeValue;
+import com.att.research.xacml.api.Decision;
+import com.att.research.xacml.api.Identifier;
+import com.att.research.xacml.api.XACML3;
+import com.att.research.xacml.std.IdentifierImpl;
+import com.att.research.xacml.std.StdAttribute;
+import com.att.research.xacml.std.StdAttributeCategory;
+import com.att.research.xacml.std.StdAttributeValue;
+import com.att.research.xacml.std.StdIdReference;
+import com.att.research.xacml.std.StdMutableAdvice;
+import com.att.research.xacml.std.StdMutableAttribute;
+import com.att.research.xacml.std.StdMutableAttributeAssignment;
+import com.att.research.xacml.std.StdMutableMissingAttributeDetail;
+import com.att.research.xacml.std.StdMutableObligation;
+import com.att.research.xacml.std.StdMutableResponse;
+import com.att.research.xacml.std.StdMutableResult;
+import com.att.research.xacml.std.StdMutableStatus;
+import com.att.research.xacml.std.StdMutableStatusDetail;
+import com.att.research.xacml.std.StdStatusCode;
+import com.att.research.xacml.std.StdVersion;
+import com.att.research.xacml.std.datatypes.DataTypes;
+import com.att.research.xacml.std.datatypes.StringNamespaceContext;
+import com.att.research.xacml.std.datatypes.XPathExpressionWrapper;
+import com.att.research.xacml.std.json.JSONResponse;
+import com.att.research.xacml.std.json.JSONStructureException;
+
+/**
+ * Test JSON Responses
+ * 
+ * TO RUN - use jUnit
+ * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test
+ * 
+ *
+ */
+public class ResponseTest {
+
+	String jsonResponse;
+	
+	StdMutableResponse response;
+	
+	StdMutableResult result;
+	
+	StdMutableStatus status;
+	
+	
+	// Note: Initially test responses without Obligations, Associated Advice, Attributes, or PolicyIdentifier
+	
+	
+	@Test
+	public void testEmptyAndDecisions() {
+		// null response
+		try {
+			jsonResponse = JSONResponse.toString(null, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// empty response (no Result object)
+		response = new StdMutableResponse();
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// just decision, no status
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// just status (empty), no decision
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();		
+		result.setStatus(status);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// just status (non-empty), no decision
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_OK);
+		result.setStatus(status);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// test other decisions without Status
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.DENY);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Deny\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.NOTAPPLICABLE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"NotApplicable\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Indeterminate{D}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Indeterminate{DP}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Indeterminate{P}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+
+		
+		// test Multiple Decisions - success
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		StdMutableResult result2 = new StdMutableResult();
+		result2.setDecision(Decision.DENY);
+		response.add(result2);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\"},{\"Decision\":\"Deny\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// test Multiple Decisions - one success and one error
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		result2 = new StdMutableResult();
+		result2.setDecision(Decision.INDETERMINATE);
+		response.add(result2);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\"},{\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+		
+
+	
+	
+	// Test with every field filled in with multiple values where appropriate
+	@Ignore //@Test
+	public void testAllFieldsResponse() {	
+		
+		// fully-loaded multiple response
+		
+		StdMutableResponse response = new StdMutableResponse();
+		// create a Status object
+		StdMutableStatus status = new StdMutableStatus(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		status.setStatusMessage("some status message");
+		StdMutableStatusDetail statusDetailIn = new StdMutableStatusDetail();
+		StdMutableMissingAttributeDetail mad = new StdMutableMissingAttributeDetail();
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "doh"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_INTEGER.getId(), "5432"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		mad.setAttributeId(XACML3.ID_ACTION_PURPOSE);
+		mad.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_ACTION);
+		mad.setDataTypeId(XACML3.ID_DATATYPE_STRING);
+		mad.setIssuer("an Issuer");
+		statusDetailIn.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetailIn);
+		// create a single result object
+		StdMutableResult result = new StdMutableResult(status);
+		// set the decision
+		result.setDecision(Decision.INDETERMINATE);
+		// put the Result into the Response
+		response.add(result);
+
+		
+		// create a new Result with a different Decision
+		status = new StdMutableStatus(StdStatusCode.STATUS_CODE_OK);
+		result = new StdMutableResult(status);
+		result.setDecision(Decision.DENY);
+		
+		StdMutableObligation obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer2", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Ned")));
+		result.addObligation(obligation);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_SUBJECT_CATEGORY_INTERMEDIARY_SUBJECT);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer3", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Maggie")));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer4", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Homer")));
+		result.addObligation(obligation);
+		
+		
+		StdMutableAdvice advice = new StdMutableAdvice();
+		advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu")));
+		advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				null, 
+				XACML3.ID_SUBJECT, 
+				"advice-issuerNoCategory", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Crusty")));
+		result.addAdvice(advice);
+		
+		
+		response.add(result);
+		
+		
+		// create a new Result with a different Decision
+		// add Child/minor status codes within the main status
+		StdStatusCode childChildChildStatusCode = new StdStatusCode(new IdentifierImpl("childChildChildStatusCode"));
+		StdStatusCode childChildStatusCode = new StdStatusCode(new IdentifierImpl("childChildStatusCode"), childChildChildStatusCode);
+		StdStatusCode child1StatusCode = new StdStatusCode(new IdentifierImpl("child1StatusCode"), childChildStatusCode);
+		StdStatusCode statusCode = new StdStatusCode(XACML3.ID_STATUS_OK, child1StatusCode);
+		
+		status = new StdMutableStatus(statusCode);
+		
+		
+		result = new StdMutableResult(status);
+		result.setDecision(Decision.PERMIT);
+		
+		
+		
+		
+		// add attribute list in result
+		Identifier categoryIdentifier = new IdentifierImpl("firstCategory");
+		Attribute[] attrList = {
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent2"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "BIssue", false),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent3"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "CIssue", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent4"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "DIssue", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent5"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), "EIssue", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrNoIssuer"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), null, true) };
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, Arrays.asList(attrList)));
+		categoryIdentifier = new IdentifierImpl("secondCategory");
+		Attribute[] secondAttrList = {
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent12"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu2"), "AIssue2", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent22"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Abc2"), "BIssue2", false),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent32"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Der2"), "CIssue2", true) };
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, Arrays.asList(secondAttrList)));
+		
+		
+		// add PolicyIdentifierList to result
+		StdIdReference policyIdentifier1 = null;
+		StdIdReference policyIdentifier2 = null;
+		StdIdReference policySetIdentifier1 = null;
+		StdIdReference policySetIdentifier2 = null;
+		try {
+			policyIdentifier1 = new StdIdReference(new IdentifierImpl("idRef1"), StdVersion.newInstance("1.2.3"));
+			policyIdentifier2 = new StdIdReference(new IdentifierImpl("idRef2_NoVersion"));
+			policySetIdentifier1 = new StdIdReference(new IdentifierImpl("idSetRef1"), StdVersion.newInstance("4.5.6.7.8.9.0"));
+			policySetIdentifier2 = new StdIdReference(new IdentifierImpl("idSetRef2_NoVersion"));
+		} catch (ParseException e1) {
+			fail("creating policyIds, e="+e1);
+		}
+		
+		result.addPolicyIdentifier(policyIdentifier1);
+		result.addPolicyIdentifier(policyIdentifier2);
+	
+		result.addPolicySetIdentifier(policySetIdentifier1);
+		result.addPolicySetIdentifier(policySetIdentifier2);
+		
+		response.add(result);
+	
+		// convert Response to JSON
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+System.out.println(jsonResponse);
+//System.out.println(JSONResponse.toString(response, true));
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusMessage\":\"some status message\",\"StatusDetail\":\"<MissingAttributeDetail Category=\\\\\\\"urn:oasis:names:tc:xacml:3.0:attribute-category:action\\\\\\\" AttributeId=\\\\\\\"urn:oasis:names:tc:xacml:2.0:action:purpose\\\\\\\" DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\" Issuer=\\\\\\\"an Issuer\\\\\\\"><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\">doh</AttributeValue><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#integer\\\\\\\">5432</AttributeValue><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\">meh</AttributeValue></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"},{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:ok\"}},\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"obligation-issuer1\",\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"obligation-issuer2\",\"Value\":\"Ned\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]},{\"Id\":\"urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject\",\"AttributeAssignment\":[{\"Issuer\":\"obligation-issuer3\",\"Value\":\"Maggie\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"obligation-issuer4\",\"Value\":\"Homer\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Deny\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"advice-issuer1\",\"Value\":\"Apu\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"advice-issuerNoCategory\",\"Value\":\"Crusty\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]},{\"Status\":{\"StatusCode\":{\"StatusCode\":{\"StatusCode\":{\"StatusCode\":{\"Value\":\"childChildChildStatusCode\"},\"Value\":\"childChildStatusCode\"},\"Value\":\"child1StatusCode\"},\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:ok\"}},\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"CIssue\",\"Value\":765.432,\"DataType\":\"http://www.w3.org/2001/XMLSchema#double\",\"AttributeId\":\"attrIdent3\"},{\"Issuer\":\"DIssue\",\"Value\":true,\"DataType\":\"http://www.w3.org/2001/XMLSchema#boolean\",\"AttributeId\":\"attrIdent4\"},{\"Issuer\":\"EIssue\",\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrIdent5\"},{\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrNoIssuer\"}]},{\"CategoryId\":\"secondCategory\",\"Attribute\":[{\"Issuer\":\"AIssue2\",\"Value\":\"Apu2\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent12\"},{\"Issuer\":\"CIssue2\",\"Value\":\"Der2\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent32\"}]}],\"Decision\":\"Permit\",\"PolicyIdentifier\":{\"PolicyIdReference\":[{\"Id\":\"idRef1\",\"Version\":\"1.2.3\"},{\"Id\":\"idRef2_NoVersion\"}],\"PolicySetIdReference\":[{\"Id\":\"idSetRef1\",\"Version\":\"4.5.6.7.8.9.0\"},{\"Id\":\"idSetRef2_NoVersion\"}]}}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+	
+	
+	
+	
+	// combinations of Status values with Decision values
+	@Test
+	public void testDecisionStatusMatch() {
+		// the tests in this method use different values and do not change structures, so we can re-use the objects
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		result.setStatus(status);
+		response.add(result);
+		
+		// StatusCode = OK
+		status.setStatusCode(StdStatusCode.STATUS_CODE_OK);
+		result.setDecision(Decision.PERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:ok\"}},\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.DENY);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:ok\"}},\"Decision\":\"Deny\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.NOTAPPLICABLE);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:ok\"}},\"Decision\":\"NotApplicable\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		
+		
+		
+		
+		// StatusCode = SyntaxError
+		status.setStatusCode(StdStatusCode.STATUS_CODE_SYNTAX_ERROR);
+		result.setDecision(Decision.PERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.DENY);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.NOTAPPLICABLE);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"}},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"}},\"Decision\":\"Indeterminate{D}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"}},\"Decision\":\"Indeterminate{DP}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"}},\"Decision\":\"Indeterminate{P}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// StatusCode = ProcessingError
+		status.setStatusCode(StdStatusCode.STATUS_CODE_PROCESSING_ERROR);
+		result.setDecision(Decision.PERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.DENY);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.NOTAPPLICABLE);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"}},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"}},\"Decision\":\"Indeterminate{D}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"}},\"Decision\":\"Indeterminate{DP}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"}},\"Decision\":\"Indeterminate{P}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+		// StatusCode = MissingAttribute
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		result.setDecision(Decision.PERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.DENY);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.NOTAPPLICABLE);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		result.setDecision(Decision.INDETERMINATE);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"}},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENY);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"}},\"Decision\":\"Indeterminate{D}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_DENYPERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"}},\"Decision\":\"Indeterminate{DP}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		result.setDecision(Decision.INDETERMINATE_PERMIT);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"}},\"Decision\":\"Indeterminate{P}\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+
+	
+	
+
+	// tests related to Status and its components
+	@Ignore //@Test
+	public void testStatus() {
+		// Status with no StatusCode - error
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Status with StatusMessage when OK
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_OK);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:ok\"},\"StatusMessage\":\"I'm ok, you're ok\"},\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with StatusDetail when OK
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_OK);
+		StdMutableStatusDetail statusDetail = new StdMutableStatusDetail();
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Status with StatusMessage when SyntaxError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_SYNTAX_ERROR);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:syntax-error\"},\"StatusMessage\":\"I'm ok, you're ok\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with empty StatusDetail when SyntaxError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_SYNTAX_ERROR);
+		statusDetail = new StdMutableStatusDetail();
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		// Status with StatusMessage when ProcessingError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_PROCESSING_ERROR);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:processing-error\"},\"StatusMessage\":\"I'm ok, you're ok\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with empty StatusDetail when ProcessingError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_PROCESSING_ERROR);
+		statusDetail = new StdMutableStatusDetail();
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+
+		
+		// Status with StatusMessage when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusMessage\":\"I'm ok, you're ok\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with empty StatusDetail when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"}},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+		// Status with StatusDetail with empty detail when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		StdMutableMissingAttributeDetail mad = new StdMutableMissingAttributeDetail();
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Status with StatusDetail with valid detail with no value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<MissingAttributeDetail Category=\\\\\\\"urn:oasis:names:tc:xacml:1.0:action\\\\\\\" AttributeId=\\\\\\\"mad\\\\\\\" DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\"></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with StatusDetail with valid detail with value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<MissingAttributeDetail Category=\\\\\\\"urn:oasis:names:tc:xacml:1.0:action\\\\\\\" AttributeId=\\\\\\\"mad\\\\\\\" DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\"><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\">meh</AttributeValue></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Status with StatusDetail with array valid detail with value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "nu?"));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<MissingAttributeDetail Category=\\\\\\\"urn:oasis:names:tc:xacml:1.0:action\\\\\\\" AttributeId=\\\\\\\"mad\\\\\\\" DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\"><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\">meh</AttributeValue><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\">nu?</AttributeValue></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// Status with StatusDetail with valid detail with Integer value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_INTEGER.getId());	
+		mad.addAttributeValue(new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(1111)));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+//			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<MissingAttributeDetail Category=\\\\\\\"urn:oasis:names:tc:xacml:1.0:action\\\\\\\" AttributeId=\\\\\\\"mad\\\\\\\" DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\"><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#integer\\\\\\\">1111</AttributeValue></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			java.io.StringWriter sw = new java.io.StringWriter();
+			java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+			e.printStackTrace(pw);
+
+
+			fail("operation failed, e="+e + sw.toString());
+		}
+		
+		// Status with StatusDetail with array valid detail with Integer value when MissingAttribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(1111)));
+		mad.addAttributeValue(new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(2222)));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<MissingAttributeDetail Category=\\\\\\\"urn:oasis:names:tc:xacml:1.0:action\\\\\\\" AttributeId=\\\\\\\"mad\\\\\\\" DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#string\\\\\\\"><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#integer\\\\\\\">1111</AttributeValue><AttributeValue DataType=\\\\\\\"http://www.w3.org/2001/XMLSchema#integer\\\\\\\">2222</AttributeValue></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+//		StringNamespaceContext snc = new StringNamespaceContext();
+//		try {
+//			snc.add("defaultURI");
+//			snc.add("md", "referenceForMD");
+//		} catch (Exception e) {
+//			fail("unable to create NamespaceContext e="+e);
+//		}
+//		XPathExpressionWrapper xpathExpressionWrapper = new XPathExpressionWrapper(snc, "//md:record");
+//
+//TODO - assume that we will never try to pass back an XPathExpression in a MissingAttributeDetail - it doesn't make sense and is unclear how to put into XML
+//		// Status with StatusDetail with valid detail with XPathExpression value when MissingAttribute
+//		response = new StdMutableResponse();
+//		result = new StdMutableResult();
+//		status = new StdMutableStatus();
+//		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+//		statusDetail = new StdMutableStatusDetail();
+//		mad = new StdMutableMissingAttributeDetail();
+//		mad.setAttributeId(new IdentifierImpl("mad"));
+//		mad.setCategory(XACML3.ID_ACTION);
+//		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+//		mad.addAttributeValue(new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("xpathCategoryId")));
+//		statusDetail.addMissingAttributeDetail(mad);
+//		status.setStatusDetail(statusDetail);
+//		result.setStatus(status);
+//		result.setDecision(Decision.INDETERMINATE);
+//		response.add(result);
+//		try {
+//			jsonResponse = JSONResponse.toString(response, false);
+//			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<AttributeValue>1111</AttributeValue><Category>urn:oasis:names:tc:xacml:1.0:action</Category><AttributeId>mad</AttributeId><DataType>http://www.w3.org/2001/XMLSchema#string</DataType></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+//		} catch (Exception e) {
+//			fail("operation failed, e="+e);
+//		}
+//		
+//		// Status with StatusDetail with array valid detail with XPathExpression value when MissingAttribute
+//		response = new StdMutableResponse();
+//		result = new StdMutableResult();
+//		status = new StdMutableStatus();
+//		status.setStatusCode(StdStatusCode.STATUS_CODE_MISSING_ATTRIBUTE);
+//		statusDetail = new StdMutableStatusDetail();
+//		mad = new StdMutableMissingAttributeDetail();
+//		mad.setAttributeId(new IdentifierImpl("mad"));
+//		mad.setCategory(XACML3.ID_ACTION);
+//		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+//		mad.addAttributeValue(new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("xpathCategoryId1")));
+//		mad.addAttributeValue(new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("xpathCategoryId2")));
+//		statusDetail.addMissingAttributeDetail(mad);
+//		status.setStatusDetail(statusDetail);
+//		result.setStatus(status);
+//		result.setDecision(Decision.INDETERMINATE);
+//		response.add(result);
+//		try {
+//			jsonResponse = JSONResponse.toString(response, false);
+//			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:missing-attribute\"},\"StatusDetail\":\"<AttributeValue>1111</AttributeValue><AttributeValue>2222</AttributeValue><Category>urn:oasis:names:tc:xacml:1.0:action</Category><AttributeId>mad</AttributeId><DataType>http://www.w3.org/2001/XMLSchema#string</DataType></MissingAttributeDetail>\"},\"Decision\":\"Indeterminate\"}]}", jsonResponse);
+//		} catch (Exception e) {
+//			fail("operation failed, e="+e);
+//		}
+		
+//TODO - try with other data types, esp XPathExpression		
+		
+		// Status with StatusDetail with array valid detail with value when SyntaxError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_SYNTAX_ERROR);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "nu?"));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Status with StatusDetail with array valid detail with value when ProcessingError
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		status.setStatusCode(StdStatusCode.STATUS_CODE_PROCESSING_ERROR);
+		statusDetail = new StdMutableStatusDetail();
+		mad = new StdMutableMissingAttributeDetail();
+		mad.setAttributeId(new IdentifierImpl("mad"));
+		mad.setCategory(XACML3.ID_ACTION);
+		mad.setDataTypeId(DataTypes.DT_STRING.getId());	
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "meh"));
+		mad.addAttributeValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "nu?"));
+		statusDetail.addMissingAttributeDetail(mad);
+		status.setStatusDetail(statusDetail);
+		result.setStatus(status);
+		result.setDecision(Decision.INDETERMINATE);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		
+		// Status with nested child StatusCodes (child status containing child status containing...)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		StdStatusCode child1StatusCode = new StdStatusCode(new IdentifierImpl("child1StatusCode"));
+		StdStatusCode statusCode = new StdStatusCode(XACML3.ID_STATUS_OK, child1StatusCode);
+		status = new StdMutableStatus(statusCode);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"StatusCode\":{\"Value\":\"child1StatusCode\"},\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:ok\"},\"StatusMessage\":\"I'm ok, you're ok\"},\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		status = new StdMutableStatus();
+		StdStatusCode childChildChildStatusCode = new StdStatusCode(new IdentifierImpl("childChildChildStatusCode"));
+		StdStatusCode childChildStatusCode = new StdStatusCode(new IdentifierImpl("childChildStatusCode"), childChildChildStatusCode);
+		child1StatusCode = new StdStatusCode(new IdentifierImpl("child1StatusCode"), childChildStatusCode);
+		statusCode = new StdStatusCode(XACML3.ID_STATUS_OK, child1StatusCode);
+		status = new StdMutableStatus(statusCode);
+		status.setStatusMessage("I'm ok, you're ok");
+		result.setStatus(status);
+		result.setDecision(Decision.PERMIT);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Status\":{\"StatusCode\":{\"StatusCode\":{\"StatusCode\":{\"StatusCode\":{\"Value\":\"childChildChildStatusCode\"},\"Value\":\"childChildStatusCode\"},\"Value\":\"child1StatusCode\"},\"Value\":\"urn:oasis:names:tc:xacml:1.0:status:ok\"},\"StatusMessage\":\"I'm ok, you're ok\"},\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+
+	}
+
+
+	
+	@Ignore //@Test
+	public void testObligations() {
+		
+		// create an XPathExpression for use later
+		StringNamespaceContext snc = new StringNamespaceContext();
+		try {
+			snc.add("defaultURI");
+			snc.add("md", "referenceForMD");
+		} catch (Exception e) {
+			fail("unable to create NamespaceContext e="+e);
+		}
+		XPathExpressionWrapper xpathExpressionWrapper = new XPathExpressionWrapper(snc, "//md:record");
+		XPathExpressionWrapper xpathExpressionWrapper2 = new XPathExpressionWrapper(snc, "//md:hospital");
+		
+		StdMutableObligation obligation;
+
+		// test Obligation single decision no attributes
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// obligation missing Id
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		
+		//	AttributeAssignment	- with AttributeId, Value,  Category, DataType, Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"obligation-issuer1\",\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		//	AttributeAssignment	- with AttributeId, Value, no Category, DataType, Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				null, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"obligation-issuer1\",\"Value\":\"Bart\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		//	AttributeAssignment	- Missing AttributeId
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				null, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		//	AttributeAssignment	- Missing Value
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				null));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"obligation-issuer1\",\"Value\":\"\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// AttributeAssignment - missing DataType
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(null, "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"obligation-issuer1\",\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// AttributeAssignment - missing issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// AttributeAssignment - Integer type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(1111))));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Value\":1111,\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// AttributeAssignment - XPathExpression type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("SimpleXPathCategory"))));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Value\":{\"Namespaces\":[{\"Namespace\":\"referenceForMD\",\"Prefix\":\"md\"},{\"Namespace\":\"defaultURI\"}],\"XPathCategory\":\"SimpleXPathCategory\",\"XPath\":\"//md:record\"},\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+
+		//
+		// Technically arrays cannot occur in Obligations and Advice elements.  The XML spec boils down to the following definition:
+		//		<Obligation (attributes of the obligation) >
+		//			<AttributeAssignment (attributes of this assignment) >value</AttributeAssignment>
+		//			<AttributeAssignment (attributes of this assignment) >value</AttributeAssignment>
+		//			:
+		//		</Obligation
+		//	which means that there may be multiple AttributeAssignments but each one has only one value.
+		//	This differs from the Attributes section in which each <Attribute> may have multiple <AttributeValue> elements.
+		// For Obligations and Advice we can simulate an array by having multiple AttributeAssignment elements with the same Category, Id and Issuer.
+		//
+
+		
+		//	AttributeAssignment	- Multiple values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Lisa")));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Maggie")));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"obligation-issuer1\",\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"obligation-issuer1\",\"Value\":\"Lisa\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"obligation-issuer1\",\"Value\":\"Maggie\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		//	AttributeAssignment	- Multiple Integer values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(1111))));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(2222))));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"obligation-issuer1", 
+				new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(3333))));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"obligation-issuer1\",\"Value\":1111,\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"obligation-issuer1\",\"Value\":2222,\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"obligation-issuer1\",\"Value\":3333,\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// Multiple XPathExpression values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		obligation = new StdMutableObligation();
+		obligation.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("SimpleXPathCategory"))));
+		obligation.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper2, new IdentifierImpl("SimpleXPathCategory"))));
+		result.addObligation(obligation);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Obligations\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Value\":{\"Namespaces\":[{\"Namespace\":\"referenceForMD\",\"Prefix\":\"md\"},{\"Namespace\":\"defaultURI\"}],\"XPathCategory\":\"SimpleXPathCategory\",\"XPath\":\"//md:record\"},\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Value\":{\"Namespaces\":[{\"Namespace\":\"referenceForMD\",\"Prefix\":\"md\"},{\"Namespace\":\"defaultURI\"}],\"XPathCategory\":\"SimpleXPathCategory\",\"XPath\":\"//md:hospital\"},\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}	
+		
+	}
+	
+	
+	
+	
+	@Ignore //@Test
+	public void testAdvice() {
+		
+		// create an XPathExpression for use later
+		StringNamespaceContext snc = new StringNamespaceContext();
+		try {
+			snc.add("defaultURI");
+			snc.add("md", "referenceForMD");
+		} catch (Exception e) {
+			fail("unable to create NamespaceContext e="+e);
+		}
+		XPathExpressionWrapper xpathExpressionWrapper = new XPathExpressionWrapper(snc, "//md:record");
+		XPathExpressionWrapper xpathExpressionWrapper2 = new XPathExpressionWrapper(snc, "//md:hospital");
+		
+		StdMutableAdvice Advice;
+
+		// test Advice single decision no attributes
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\"}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Advice missing Id
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		
+		
+		//	AttributeAssignment	- with AttributeId, Value,  Category, DataType, Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"Advice-issuer1\",\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		//	AttributeAssignment	- with AttributeId, Value, no Category, DataType, Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				null, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"Advice-issuer1\",\"Value\":\"Bart\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		//	AttributeAssignment	- Missing AttributeId
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				null, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		//	AttributeAssignment	- Missing Value
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				null));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"Advice-issuer1\",\"Value\":\"\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// AttributeAssignment - missing DataType
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(null, "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"Advice-issuer1\",\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// AttributeAssignment - missing issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// AttributeAssignment - Integer type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(1111))));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Value\":1111,\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// AttributeAssignment - XPathExpression type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("SimpleXPathCategory"))));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Value\":{\"Namespaces\":[{\"Namespace\":\"referenceForMD\",\"Prefix\":\"md\"},{\"Namespace\":\"defaultURI\"}],\"XPathCategory\":\"SimpleXPathCategory\",\"XPath\":\"//md:record\"},\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+
+		//
+		// Technically arrays cannot occur in Obligations and Advice elements.  The XML spec boils down to the following definition:
+		//		<Obligation (attributes of the obligation) >
+		//			<AttributeAssignment (attributes of this assignment) >value</AttributeAssignment>
+		//			<AttributeAssignment (attributes of this assignment) >value</AttributeAssignment>
+		//			:
+		//		</Obligation
+		//	which means that there may be multiple AttributeAssignments but each one has only one value.
+		//	This differs from the Attributes section in which each <Attribute> may have multiple <AttributeValue> elements.
+		// For Obligations and Advice we can simulate an array by having multiple AttributeAssignment elements with the same Category, Id and Issuer.
+		//
+		
+		//	AttributeAssignment	- Multiple values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart")));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Lisa")));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Maggie")));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"Advice-issuer1\",\"Value\":\"Bart\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"Advice-issuer1\",\"Value\":\"Lisa\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"Advice-issuer1\",\"Value\":\"Maggie\",\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		//	AttributeAssignment	- Multiple Integer values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(1111))));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(2222))));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				"Advice-issuer1", 
+				new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(3333))));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Issuer\":\"Advice-issuer1\",\"Value\":1111,\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"Advice-issuer1\",\"Value\":2222,\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Issuer\":\"Advice-issuer1\",\"Value\":3333,\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// Multiple XPathExpression values with same Category and Id (one way of doing array)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		Advice = new StdMutableAdvice();
+		Advice.setId(XACML3.ID_ACTION_IMPLIED_ACTION);
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("SimpleXPathCategory"))));
+		Advice.addAttributeAssignment(new StdMutableAttributeAssignment(
+				XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE, 
+				XACML3.ID_SUBJECT, 
+				null, 
+				new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper2, new IdentifierImpl("SimpleXPathCategory"))));
+		result.addAdvice(Advice);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"AssociatedAdvice\":[{\"Id\":\"urn:oasis:names:tc:xacml:1.0:action:implied-action\",\"AttributeAssignment\":[{\"Value\":{\"Namespaces\":[{\"Namespace\":\"referenceForMD\",\"Prefix\":\"md\"},{\"Namespace\":\"defaultURI\"}],\"XPathCategory\":\"SimpleXPathCategory\",\"XPath\":\"//md:record\"},\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"},{\"Value\":{\"Namespaces\":[{\"Namespace\":\"referenceForMD\",\"Prefix\":\"md\"},{\"Namespace\":\"defaultURI\"}],\"XPathCategory\":\"SimpleXPathCategory\",\"XPath\":\"//md:hospital\"},\"Category\":\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\",\"DataType\":\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\",\"AttributeId\":\"urn:oasis:names:tc:xacml:1.0:subject\"}]}]}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+	
+	
+	
+	
+	
+
+	
+	
+
+	
+	// Attributes tests
+	@Ignore //@Test
+	public void testAttributes() {
+		
+		// create an XPathExpression for use later
+		StringNamespaceContext snc = new StringNamespaceContext();
+		try {
+			snc.add("defaultURI");
+			snc.add("md", "referenceForMD");
+		} catch (Exception e) {
+			fail("unable to create NamespaceContext e="+e);
+		}
+		XPathExpressionWrapper xpathExpressionWrapper = new XPathExpressionWrapper(snc, "//md:record");
+		
+		
+		Identifier categoryIdentifier;
+		List<Attribute> attrList = new ArrayList<Attribute>();
+		StdMutableAttribute mutableAttribute;
+		
+		// Attr list with no entries
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// one Attribute
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// multiple attributes
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent2"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "BIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent3"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "CIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent4"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "DIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent5"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), "EIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"BIssue\",\"Value\":\"P10Y4M\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\",\"AttributeId\":\"attrIdent2\"},{\"Issuer\":\"CIssue\",\"Value\":765.432,\"DataType\":\"http://www.w3.org/2001/XMLSchema#double\",\"AttributeId\":\"attrIdent3\"},{\"Issuer\":\"DIssue\",\"Value\":true,\"DataType\":\"http://www.w3.org/2001/XMLSchema#boolean\",\"AttributeId\":\"attrIdent4\"},{\"Issuer\":\"EIssue\",\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrIdent5\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// IncludeInResult=false/true
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", false));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// Missing AttributeId (mandatory)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, null, new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Missing mandatory Value
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), null), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// Missing optional Issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), null, true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// missing optional DataType
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(null, "Apu"), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// same id, same type different issuer
+		// (This is not an array of values because issuer is different)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart"), "BIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Simpson"), "CIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"BIssue\",\"Value\":\"Bart\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"CIssue\",\"Value\":\"Simpson\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// same id, same type different issuer
+		// (This is effectively an array of values, but we return them as separate values to the client)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Simpson"), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"AIssue\",\"Value\":\"Bart\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"AIssue\",\"Value\":\"Simpson\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// same Id, different types, same issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"AIssue\",\"Value\":\"P10Y4M\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"AIssue\",\"Value\":765.432,\"DataType\":\"http://www.w3.org/2001/XMLSchema#double\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"AIssue\",\"Value\":true,\"DataType\":\"http://www.w3.org/2001/XMLSchema#boolean\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"AIssue\",\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"AIssue\",\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		// same Id, different types, different issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "BIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "CIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "DIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), "EIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), null, true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"BIssue\",\"Value\":\"P10Y4M\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"CIssue\",\"Value\":765.432,\"DataType\":\"http://www.w3.org/2001/XMLSchema#double\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"DIssue\",\"Value\":true,\"DataType\":\"http://www.w3.org/2001/XMLSchema#boolean\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"EIssue\",\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrIdent1\"},{\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+
+		// different Id, different types, same issuer
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent2"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "AIssue"), "BIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent3"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent4"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "AIssue", true));
+			attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent5"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"BIssue\",\"Value\":\"AIssue\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#yearMonthDuration\",\"AttributeId\":\"attrIdent2\"},{\"Issuer\":\"AIssue\",\"Value\":765.432,\"DataType\":\"http://www.w3.org/2001/XMLSchema#double\",\"AttributeId\":\"attrIdent3\"},{\"Issuer\":\"AIssue\",\"Value\":true,\"DataType\":\"http://www.w3.org/2001/XMLSchema#boolean\",\"AttributeId\":\"attrIdent4\"},{\"Issuer\":\"AIssue\",\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrIdent5\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// one Attribute of type XPathExpression (the only complex data type)
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+				attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<XPathExpressionWrapper>(DataTypes.DT_XPATHEXPRESSION.getId(), xpathExpressionWrapper, new IdentifierImpl("xpathCategory")), "AIssue", true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":{\"Namespaces\":[{\"Namespace\":\"referenceForMD\",\"Prefix\":\"md\"},{\"Namespace\":\"defaultURI\"}],\"XPathCategory\":\"xpathCategory\",\"XPath\":\"//md:record\"},\"DataType\":\"urn:oasis:names:tc:xacml:3.0:data-type:xpathExpression\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// multiple sets of values
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		attrList.clear();
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"), "AIssue", true));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent2"), new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"), "BIssue", false));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent3"), new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432), "CIssue", true));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent4"), new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true), "DIssue", true));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent5"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), "EIssue", true));
+		attrList.add(new StdAttribute(categoryIdentifier, new IdentifierImpl("attrNoIssuer"), new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)), null, true));
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		categoryIdentifier = new IdentifierImpl("secondCategory");
+		Attribute[] secondAttrList = {
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent12"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu2"), "AIssue2", true),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent22"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Abc2"), "BIssue2", false),
+				new StdAttribute(categoryIdentifier, new IdentifierImpl("attrIdent32"), new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Der2"), "CIssue2", true) };
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, Arrays.asList(secondAttrList)));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":\"Apu\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"},{\"Issuer\":\"CIssue\",\"Value\":765.432,\"DataType\":\"http://www.w3.org/2001/XMLSchema#double\",\"AttributeId\":\"attrIdent3\"},{\"Issuer\":\"DIssue\",\"Value\":true,\"DataType\":\"http://www.w3.org/2001/XMLSchema#boolean\",\"AttributeId\":\"attrIdent4\"},{\"Issuer\":\"EIssue\",\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrIdent5\"},{\"Value\":4567,\"DataType\":\"http://www.w3.org/2001/XMLSchema#integer\",\"AttributeId\":\"attrNoIssuer\"}]},{\"CategoryId\":\"secondCategory\",\"Attribute\":[{\"Issuer\":\"AIssue2\",\"Value\":\"Apu2\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent12\"},{\"Issuer\":\"CIssue2\",\"Value\":\"Der2\",\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent32\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// array of values - same type
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		attrList.clear();
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		mutableAttribute = new StdMutableAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), (Collection<AttributeValue<?>>)null, "AIssue", true);
+
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"));
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Bart"));
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Homer"));
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Ned"));
+			
+		attrList.add(mutableAttribute);
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":[\"Apu\",\"Bart\",\"Homer\",\"Ned\"],\"DataType\":\"http://www.w3.org/2001/XMLSchema#string\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// array of values - compatible different types
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		attrList.clear();
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		mutableAttribute = new StdMutableAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), (Collection<AttributeValue<?>>)null, "AIssue", true);
+
+			mutableAttribute.addValue(new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)));
+			mutableAttribute.addValue(new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432));
+			mutableAttribute.addValue(new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)));
+		attrList.add(mutableAttribute);
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Category\":[{\"CategoryId\":\"firstCategory\",\"Attribute\":[{\"Issuer\":\"AIssue\",\"Value\":[4567,765.432,4567],\"DataType\":\"http://www.w3.org/2001/XMLSchema#double\",\"AttributeId\":\"attrIdent1\"}]}],\"Decision\":\"Permit\"}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// array of values - incompatible different types
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		attrList.clear();
+		categoryIdentifier = new IdentifierImpl("firstCategory");
+		mutableAttribute = new StdMutableAttribute(categoryIdentifier, new IdentifierImpl("attrIdent1"), (Collection<AttributeValue<?>>)null, "AIssue", true);
+
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_STRING.getId(), "Apu"));
+			mutableAttribute.addValue(new StdAttributeValue<String>(DataTypes.DT_YEARMONTHDURATION.getId(), "P10Y4M"));
+			mutableAttribute.addValue(new StdAttributeValue<Double>(DataTypes.DT_DOUBLE.getId(), 765.432));
+			mutableAttribute.addValue(new StdAttributeValue<Boolean>(DataTypes.DT_BOOLEAN.getId(), true));
+			mutableAttribute.addValue(new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)));
+			mutableAttribute.addValue(new StdAttributeValue<BigInteger>(DataTypes.DT_INTEGER.getId(), BigInteger.valueOf(4567)));
+		attrList.add(mutableAttribute);
+		result.addAttributeCategory(new StdAttributeCategory(categoryIdentifier, attrList));
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+	}
+	
+	
+	
+	
+	
+	// PolicyIdentifier tests
+	@Ignore //@Test
+	public void testPolicyIdentifier() {
+		
+		StdIdReference policyIdentifier1 = null;
+		StdIdReference policyIdentifier2 = null;
+		StdIdReference policySetIdentifier1 = null;
+		StdIdReference policySetIdentifier2 = null;
+		
+		// multiple PolicyIdentifiers of both types
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		try {
+			policyIdentifier1 = new StdIdReference(new IdentifierImpl("idRef1"), StdVersion.newInstance("1.2.3"));
+			policyIdentifier2 = new StdIdReference(new IdentifierImpl("idRef2_NoVersion"));
+			policySetIdentifier1 = new StdIdReference(new IdentifierImpl("idSetRef1"), StdVersion.newInstance("4.5.6.7.8.9.0"));
+			policySetIdentifier2 = new StdIdReference(new IdentifierImpl("idSetRef2_NoVersion"));
+		} catch (ParseException e1) {
+			fail("creating policyIds, e="+e1);
+		}
+		result.addPolicyIdentifier(policyIdentifier1);
+		result.addPolicyIdentifier(policyIdentifier2);
+		result.addPolicySetIdentifier(policySetIdentifier1);
+		result.addPolicySetIdentifier(policySetIdentifier2);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"PolicyIdentifier\":{\"PolicyIdReference\":[{\"Id\":\"idRef1\",\"Version\":\"1.2.3\"},{\"Id\":\"idRef2_NoVersion\"}],\"PolicySetIdReference\":[{\"Id\":\"idSetRef1\",\"Version\":\"4.5.6.7.8.9.0\"},{\"Id\":\"idSetRef2_NoVersion\"}]}}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// PolicyIdentifier exists but has no IdReferences
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		policyIdentifier1 = null;
+		result.addPolicyIdentifier(policyIdentifier1);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// PolicySetIdentifier exists but has not IdReferences
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		policySetIdentifier1 = null;
+		result.addPolicyIdentifier(policySetIdentifier1);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			fail("Operation should throw exception");
+		} catch (JSONStructureException e) {
+			// correct response
+		} catch (Exception e) {
+			fail ("Failed convert from JSON to object: " + e);
+		}
+		
+		// PolicyIdentifier with PolicyIdReference and no PolicySetIdReference
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		try {
+			policyIdentifier1 = new StdIdReference(new IdentifierImpl("idRef1"), StdVersion.newInstance("1.2.3"));
+		} catch (ParseException e1) {
+			fail("creating policyIds, e="+e1);
+		}
+		result.addPolicyIdentifier(policyIdentifier1);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"PolicyIdentifier\":{\"PolicyIdReference\":[{\"Id\":\"idRef1\",\"Version\":\"1.2.3\"}]}}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		
+		// PolicyIdentifier with no PolicyIdReference and with PolicySetIdReference
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+		try {
+			policySetIdentifier1 = new StdIdReference(new IdentifierImpl("idSetRef1"), StdVersion.newInstance("4.5.6.7.8.9.0"));
+		} catch (ParseException e1) {
+			fail("creating policyIds, e="+e1);
+		}
+		result.addPolicySetIdentifier(policySetIdentifier1);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"PolicyIdentifier\":{\"PolicySetIdReference\":[{\"Id\":\"idSetRef1\",\"Version\":\"4.5.6.7.8.9.0\"}]}}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+		
+		
+		// IdReferences without version
+		response = new StdMutableResponse();
+		result = new StdMutableResult();
+		result.setDecision(Decision.PERMIT);
+
+			policyIdentifier1 = new StdIdReference(new IdentifierImpl("idRef1"), null);
+			policyIdentifier2 = new StdIdReference(new IdentifierImpl("idRef2_NoVersion"));
+			policySetIdentifier1 = new StdIdReference(new IdentifierImpl("idSetRef1"));
+			policySetIdentifier2 = new StdIdReference(new IdentifierImpl("idSetRef2_NoVersion"));
+
+		result.addPolicyIdentifier(policyIdentifier1);
+		result.addPolicyIdentifier(policyIdentifier2);
+		result.addPolicySetIdentifier(policySetIdentifier1);
+		result.addPolicySetIdentifier(policySetIdentifier2);
+		response.add(result);
+		try {
+			jsonResponse = JSONResponse.toString(response, false);
+			assertEquals("{\"Response\":[{\"Decision\":\"Permit\",\"PolicyIdentifier\":{\"PolicyIdReference\":[{\"Id\":\"idRef1\"},{\"Id\":\"idRef2_NoVersion\"}],\"PolicySetIdReference\":[{\"Id\":\"idSetRef1\"},{\"Id\":\"idSetRef2_NoVersion\"}]}}]}", jsonResponse);
+		} catch (Exception e) {
+			fail("operation failed, e="+e);
+		}
+	}
+
+
+//TODO - the JSON and XML spec imply that the Result Attributes may include the Content (It is part of the UML)
+	
+	
+	// test indentation???
+	
+	// order does not matter??
+	
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ECOMP-XACML/src/test/resources/log4j.properties b/ECOMP-XACML/src/test/resources/log4j.properties
new file mode 100644
index 0000000..4c9773d
--- /dev/null
+++ b/ECOMP-XACML/src/test/resources/log4j.properties
@@ -0,0 +1,42 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+#
+# Use this properties for debugging and development.
+#
+#
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=INFO, MAIN_LOG
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.MAIN_LOG=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.MAIN_LOG.layout=org.apache.log4j.PatternLayout
+log4j.appender.MAIN_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS} [%t] %-5p %l- %m%n
+
+#
+# This is specifically for Xacml request/response logging
+#
+log4j.logger.xacml.request=INFO, REQUEST_LOG
+
+log4j.appender.REQUEST_LOG=org.apache.log4j.ConsoleAppender
+log4j.appender.REQUEST_LOG.layout=org.apache.log4j.PatternLayout
+log4j.appender.REQUEST_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS} %m%n
diff --git a/ECOMP-XACML/src/test/resources/logback.xml b/ECOMP-XACML/src/test/resources/logback.xml
new file mode 100644
index 0000000..f2b70a0
--- /dev/null
+++ b/ECOMP-XACML/src/test/resources/logback.xml
@@ -0,0 +1,252 @@
+<!--
+  ============LICENSE_START=======================================================
+  ECOMP-XACML
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+  -->
+
+<configuration scan="true" scanPeriod="3 seconds" debug="true">
+  <!--<jmxConfigurator /> -->
+  <!-- directory path for all other type logs -->
+  <property name="logDir" value="logs" />
+  
+  <!-- directory path for debugging type logs -->
+  <property name="debugDir" value="logs" />
+  
+  <!--  specify the component name 
+    <ECOMP-component-name>::= "MSO" | "DCAE" | "ASDC " | "AAI" |"Policy" | "SDNC" | "AC"  -->
+  <property name="componentName" value="Policy"></property>
+  <property name="subComponentName" value="XACML"></property>
+  
+  <!--  log file names -->
+  <property name="errorLogName" value="error" />
+  <property name="metricsLogName" value="metrics" />
+  <property name="auditLogName" value="audit" />
+  <property name="debugLogName" value="debug" />
+  
+  
+     <!-- modified time stamp format -->
+ 
+   <!--    A U D I T 
+           <property name="defaultAuditPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+           <property name="defaultAuditPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{requestId}|%X{serviceInstanceId}|%t|%X{serverName}|%X{serviceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{instanceUuid}|%p|%X{severity}|%X{serverIpAddress}|%X{ElapsedTime}|%X{server}|%X{clientIpAddress}|%c||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+   -->
+   <property name="defaultAuditPattern" value="%X{TransactionBeginTimestamp}|%X{TransactionEndTimestamp}|%X{requestId}|%X{serviceInstanceId}|%t|%X{serverName}|%X{serviceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{instanceUuid}|%p|%X{severity}|%X{serverIpAddress}|%X{TransactionElapsedTime}|%X{server}|%X{clientIpAddress}|%c||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+  
+  
+  
+   <!--    M E T R I C 
+          <property name="defaultMetricPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+   -->
+   <property name="defaultMetricPattern" value="%X{MetricBeginTimestamp}|%X{MetricEndTimestamp}|%X{requestId}|%X{serviceInstanceId}|%t|%X{serverName}|%X{serviceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%p|%X{severity}|%X{serverIpAddress}|%X{MetricElapsedTime}|%X{server}|%X{clientIpAddress}|%c||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+  
+     
+   
+   <!--   E R R O R
+          <property name="defaultErrorPattern" value="%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%X{RequestId}|%thread|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{ErrorCategory}|%X{ErrorCode}|%X{ErrorDesciption}|%msg%n" />
+   -->
+   <property name="defaultErrorPattern" value="%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%X{requestId}|%t|%X{serviceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{ErrorCategory}|%X{ErrorCode}|%X{ErrorDesciption}|%msg%n" />
+  
+  
+  
+   <!--   D E B U G
+          <property name="debugLoggerPatternOld" value="%d{MM/dd-HH:mm:ss.SSS}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{Timer}|[%caller{3}]|%msg%n" />
+          <property name="debugLoggerPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" /> -->
+   -->
+   <property name="debugLoggerPattern" value="%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%X{RequestId}|%msg%n" />  
+   
+ 
+   
+   <!--   D E F A U L T 
+          <property name="defaultPatternOld" value="%d{MM/dd-HH:mm:ss.SSS}|%logger|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}|%msg%n" />
+          <property name="defaultPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n" />
+   -->
+   <property name="defaultPattern" value="%d{&quot;yyyy-MM-dd'T'HH:mm:ss.SSSXXX&quot;, UTC}|%X{requestId}|%X{serviceInstanceId}|%t|%X{serverName}|%X{serviceName}|%X{instanceUuid}|%p|%X{severity}|%X{serverIpAddress}|%X{server}|%X{clientIpAddress}|%c||%msg%n" />
+   
+ 
+ 
+   <!--   P A T H
+          <property name="logDirectory" value="${catalina.base}/${logDir}/${componentName}/${subComponentName}" />
+          <property name="debugLogDirectory" value="${catalina.base}/${debugDir}/${componentName}/${subComponentName}" />   
+   -->   
+   <property name="logDirectory" value="${logDir}/${componentName}/${subComponentName}" />
+   <property name="debugLogDirectory" value="${debugDir}/${componentName}/${subComponentName}" />
+   
+
+ 
+ 
+  <!-- Example evaluator filter applied against console appender -->
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>${defaultPattern}</pattern>
+    </encoder>
+  </appender>
+
+  <!-- ============================================================================ -->
+  <!-- EELF Appenders -->
+  <!-- ============================================================================ -->
+
+  <!-- The EELFAppender is used to record events to the general application 
+    log -->
+        
+  <!-- EELF Audit Appender. This appender is used to record audit engine 
+    related logging events. The audit logger and appender are specializations 
+    of the EELF application root logger and appender. This can be used to segregate 
+    Policy engine events from other components, or it can be eliminated to record 
+    these events as part of the application root log. -->
+    
+  <appender name="EELFAudit"
+    class="ch.qos.logback.core.rolling.RollingFileAppender">
+    <file>${logDirectory}/${auditLogName}.log</file>
+    <rollingPolicy
+      class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+      <fileNamePattern>${logDirectory}/${auditLogName}.%i.log.zip
+      </fileNamePattern>
+      <minIndex>1</minIndex>
+      <maxIndex>9</maxIndex>
+    </rollingPolicy>
+    <triggeringPolicy
+      class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+      <maxFileSize>5MB</maxFileSize>
+    </triggeringPolicy>
+    <encoder>
+         <pattern>${defaultAuditPattern}</pattern>
+    </encoder>
+  </appender>
+
+  <appender name="asyncEELFAudit" class="ch.qos.logback.classic.AsyncAppender">
+    <queueSize>256</queueSize>
+    <appender-ref ref="EELFAudit" />
+  </appender>
+
+
+
+
+<appender name="EELFMetrics"
+    class="ch.qos.logback.core.rolling.RollingFileAppender">
+    <file>${logDirectory}/${metricsLogName}.log</file>
+    <rollingPolicy
+      class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+      <fileNamePattern>${logDirectory}/${metricsLogName}.%i.log.zip
+      </fileNamePattern>
+      <minIndex>1</minIndex>
+      <maxIndex>9</maxIndex>
+    </rollingPolicy>
+    <triggeringPolicy
+      class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+      <maxFileSize>5MB</maxFileSize>
+    </triggeringPolicy>
+    <encoder>
+      <!-- <pattern>"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - 
+        %msg%n"</pattern> -->
+      <pattern>${defaultMetricPattern}</pattern>
+    </encoder>
+  </appender>
+  
+  <appender name="asyncEELFMetrics" class="ch.qos.logback.classic.AsyncAppender">
+    <queueSize>256</queueSize>
+    <appender-ref ref="EELFMetrics"/>
+  </appender>
+
+
+
+   
+  <appender name="EELFError"
+    class="ch.qos.logback.core.rolling.RollingFileAppender">
+    <file>${logDirectory}/${errorLogName}.log</file>
+    <rollingPolicy
+      class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+      <fileNamePattern>${logDirectory}/${errorLogName}.%i.log.zip
+      </fileNamePattern>
+      <minIndex>1</minIndex>
+      <maxIndex>9</maxIndex>
+    </rollingPolicy>
+    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+     <level>ERROR</level>
+     </filter>
+    <triggeringPolicy
+      class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+      <maxFileSize>5MB</maxFileSize>
+    </triggeringPolicy>
+    <encoder>
+      <pattern>${defaultErrorPattern}</pattern>
+    </encoder>
+  </appender>
+  
+  <appender name="asyncEELFError" class="ch.qos.logback.classic.AsyncAppender">
+    <queueSize>256</queueSize>
+    <appender-ref ref="EELFError"/>
+  </appender>
+
+
+  
+  <appender name="EELFDebug"
+    class="ch.qos.logback.core.rolling.RollingFileAppender">
+    <file>${debugLogDirectory}/${debugLogName}.log</file>
+    <rollingPolicy
+      class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+      <fileNamePattern>${debugLogDirectory}/${debugLogName}.%i.log.zip
+      </fileNamePattern>
+      <minIndex>1</minIndex>
+      <maxIndex>9</maxIndex>
+    </rollingPolicy>
+    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+     <level>INFO</level>
+     </filter>
+    <triggeringPolicy
+      class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+      <maxFileSize>5MB</maxFileSize>
+    </triggeringPolicy>
+    <encoder>
+      <pattern>${debugLoggerPattern}</pattern>
+    </encoder>
+  </appender>
+  
+  <appender name="asyncEELFDebug" class="ch.qos.logback.classic.AsyncAppender">
+    <queueSize>256</queueSize>
+    <appender-ref ref="EELFDebug" />
+    <includeCallerData>true</includeCallerData>
+  </appender>
+ 
+  
+  <!-- ============================================================================ -->
+  <!--  EELF loggers -->
+  <!-- ============================================================================ -->
+ 
+  <logger name="com.att.eelf.audit" level="info" additivity="false">
+    <appender-ref ref="asyncEELFAudit" />
+  </logger>
+  
+  <logger name="com.att.eelf.metrics" level="info" additivity="false">
+        <appender-ref ref="asyncEELFMetrics" />
+  </logger>
+ 
+    <logger name="com.att.eelf.error" level="error" additivity="false">
+  <appender-ref ref="asyncEELFError" />
+  </logger>
+  
+   <logger name="com.att.eelf.debug" level="info" additivity="false">
+        <appender-ref ref="asyncEELFDebug" />
+  </logger>
+  
+  
+  
+  <root level="INFO">
+        <appender-ref ref="asyncEELFDebug" />
+        <appender-ref ref="asyncEELFError" />
+  </root>
+
+</configuration>
diff --git a/ECOMP-XACML/src/test/resources/logging.properties b/ECOMP-XACML/src/test/resources/logging.properties
new file mode 100644
index 0000000..6d1bd48
--- /dev/null
+++ b/ECOMP-XACML/src/test/resources/logging.properties
@@ -0,0 +1,32 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
+
+.level = FINE
+
+java.util.logging.SimpleFormatter.format=%4$s: %5$s %n
+
+java.util.logging.ConsoleHandler.level = FINEST
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+java.util.logging.FileHandler.level = SEVERE
+java.util.logging.FileHandler.pattern=%h/xacml_log%u.log
+java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
diff --git a/ECOMP-XACML/src/test/resources/xacml.pip.properties b/ECOMP-XACML/src/test/resources/xacml.pip.properties
new file mode 100644
index 0000000..dbff010
--- /dev/null
+++ b/ECOMP-XACML/src/test/resources/xacml.pip.properties
@@ -0,0 +1,23 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+#
+#Fri Mar 06 12:06:30 EST 2015
+xacml.pip.engines=
diff --git a/ECOMP-XACML/src/test/resources/xacml.policy.properties b/ECOMP-XACML/src/test/resources/xacml.policy.properties
new file mode 100644
index 0000000..b1247cd
--- /dev/null
+++ b/ECOMP-XACML/src/test/resources/xacml.policy.properties
@@ -0,0 +1,25 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+#
+#Fri Mar 06 12:06:30 EST 2015
+xacml.referencedPolicies=
+xacml.rootPolicies=
+
diff --git a/ECOMP-XACML/testclient.properties b/ECOMP-XACML/testclient.properties
new file mode 100644
index 0000000..84bcd43
--- /dev/null
+++ b/ECOMP-XACML/testclient.properties
@@ -0,0 +1,21 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+test=test,MASTER
diff --git a/ECOMP-XACML/testpdp.properties b/ECOMP-XACML/testpdp.properties
new file mode 100644
index 0000000..500f8a4
--- /dev/null
+++ b/ECOMP-XACML/testpdp.properties
@@ -0,0 +1,21 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+PDP_URL= , test, test
diff --git a/ECOMP-XACML/xacml.pap.properties b/ECOMP-XACML/xacml.pap.properties
new file mode 100644
index 0000000..15c5cfb
--- /dev/null
+++ b/ECOMP-XACML/xacml.pap.properties
@@ -0,0 +1,107 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+#
+# This is our factory that will create our engine
+#
+xacml.PAP.papEngineFactory=org.openecomp.policy.xacml.std.pap.StdEngineFactory
+
+#
+# Where we store our PAP PDP Group/Node information
+#
+xacml.pap.pdps=pdps
+#
+# Need the PAP's url (how PDPs will reach it) configured here
+# because we need it to generate the URLs of the Policy Files
+# sent to the PDPs in the configuration when the PAP is first brought up.
+# (In other cases, such as the PDP calling the PAP, we could generate this URL, 
+# but for startup there is no other way to get it.)
+#
+#
+
+xacml.rest.pap.url=http://localhost:8070/pap/
+
+#
+# Upon startup, have the PAP servlet send latest configuration information to all
+# the PDP nodes it knows about.
+#
+xacml.rest.pap.initiate.pdp=true
+#
+# Heartbeat from PAP to PDPs
+#
+# How much time (in milliseconds) between heartbeats
+# (i.e. the time between completing the heartbeat with all PDPs and starting the next cycle)
+#
+xacml.rest.pap.heartbeat.interval=10000
+#
+# Heartbeat connection timeout (in milliseconds)
+#
+xacml.rest.pap.heartbeat.timeout=10000
+
+################################################################################################
+# Adding properties for getting properties previously used by PAP-ADMIN for creating Policies
+# THis is part of the Policy Creation API project
+################################################################################################
+
+# Set your domain here:
+xacml.rest.pap.domain=com
+
+# Location where all the user workspaces are located.
+xacml.rest.pap.workspace=workspace
+
+# Location where the GIT repository is located
+xacml.rest.pap.repository=repository
+
+# new Property Please mention your PAP-REST webapps Location here. 
+xacml.rest.config.webapps=C:\\Second Tomcat\\apache-tomcat-8.0.23\\webapps\\ConfigPAP\\
+
+#Turn the audit on to synchronize the DB/file system
+#xacml.rest.pap.run.audit.flag=true
+#Turn the audit off to not synchronize the DB/file system
+#xacml.rest.pap.run.audit.flag=false
+xacml.rest.pap.run.audit.flag=false
+
+#Audit will synchronize the file system to match the contents of the DB
+#xacml.rest.pap.filesystem.audit=true
+#Audit will synchronize the DB to match the contents of the file system 
+#xacml.rest.pap.filesystem.audit=false
+xacml.rest.pap.filesystem.audit=false
+
+# id
+xacml.rest.pap.userid=testpap
+# pass
+xacml.rest.pap.password=alpha123
+# pdps file
+xacml.rest.pdp.idfile=test.properties
+
+#Properties for db access
+javax.persistence.jdbc.driver=org.h2.Driver
+javax.persistence.jdbc.url=jdbc:h2:file:./sql/xacmlTest
+javax.persistence.jdbc.user=sa
+javax.persistence.jdbc.password=
+
+#Time in ms which a Policy DB transaction will wait to get the transaction lock object
+xacml.rest.pap.transaction.waitms=1000
+	
+#Policy DB transaction timeout in ms after it has obtained the transaction lock object
+xacml.rest.pap.transaction.timeoutms=500
+	
+#Policy Audit timeout in ms after it has obtained the transaction lock object
+xacml.rest.pap.audit.timeoutms=5000
diff --git a/ECOMP-XACML/xacml.pdp.properties b/ECOMP-XACML/xacml.pdp.properties
new file mode 100644
index 0000000..fc731bf
--- /dev/null
+++ b/ECOMP-XACML/xacml.pdp.properties
@@ -0,0 +1,86 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+# Default XACML Properties File for PDP RESTful servlet
+#
+# Standard API Factories
+#
+xacml.dataTypeFactory=com.att.research.xacml.std.StdDataTypeFactory
+xacml.pdpEngineFactory=com.att.research.xacmlatt.pdp.ATTPDPEngineFactory
+xacml.pepEngineFactory=com.att.research.xacml.std.pep.StdEngineFactory
+# NOT USED SEE BELOW xacml.pipFinderFactory=org.openecomp.policy.xacml.std.pip.StdPIPFinderFactory
+xacml.traceEngineFactory=com.att.research.xacml.std.trace.LoggingTraceEngineFactory
+#
+# AT&T PDP Implementation Factories
+#
+xacml.att.evaluationContextFactory=com.att.research.xacmlatt.pdp.std.StdEvaluationContextFactory
+xacml.att.combiningAlgorithmFactory=com.att.research.xacmlatt.pdp.std.StdCombiningAlgorithmFactory
+xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctionDefinitionFactory
+# NOT USED SEE BELOW xacml.att.policyFinderFactory=com.att.research.xacmlatt.pdp.std.StdPolicyFinderFactory
+
+#
+# AT&T RESTful PDP Implementation Factories
+#
+xacml.pipFinderFactory=org.openecomp.policy.pdp.rest.impl.XACMLPdpPIPFinderFactory
+xacml.att.policyFinderFactory=org.openecomp.policy.pdp.rest.impl.XACMLPdpPolicyFinderFactory
+#
+# When set to true, this flag tells the StdPolicyFinderFactory to combined all the root policy files into
+# into one PolicySet and use the given Policy Algorithm.
+#
+xacml.att.policyFinderFactory.combineRootPolicies=urn:com:att:xacml:3.0:policy-combining-algorithm:combined-deny-overrides
+#
+# PDP RESTful API properties
+# 
+# Set this to the address where the XACML-PAP-REST servlet is running
+# http://localhost:9090/pap/
+xacml.rest.pap.url=http://localhost:8070/pap/
+#
+# Give the running PDP an ID for the PAP. The url that its running as is a good choice.
+# The PAP identifies PDP's using the URL of the PDP.
+#
+xacml.rest.pdp.id=http://localhost:8082/pdp/
+#
+# Set the directory where the PDP holds its Policy Cache and PIP Configuration
+#
+xacml.rest.pdp.config=config_testing
+
+xacml.rest.pdp.webapps=/webapps
+
+xacml.rest.pdp.configparams=../webapps/configparams
+#
+# Initialize register with PAP servlet
+#
+xacml.rest.pdp.register=true
+#
+# Sleep period in seconds between register attempts
+#
+xacml.rest.pdp.register.sleep=15
+#
+# number of attempts to register. -1 means keep trying forever.
+#
+xacml.rest.pdp.register.retries=-1
+#
+# max number of bytes in a POST of a XML/JSON request
+#
+xacml.rest.pdp.maxcontent=32767
+# 
+# testClient file
+# 
+xacml.rest.pep.idfile = testclient.properties
diff --git a/ECOMP-XACML/xacml.properties b/ECOMP-XACML/xacml.properties
new file mode 100644
index 0000000..0c56302
--- /dev/null
+++ b/ECOMP-XACML/xacml.properties
@@ -0,0 +1,46 @@
+###
+# ============LICENSE_START=======================================================
+# ECOMP-XACML
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+# Default XACML Properties File
+# Standard API Factories
+#
+xacml.dataTypeFactory=com.att.research.xacml.std.StdDataTypeFactory
+xacml.pdpEngineFactory=com.att.research.xacmlatt.pdp.ATTPDPEngineFactory
+xacml.pepEngineFactory=com.att.research.xacml.std.pep.StdEngineFactory
+xacml.pipFinderFactory=com.att.research.xacml.std.pip.StdPIPFinderFactory
+
+# If there is a standard set of PIPEngines:
+# xacml.pip.engines=engine1,engine2,...,engineN
+# engine1.classname=com.att.research.xacmlpip.OraclePIP
+# engine1.prop1=foo
+# engine1.prop2=bar
+# ...
+# engine2.classname=com.att.research.xacmlpip.ActiveDirectoryPIP
+# ...
+
+# AT&T PDP Implementation Factories
+#
+xacml.att.evaluationContextFactory=com.att.research.xacmlatt.pdp.std.StdEvaluationContextFactory
+xacml.att.combiningAlgorithmFactory=com.att.research.xacmlatt.pdp.std.StdCombiningAlgorithmFactory
+xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctionDefinitionFactory
+xacml.att.policyFinderFactory=com.att.research.xacmlatt.pdp.std.StdPolicyFinderFactory
+
+# If there is a standard policy for the engine:
+# xacml.att.stdPolicyFinderFactory.rootPolicyFile=/etc/stdpolicyset.xml