DISPATCH-311: Reorganize policy schema
Rename items in entity 'policy'.
Rename entity 'policyRuleset' to 'vhost'.
diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json
index e36896b..37f7a3c 100644
--- a/python/qpid_dispatch/management/qdrouter.json
+++ b/python/qpid_dispatch/management/qdrouter.json
@@ -1346,38 +1346,31 @@
             "extends": "configurationEntity",
             "singleton": true,
             "attributes": {
-                "maximumConnections": {
+                "maxConnections": {
                     "type": "integer",
                     "default": 0,
-                    "description": "Global maximum number of concurrent client connections allowed. Zero implies no limit. This limit is always enforced even if no other policy settings have been defined.",
+                    "description": "Global maximum number of concurrent client connections allowed. This limit is always enforced even if no other policy settings have been defined.",
                     "required": false,
                     "create": true
                 },
-                "enableAccessRules": {
+                "enableVhostPolicy": {
                     "type": "boolean",
                     "default": false,
-                    "description": "Enable user rule set processing and connection denial.",
+                    "description": "Enable vhost policy connection denial, and resource limit enforcement",
                     "required": false,
                     "create": true
                 },
-                "policyFolder": {
+                "policyDir": {
                     "type": "path",
                     "default": "",
-                    "description": "The absolute path to a folder that holds policyRuleset definition .json files. For a small system the rulesets may all be defined in this file. At a larger scale it is better to have the policy files in their own folder and to have none of the rulesets defined here. All rulesets in all .json files in this folder are processed.",
+                    "description": "Absolute path to a directory that holds vhost definition .json files. All vhost definitions in all .json files in this directory are processed.",
                     "required": false,
                     "create": true
                 },
-                "defaultApplication": {
+                "defaultVhost": {
                     "type": "string",
-                    "default": "",
-                    "description": "Application policyRuleset to use for connections with no open.hostname or a hostname that does not match any existing policy. For users that don't wish to use open.hostname or any multi-tennancy feature, this default policy can be the only policy in effect for the network.",
-                    "required": false,
-                    "create": true
-                },
-                "defaultApplicationEnabled": {
-                    "type": "boolean",
-                    "default": false,
-                    "description": "Enable defaultApplication policy fallback logic.",
+                    "default": "$default",
+                    "description": "Vhost rule set name to use for connections with a vhost that is otherwise not defined. Default vhost processing may be disabled either by erasing the definition of defaultVhost or by not defining a vhost object named '$default'.",
                     "required": false,
                     "create": true
                 },
@@ -1387,7 +1380,7 @@
             }
         },
 
-        "policyRuleset": {
+        "vhost": {
             "description": "Per application definition of the locations from which users may connect and the groups to which users belong.",
             "extends": "configurationEntity",
             "operations": ["CREATE"],
diff --git a/python/qpid_dispatch/management/qdrouter.policyRuleset.settings.txt b/python/qpid_dispatch/management/qdrouter.policyRuleset.settings.txt
index 773df7a..653a378 100644
--- a/python/qpid_dispatch/management/qdrouter.policyRuleset.settings.txt
+++ b/python/qpid_dispatch/management/qdrouter.policyRuleset.settings.txt
@@ -21,9 +21,9 @@
 entity types of the Qpid Dispatch Router management model.  The model is based
 on the AMQP management specification.
 
-Schema entity `policyRuleset` includes several attributes of type map. In the current form the management schema provides no way to define the keys and values in these attributes. These maps cannot be specified in the schema and they cannot be checked by the schema processing. 
+Schema entity `vhost` includes several attributes of type map. In the current form the management schema provides no way to define the keys and values in these attributes. These maps cannot be specified in the schema and they cannot be checked by the schema processing. 
 
-Until the schema is extended specify embedded maps this document describes the policyRuleset settings.
+Until the schema is extended specify embedded maps this document describes the vhost settings.
 
   "policyAppSettings": {
       "description": "For a given user group define the policy settings applied to the user's AMQP connection.",
diff --git a/python/qpid_dispatch_internal/management/agent.py b/python/qpid_dispatch_internal/management/agent.py
index 8fd4e84..01f52cb 100644
--- a/python/qpid_dispatch_internal/management/agent.py
+++ b/python/qpid_dispatch_internal/management/agent.py
@@ -312,7 +312,7 @@
         return self.attributes.get('module')
 
 
-class PolicyRulesetEntity(EntityAdapter):
+class VhostEntity(EntityAdapter):
     def create(self):
         self._policy.create_ruleset(self.attributes)
 
diff --git a/python/qpid_dispatch_internal/management/config.py b/python/qpid_dispatch_internal/management/config.py
index 881def8..28ba91b 100644
--- a/python/qpid_dispatch_internal/management/config.py
+++ b/python/qpid_dispatch_internal/management/config.py
@@ -182,13 +182,12 @@
 
     from qpid_dispatch_internal.display_name.display_name import DisplayNameService
     displayname_service = DisplayNameService("$displayname")
-    policyFolder = config.by_type('policy')[0]['policyFolder']
-    policyDefaultApplication = config.by_type('policy')[0]['defaultApplication']
-    policyDefaultApplicationEnabled = config.by_type('policy')[0]['defaultApplicationEnabled']
+    policyDir = config.by_type('policy')[0]['policyDir']
+    policyDefaultVhost = config.by_type('policy')[0]['defaultVhost']
     # Remaining configuration
     for t in "fixedAddress", "listener", "connector", "waypoint", "linkRoutePattern", \
              "router.config.address", "router.config.linkRoute", "router.config.autoLink", \
-             "policy", "policyRuleset":
+             "policy", "vhost":
         for a in config.by_type(t):
             configure(a)
             if t == "listener":
@@ -200,15 +199,15 @@
     for e in config.entities:
         configure(e)
 
-    # Load the policyRulesets from the .json files in policyFolder
-    # Only policyRulesets are loaded. Other entities are silently discarded.
-    if not policyFolder == '':
-        apath = os.path.abspath(policyFolder)
-        for i in os.listdir(policyFolder):
+    # Load the vhosts from the .json files in policyDir
+    # Only vhosts are loaded. Other entities are silently discarded.
+    if not policyDir == '':
+        apath = os.path.abspath(policyDir)
+        for i in os.listdir(policyDir):
             if i.endswith(".json"):
                 pconfig = PolicyConfig(os.path.join(apath, i))
-                for a in pconfig.by_type("policyRuleset"):
+                for a in pconfig.by_type("vhost"):
                     agent.configure(a)
 
     # Set policy default application after all rulesets loaded
-    agent.policy.set_default_application(policyDefaultApplication, policyDefaultApplicationEnabled)
+    agent.policy.set_default_vhost(policyDefaultVhost)
diff --git a/python/qpid_dispatch_internal/policy/policy_local.py b/python/qpid_dispatch_internal/policy/policy_local.py
index cb62896..52339ca 100644
--- a/python/qpid_dispatch_internal/policy/policy_local.py
+++ b/python/qpid_dispatch_internal/policy/policy_local.py
@@ -487,14 +487,10 @@
         # Entries destroyed as sockets closed
         self._connections = {}
 
-        # _default_application is a string
-        #  holds the name of the policyRuleset to use when the
+        # _default_vhost is a string
+        #  holds the name of the vhost to use when the
         #  open.hostname is not found in the rulesetdb
-        self._default_application = ""
-
-        # _default_application_enabled is a boolean
-        #  controls default application fallback logic
-        self._default_application_enabled = False
+        self._default_vhost = ""
 
     #
     # Service interfaces
@@ -559,22 +555,24 @@
         """
         return self.rulesetdb.keys()
 
-    def set_default_application(self, name, enabled):
+    def set_default_vhost(self, name):
         """
-        Set the default application name and control its enablement.
-        Raise PolicyError if the named application is enabled but absent.
+        Set the default vhost name.
         @param name: the name of the default application
-        @param enabled: default application ruleset logic is active
         @return: none
         """
-        self._default_application = name
-        self._default_application_enabled = enabled
-        if enabled:
-            if not name in self.policy_db_get_names():
-                raise PolicyError("Policy fallback defaultApplication '%s' does not exist" % name)
-            self._manager.log_info("Policy fallback defaultApplication is enabled: '%s'" % name)
-        else:
-            self._manager.log_info("Policy fallback defaultApplication is disabled")
+        self._default_vhost = name
+        self._manager.log_info("Policy fallback defaultVhost is enabled: '%s'" % name)
+
+
+    def default_vhost_enabled(self):
+        """
+        The default vhost is enabled if the name is not blank and
+        the vhost is defined in rulesetdb.
+        @return:
+        """
+        return not self._default_vhost == "" and self._default_vhost in self.rulesetdb
+
 
     #
     # Runtime query interface
@@ -596,8 +594,8 @@
         try:
             app = app_in
             if not app_in in self.rulesetdb:
-                if self._default_application_enabled:
-                    app = self._default_application
+                if self.default_vhost_enabled():
+                    app = self._default_vhost
                 else:
                     self._manager.log_info(
                         "DENY AMQP Open for user '%s', host '%s', application '%s': "
@@ -684,8 +682,9 @@
         """
         try:
             appname = appname_in
-            if not appname in self.rulesetdb and self._default_application_enabled:
-                appname = self._default_application
+            if not appname in self.rulesetdb:
+                if self.default_vhost_enabled():
+                    appname = self._default_vhost
 
             if not appname in self.rulesetdb:
                 self._manager.log_info(
diff --git a/python/qpid_dispatch_internal/policy/policy_manager.py b/python/qpid_dispatch_internal/policy/policy_manager.py
index 7cb72fb..cb0247b 100644
--- a/python/qpid_dispatch_internal/policy/policy_manager.py
+++ b/python/qpid_dispatch_internal/policy/policy_manager.py
@@ -80,14 +80,13 @@
     #
     # Management interface to set the default application
     #
-    def set_default_application(self, name, enabled):
+    def set_default_vhost(self, name):
         """
         Set default application
         @param name:
-        @param enabled
         @return:
         """
-        self._policy_local.set_default_application(name, enabled)
+        self._policy_local.set_default_vhost(name)
 
     #
     # Runtime query interface
diff --git a/src/policy.c b/src/policy.c
index 48723d0..aa67964 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -65,8 +65,8 @@
     void                 *py_policy_manager;
                           // configured settings
     int                   max_connection_limit;
-    char                 *policyFolder;
-    bool                  enableAccessRules;
+    char                 *policyDir;
+    bool                  enableVhostPolicy;
                           // live statistics
     int                   connections_processed;
     int                   connections_denied;
@@ -83,8 +83,8 @@
     policy->qd                   = qd;
     policy->log_source           = qd_log_source("POLICY");
     policy->max_connection_limit = 0;
-    policy->policyFolder         = 0;
-    policy->enableAccessRules    = false;
+    policy->policyDir         = 0;
+    policy->enableVhostPolicy    = false;
     policy->connections_processed= 0;
     policy->connections_denied   = 0;
     policy->connections_current  = 0;
@@ -99,8 +99,8 @@
  **/
 void qd_policy_free(qd_policy_t *policy)
 {
-    if (policy->policyFolder)
-        free(policy->policyFolder);
+    if (policy->policyDir)
+        free(policy->policyDir);
     free(policy);
 }
 
@@ -110,19 +110,19 @@
 
 qd_error_t qd_entity_configure_policy(qd_policy_t *policy, qd_entity_t *entity)
 {
-    policy->max_connection_limit = qd_entity_opt_long(entity, "maximumConnections", 0); CHECK();
+    policy->max_connection_limit = qd_entity_opt_long(entity, "maxConnections", 0); CHECK();
     if (policy->max_connection_limit < 0)
-        return qd_error(QD_ERROR_CONFIG, "maximumConnections must be >= 0");
-    policy->policyFolder =
-        qd_entity_opt_string(entity, "policyFolder", 0); CHECK();
-    policy->enableAccessRules = qd_entity_opt_bool(entity, "enableAccessRules", false); CHECK();
-    qd_log(policy->log_source, QD_LOG_INFO, "Policy configured maximumConnections: %d, policyFolder: '%s', access rules enabled: '%s'",
-           policy->max_connection_limit, policy->policyFolder, (policy->enableAccessRules ? "true" : "false"));
+        return qd_error(QD_ERROR_CONFIG, "maxConnections must be >= 0");
+    policy->policyDir =
+        qd_entity_opt_string(entity, "policyDir", 0); CHECK();
+    policy->enableVhostPolicy = qd_entity_opt_bool(entity, "enableVhostPolicy", false); CHECK();
+    qd_log(policy->log_source, QD_LOG_INFO, "Policy configured maxConnections: %d, policyDir: '%s', access rules enabled: '%s'",
+           policy->max_connection_limit, policy->policyDir, (policy->enableVhostPolicy ? "true" : "false"));
     return QD_ERROR_NONE;
 
 error:
-    if (policy->policyFolder)
-        free(policy->policyFolder);
+    if (policy->policyDir)
+        free(policy->policyDir);
     qd_policy_free(policy);
     return qd_error_code();
 }
@@ -222,7 +222,7 @@
 
     n_connections -= 1;
     assert (n_connections >= 0);
-    if (policy->enableAccessRules) {
+    if (policy->enableVhostPolicy) {
         // HACK ALERT: TODO: This should be deferred to a Python thread
         qd_python_lock_state_t lock_state = qd_python_lock();
         PyObject *module = PyImport_ImportModule("qpid_dispatch_internal.policy.policy_manager");
@@ -262,7 +262,7 @@
 // allow or deny the Open. Denied Open attempts are
 // effected by returning Open and then Close_with_condition.
 //
-/** Look up user/host/app in python policyRuleset and give the AMQP Open
+/** Look up user/host/app in python vhost and give the AMQP Open
  *  a go-no_go decision. Return false if the mechanics of calling python
  *  fails. A policy lookup will deny the connection by returning a blank
  *  usergroup name in the name buffer.
@@ -707,7 +707,7 @@
         qd_policy_t *policy = qd->policy;
         bool connection_allowed = true;
 
-        if (policy->enableAccessRules) {
+        if (policy->enableVhostPolicy) {
             // Open connection or not based on policy.
             pn_transport_t *pn_trans = pn_connection_transport(conn);
             const char *hostip = qdpn_connector_hostip(qd_conn->pn_cxtr);
diff --git a/tests/policy-1/management-access.json b/tests/policy-1/management-access.json
index b642b94..48e544a 100644
--- a/tests/policy-1/management-access.json
+++ b/tests/policy-1/management-access.json
@@ -23,7 +23,7 @@
 #    localhost   - proton 0.13
 #    unnamed host- proton 0.13
 [
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "",
       "maxConnections": 50,
       "maxConnPerUser": 5,
@@ -45,7 +45,7 @@
       }
     }
   ],
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "0.0.0.0",
       "maxConnections": 50,
       "maxConnPerUser": 5,
@@ -67,7 +67,7 @@
       }
     }
   ],
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "localhost",
       "maxConnections": 50,
       "maxConnPerUser": 5,
diff --git a/tests/policy-1/policy-boardwalk.json b/tests/policy-1/policy-boardwalk.json
index 174bdef..d5c611a 100644
--- a/tests/policy-1/policy-boardwalk.json
+++ b/tests/policy-1/policy-boardwalk.json
@@ -19,7 +19,7 @@
 
 [
     # The boardwalk policy ruleset
-    ["policyRuleset",
+    ["vhost",
         {
             "applicationName": "boardwalk",
             "maxConnections": 10,
diff --git a/tests/policy-1/policy-safari.json b/tests/policy-1/policy-safari.json
index a61bbd9..be28e96 100644
--- a/tests/policy-1/policy-safari.json
+++ b/tests/policy-1/policy-safari.json
@@ -18,7 +18,7 @@
 ##
 [
     # The safari policy ruleset
-    ["policyRuleset",
+    ["vhost",
         {
             "applicationName": "safari",
             "maxConnections": 10,
diff --git a/tests/policy-1/test-policy-conf-includes-folder.conf.in b/tests/policy-1/test-policy-conf-includes-folder.conf.in
index 3dbcc77..bd2e750 100644
--- a/tests/policy-1/test-policy-conf-includes-folder.conf.in
+++ b/tests/policy-1/test-policy-conf-includes-folder.conf.in
@@ -34,7 +34,7 @@
 }
 
 policy {
-    maximumConnections: 10
-    enableAccessRules: true
-    policyFolder: ${CMAKE_CURRENT_BINARY_DIR}/policy-1
+    maxConnections: 10
+    enableVhostPolicy: true
+    policyDir: ${CMAKE_CURRENT_BINARY_DIR}/policy-1
 }
\ No newline at end of file
diff --git a/tests/policy-2/test-router-with-policy.json.in b/tests/policy-2/test-router-with-policy.json.in
index 1ec3ef1..a38608f 100644
--- a/tests/policy-2/test-router-with-policy.json.in
+++ b/tests/policy-2/test-router-with-policy.json.in
@@ -25,11 +25,11 @@
 	"module": "DEFAULT"
     }],
     ["policy", {
-	"maximumConnections": 20,
-	"enableAccessRules": "true"
+	"maxConnections": 20,
+	"enableVhostPolicy": "true"
     }],
 # Some ruleset
-    ["policyRuleset", {
+    ["vhost", {
       "applicationName": "photoserver",
       "maxConnections": 50,
       "maxConnPerUser": 5,
@@ -145,7 +145,7 @@
         }
       }
   }],
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "",
       "maxConnections": 50,
       "maxConnPerUser": 5,
@@ -167,7 +167,7 @@
       }
     }
   ],
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "0.0.0.0",
       "maxConnections": 50,
       "maxConnPerUser": 5,
@@ -189,7 +189,7 @@
       }
     }
   ],
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "localhost",
       "maxConnections": 50,
       "maxConnPerUser": 5,
diff --git a/tests/policy-3/test-sender-receiver-limits.json b/tests/policy-3/test-sender-receiver-limits.json
index f7fc033..7a30aaf 100644
--- a/tests/policy-3/test-sender-receiver-limits.json
+++ b/tests/policy-3/test-sender-receiver-limits.json
@@ -1,7 +1,7 @@
 [
 # Ruleset with differing number of senders and receivers
 # so tests can determine that correct limit is matched.
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "",
       "maxConnections": 50,
       "maxConnPerUser": 2,
@@ -23,7 +23,7 @@
       }
     }
   ],
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "0.0.0.0",
       "maxConnections": 50,
       "maxConnPerUser": 2,
@@ -45,7 +45,7 @@
       }
     }
   ],
-  ["policyRuleset", {
+  ["vhost", {
       "applicationName": "localhost",
       "maxConnections": 50,
       "maxConnPerUser": 2,
diff --git a/tests/router_policy_test.py b/tests/router_policy_test.py
index c2359f2..d6eefca 100644
--- a/tests/router_policy_test.py
+++ b/tests/router_policy_test.py
@@ -200,8 +200,8 @@
         self.assertTrue(
             self.policy.lookup_user('zeke', '192.168.100.5', 'galleria', "connid", 5) == '')
 
-        # Enable the fallback defaultApplication and show the same user can now connect
-        self.policy.set_default_application('photoserver', True)
+        # Enable the fallback defaultVhost and show the same user can now connect
+        self.policy.set_default_vhost('photoserver')
         settingsname = self.policy.lookup_user('zeke', '192.168.100.5', 'galleria', "connid", 5)
         self.assertTrue(settingsname == 'test')
 
@@ -222,18 +222,10 @@
         self.assertTrue(upolicy['sources'] == 'private')
 
         # Disable fallback and show failure again
-        self.policy.set_default_application('', False)
+        self.policy.set_default_vhost('')
         self.assertTrue(
             self.policy.lookup_user('zeke', '192.168.100.5', 'galleria', "connid", 5) == '')
 
-        # Configuration will not allow default application to point to bogus app ruleset
-        was_allowed = True
-        try:
-            self.policy.set_default_application('foobar', True)
-        except:
-            was_allowed = False
-        self.assertTrue(was_allowed == False)
-
 class PolicyAppConnectionMgrTests(TestCase):
 
     def test_policy_app_conn_mgr_fail_by_total(self):
diff --git a/tests/system_tests_policy.py b/tests/system_tests_policy.py
index f8fd556..e01e666 100644
--- a/tests/system_tests_policy.py
+++ b/tests/system_tests_policy.py
@@ -35,7 +35,7 @@
         config = Qdrouterd.Config([
             ('router', {'mode': 'standalone', 'id': 'QDR.Policy'}),
             ('listener', {'port': cls.tester.get_port()}),
-            ('policy', {'maximumConnections': 2})
+            ('policy', {'maxConnections': 2, 'enableVhostPolicy': 'false'})
         ])
 
         cls.router = cls.tester.qdrouterd('conn-limit-router', config, wait=True)
@@ -82,7 +82,7 @@
         config = Qdrouterd.Config([
             ('router', {'mode': 'standalone', 'id': 'QDR.Policy'}),
             ('listener', {'port': cls.tester.get_port()}),
-            ('policy', {'maximumConnections': 2, 'policyFolder': policy_config_path, 'enableAccessRules': 'true'})
+            ('policy', {'maxConnections': 2, 'policyDir': policy_config_path, 'enableVhostPolicy': 'true'})
         ])
 
         cls.router = cls.tester.qdrouterd('conn-limit-router', config, wait=True)
@@ -104,7 +104,7 @@
     def test_verify_policies_are_loaded(self):
         addr = self.address()
 
-        rulesets = json.loads(self.run_qdmanage('query --type=policyRuleset'))
+        rulesets = json.loads(self.run_qdmanage('query --type=vhost'))
         self.assertEqual(len(rulesets), 5)
 
 class SenderReceiverLimits(TestCase):
@@ -121,7 +121,7 @@
         config = Qdrouterd.Config([
             ('router', {'mode': 'standalone', 'id': 'QDR.Policy'}),
             ('listener', {'port': cls.tester.get_port()}),
-            ('policy', {'maximumConnections': 2, 'policyFolder': policy_config_path, 'enableAccessRules': 'true'})
+            ('policy', {'maxConnections': 2, 'policyDir': policy_config_path, 'enableVhostPolicy': 'true'})
         ])
 
         cls.router = cls.tester.qdrouterd('SenderReceiverLimits', config, wait=True)