Submit Policy Tutorials

So app developers can more easily download and test client code etc.

Issue-ID: POLICY-2876
Change-Id: I360cd0d637150cd0c2353c6284803f4438e96556
Signed-off-by: Pamela Dragosh <pdragosh@research.att.com>
diff --git a/pom.xml b/pom.xml
index 53e215a..82889ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,6 +51,7 @@
         <module>packages</module>
         <module>testsuites</module>
         <module>xacml-test</module>
+        <module>tutorials</module>
     </modules>
 
     <dependencies>
diff --git a/tutorials/pom.xml b/tutorials/pom.xml
new file mode 100644
index 0000000..66a1892
--- /dev/null
+++ b/tutorials/pom.xml
@@ -0,0 +1,47 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP Policy Engine - XACML PDP
+  ================================================================================
+  Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+  Modifications Copyright (C) 2020 Bell Canada.
+  ================================================================================
+  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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.onap.policy.xacml-pdp</groupId>
+        <artifactId>policy-xacml-pdp</artifactId>
+        <version>2.3.4-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>xacml-tutorials</artifactId>
+    <packaging>pom</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>This sub-module holds the XACML PDP Application Tutorials.</description>
+
+    <properties>
+        <!-- There code is not shipped with final artifact, for user testing only -->
+        <sonar.skip>true</sonar.skip>
+    </properties>
+
+    <modules>
+        <module>tutorial-xacml-application</module>
+        <module>tutorial-enforcement</module>
+    </modules>
+
+</project>
diff --git a/tutorials/tutorial-enforcement/README.md b/tutorials/tutorial-enforcement/README.md
new file mode 100644
index 0000000..23321fd
--- /dev/null
+++ b/tutorials/tutorial-enforcement/README.md
@@ -0,0 +1,20 @@
+Copyright 2020 AT&T Intellectual Property. All rights reserved.
+This file is licensed under the CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL LICENSE
+Full license text at https://creativecommons.org/licenses/by/4.0/legalcode
+
+The Policy Enforcement Tutorial can be built:
+
+mvn clean install
+
+Be sure to start the Policy Framework application components if you are not testing this in a lab. See
+src/main/docker/README.txt for details to run local instances of the components.
+
+You can run the application via code by running the App.main method with command line argument with IP then Port
+of the XACML PDP, followed by the IP then Port of Dmaap.
+
+App.main(new String[] {"0.0.0.0", "6969", "0.0.0.0", "3904"});
+
+or from Eclipse by right-clicking App.java and selecting "Run As" and select "Java Application". Edit the
+configuration by adding these command line arguments: "0.0.0.0" "6969" "0.0.0.0" "3904"
+
+Quit the application by typing 'q' into stdin.
diff --git a/tutorials/tutorial-enforcement/pom.xml b/tutorials/tutorial-enforcement/pom.xml
new file mode 100644
index 0000000..d4065a5
--- /dev/null
+++ b/tutorials/tutorial-enforcement/pom.xml
@@ -0,0 +1,56 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP Policy Engine - XACML PDP
+  ================================================================================
+  Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+  Modifications Copyright (C) 2020 Bell Canada.
+  ================================================================================
+  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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onap.policy.xacml-pdp</groupId>
+        <artifactId>xacml-tutorials</artifactId>
+        <version>2.3.4-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.onap.policy.tutorial</groupId>
+    <artifactId>tutorial-xacml-enforcement</artifactId>
+    <packaging>jar</packaging>
+
+    <name>tutorial-xacml-enforcement</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onap.policy.models</groupId>
+            <artifactId>policy-models-decisions</artifactId>
+            <version>${policy.models.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models</groupId>
+            <artifactId>policy-models-pap</artifactId>
+            <version>${policy.models.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.common</groupId>
+            <artifactId>policy-endpoints</artifactId>
+            <version>${policy.common.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/tutorials/tutorial-enforcement/src/main/docker/README.txt b/tutorials/tutorial-enforcement/src/main/docker/README.txt
new file mode 100644
index 0000000..eed0a74
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/main/docker/README.txt
@@ -0,0 +1,36 @@
+docker-compose -f docker-compose.yml run --rm start_dependencies
+
+docker-compose -f docker-compose.yml run --rm start_all
+
+
+curl -X POST http://0.0.0.0:3904/events/POLICY-PDP-PAP
+
+Should return JSON similar to this:
+{"serverTimeMs":0,"count":0}
+
+
+curl -k -u 'healthcheck:zb!XztG34' 'https://0.0.0.0:6969/policy/pdpx/v1/healthcheck'
+
+Should return JSON similar to this:
+{"name":"Policy Xacml PDP","url":"self","healthy":true,"code":200,"message":"alive"}
+
+
+curl -k -u 'healthcheck:zb!XztG34' 'https://0.0.0.0:6767/policy/api/v1/healthcheck'
+Should return JSON similar to this:
+{
+    "name": "Policy API",
+    "url": "policy-api",
+    "healthy": true,
+    "code": 200,
+    "message": "alive"
+}
+
+curl -k -u 'healthcheck:zb!XztG34' 'https://0.0.0.0:6868/policy/pap/v1/healthcheck'
+{
+    "name": "Policy PAP",
+    "url": "policy-pap",
+    "healthy": true,
+    "code": 200,
+    "message": "alive"
+}
+
diff --git a/tutorials/tutorial-enforcement/src/main/docker/config/db/db.conf b/tutorials/tutorial-enforcement/src/main/docker/config/db/db.conf
new file mode 100644
index 0000000..42f3584
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/main/docker/config/db/db.conf
@@ -0,0 +1,20 @@
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2020 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+MYSQL_ROOT_PASSWORD=secret
+MYSQL_USER=policy_user
+MYSQL_PASSWORD=policy_user
\ No newline at end of file
diff --git a/tutorials/tutorial-enforcement/src/main/docker/config/db/db.sh b/tutorials/tutorial-enforcement/src/main/docker/config/db/db.sh
new file mode 100644
index 0000000..499764d
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/main/docker/config/db/db.sh
@@ -0,0 +1,26 @@
+#!/bin/bash -xv
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2020 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+
+for db in policyadmin operationshistory
+do
+     mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" --execute "CREATE DATABASE IF NOT EXISTS ${db};"
+     mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" --execute "GRANT ALL PRIVILEGES ON \`${db}\`.* TO '${MYSQL_USER}'@'%' ;"
+done
+
+mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" --execute "FLUSH PRIVILEGES;"
diff --git a/tutorials/tutorial-enforcement/src/main/docker/config/sim/simParameters.json b/tutorials/tutorial-enforcement/src/main/docker/config/sim/simParameters.json
new file mode 100644
index 0000000..bd43520
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/main/docker/config/sim/simParameters.json
@@ -0,0 +1,15 @@
+{
+    "dmaapProvider": {
+        "name": "DMaaP simulator",
+        "topicSweepSec": 300
+    },
+    "restServers": [
+        {
+            "name": "DMaaP simulator",
+            "providerClass": "org.onap.policy.models.sim.dmaap.rest.DmaapSimRestControllerV1",
+            "host": "0.0.0.0",
+            "port": 3904,
+            "https": false
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tutorials/tutorial-enforcement/src/main/docker/docker-compose.yml b/tutorials/tutorial-enforcement/src/main/docker/docker-compose.yml
new file mode 100644
index 0000000..bf55d0f
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/main/docker/docker-compose.yml
@@ -0,0 +1,105 @@
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2020 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+version: '2'
+services:
+   mariadb:
+      image: mariadb:10.2.14
+      container_name: mariadb
+      hostname: mariadb
+      command: ['--lower-case-table-names=1', '--wait_timeout=28800']
+      env_file: config/db/db.conf
+      volumes:
+         - ./config/db:/docker-entrypoint-initdb.d
+      expose:
+       - 3306
+   message-router:
+      image: nexus3.onap.org:10001/onap/policy-models-simulator:latest
+      container_name: dmaap-simulator
+      hostname: dmaap-simulator
+      volumes:
+       - ./config/sim:/opt/app/policy/simulators/etc/mounted:ro
+      ports:
+       - "3904:3904"
+      expose:
+       - 3904
+   pap:
+      # Released Guilin image
+      image: nexus3.onap.org:10001/onap/policy-pap:2.3.3
+      container_name: policy-pap
+      depends_on:
+       - mariadb
+       - message-router
+      hostname: policy-pap
+      ports:
+       - "6868:6969"
+      expose:
+       - 6868
+   api:
+      # Released Guilin image
+      image: nexus3.onap.org:10001/onap/policy-api:2.3.3
+      container_name: policy-api
+      depends_on:
+       - mariadb
+      hostname: policy-api
+      ports:
+       - "6767:6969"
+      expose:
+       - 6767
+   xacml-pdp:
+      # Released Guilin image
+      image: nexus3.onap.org:10001/onap/policy-xacml-pdp:2.3.3
+      container_name: policy-xacml-pdp
+      depends_on:
+       - mariadb
+       - message-router
+       - pap
+      hostname: policy-xacml-pdp
+      ports:
+       - "6969:6969"
+      expose:
+       - 6969
+   start_dependencies:
+      image: dadarek/wait-for-dependencies
+      environment:
+        TIMEOUT_LENGTH: 60
+      container_name: policy-wait
+      depends_on:
+        - mariadb
+        - message-router
+      hostname: policy-wait
+      command:
+        mariadb:3306
+        message-router:3904
+   start_all:
+      image: dadarek/wait-for-dependencies
+      environment:
+        TIMEOUT_LENGTH: 60
+      container_name: policy-wait-all
+      depends_on:
+        - mariadb
+        - message-router
+        - api
+        - pap
+        - xacml-pdp
+      hostname: policy-wait-all
+      command:
+        mariadb:3306
+        message-router:3904
+        api:6969
+        pap:6969
+        xacml-pdp:6969
diff --git a/tutorials/tutorial-enforcement/src/main/java/org/onap/policy/tutorial/policyenforcement/App.java b/tutorials/tutorial-enforcement/src/main/java/org/onap/policy/tutorial/policyenforcement/App.java
new file mode 100644
index 0000000..764b3bd
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/main/java/org/onap/policy/tutorial/policyenforcement/App.java
@@ -0,0 +1,227 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 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.onap.policy.tutorial.policyenforcement;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Scanner;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
+import org.onap.policy.common.endpoints.event.comm.TopicListener;
+import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
+import org.onap.policy.common.endpoints.http.client.HttpClient;
+import org.onap.policy.common.endpoints.http.client.HttpClientConfigException;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
+import org.onap.policy.common.endpoints.parameters.TopicParameterGroup;
+import org.onap.policy.common.endpoints.parameters.TopicParameters;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.models.decisions.concepts.DecisionRequest;
+import org.onap.policy.models.decisions.concepts.DecisionResponse;
+import org.onap.policy.models.pap.concepts.PolicyNotification;
+import org.onap.policy.models.pap.concepts.PolicyStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class App extends Thread implements TopicListener {
+    private static Logger logger                           = LoggerFactory.getLogger(App.class);
+    private static final String MY_POLICYTYPEID = "onap.policies.monitoring.MyAnalytic";
+    private String xacmlPdpHost;
+    private String xacmlPdpPort;
+    private DecisionRequest decisionRequest = new DecisionRequest();
+    private Integer requestId = 1;
+    private HttpClient client = null;
+
+    /**
+     * Constructor.
+     *
+     * @param args Command line arguments
+     */
+    public App(String[] args) {
+        xacmlPdpHost = args[0];
+        xacmlPdpPort = args[1];
+
+        TopicParameters params = new TopicParameters();
+        params.setTopicCommInfrastructure("dmaap");
+        params.setFetchLimit(1);
+        params.setFetchTimeout(5000);
+        params.setTopic("POLICY-NOTIFICATION");
+        params.setServers(Arrays.asList(args[2] + ":" + args[3]));
+        TopicParameterGroup topicParams = new TopicParameterGroup();
+        topicParams.setTopicSources(Arrays.asList(params));
+
+        TopicEndpointManager.getManager().addTopics(topicParams);
+        TopicEndpointManager.getManager().getDmaapTopicSource("POLICY-NOTIFICATION").register(this);
+
+        decisionRequest.setOnapComponent("myComponent");
+        decisionRequest.setOnapName("myName");
+        decisionRequest.setOnapInstance("myInstanceId");
+        decisionRequest.setAction("configure");
+        Map<String, Object> resources = new HashMap<>();
+        resources.put("policy-type", MY_POLICYTYPEID);
+        decisionRequest.setResource(resources);
+    }
+
+    /**
+     * Thread run method that creates a connection and gets an initial Decision on which policy(s)
+     * we should be enforcing.
+     * Then sits waiting for the user to enter q or Q from the keyboard to quit. While waiting,
+     * listen on Dmaap topic for notification that the policy has changed.
+     */
+    @Override
+    public void run() {
+        logger.info("running - type q to stdin to quit");
+        try {
+            client = HttpClientFactoryInstance.getClientFactory().build(BusTopicParams.builder()
+                    .clientName("myClientName").useHttps(true).allowSelfSignedCerts(true)
+                    .hostname(xacmlPdpHost).port(Integer.parseInt(xacmlPdpPort))
+                    .userName("healthcheck").password("zb!XztG34").basePath("policy/pdpx/v1")
+                    .managed(true)
+                    .serializationProvider("org.onap.policy.common.gson.GsonMessageBodyHandler")
+                    .build());
+        } catch (NumberFormatException | HttpClientConfigException e) {
+            logger.error("Could not create Http client", e);
+            return;
+        }
+
+        Map<String, Object> policies = getDecision(client, this.decisionRequest);
+        if (policies.isEmpty()) {
+            logger.info("Not enforcing any policies to start");
+        }
+        for (Entry<String, Object> entrySet : policies.entrySet()) {
+            logger.info("Enforcing: {}", entrySet.getKey());
+        }
+
+        TopicEndpointManager.getManager().start();
+
+        @SuppressWarnings("resource") // never close System.in
+        Scanner input = new Scanner(System.in);
+        while (!Thread.currentThread().isInterrupted()) {
+            String quit = input.nextLine();
+            if ("q".equalsIgnoreCase(quit)) {
+                logger.info("quiting");
+                break;
+            }
+        }
+
+        TopicEndpointManager.getManager().shutdown();
+
+    }
+
+    /**
+     * This method is called when a topic event is received.
+     */
+    @Override
+    public void onTopicEvent(CommInfrastructure infra, String topic, String event) {
+        logger.info("onTopicEvent {}", event);
+        if (scanForPolicyType(event)) {
+            Map<String, Object> newPolicies = getDecision(client, this.decisionRequest);
+            if (newPolicies.isEmpty()) {
+                logger.info("Not enforcing any policies");
+            }
+            for (Entry<String, Object> entrySet : newPolicies.entrySet()) {
+                logger.info("Now Enforcing: {}", entrySet.getKey());
+            }
+        }
+    }
+
+    /**
+     * Helper method that parses a DMaap message event for POLICY-NOTIFICATION
+     * looking for our supported policy type to enforce.
+     *
+     * @param msg Dmaap Message
+     * @return true if MY_POLICYTYPEID is in the message
+     */
+    private boolean scanForPolicyType(String msg) {
+        StandardCoder gson = new StandardCoder();
+        try {
+            PolicyNotification notification = gson.decode(msg, PolicyNotification.class);
+            for (PolicyStatus added : notification.getAdded()) {
+                if (MY_POLICYTYPEID.equals(added.getPolicyTypeId())) {
+                    return true;
+                }
+            }
+            for (PolicyStatus deleted : notification.getDeleted()) {
+                if (MY_POLICYTYPEID.equals(deleted.getPolicyTypeId())) {
+                    return true;
+                }
+            }
+        } catch (CoderException e) {
+            logger.error("StandardCoder failed to parse PolicyNotification", e);
+        }
+        return false;
+    }
+
+
+    /**
+     * Helper method that calls the XACML PDP Decision API to get a Decision
+     * as to which policy we should be enforcing.
+     *
+     * @param client HttpClient to use to make REST call
+     * @param decisionRequest DecisionRequest object to send
+     * @return The Map of policies that was in the DecisionResponse object
+     */
+    private Map<String, Object> getDecision(HttpClient client, DecisionRequest decisionRequest) {
+        decisionRequest.setRequestId(requestId.toString());
+        requestId++;
+
+        Entity<DecisionRequest> entityRequest =
+                Entity.entity(decisionRequest, MediaType.APPLICATION_JSON);
+        Response response = client.post("/decision", entityRequest, Collections.emptyMap());
+
+        if (response.getStatus() != 200) {
+            logger.error(
+                    "Decision API failed - is the IP/port correct? {}", response.getStatus());
+            return Collections.emptyMap();
+        }
+
+        DecisionResponse decisionResponse = HttpClient.getBody(response, DecisionResponse.class);
+
+        return decisionResponse.getPolicies();
+    }
+
+    /**
+     * Our Main application entry point.
+     *
+     * @param args command line arguments
+     */
+    public static void main(String[] args) {
+        logger.info("Hello Welcome to ONAP Enforcement Tutorial!");
+
+        App app = new App(args);
+
+        app.start();
+
+        try {
+            app.join();
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            logger.warn("Thread interrupted");
+        }
+
+        logger.info("Tutorial ended");
+    }
+
+}
diff --git a/tutorials/tutorial-enforcement/src/test/resources/MyAnalytic.yaml b/tutorials/tutorial-enforcement/src/test/resources/MyAnalytic.yaml
new file mode 100644
index 0000000..23cf3c6
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/test/resources/MyAnalytic.yaml
@@ -0,0 +1,16 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+   onap.policies.Monitoring:
+      derived_from: tosca.policies.Root
+      version: 1.0.0
+      name: onap.policies.Monitoring
+      description: a base policy type for all policies that govern monitoring provisioning
+   onap.policies.monitoring.MyAnalytic:
+      derived_from: onap.policies.Monitoring
+      type_version: 1.0.0
+      version: 1.0.0
+      description: Example analytic
+      properties:
+         myProperty:
+            type: string
+            required: true
\ No newline at end of file
diff --git a/tutorials/tutorial-enforcement/src/test/resources/MyPolicies.yaml b/tutorials/tutorial-enforcement/src/test/resources/MyPolicies.yaml
new file mode 100644
index 0000000..00c5ef9
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/test/resources/MyPolicies.yaml
@@ -0,0 +1,14 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+topology_template:
+   policies:
+     -
+       policy1:
+           type: onap.policies.monitoring.MyAnalytic
+           type_version: 1.0.0
+           version: 1.0.0
+           name: policy1
+           metadata:
+             policy-id: policy1
+             policy-version: 1.0.0
+           properties:
+             myProperty: value1
\ No newline at end of file
diff --git a/tutorials/tutorial-enforcement/src/test/resources/postman/Policy Enforcement Tutorial.postman_collection.json b/tutorials/tutorial-enforcement/src/test/resources/postman/Policy Enforcement Tutorial.postman_collection.json
new file mode 100644
index 0000000..85de39b
--- /dev/null
+++ b/tutorials/tutorial-enforcement/src/test/resources/postman/Policy Enforcement Tutorial.postman_collection.json
@@ -0,0 +1,597 @@
+{
+	"info": {
+		"_postman_id": "f00b4c77-8f4b-423f-a132-2bcdd4adf598",
+		"name": "Policy Enforcement Tutorial",
+		"description": "Collection of Postman API calls to support the Policy Enforcement Tutorial",
+		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+	},
+	"item": [
+		{
+			"name": "Api Healthcheck",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "https://0.0.0.0:6767/policy/api/v1/healthcheck",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6767",
+					"path": [
+						"policy",
+						"api",
+						"v1",
+						"healthcheck"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "Create MyAnalytic Policy Type",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/yaml"
+					},
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/yaml"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n   onap.policies.Monitoring:\n      derived_from: tosca.policies.Root\n      version: 1.0.0\n      name: onap.policies.Monitoring\n      description: a base policy type for all policies that govern monitoring provisioning\n   onap.policies.monitoring.MyAnalytic:\n      derived_from: onap.policies.Monitoring\n      type_version: 1.0.0\n      version: 1.0.0\n      description: Example analytic\n      properties:\n         myProperty:\n            type: string\n            required: true"
+				},
+				"url": {
+					"raw": "https://0.0.0.0:6767/policy/api/v1/policytypes",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6767",
+					"path": [
+						"policy",
+						"api",
+						"v1",
+						"policytypes"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "Create policy1 MyAnalytic Policy",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/yaml"
+					},
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/yaml"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "tosca_definitions_version: tosca_simple_yaml_1_1_0\ntopology_template:\n   policies:\n     -\n       policy1:\n           type: onap.policies.monitoring.MyAnalytic\n           type_version: 1.0.0\n           version: 1.0.0\n           name: policy1\n           metadata:\n             policy-id: policy1\n             policy-version: 1.0.0\n           properties:\n             myProperty: value1\n             "
+				},
+				"url": {
+					"raw": "https://0.0.0.0:6767/policy/api/v1/policytypes/onap.policies.monitoring.MyAnalytic/versions/1.0.0/policies",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6767",
+					"path": [
+						"policy",
+						"api",
+						"v1",
+						"policytypes",
+						"onap.policies.monitoring.MyAnalytic",
+						"versions",
+						"1.0.0",
+						"policies"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "PAP Healthcheck",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "https://0.0.0.0:6868/policy/pap/v1/healthcheck",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6868",
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"healthcheck"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "PAP Get PDPs",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "https://0.0.0.0:6868/policy/pap/v1/pdps",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6868",
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "Simple Deploy Policy - policy1",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "{\r\n  \"policies\" : [\r\n    {\r\n      \"policy-id\": \"policy1\",\r\n      \"policy-version\": \"1.0.0\"\r\n    }\r\n    ]\r\n}"
+				},
+				"url": {
+					"raw": "{https://0.0.0.0:6868/policy/pap/v1/pdps/policies",
+					"protocol": "{https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6868",
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps",
+						"policies"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "Xacml Healthcheck",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "https://0.0.0.0:6969/policy/pdpx/v1/healthcheck",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6969",
+					"path": [
+						"policy",
+						"pdpx",
+						"v1",
+						"healthcheck"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "Xacml Statistics",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "https://0.0.0.0:6969/policy/pdpx/v1/healthcheck",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6969",
+					"path": [
+						"policy",
+						"pdpx",
+						"v1",
+						"healthcheck"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "Xacml Decision - MyAnalytic policy-type",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "{\n  \"ONAPName\": \"myName\",\n  \"ONAPComponent\": \"myComponent\",\n  \"ONAPInstance\": \"myInstanceId\",\n  \"requestId\": \"1\",\n  \"action\": \"configure\",\n  \"resource\": {\n      \"policy-type\": \"onap.policies.monitoring.MyAnalytic\"\n  }\n}"
+				},
+				"url": {
+					"raw": "https://0.0.0.0:6969/policy/pdpx/v1/decision",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6969",
+					"path": [
+						"policy",
+						"pdpx",
+						"v1",
+						"decision"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "Dmaap Simulator - Policy Update Notification",
+			"request": {
+				"auth": {
+					"type": "noauth"
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "{\n  \"messageName\": \"PDP_STATE_CHANGE\",\n  \"requestId\": \"05d08a05-e182-46fa-a6d1-5500e52cd3e5\",\n  \"timestampMs\": \"1576598570797\", \n  \"name\": \"PamelaDragosh.local\",\n  \"pdpGroup\": \"defaultGroup\",\n  \"pdpSubgroup\":\"XacmlPdpGroup\",\n  \"state\":\"ACTIVE\"\n}"
+				},
+				"url": {
+					"raw": "http://localhost:3904/events/POLICY-PDP-PAP",
+					"protocol": "http",
+					"host": [
+						"localhost"
+					],
+					"port": "3904",
+					"path": [
+						"events",
+						"POLICY-PDP-PAP"
+					]
+				}
+			},
+			"response": []
+		},
+		{
+			"name": "Simple Undeploy Policy Copy",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "DELETE",
+				"header": [
+					{
+						"key": "Accept",
+						"value": "application/json",
+						"type": "text"
+					},
+					{
+						"key": "Content-Type",
+						"value": "application/json",
+						"type": "text"
+					}
+				],
+				"url": {
+					"raw": "https://0.0.0.0:6868/policy/pap/v1/pdps/policies/onap.policies.monitoring.MyAnalytic",
+					"protocol": "https",
+					"host": [
+						"0",
+						"0",
+						"0",
+						"0"
+					],
+					"port": "6868",
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps",
+						"policies",
+						"onap.policies.monitoring.MyAnalytic"
+					]
+				}
+			},
+			"response": []
+		}
+	],
+	"auth": {
+		"type": "basic",
+		"basic": [
+			{
+				"key": "password",
+				"value": "",
+				"type": "string"
+			},
+			{
+				"key": "username",
+				"value": "",
+				"type": "string"
+			}
+		]
+	},
+	"protocolProfileBehavior": {}
+}
\ No newline at end of file
diff --git a/tutorials/tutorial-xacml-application/pom.xml b/tutorials/tutorial-xacml-application/pom.xml
new file mode 100644
index 0000000..aa776a8
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/pom.xml
@@ -0,0 +1,101 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP Policy Engine - XACML Application Tutorial
+  ================================================================================
+  Copyright (C) 2020 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/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.onap.policy.xacml-pdp</groupId>
+    <artifactId>xacml-tutorials</artifactId>
+    <version>2.3.4-SNAPSHOT</version>
+  </parent>
+
+  <groupId>org.onap.policy.tutorial.xacml-application</groupId>
+  <artifactId>tutorial-xacml-application</artifactId>
+  <packaging>jar</packaging>
+
+  <name>tutorial-xacml-application</name>
+
+  <properties>
+    <!-- There is code to support JUnit testing in this sub-module. -->
+    <sonar.skip>true</sonar.skip>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.onap.policy.xacml-pdp.applications</groupId>
+      <artifactId>common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.onap.policy.xacml-pdp</groupId>
+      <artifactId>xacml-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>docker</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+            <configuration>
+              <verbose>true</verbose>
+              <images>
+                <image>
+                  <name>onap/policy-xacml-tutorial</name>
+                  <alias>xacml-pdp</alias>
+                  <build>
+                    <contextDir>${project.basedir}/src/main/docker</contextDir>
+                    <assembly>
+                        <descriptorRef>artifact-with-dependencies</descriptorRef>
+                    </assembly>
+                  </build>
+                </image>
+              </images>
+            </configuration>
+            <executions>
+                <execution>
+                    <id>clean-images</id>
+                    <phase>pre-clean</phase>
+                    <goals>
+                        <goal>remove</goal>
+                    </goals>
+                </execution>
+                <execution>
+                    <id>generate-images</id>
+                    <phase>package</phase>
+                    <goals>
+                        <goal>build</goal>
+                    </goals>
+                </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
diff --git a/tutorials/tutorial-xacml-application/postman/PolicyApplicationTutorial.postman_collection.json b/tutorials/tutorial-xacml-application/postman/PolicyApplicationTutorial.postman_collection.json
new file mode 100644
index 0000000..dbb1e0d
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/postman/PolicyApplicationTutorial.postman_collection.json
@@ -0,0 +1,738 @@
+{
+	"info": {
+		"_postman_id": "20eb42db-f0a7-4b65-8ccd-c3a5f56cb526",
+		"name": "Policy Application Tutorial",
+		"description": "Collection of Postman API calls to support the Policy Enforcement Tutorial",
+		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+	},
+	"item": [
+		{
+			"name": "Api Healthcheck",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "{{POLICY-API-URL}}/policy/api/v1/healthcheck",
+					"host": [
+						"{{POLICY-API-URL}}"
+					],
+					"path": [
+						"policy",
+						"api",
+						"v1",
+						"healthcheck"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Create Authorization Policy Type",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/yaml"
+					},
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/yaml"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n    onap.policies.Authorization:\n        derived_from: tosca.policies.Root\n        version: 1.0.0\n        description: Example tutorial policy type for doing user authorization\n        properties:\n            user:\n                type: string\n                required: true\n                description: The unique user name\n            permissions:\n                type: list\n                required: true\n                description: A list of resource permissions\n                entry_schema:\n                    type: onap.datatypes.Tutorial\ndata_types:\n    onap.datatypes.Tutorial:\n        derived_from: tosca.datatypes.Root\n        version: 1.0.0\n        properties:\n            entity:\n                type: string\n                required: true\n                description: The resource\n            permission:\n                type: string\n                required: true\n                description: The permission level\n                constraints:\n                    - valid_values: [read, write, delete]\n",
+					"options": {
+						"raw": {
+							"language": "text"
+						}
+					}
+				},
+				"url": {
+					"raw": "{{POLICY-API-URL}}/policy/api/v1/policytypes",
+					"host": [
+						"{{POLICY-API-URL}}"
+					],
+					"path": [
+						"policy",
+						"api",
+						"v1",
+						"policytypes"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Create policies",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/yaml"
+					},
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/yaml"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "tosca_definitions_version: tosca_simple_yaml_1_1_0\ntopology_template:\n    policies:\n        -\n            onap.policy.tutorial.demo:\n                type: onap.policies.Authorization\n                type_version: 1.0.0\n                version: 1.0.0\n                metadata:\n                    policy-id: onap.policy.tutorial.demo\n                    policy-version: 1\n                properties:\n                    user: demo\n                    permissions:\n                        -\n                            entity: foo\n                            permission: read\n                        -\n                            entity: foo\n                            permission: write\n        -\n            onap.policy.tutorial.audit:\n                type: onap.policies.Authorization\n                version: 1.0.0\n                type_version: 1.0.0\n                metadata:\n                    policy-id: onap.policy.tutorial.bar\n                    policy-version: 1\n                properties:\n                    user: audit\n                    permissions:\n                        -\n                            entity: foo\n                            permission: read\n",
+					"options": {
+						"raw": {
+							"language": "text"
+						}
+					}
+				},
+				"url": {
+					"raw": "{{POLICY-API-URL}}/policy/api/v1/policytypes/onap.policies.Authorization/versions/1.0.0/policies",
+					"host": [
+						"{{POLICY-API-URL}}"
+					],
+					"path": [
+						"policy",
+						"api",
+						"v1",
+						"policytypes",
+						"onap.policies.Authorization",
+						"versions",
+						"1.0.0",
+						"policies"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "PAP Healthcheck",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "{{POLICY-PAP-URL}}/policy/pap/v1/healthcheck",
+					"host": [
+						"{{POLICY-PAP-URL}}"
+					],
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"healthcheck"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "PAP Get PDPs",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "{{POLICY-PAP-URL}}/policy/pap/v1/pdps",
+					"host": [
+						"{{POLICY-PAP-URL}}"
+					],
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "PdpGroup State Change PASSIVE",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "PUT",
+				"header": [
+					{
+						"key": "Content-Type",
+						"value": "application/json",
+						"type": "text"
+					},
+					{
+						"key": "Accept",
+						"value": "application/json",
+						"type": "text"
+					}
+				],
+				"url": {
+					"raw": "{{POLICY-PAP-URL}}/policy/pap/v1/pdps/groups/defaultGroup?state=PASSIVE",
+					"host": [
+						"{{POLICY-PAP-URL}}"
+					],
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps",
+						"groups",
+						"defaultGroup"
+					],
+					"query": [
+						{
+							"key": "state",
+							"value": "PASSIVE"
+						}
+					]
+				},
+				"description": "This is an API to change the current state of a PdpGroup (example - \"defaultGroup\") resulting in changing state of all the PDP instances registered with the PdpGroup. As of now, the allowed states are ACTIVE and PASSIVE."
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Delete PdpGroup",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "DELETE",
+				"header": [
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "{{POLICY-PAP-URL}}/policy/pap/v1/pdps/groups/defaultGroup",
+					"host": [
+						"{{POLICY-PAP-URL}}"
+					],
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps",
+						"groups",
+						"defaultGroup"
+					]
+				},
+				"description": "This is an API to delete a specific PdpGroup (example - \"SampleGroup\") currently available in Policy DB, resulting in removing all the PDP instances registered with the group."
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Create/Update PdpGroup",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "{\n    \"groups\": [\n        {\n            \"name\": \"defaultGroup\",\n            \"pdpGroupState\": \"ACTIVE\",\n            \"properties\": {},\n            \"pdpSubgroups\": [\n                {\n                    \"pdpType\": \"xacml\",\n                    \"desiredInstanceCount\": 1,\n                    \"properties\": {},\n                    \"supportedPolicyTypes\": [\n                        {\n                            \"name\": \"onap.policies.Authorization\",\n                            \"version\": \"1.0.0\"\n                        }\n                    ],\n                    \"policies\": []\n                }\n            ]\n        }\n    ]\n}"
+				},
+				"url": {
+					"raw": "{{POLICY-PAP-URL}}/policy/pap/v1/pdps/groups/batch",
+					"host": [
+						"{{POLICY-PAP-URL}}"
+					],
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps",
+						"groups",
+						"batch"
+					]
+				},
+				"description": "This is a generic API to create/update PdpGroups in Policy DB. However, the supportedPolicyTypes field of PdpSubGroup cannot be changed once created."
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Simple Deploy Policy - onap.policy.tutorial.demo",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "{\r\n  \"policies\" : [\r\n    {\r\n      \"policy-id\": \"onap.policy.tutorial.demo\",\r\n      \"policy-version\": \"1.0.0\"\r\n    },\r\n    {\r\n      \"policy-id\": \"onap.policy.tutorial.audit\",\r\n      \"policy-version\": \"1.0.0\"\r\n    }\r\n    ]\r\n}"
+				},
+				"url": {
+					"raw": "{{POLICY-PAP-URL}}/policy/pap/v1/pdps/policies",
+					"host": [
+						"{{POLICY-PAP-URL}}"
+					],
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps",
+						"policies"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Dmaap Simulator - Policy Update Notification",
+			"protocolProfileBehavior": {
+				"disableBodyPruning": true
+			},
+			"request": {
+				"auth": {
+					"type": "noauth"
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": ""
+				},
+				"url": {
+					"raw": "{{DMAAP-URL}}/events/POLICY-NOTIFICATION/group/id?timeout=5000",
+					"host": [
+						"{{DMAAP-URL}}"
+					],
+					"path": [
+						"events",
+						"POLICY-NOTIFICATION",
+						"group",
+						"id"
+					],
+					"query": [
+						{
+							"key": "timeout",
+							"value": "5000"
+						}
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Xacml Healthcheck",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "{{POLICY-XACML-URL}}/policy/pdpx/v1/healthcheck",
+					"host": [
+						"{{POLICY-XACML-URL}}"
+					],
+					"path": [
+						"policy",
+						"pdpx",
+						"v1",
+						"healthcheck"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Xacml Statistics",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "GET",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"url": {
+					"raw": "{{POLICY-XACML-URL}}/policy/pdpx/v1/statistics",
+					"host": [
+						"{{POLICY-XACML-URL}}"
+					],
+					"path": [
+						"policy",
+						"pdpx",
+						"v1",
+						"statistics"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Xacml Decision - Authorization policy-type",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "POST",
+				"header": [
+					{
+						"key": "Content-Type",
+						"type": "text",
+						"value": "application/json"
+					},
+					{
+						"key": "Accept",
+						"type": "text",
+						"value": "application/json"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": "{\n  \"ONAPName\": \"TutorialPEP\",\n  \"ONAPComponent\": \"TutorialPEPComponent\",\n  \"ONAPInstance\": \"TutorialPEPInstance\",\n  \"requestId\": \"unique-request-id-tutorial\",\n  \"action\": \"authorize\",\n  \"resource\": {\n    \"user\": \"audit\",\n    \"entity\": \"foo\",\n    \"permission\" : \"read\"\n  }\n}"
+				},
+				"url": {
+					"raw": "{{POLICY-XACML-URL}}/policy/pdpx/v1/decision",
+					"host": [
+						"{{POLICY-XACML-URL}}"
+					],
+					"path": [
+						"policy",
+						"pdpx",
+						"v1",
+						"decision"
+					]
+				}
+			},
+			"response": [
+			]
+		},
+		{
+			"name": "Simple Undeploy Policy",
+			"request": {
+				"auth": {
+					"type": "basic",
+					"basic": [
+						{
+							"key": "password",
+							"value": "zb!XztG34",
+							"type": "string"
+						},
+						{
+							"key": "username",
+							"value": "healthcheck",
+							"type": "string"
+						}
+					]
+				},
+				"method": "DELETE",
+				"header": [
+					{
+						"key": "Accept",
+						"value": "application/json",
+						"type": "text"
+					},
+					{
+						"key": "Content-Type",
+						"value": "application/json",
+						"type": "text"
+					}
+				],
+				"url": {
+					"raw": "{{POLICY-PAP-URL}}/policy/pap/v1/pdps/policies/onap.policy.tutorial.demo",
+					"host": [
+						"{{POLICY-PAP-URL}}"
+					],
+					"path": [
+						"policy",
+						"pap",
+						"v1",
+						"pdps",
+						"policies",
+						"onap.policy.tutorial.demo"
+					]
+				}
+			},
+			"response": [
+			]
+		}
+	],
+	"auth": {
+		"type": "basic",
+		"basic": [
+			{
+				"key": "password",
+				"value": "",
+				"type": "string"
+			},
+			{
+				"key": "username",
+				"value": "",
+				"type": "string"
+			}
+		]
+	},
+	"protocolProfileBehavior": {
+	}
+}
diff --git a/tutorials/tutorial-xacml-application/src/main/docker/Dockerfile b/tutorials/tutorial-xacml-application/src/main/docker/Dockerfile
new file mode 100644
index 0000000..2610651
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/docker/Dockerfile
@@ -0,0 +1,7 @@
+FROM onap/policy-xacml-pdp
+
+ADD maven/${project.build.finalName}.jar /opt/app/policy/pdpx/lib/${project.build.finalName}.jar
+
+RUN mkdir -p /opt/app/policy/pdpx/apps/tutorial
+
+COPY --chown=policy:policy xacml.properties /opt/app/policy/pdpx/apps/tutorial
\ No newline at end of file
diff --git a/tutorials/tutorial-xacml-application/src/main/docker/README.txt b/tutorials/tutorial-xacml-application/src/main/docker/README.txt
new file mode 100644
index 0000000..a29a44b
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/docker/README.txt
@@ -0,0 +1,36 @@
+docker-compose -f docker-compose.yml run --rm start_dependencies
+
+docker-compose -f docker-compose.yml run --rm start_all
+
+
+curl -X POST http://0.0.0.0:3904/events/POLICY-PDP-PAP
+
+Should return JSON similar to this:
+{"serverTimeMs":0,"count":0}
+
+
+curl -k -u 'healthcheck:zb!XztG34' 'https://0.0.0.0:6969/policy/pdpx/v1/healthcheck'
+
+Should return JSON similar to this:
+{"name":"Policy Xacml PDP","url":"self","healthy":true,"code":200,"message":"alive"}
+
+
+curl -k -u 'healthcheck:zb!XztG34' 'https://0.0.0.0:6767/policy/api/v1/healthcheck'
+Should return JSON similar to this:
+{
+    "name": "Policy API",
+    "url": "policy-api",
+    "healthy": true,
+    "code": 200,
+    "message": "alive"
+}
+
+curl -k -u 'healthcheck:zb!XztG34' 'https://0.0.0.0:6868/policy/pap/v1/healthcheck'
+Should return JSON similar to this:
+{
+    "name": "Policy PAP",
+    "url": "policy-pap",
+    "healthy": true,
+    "code": 200,
+    "message": "alive"
+}
\ No newline at end of file
diff --git a/tutorials/tutorial-xacml-application/src/main/docker/config/db/db.conf b/tutorials/tutorial-xacml-application/src/main/docker/config/db/db.conf
new file mode 100644
index 0000000..42f3584
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/docker/config/db/db.conf
@@ -0,0 +1,20 @@
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2020 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+MYSQL_ROOT_PASSWORD=secret
+MYSQL_USER=policy_user
+MYSQL_PASSWORD=policy_user
\ No newline at end of file
diff --git a/tutorials/tutorial-xacml-application/src/main/docker/config/db/db.sh b/tutorials/tutorial-xacml-application/src/main/docker/config/db/db.sh
new file mode 100644
index 0000000..499764d
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/docker/config/db/db.sh
@@ -0,0 +1,26 @@
+#!/bin/bash -xv
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2020 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+
+for db in policyadmin operationshistory
+do
+     mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" --execute "CREATE DATABASE IF NOT EXISTS ${db};"
+     mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" --execute "GRANT ALL PRIVILEGES ON \`${db}\`.* TO '${MYSQL_USER}'@'%' ;"
+done
+
+mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" --execute "FLUSH PRIVILEGES;"
diff --git a/tutorials/tutorial-xacml-application/src/main/docker/config/sim/simParameters.json b/tutorials/tutorial-xacml-application/src/main/docker/config/sim/simParameters.json
new file mode 100644
index 0000000..bd43520
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/docker/config/sim/simParameters.json
@@ -0,0 +1,15 @@
+{
+    "dmaapProvider": {
+        "name": "DMaaP simulator",
+        "topicSweepSec": 300
+    },
+    "restServers": [
+        {
+            "name": "DMaaP simulator",
+            "providerClass": "org.onap.policy.models.sim.dmaap.rest.DmaapSimRestControllerV1",
+            "host": "0.0.0.0",
+            "port": 3904,
+            "https": false
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tutorials/tutorial-xacml-application/src/main/docker/docker-compose.yml b/tutorials/tutorial-xacml-application/src/main/docker/docker-compose.yml
new file mode 100644
index 0000000..2809f64
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/docker/docker-compose.yml
@@ -0,0 +1,106 @@
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2020 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+version: '2'
+services:
+   mariadb:
+      image: mariadb:10.2.14
+      container_name: mariadb
+      hostname: mariadb
+      command: ['--lower-case-table-names=1', '--wait_timeout=28800']
+      env_file: config/db/db.conf
+      volumes:
+         - ./config/db:/docker-entrypoint-initdb.d
+      expose:
+       - 3306
+   message-router:
+      image: nexus3.onap.org:10001/onap/policy-models-simulator:latest
+      container_name: dmaap-simulator
+      hostname: dmaap-simulator
+      volumes:
+       - ./config/sim:/opt/app/policy/simulators/etc/mounted:ro
+      ports:
+       - "3904:3904"
+      expose:
+       - 3904
+   api:
+      # Guilin released images
+      image: nexus3.onap.org:10001/onap/policy-api:2.3.3
+      container_name: policy-api
+      depends_on:
+       - mariadb
+      hostname: policy-api
+      ports:
+       - "6767:6969"
+      expose:
+       - 6767
+   pap:
+      # Guilin released images
+      image: nexus3.onap.org:10001/onap/policy-pap:2.3.3
+      container_name: policy-pap
+      depends_on:
+       - mariadb
+       - message-router
+       - api
+      hostname: policy-pap
+      ports:
+       - "6868:6969"
+      expose:
+       - 6868
+   xacml-pdp:
+      image: onap/policy-xacml-tutorial
+      container_name: policy-xacml-pdp
+      depends_on:
+       - mariadb
+       - message-router
+       - api
+       - pap
+      hostname: policy-xacml-pdp
+      ports:
+       - "6969:6969"
+      expose:
+       - 6969
+   start_dependencies:
+      image: dadarek/wait-for-dependencies
+      environment:
+        TIMEOUT_LENGTH: 60
+      container_name: policy-wait
+      depends_on:
+        - mariadb
+        - message-router
+      hostname: policy-wait
+      command:
+        mariadb:3306
+        message-router:3904
+   start_all:
+      image: dadarek/wait-for-dependencies
+      environment:
+        TIMEOUT_LENGTH: 60
+      container_name: policy-wait-all
+      depends_on:
+        - mariadb
+        - message-router
+        - api
+        - pap
+        - xacml-pdp
+      hostname: policy-wait-all
+      command:
+        mariadb:3306
+        message-router:3904
+        api:6969
+        pap:6969
+        xacml-pdp:6969
diff --git a/tutorials/tutorial-xacml-application/src/main/docker/xacml.properties b/tutorials/tutorial-xacml-application/src/main/docker/xacml.properties
new file mode 100644
index 0000000..277b098
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/docker/xacml.properties
@@ -0,0 +1,31 @@
+#
+# Properties that the embedded PDP engine uses to configure and load
+#
+# 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
+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
+#
+# ONAP PDP Implementation Factories
+#
+xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory
+
+#
+# Use a root combining algorithm
+#
+xacml.att.policyFinderFactory.combineRootPolicies=urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-overrides
+
+#
+# Policies to load
+#
+xacml.rootPolicies=
+xacml.referencedPolicies=
\ No newline at end of file
diff --git a/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialApplication.java b/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialApplication.java
new file mode 100644
index 0000000..3c76494
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialApplication.java
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 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.onap.policy.tutorial.tutorial;
+
+import java.util.Arrays;
+import java.util.List;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
+import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider;
+
+public class TutorialApplication extends StdXacmlApplicationServiceProvider {
+
+    private final ToscaPolicyTypeIdentifier supportedPolicyType =
+            new ToscaPolicyTypeIdentifier("onap.policies.Authorization", "1.0.0");
+    private final TutorialTranslator translator = new TutorialTranslator();
+
+    @Override
+    public String applicationName() {
+        return "tutorial";
+    }
+
+    @Override
+    public List<String> actionDecisionsSupported() {
+        return Arrays.asList("authorize");
+    }
+
+    @Override
+    public synchronized List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
+        return Arrays.asList(supportedPolicyType);
+    }
+
+    @Override
+    public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
+        return supportedPolicyType.equals(policyTypeId);
+    }
+
+    @Override
+    protected ToscaPolicyTranslator getTranslator(String type) {
+        return translator;
+    }
+
+}
diff --git a/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialRequest.java b/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialRequest.java
new file mode 100644
index 0000000..4bb94cd
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialRequest.java
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 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.onap.policy.tutorial.tutorial;
+
+import com.att.research.xacml.std.annotations.XACMLAction;
+import com.att.research.xacml.std.annotations.XACMLRequest;
+import com.att.research.xacml.std.annotations.XACMLResource;
+import com.att.research.xacml.std.annotations.XACMLSubject;
+import java.util.Map;
+import java.util.Map.Entry;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import org.onap.policy.models.decisions.concepts.DecisionRequest;
+
+@Getter
+@Setter
+@ToString
+@XACMLRequest(ReturnPolicyIdList = true)
+public class TutorialRequest {
+    @XACMLSubject(includeInResults = true)
+    private String onapName;
+
+    @XACMLSubject(attributeId = "urn:org:onap:onap-component", includeInResults = true)
+    private String onapComponent;
+
+    @XACMLSubject(attributeId = "urn:org:onap:onap-instance", includeInResults = true)
+    private String onapInstance;
+
+    @XACMLAction()
+    private String action;
+
+    @XACMLResource(attributeId = "urn:org:onap:tutorial-user", includeInResults = true)
+    private String user;
+
+    @XACMLResource(attributeId = "urn:org:onap:tutorial-entity", includeInResults = true)
+    private String entity;
+
+    @XACMLResource(attributeId = "urn:org:onap:tutorial-permission", includeInResults = true)
+    private String permission;
+
+    /**
+     * createRequest.
+     *
+     * @param decisionRequest Incoming
+     * @return TutorialRequest object
+     */
+    public static TutorialRequest createRequest(DecisionRequest decisionRequest) {
+        //
+        // Create our object
+        //
+        TutorialRequest request = new TutorialRequest();
+        //
+        // Add the subject attributes
+        //
+        request.onapName = decisionRequest.getOnapName();
+        request.onapComponent = decisionRequest.getOnapComponent();
+        request.onapInstance = decisionRequest.getOnapInstance();
+        //
+        // Add the action attribute
+        //
+        request.action = decisionRequest.getAction();
+        //
+        // Add the resource attributes
+        //
+        Map<String, Object> resources = decisionRequest.getResource();
+        for (Entry<String, Object> entrySet : resources.entrySet()) {
+            if ("user".equals(entrySet.getKey())) {
+                request.user = entrySet.getValue().toString();
+            }
+            if ("entity".equals(entrySet.getKey())) {
+                request.entity = entrySet.getValue().toString();
+            }
+            if ("permission".equals(entrySet.getKey())) {
+                request.permission = entrySet.getValue().toString();
+            }
+        }
+
+        return request;
+    }
+}
diff --git a/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialTranslator.java b/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialTranslator.java
new file mode 100644
index 0000000..7a6b5d8
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/java/org/onap/policy/tutorial/tutorial/TutorialTranslator.java
@@ -0,0 +1,168 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 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.onap.policy.tutorial.tutorial;
+
+import com.att.research.xacml.api.DataTypeException;
+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.Response;
+import com.att.research.xacml.api.Result;
+import com.att.research.xacml.api.XACML3;
+import com.att.research.xacml.std.IdentifierImpl;
+import com.att.research.xacml.std.annotations.RequestParser;
+import java.util.List;
+import java.util.Map;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
+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 org.onap.policy.models.decisions.concepts.DecisionRequest;
+import org.onap.policy.models.decisions.concepts.DecisionResponse;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
+import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
+import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
+import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
+
+public class TutorialTranslator implements ToscaPolicyTranslator {
+
+    private static final Identifier ID_TUTORIAL_USER = new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-user");
+    private static final Identifier ID_TUTORIAL_ENTITY =
+            new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-entity");
+    private static final Identifier ID_TUTORIAL_PERM =
+            new IdentifierImpl(ToscaDictionary.ID_URN_ONAP, "tutorial-permission");
+
+    /**
+     * Convert Policy from TOSCA to XACML.
+     */
+    @SuppressWarnings("unchecked")
+    public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
+        //
+        // Here is our policy with a version and default combining algo
+        //
+        PolicyType newPolicyType = new PolicyType();
+        newPolicyType.setPolicyId(toscaPolicy.getMetadata().get("policy-id"));
+        newPolicyType.setVersion(toscaPolicy.getMetadata().get("policy-version"));
+        //
+        // When choosing the rule combining algorithm, be sure to be mindful of the
+        // setting xacml.att.policyFinderFactory.combineRootPolicies in the
+        // xacml.properties file. As that choice for ALL the policies together may have
+        // an impact on the decision rendered from each individual policy.
+        //
+        // In this case, we will only produce XACML rules for permissions. If no permission
+        // combo exists, then the default is to deny.
+        //
+        newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue());
+        //
+        // Create the target for the Policy.
+        //
+        // For simplicity, let's just match on the action "authorize" and the user
+        //
+        MatchType matchAction = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+                XACML3.ID_FUNCTION_STRING_EQUAL, "authorize", XACML3.ID_DATATYPE_STRING,
+                XACML3.ID_ACTION_ACTION_ID, XACML3.ID_ATTRIBUTE_CATEGORY_ACTION);
+        Map<String, Object> props = toscaPolicy.getProperties();
+        String user = props.get("user").toString();
+        MatchType matchUser = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL, user,
+                XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_USER, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
+        AnyOfType anyOf = new AnyOfType();
+        //
+        // Create AllOf (AND) of just Policy Id
+        //
+        anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchAction, matchUser));
+        TargetType target = new TargetType();
+        target.getAnyOf().add(anyOf);
+        newPolicyType.setTarget(target);
+        //
+        // Now add the rule for each permission
+        //
+        int ruleNumber = 0;
+        List<Object> permissions = (List<Object>) props.get("permissions");
+        for (Object permission : permissions) {
+
+            MatchType matchEntity = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(XACML3.ID_FUNCTION_STRING_EQUAL,
+                    ((Map<String, String>) permission).get("entity"), XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_ENTITY,
+                    XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
+
+            MatchType matchPermission = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+                    XACML3.ID_FUNCTION_STRING_EQUAL, ((Map<String, String>) permission).get("permission"),
+                    XACML3.ID_DATATYPE_STRING, ID_TUTORIAL_PERM, XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
+            anyOf = new AnyOfType();
+            anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(matchEntity, matchPermission));
+            target = new TargetType();
+            target.getAnyOf().add(anyOf);
+
+            RuleType rule = new RuleType();
+            rule.setDescription("Default is to PERMIT if the policy matches.");
+            rule.setRuleId(newPolicyType.getPolicyId() + ":rule" + ruleNumber);
+
+            rule.setEffect(EffectType.PERMIT);
+            rule.setTarget(target);
+
+            newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
+
+            ruleNumber++;
+        }
+        return newPolicyType;
+    }
+
+    /**
+     * Convert ONAP DecisionRequest to XACML Request.
+     */
+    public Request convertRequest(DecisionRequest request) {
+        try {
+            return RequestParser.parseRequest(TutorialRequest.createRequest(request));
+        } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
+            // Empty
+        }
+        return null;
+    }
+
+    /**
+     * Convert XACML Response to ONAP DecisionResponse.
+     */
+    public DecisionResponse convertResponse(Response xacmlResponse) {
+        DecisionResponse decisionResponse = new DecisionResponse();
+        //
+        // Iterate through all the results
+        //
+        for (Result xacmlResult : xacmlResponse.getResults()) {
+            //
+            // Check the result
+            //
+            if (xacmlResult.getDecision() == Decision.PERMIT) {
+                //
+                // Just simply return a Permit response
+                //
+                decisionResponse.setStatus(Decision.PERMIT.toString());
+            } else {
+                //
+                // Just simply return a Deny response
+                //
+                decisionResponse.setStatus(Decision.DENY.toString());
+            }
+        }
+
+        return decisionResponse;
+    }
+
+}
diff --git a/tutorials/tutorial-xacml-application/src/main/resources/META-INF/services/org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider b/tutorials/tutorial-xacml-application/src/main/resources/META-INF/services/org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider
new file mode 100644
index 0000000..942cc59
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/resources/META-INF/services/org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider
@@ -0,0 +1 @@
+org.onap.policy.tutorial.tutorial.TutorialApplication
\ No newline at end of file
diff --git a/tutorials/tutorial-xacml-application/src/main/resources/xacml.properties b/tutorials/tutorial-xacml-application/src/main/resources/xacml.properties
new file mode 100644
index 0000000..277b098
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/main/resources/xacml.properties
@@ -0,0 +1,31 @@
+#
+# Properties that the embedded PDP engine uses to configure and load
+#
+# 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
+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
+#
+# ONAP PDP Implementation Factories
+#
+xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory
+
+#
+# Use a root combining algorithm
+#
+xacml.att.policyFinderFactory.combineRootPolicies=urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-overrides
+
+#
+# Policies to load
+#
+xacml.rootPolicies=
+xacml.referencedPolicies=
\ No newline at end of file
diff --git a/tutorials/tutorial-xacml-application/src/test/java/org/onap/policy/tutorial/tutorial/TutorialApplicationTest.java b/tutorials/tutorial-xacml-application/src/test/java/org/onap/policy/tutorial/tutorial/TutorialApplicationTest.java
new file mode 100644
index 0000000..28d25ee
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/test/java/org/onap/policy/tutorial/tutorial/TutorialApplicationTest.java
@@ -0,0 +1,120 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 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.onap.policy.tutorial.tutorial;
+
+import static org.junit.Assert.assertEquals;
+
+import com.att.research.xacml.api.Response;
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.onap.policy.common.endpoints.parameters.RestServerParameters;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.resources.TextFileUtils;
+import org.onap.policy.models.decisions.concepts.DecisionRequest;
+import org.onap.policy.models.decisions.concepts.DecisionResponse;
+import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
+import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider;
+import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
+import org.onap.policy.pdp.xacml.xacmltest.TestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TutorialApplicationTest {
+    private static final Logger LOGGER = LoggerFactory.getLogger(TutorialApplicationTest.class);
+    private static Properties properties = new Properties();
+    private static File propertiesFile;
+    private static XacmlApplicationServiceProvider service;
+    private static StandardCoder gson = new StandardCoder();
+
+    @ClassRule
+    public static final TemporaryFolder policyFolder = new TemporaryFolder();
+
+    /**
+     * setup the tests.
+     *
+     * @throws Exception Should not have exceptions thrown.
+     */
+    @BeforeClass
+    public static void setup() throws Exception {
+        //
+        // Setup our temporary folder
+        //
+        XacmlPolicyUtils.FileCreator myCreator = (String filename) -> policyFolder.newFile(filename);
+        propertiesFile = XacmlPolicyUtils.copyXacmlPropertiesContents("src/test/resources/xacml.properties",
+                properties, myCreator);
+        //
+        // Load XacmlApplicationServiceProvider service
+        //
+        ServiceLoader<XacmlApplicationServiceProvider> applicationLoader =
+                ServiceLoader.load(XacmlApplicationServiceProvider.class);
+        //
+        // Look for our class instance and save it
+        //
+        for (XacmlApplicationServiceProvider application : applicationLoader) {
+            //
+            // Is it our service?
+            //
+            if (application instanceof TutorialApplication) {
+                service = application;
+            }
+        }
+        //
+        // Tell the application to initialize based on the properties file
+        // we just built for it.
+        //
+        service.initialize(propertiesFile.toPath().getParent(), new RestServerParameters());
+    }
+
+    @Test
+    public void test() throws CoderException, XacmlApplicationException, IOException {
+        //
+        // Now load the tutorial policies.
+        //
+        TestUtils.loadPolicies("src/test/resources/tutorial-policies.yaml", service);
+        //
+        // Load a Decision request
+        //
+        DecisionRequest decisionRequest = gson.decode(
+                TextFileUtils
+                .getTextFileAsString("src/test/resources/tutorial-decision-request.json"),
+                DecisionRequest.class);
+        //
+        // Test a decision - should start with a permit
+        //
+        Pair<DecisionResponse, Response> decision = service.makeDecision(decisionRequest, null);
+        LOGGER.info(decision.getLeft().toString());
+        assertEquals("Permit", decision.getLeft().getStatus());
+        //
+        // This should be a deny
+        //
+        decisionRequest.getResource().put("user", "audit");
+        decision = service.makeDecision(decisionRequest, null);
+        LOGGER.info(decision.getLeft().toString());
+        assertEquals("Deny", decision.getLeft().getStatus());
+    }
+
+}
diff --git a/tutorials/tutorial-xacml-application/src/test/resources/tutorial-decision-request.json b/tutorials/tutorial-xacml-application/src/test/resources/tutorial-decision-request.json
new file mode 100644
index 0000000..f3a7f9a
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/test/resources/tutorial-decision-request.json
@@ -0,0 +1,12 @@
+{
+  "ONAPName": "TutorialPEP",
+  "ONAPComponent": "TutorialPEPComponent",
+  "ONAPInstance": "TutorialPEPInstance",
+  "requestId": "unique-request-id-tutorial",
+  "action": "authorize",
+  "resource": {
+    "user": "demo",
+    "entity": "foo",
+    "permission" : "write"
+  }
+}
diff --git a/tutorials/tutorial-xacml-application/src/test/resources/tutorial-policies.yaml b/tutorials/tutorial-xacml-application/src/test/resources/tutorial-policies.yaml
new file mode 100644
index 0000000..fa35365
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/test/resources/tutorial-policies.yaml
@@ -0,0 +1,34 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+topology_template:
+    policies:
+        -
+            onap.policy.tutorial.demo:
+                type: onap.policies.Authorization
+                type_version: 1.0.0
+                version: 1.0.0
+                metadata:
+                    policy-id: onap.policy.tutorial.demo
+                    policy-version: 1
+                properties:
+                    user: demo
+                    permissions:
+                        -
+                            entity: foo
+                            permission: read
+                        -
+                            entity: foo
+                            permission: write
+        -
+            onap.policy.tutorial.audit:
+                type: onap.policies.Authorization
+                version: 1.0.0
+                type_version: 1.0.0
+                metadata:
+                    policy-id: onap.policy.tutorial.bar
+                    policy-version: 1
+                properties:
+                    user: audit
+                    permissions:
+                        -
+                            entity: foo
+                            permission: read
diff --git a/tutorials/tutorial-xacml-application/src/test/resources/tutorial-policy-type.yaml b/tutorials/tutorial-xacml-application/src/test/resources/tutorial-policy-type.yaml
new file mode 100644
index 0000000..7948bd2
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/test/resources/tutorial-policy-type.yaml
@@ -0,0 +1,32 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+    onap.policies.Authorization:
+        derived_from: tosca.policies.Root
+        version: 1.0.0
+        description: Example tutorial policy type for doing user authorization
+        properties:
+            user:
+                type: string
+                required: true
+                description: The unique user name
+            permissions:
+                type: list
+                required: true
+                description: A list of resource permissions
+                entry_schema:
+                    type: onap.datatypes.Tutorial
+data_types:
+    onap.datatypes.Tutorial:
+        derived_from: tosca.datatypes.Root
+        version: 1.0.0
+        properties:
+            entity:
+                type: string
+                required: true
+                description: The resource
+            permission:
+                type: string
+                required: true
+                description: The permission level
+                constraints:
+                    - valid_values: [read, write, delete]
diff --git a/tutorials/tutorial-xacml-application/src/test/resources/xacml.properties b/tutorials/tutorial-xacml-application/src/test/resources/xacml.properties
new file mode 100644
index 0000000..277b098
--- /dev/null
+++ b/tutorials/tutorial-xacml-application/src/test/resources/xacml.properties
@@ -0,0 +1,31 @@
+#
+# Properties that the embedded PDP engine uses to configure and load
+#
+# 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
+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
+#
+# ONAP PDP Implementation Factories
+#
+xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory
+
+#
+# Use a root combining algorithm
+#
+xacml.att.policyFinderFactory.combineRootPolicies=urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-overrides
+
+#
+# Policies to load
+#
+xacml.rootPolicies=
+xacml.referencedPolicies=
\ No newline at end of file