metron-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rmerri...@apache.org
Subject [3/3] metron git commit: METRON-1337 List of facets should not be hardcoded (merrimanr) closes apache/metron#853
Date Tue, 06 Mar 2018 14:09:39 GMT
METRON-1337 List of facets should not be hardcoded (merrimanr) closes apache/metron#853


Project: http://git-wip-us.apache.org/repos/asf/metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/e22479e6
Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/e22479e6
Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/e22479e6

Branch: refs/heads/master
Commit: e22479e62fab2ae64de1ab803e0f9f0a5fab98b3
Parents: 9b4b402
Author: merrimanr <merrimanr@gmail.com>
Authored: Tue Mar 6 08:09:22 2018 -0600
Committer: merrimanr <merrimanr@apache.org>
Committed: Tue Mar 6 08:09:22 2018 -0600

----------------------------------------------------------------------
 .../CURRENT/configuration/metron-rest-env.xml   |  12 +
 .../common-services/METRON/CURRENT/metainfo.xml |   7 +
 .../CURRENT/package/scripts/metron_service.py   |  10 +
 .../package/scripts/params/params_linux.py      |   7 +-
 .../package/scripts/params/status_params.py     |   7 +-
 .../CURRENT/package/scripts/rest_commands.py    |  69 +++-
 .../CURRENT/package/scripts/rest_master.py      |  14 +-
 .../alert-filters/alert-filters.e2e-spec.ts     |  11 +-
 .../meta-alerts/meta-alert.e2e-spec.ts          |   5 +-
 .../alerts-list/tree-view/tree-view.e2e-spec.ts |   5 +-
 .../alert-filters/alert-filters.component.ts    |   4 +-
 .../src/app/model/search-request.ts             |   2 +-
 .../app/shared/group-by/group-by.component.ts   |   4 +-
 .../apache/metron/rest/model/AlertProfile.java  |  88 -----
 .../metron/rest/model/AlertsUIUserSettings.java |  90 +++++
 metron-interface/metron-rest/README.md          |  53 ++-
 .../apache/metron/rest/MetronRestConstants.java |   4 +
 .../apache/metron/rest/config/HBaseConfig.java  |  55 +++
 .../metron/rest/controller/AlertController.java | 119 -------
 .../rest/controller/AlertsUIController.java     | 124 +++++++
 .../metron/rest/controller/UserController.java  |   3 +-
 .../rest/repository/AlertProfileRepository.java |  25 --
 .../metron/rest/service/AlertService.java       |  39 ---
 .../rest/service/AlertsProfileService.java      |  32 --
 .../metron/rest/service/AlertsUIService.java    |  41 +++
 .../apache/metron/rest/service/UserService.java |  33 ++
 .../rest/service/impl/AlertServiceImpl.java     |  97 ------
 .../service/impl/AlertsProfileServiceImpl.java  |  66 ----
 .../rest/service/impl/AlertsUIServiceImpl.java  | 131 +++++++
 .../rest/service/impl/SearchServiceImpl.java    |  22 +-
 .../src/main/resources/application-test.yml     |   2 +
 .../src/main/resources/application.yml          |   9 +-
 .../metron/rest/config/HBaseConfigTest.java     |  69 ++++
 .../apache/metron/rest/config/TestConfig.java   |  26 +-
 .../AlertControllerIntegrationTest.java         | 345 -------------------
 .../AlertsUIControllerIntegrationTest.java      | 340 ++++++++++++++++++
 .../SearchControllerIntegrationTest.java        |  61 +++-
 .../UserControllerIntegrationTest.java          |  40 ++-
 .../rest/service/impl/AlertServiceImplTest.java | 152 --------
 .../service/impl/AlertsUIServiceImplTest.java   | 180 ++++++++++
 .../service/impl/SearchServiceImplTest.java     |  60 +++-
 .../elasticsearch/dao/ElasticsearchDao.java     |  23 +-
 .../metron/hbase/client/UserSettingsClient.java | 175 ++++++++++
 .../hbase/client/UserSettingsClientTest.java    | 101 ++++++
 .../apache/metron/hbase/mock/MockHTable.java    |   7 +-
 .../indexing/dao/search/SearchRequest.java      |  15 +-
 .../metron/indexing/dao/search/SortField.java   |  15 +
 .../apache/metron/indexing/dao/InMemoryDao.java |  18 +
 48 files changed, 1742 insertions(+), 1075 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml
index 8ba29b5..78ea27e 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-rest-env.xml
@@ -144,4 +144,16 @@
             <editable-only-at-install>true</editable-only-at-install>
         </value-attributes>
     </property>
+    <property>
+        <name>user_settings_hbase_table</name>
+        <value>user_settings</value>
+        <description>The HBase table which will hold user settings</description>
+        <display-name>User Settings HBase Table</display-name>
+    </property>
+    <property>
+        <name>user_settings_hbase_cf</name>
+        <value>cf</value>
+        <description>The HBase column family which will hold user settings in HBase.</description>
+        <display-name>User Settings HBase Column Family</display-name>
+    </property>
 </configuration>

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml
index 2b5b405..7a680a4 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/metainfo.xml
@@ -241,6 +241,13 @@
               </auto-deploy>
             </dependency>
             <dependency>
+              <name>HBASE/HBASE_CLIENT</name>
+              <scope>host</scope>
+              <auto-deploy>
+                  <enabled>true</enabled>
+              </auto-deploy>
+            </dependency>
+            <dependency>
               <name>ZOOKEEPER/ZOOKEEPER_SERVER</name>
               <scope>cluster</scope>
               <auto-deploy>

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
index 330d3c0..2478b8b 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
@@ -94,6 +94,16 @@ def build_global_config_patch(params, patch_file):
         "op": "add",
         "path": "/profiler.client.period.duration.units",
         "value": "{{profiler_period_units}}"
+    },
+    {
+        "op": "add",
+        "path": "/user.settings.hbase.table",
+        "value": "{{user_settings_hbase_table}}"
+    },
+    {
+        "op": "add",
+        "path": "/user.settings.hbase.cf",
+        "value": "{{user_settings_hbase_cf}}"
     }
   ]
   """

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
index 3506fab..ceb9e4e 100755
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
@@ -72,7 +72,6 @@ metron_zookeeper_config_path = status_params.metron_zookeeper_config_path
 zk_configured_flag_file = status_params.zk_configured_flag_file
 parsers_configured_flag_file = status_params.parsers_configured_flag_file
 parsers_acl_configured_flag_file = status_params.parsers_acl_configured_flag_file
-rest_acl_configured_flag_file = status_params.rest_acl_configured_flag_file
 enrichment_kafka_configured_flag_file = status_params.enrichment_kafka_configured_flag_file
 enrichment_kafka_acl_configured_flag_file = status_params.enrichment_kafka_acl_configured_flag_file
 enrichment_hbase_configured_flag_file = status_params.enrichment_hbase_configured_flag_file
@@ -84,6 +83,10 @@ indexing_hbase_configured_flag_file = status_params.indexing_hbase_configured_fl
 indexing_hbase_acl_configured_flag_file = status_params.indexing_hbase_acl_configured_flag_file
 indexing_hdfs_perm_configured_flag_file = status_params.indexing_hdfs_perm_configured_flag_file
 elasticsearch_template_installed_flag_file = status_params.elasticsearch_template_installed_flag_file
+rest_kafka_configured_flag_file = status_params.rest_kafka_configured_flag_file
+rest_kafka_acl_configured_flag_file = status_params.rest_kafka_acl_configured_flag_file
+rest_hbase_configured_flag_file = status_params.rest_hbase_configured_flag_file
+rest_hbase_acl_configured_flag_file = status_params.rest_hbase_acl_configured_flag_file
 global_properties_template = config['configurations']['metron-env']['elasticsearch-properties']
 
 # Elasticsearch hosts and port management
@@ -249,6 +252,8 @@ metron_rest_pid = 'metron-rest.pid'
 metron_indexing_classpath = config['configurations']['metron-rest-env']['metron_indexing_classpath']
 metron_rest_classpath = config['configurations']['metron-rest-env']['metron_rest_classpath']
 metron_sysconfig = config['configurations']['metron-rest-env']['metron_sysconfig']
+user_settings_hbase_table = status_params.user_settings_hbase_table
+user_settings_hbase_cf = status_params.user_settings_hbase_cf
 
 # Enrichment
 geoip_url = config['configurations']['metron-enrichment-env']['geoip_url']

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py
index 62cfc7a..ed2edfb 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/status_params.py
@@ -37,7 +37,6 @@ zk_configured_flag_file = metron_zookeeper_config_path + '/../metron_zookeeper_c
 parsers = config['configurations']['metron-parsers-env']['parsers']
 parsers_configured_flag_file = metron_zookeeper_config_path + '/../metron_parsers_configured'
 parsers_acl_configured_flag_file = metron_zookeeper_config_path + '/../metron_parsers_acl_configured'
-rest_acl_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_acl_configured'
 
 # Enrichment
 metron_enrichment_topology = 'enrichment'
@@ -81,6 +80,12 @@ elasticsearch_template_installed_flag_file = metron_zookeeper_config_path + '/..
 
 # REST
 metron_rest_port = config['configurations']['metron-rest-env']['metron_rest_port']
+rest_kafka_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_kafka_configured'
+rest_kafka_acl_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_kafka_acl_configured'
+rest_hbase_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_hbase_configured'
+rest_hbase_acl_configured_flag_file = metron_zookeeper_config_path + '/../metron_rest_hbase_acl_configured'
+user_settings_hbase_table = config['configurations']['metron-rest-env']['user_settings_hbase_table']
+user_settings_hbase_cf = config['configurations']['metron-rest-env']['user_settings_hbase_cf']
 
 # Alerts UI
 metron_alerts_ui_host = default("/clusterHostInfo/metron_alerts_ui_hosts", [hostname])[0]

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py
index 4f717bb..e97af05 100755
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_commands.py
@@ -33,13 +33,19 @@ from metron_security import kinit
 # Wrap major operations and functionality in this class
 class RestCommands:
     __params = None
-    __acl_configured = False
+    __kafka_configured = False
+    __kafka_acl_configured = False
+    __hbase_configured = False
+    __hbase_acl_configured = False
 
     def __init__(self, params):
         if params is None:
             raise ValueError("params argument is required for initialization")
         self.__params = params
-        self.__acl_configured = os.path.isfile(self.__params.rest_acl_configured_flag_file)
+        self.__kafka_configured = os.path.isfile(self.__params.rest_kafka_configured_flag_file)
+        self.__kafka_acl_configured = os.path.isfile(self.__params.rest_kafka_acl_configured_flag_file)
+        self.__hbase_configured = os.path.isfile(self.__params.rest_hbase_configured_flag_file)
+        self.__hbase_acl_configured = os.path.isfile(self.__params.rest_hbase_acl_configured_flag_file)
         Directory(params.metron_rest_pid_dir,
                   mode=0755,
                   owner=params.metron_user,
@@ -53,15 +59,33 @@ class RestCommands:
                   create_parents=True
                   )
 
-    def is_acl_configured(self):
-        return self.__acl_configured
-
-    def set_acl_configured(self):
-        metron_service.set_configured(self.__params.metron_user, self.__params.rest_acl_configured_flag_file, "Setting REST ACL configured to true")
-
     def __get_topics(self):
         return [self.__params.metron_escalation_topic]
 
+    def is_kafka_configured(self):
+        return self.__kafka_configured
+
+    def is_kafka_acl_configured(self):
+        return self.__kafka_acl_configured
+
+    def is_hbase_configured(self):
+        return self.__hbase_configured
+
+    def is_hbase_acl_configured(self):
+        return self.__hbase_acl_configured
+
+    def set_kafka_configured(self):
+        metron_service.set_configured(self.__params.metron_user, self.__params.rest_kafka_configured_flag_file, "Setting Kafka configured to True for rest")
+
+    def set_kafka_acl_configured(self):
+        metron_service.set_configured(self.__params.metron_user, self.__params.rest_kafka_acl_configured_flag_file, "Setting Kafka ACL configured to True for rest")
+
+    def set_hbase_configured(self):
+        metron_service.set_configured(self.__params.metron_user, self.__params.rest_hbase_configured_flag_file, "Setting HBase configured to True for rest")
+
+    def set_hbase_acl_configured(self):
+        metron_service.set_configured(self.__params.metron_user, self.__params.rest_hbase_acl_configured_flag_file, "Setting HBase ACL configured to True for rest")
+
     def init_kafka_topics(self):
         Logger.info('Creating Kafka topics for rest')
         metron_service.init_kafka_topics(self.__params, self.__get_topics())
@@ -179,6 +203,35 @@ class RestCommands:
             self.__params.metron_rest_port,
             self.__params.metron_user)
 
+    def create_hbase_tables(self):
+        Logger.info("Creating HBase Tables")
+        metron_service.create_hbase_table(self.__params,
+                                          self.__params.user_settings_hbase_table,
+                                          self.__params.user_settings_hbase_cf)
+        Logger.info("Done creating HBase Tables")
+        self.set_hbase_configured()
+
+    def set_hbase_acls(self):
+        Logger.info("Setting HBase ACLs")
+        if self.__params.security_enabled:
+            kinit(self.__params.kinit_path_local,
+                  self.__params.hbase_keytab_path,
+                  self.__params.hbase_principal_name,
+                  execute_user=self.__params.hbase_user)
+
+        cmd = "echo \"grant '{0}', 'RW', '{1}'\" | hbase shell -n"
+        add_rest_acl_cmd = cmd.format(self.__params.metron_user, self.__params.user_settings_hbase_table)
+        Execute(add_rest_acl_cmd,
+                tries=3,
+                try_sleep=5,
+                logoutput=False,
+                path='/usr/sbin:/sbin:/usr/local/bin:/bin:/usr/bin',
+                user=self.__params.hbase_user
+                )
+
+        Logger.info("Done setting HBase ACLs")
+        self.set_hbase_acl_configured()
+
     def service_check(self, env):
         """
         Performs a service check for the REST application

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py
index 2f419df..36a68c6 100755
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/rest_master.py
@@ -26,9 +26,9 @@ from resource_management.libraries.functions.format import format
 from resource_management.libraries.functions.get_user_call_output import get_user_call_output
 from resource_management.libraries.script import Script
 
+import metron_service
 from rest_commands import RestCommands
 
-
 class RestMaster(Script):
 
     def install(self, env):
@@ -43,11 +43,17 @@ class RestMaster(Script):
              content=Template("metron.j2")
              )
 
+        metron_service.refresh_configs(params)
+
         commands = RestCommands(params)
-        commands.init_kafka_topics()
-        if params.security_enabled and not commands.is_acl_configured():
+
+        if not commands.is_kafka_configured():
+            commands.init_kafka_topics()
+        if not commands.is_hbase_configured():
+            commands.create_hbase_tables()
+        if params.security_enabled and not commands.is_kafka_acl_configured():
             commands.init_kafka_acls()
-            commands.set_acl_configured()
+            commands.set_kafka_acl_configured()
 
     def start(self, env, upgrade_type=None):
         from params import params

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts
index 11b8ae3..b21e316 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts
@@ -43,7 +43,7 @@ describe('metron-alerts facets', function() {
   });
 
   it('should display facets data', () => {
-    let facetValues = [ 'enrichm...:country 3', 'host 9', 'ip_dst_addr 8', 'ip_src_addr 2', 'source:type 1' ];
+    let facetValues = [ 'enrichm...:country 3', 'ip_dst_addr 8', 'ip_src_addr 2', 'source:type 1' ];
 
     page.navgateToAlertList();
     expect(page.getFacetsTitle()).toEqualBcoz(['Filters'], 'for Title as Filters');
@@ -55,19 +55,16 @@ describe('metron-alerts facets', function() {
     expect(page.getFacetState(1)).toEqualBcoz('collapse', 'for second facet');
     expect(page.getFacetState(2)).toEqualBcoz('collapse', 'for third facet');
     expect(page.getFacetState(3)).toEqualBcoz('collapse', 'for fourth facet');
-    expect(page.getFacetState(4)).toEqualBcoz('collapse', 'for fifth facet');
 
     page.toggleFacetState(0);
     page.toggleFacetState(1);
     page.toggleFacetState(2);
     page.toggleFacetState(3);
-    page.toggleFacetState(4);
 
     expect(page.getFacetState(0)).toEqualBcoz('collapse show', 'for first facet');
     expect(page.getFacetState(1)).toEqualBcoz('collapse show', 'for second facet');
     expect(page.getFacetState(2)).toEqualBcoz('collapse show', 'for third facet');
     expect(page.getFacetState(3)).toEqualBcoz('collapse show', 'for fourth facet');
-    expect(page.getFacetState(4)).toEqualBcoz('collapse show', 'for fifth facet');
   });
 
   it('should have all facet  values', () => {
@@ -84,8 +81,7 @@ describe('metron-alerts facets', function() {
     };
 
     expect(page.getFacetValues(0)).toEqualBcoz({ US: '22', RU: '44', FR: '25' }, 'for enrichment facet');
-    expect(page.getFacetValues(1)).toEqual(hostMap, 'for host facet');
-    expect(page.getFacetValues(4)).toEqual({ alerts_ui_e2e: '169' }, 'for source:type facet');
+    expect(page.getFacetValues(3)).toEqual({ alerts_ui_e2e: '169' }, 'for source:type facet');
   });
 
   it('should collapse all facets', () => {
@@ -93,19 +89,16 @@ describe('metron-alerts facets', function() {
     expect(page.getFacetState(1)).toEqualBcoz('collapse show', 'for second facet');
     expect(page.getFacetState(2)).toEqualBcoz('collapse show', 'for third facet');
     expect(page.getFacetState(3)).toEqualBcoz('collapse show', 'for fourth facet');
-    expect(page.getFacetState(4)).toEqualBcoz('collapse show', 'for fifth facet');
 
     page.toggleFacetState(0);
     page.toggleFacetState(1);
     page.toggleFacetState(2);
     page.toggleFacetState(3);
-    page.toggleFacetState(4);
 
     expect(page.getFacetState(0)).toEqualBcoz('collapse', 'for first facet');
     expect(page.getFacetState(1)).toEqualBcoz('collapse', 'for second facet');
     expect(page.getFacetState(2)).toEqualBcoz('collapse', 'for third facet');
     expect(page.getFacetState(3)).toEqualBcoz('collapse', 'for fourth facet');
-    expect(page.getFacetState(4)).toEqualBcoz('collapse', 'for fifth facet');
   });
 });
 

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts
index 38bacee..00d677e 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts
@@ -152,7 +152,6 @@ describe('meta-alerts workflow', function() {
     let groupByItems = {
       'source:type': '1',
       'ip_dst_addr': '7',
-      'host': '9',
       'enrichm...:country': '3',
       'ip_src_addr': '2'
     };
@@ -215,8 +214,8 @@ describe('meta-alerts workflow', function() {
     expect(tablePage.getPaginationText()).toEqualBcoz('1 - 25 of 150', 'pagination text to be present');
 
     // Meta Alert should appear in Filters
-    alertFacetsPage.toggleFacetState(4);
-    expect(alertFacetsPage.getFacetValues(4)).toEqual({'metaalert': '1' }, 'for source:type facet');
+    alertFacetsPage.toggleFacetState(3);
+    expect(alertFacetsPage.getFacetValues(3)).toEqual({'metaalert': '1' }, 'for source:type facet');
 
     // Meta Alert should not appear in Groups
     expect(treePage.getGroupByItemNames()).toEqualBcoz(Object.keys(groupByItems), 'Group By Elements names should be present');

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts
index 87636cd..339b19f 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts
@@ -49,14 +49,13 @@ describe('metron-alerts tree view', function () {
     let groupByItems = {
       'source:type': '1',
       'ip_dst_addr': '8',
-      'host': '9',
       'enrichm...:country': '3',
       'ip_src_addr': '2'
     };
-    expect(page.getGroupByCount()).toEqualBcoz(Object.keys(groupByItems).length, '5 Group By Elements should be present');
+    expect(page.getGroupByCount()).toEqualBcoz(Object.keys(groupByItems).length, '4 Group By Elements should be present');
     expect(page.getGroupByItemNames()).toEqualBcoz(Object.keys(groupByItems), 'Group By Elements names should be present');
     expect(page.getGroupByItemCounts()).toEqualBcoz(Object.keys(groupByItems).map(key => groupByItems[key]),
-                                                    '5 Group By Elements values should be present');
+                                                    '4 Group By Elements values should be present');
   });
 
   it('drag and drop should change group order', () => {

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts
index 2a78ecd..12d98e7 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts
@@ -24,9 +24,11 @@ export class AlertFiltersComponent implements OnChanges {
   }
 
   prepareData() {
+    let facetFields = Object.keys(this.facets);
+    this.data = this.data.filter(collapsableData => facetFields.includes(collapsableData.groupName));
     this.data.map(collapsableData => collapsableData.groupItems = []);
 
-    for (let key of Object.keys(this.facets)) {
+    for (let key of facetFields) {
       let facet = this.facets[key];
       let facetItems: CollapseComponentDataItems[] = [];
 

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/src/app/model/search-request.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/model/search-request.ts b/metron-interface/metron-alerts/src/app/model/search-request.ts
index 44e23db..ad174cf 100644
--- a/metron-interface/metron-alerts/src/app/model/search-request.ts
+++ b/metron-interface/metron-alerts/src/app/model/search-request.ts
@@ -25,5 +25,5 @@ export class SearchRequest {
   query: string;
   size: number;
   sort: SortField[];
-  facetFields: string[] = Array.from(new Set(DEFAULT_FACETS.concat(DEFAULT_GROUPS)));
+  facetFields: string[] = [];
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts b/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts
index 1c6e633..2e034d5 100644
--- a/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts
+++ b/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.ts
@@ -45,7 +45,9 @@ export class GroupByComponent implements OnInit, OnChanges {
   }
 
   prepareData() {
-    for (let key of Object.keys(this.facets)) {
+    let facetFields = Object.keys(this.facets);
+    this.data = this.data.filter(groupByData => facetFields.includes(groupByData.name));
+    for (let key of facetFields) {
       let facet = this.facets[key];
       let count = Object.keys(facet).length;
       let groupByItem = this.data.filter(groupByData => groupByData.name === key)[0];

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertProfile.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertProfile.java b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertProfile.java
deleted file mode 100644
index c126ce7..0000000
--- a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertProfile.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.metron.rest.model;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.List;
-import javax.persistence.Convert;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import org.apache.metron.rest.converter.JsonConverter;
-
-@Entity
-public class AlertProfile {
-
-  @Id
-  @JsonProperty(access = JsonProperty.Access.READ_ONLY)
-  private String id;
-
-  @Convert(converter = JsonConverter.class)
-  private List<String> tableColumns;
-
-  @Convert(converter = JsonConverter.class)
-  private List<SavedSearch> savedSearches;
-
-  public String getId() {
-    return id;
-  }
-
-  public void setId(String id) {
-    this.id = id;
-  }
-
-  public List<String> getTableColumns() {
-    return tableColumns;
-  }
-
-  public void setTableColumns(List<String> tableColumns) {
-    this.tableColumns = tableColumns;
-  }
-
-  public List<SavedSearch> getSavedSearches() {
-    return savedSearches;
-  }
-
-  public void setSavedSearches(List<SavedSearch> savedSearches) {
-    this.savedSearches = savedSearches;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-
-    AlertProfile that = (AlertProfile) o;
-
-    return id != null ? id.equals(that.id) : that.id == null &&
-        (tableColumns != null ? tableColumns.equals(that.tableColumns) : that.tableColumns == null &&
-        (savedSearches != null ? savedSearches.equals(that.savedSearches) : that.savedSearches == null));
-  }
-
-  @Override
-  public int hashCode() {
-    int result = id != null ? id.hashCode() : 0;
-    result = 31 * result + (tableColumns != null ? tableColumns.hashCode() : 0);
-    result = 31 * result + (savedSearches != null ? savedSearches.hashCode() : 0);
-    return result;
-  }
-}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertsUIUserSettings.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertsUIUserSettings.java b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertsUIUserSettings.java
new file mode 100644
index 0000000..7c92cf4
--- /dev/null
+++ b/metron-interface/metron-rest-client/src/main/java/org/apache/metron/rest/model/AlertsUIUserSettings.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.metron.rest.model;
+
+import java.util.List;
+
+public class AlertsUIUserSettings {
+
+  private String user;
+
+  private List<String> tableColumns;
+
+  private List<SavedSearch> savedSearches;
+
+  private List<String> facetFields;
+
+  public String getUser() {
+    return user;
+  }
+
+  public void setUser(String user) {
+    this.user = user;
+  }
+
+  public List<String> getTableColumns() {
+    return tableColumns;
+  }
+
+  public void setTableColumns(List<String> tableColumns) {
+    this.tableColumns = tableColumns;
+  }
+
+  public List<SavedSearch> getSavedSearches() {
+    return savedSearches;
+  }
+
+  public void setSavedSearches(List<SavedSearch> savedSearches) {
+    this.savedSearches = savedSearches;
+  }
+
+  public List<String> getFacetFields() {
+    return facetFields;
+  }
+
+  public void setFacetFields(List<String> facetFields) {
+    this.facetFields = facetFields;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    AlertsUIUserSettings that = (AlertsUIUserSettings) o;
+
+    return (user != null ? user.equals(that.user) : that.user == null) &&
+        (tableColumns != null ? tableColumns.equals(that.tableColumns) : that.tableColumns == null) &&
+        (savedSearches != null ? savedSearches.equals(that.savedSearches) : that.savedSearches == null) &&
+        (facetFields != null ? facetFields.equals(that.facetFields) : that.facetFields == null);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = user != null ? user.hashCode() : 0;
+    result = 31 * result + (tableColumns != null ? tableColumns.hashCode() : 0);
+    result = 31 * result + (savedSearches != null ? savedSearches.hashCode() : 0);
+    result = 31 * result + (facetFields != null ? facetFields.hashCode() : 0);
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/README.md
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/README.md b/metron-interface/metron-rest/README.md
index d51dc52..25e112e 100644
--- a/metron-interface/metron-rest/README.md
+++ b/metron-interface/metron-rest/README.md
@@ -213,11 +213,11 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
 
 |            |
 | ---------- |
-| [ `POST /api/v1/alert/escalate`](#get-apiv1alertescalate)|
-| [ `GET /api/v1/alert/profile`](#get-apiv1alertprofile)|
-| [ `GET /api/v1/alert/profile/all`](#get-apiv1alertprofileall)|
-| [ `DELETE /api/v1/alert/profile`](#delete-apiv1alertprofile)|
-| [ `POST /api/v1/alert/profile`](#post-apiv1alertprofile)|
+| [ `POST /api/v1/alerts/ui/escalate`](#get-apiv1alertsuiescalate)|
+| [ `GET /api/v1/alerts/ui/settings`](#get-apiv1alertsuisettings)|
+| [ `GET /api/v1/alerts/ui/settings/all`](#get-apiv1alertsuisettingsall)|
+| [ `DELETE /api/v1/alerts/ui/settings`](#delete-apiv1alertsuisettings)|
+| [ `POST /api/v1/alerts/ui/settings`](#post-apiv1alertsuisettings)|
 | [ `GET /api/v1/global/config`](#get-apiv1globalconfig)|
 | [ `DELETE /api/v1/global/config`](#delete-apiv1globalconfig)|
 | [ `POST /api/v1/global/config`](#post-apiv1globalconfig)|
@@ -288,42 +288,41 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
 | [ `PUT /api/v1/update/replace`](#patch-apiv1updatereplace)|
 | [ `GET /api/v1/user`](#get-apiv1user)|
 
-### `POST /api/v1/alert/escalate`
+### `POST /api/v1/alerts/ui/escalate`
   * Description: Escalates a list of alerts by producing it to the Kafka escalate topic
   * Input:
     * alerts - The alerts to be escalated
   * Returns:
     * 200 - Alerts were escalated
-
-### `GET /api/v1/alert/profile`
-  * Description: Retrieves the current user's alerts profile
+    
+### `GET /api/v1/alerts/ui/settings`
+  * Description: Retrieves the current user's settings
   * Returns:
-    * 200 - Alerts profile
-    * 404 - The current user does not have an alerts profile
+    * 200 - User settings
+    * 404 - he current user does not have settings
 
-### `GET /api/v1/alert/profile/all`
-  * Description: Retrieves all users' alerts profiles.  Only users that are part of the "ROLE_ADMIN" role are allowed to get all alerts profiles.
+### `GET /api/v1/alerts/ui/settings/all`
+  * Description: Retrieves all users' settings.  Only users that are part of the "ROLE_ADMIN" role are allowed to get all user settings.
   * Returns:
-    * 200 - List of all alerts profiles
-    * 403 - The current user does not have permission to get all alerts profiles
+    * 200 - List of all user settings
+    * 403 - The current user does not have permission to get all user settings
 
-### `DELETE /api/v1/alert/profile`
-  * Description: Deletes a user's alerts profile.  Only users that are part of the "ROLE_ADMIN" role are allowed to delete user alerts profiles.
+### `DELETE /api/v1/alerts/ui/settings`
+  * Description: Deletes a user's settings.  Only users that are part of the "ROLE_ADMIN" role are allowed to delete user settings.
   * Input:
-    * user - The user whose prolife will be deleted
+    * user - The user whose settings will be deleted
   * Returns:
-    * 200 - Alerts profile was deleted
-    * 403 - The current user does not have permission to delete alerts profiles
-    * 404 - Alerts profile could not be found
+    * 200 - User settings were deleted
+    * 403 - The current user does not have permission to delete user settings
+    * 404 - User settings could not be found
 
-### `POST /api/v1/alert/profile`
-  * Description: Creates or updates the current user's alerts profile
+### `POST /api/v1/alerts/ui/settings`
+  * Description: Creates or updates the current user's settings
   * Input:
-    * alertsProfile - The alerts profile to be saved
+    * alertsUIUserSettings - The user settings to be saved
   * Returns:
-    * 200 - Alerts profile updated. Returns saved alerts profile.
-    * 201 - Alerts profile created. Returns saved alerts profile.
-
+    * 200 - User settings updated. Returns saved settings.
+    * 201 - User settings created. Returns saved settings.
 
 ### `GET /api/v1/global/config`
   * Description: Retrieves the current Global Config from Zookeeper

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
index f18d4cf..4567197 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/MetronRestConstants.java
@@ -59,6 +59,7 @@ public class MetronRestConstants {
 
   public static final String SEARCH_MAX_RESULTS = "search.max.results";
   public static final String SEARCH_MAX_GROUPS = "search.max.groups";
+  public static final String SEARCH_FACET_FIELDS_SPRING_PROPERTY = "search.facet.fields";
   public static final String INDEX_DAO_IMPL = "index.dao.impl";
   public static final String INDEX_HBASE_TABLE_PROVIDER_IMPL = "index.hbase.provider";
   public static final String INDEX_WRITER_NAME = "index.writer.name";
@@ -68,4 +69,7 @@ public class MetronRestConstants {
 
   public static final String SECURITY_ROLE_USER = "USER";
   public static final String SECURITY_ROLE_ADMIN = "ADMIN";
+
+  public static final String USER_SETTINGS_HBASE_TABLE_SPRING_PROPERTY = "user.settings.table";
+  public static final String USER_SETTINGS_HBASE_CF_SPRING_PROPERTY = "user.settings.cf";
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/HBaseConfig.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/HBaseConfig.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/HBaseConfig.java
new file mode 100644
index 0000000..c96b9e8
--- /dev/null
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/HBaseConfig.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.metron.rest.config;
+
+import org.apache.metron.hbase.HTableProvider;
+import org.apache.metron.hbase.client.UserSettingsClient;
+import org.apache.metron.rest.RestException;
+import org.apache.metron.rest.service.GlobalConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+
+@Configuration
+@Profile("!" + TEST_PROFILE)
+public class HBaseConfig {
+
+    @Autowired
+    private GlobalConfigService globalConfigService;
+
+    @Autowired
+    public HBaseConfig(GlobalConfigService globalConfigService) {
+        this.globalConfigService = globalConfigService;
+    }
+
+    @Bean()
+    public UserSettingsClient userSettingsClient() {
+      UserSettingsClient userSettingsClient = new UserSettingsClient();
+      userSettingsClient.init(() -> {
+        try {
+          return globalConfigService.get();
+        } catch (RestException e) {
+          throw new IllegalStateException("Unable to retrieve the global config.", e);
+        }
+      }, new HTableProvider());
+      return userSettingsClient;
+    }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertController.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertController.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertController.java
deleted file mode 100644
index d8d5411..0000000
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertController.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-package org.apache.metron.rest.controller;
-
-import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_ADMIN;
-
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import java.util.List;
-import java.util.Map;
-import org.apache.metron.rest.RestException;
-import org.apache.metron.rest.model.AlertProfile;
-import org.apache.metron.rest.service.AlertService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.access.annotation.Secured;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * The API resource that is used for alert-related operations.
- */
-@RestController
-@RequestMapping("/api/v1/alert")
-public class AlertController {
-
-  /**
-   * Service used to interact with alerts.
-   */
-  @Autowired
-  private AlertService alertService;
-
-  @ApiOperation(value = "Escalates a list of alerts by producing it to the Kafka escalate topic")
-  @ApiResponse(message = "Alerts were escalated", code = 200)
-  @RequestMapping(value = "/escalate", method = RequestMethod.POST)
-  ResponseEntity<Void> escalate(final @ApiParam(name = "alerts", value = "The alerts to be escalated", required = true) @RequestBody List<Map<String, Object>> alerts) throws RestException {
-    alertService.escalateAlerts(alerts);
-    return new ResponseEntity<>(HttpStatus.OK);
-  }
-
-  @ApiOperation(value = "Retrieves the current user's alerts profile")
-  @ApiResponses(value = {@ApiResponse(message = "Alerts profile", code = 200),
-      @ApiResponse(message = "The current user does not have an alerts profile", code = 404)})
-  @RequestMapping(value = "/profile", method = RequestMethod.GET)
-  ResponseEntity<AlertProfile> get() throws RestException {
-    AlertProfile alertsProfile = alertService.getProfile();
-    if (alertsProfile != null) {
-      return new ResponseEntity<>(alertsProfile, HttpStatus.OK);
-    } else {
-      return new ResponseEntity<>(HttpStatus.NOT_FOUND);
-    }
-  }
-
-  @Secured({"ROLE_" + SECURITY_ROLE_ADMIN})
-  @ApiOperation(value = "Retrieves all users' alerts profiles.  Only users that are part of "
-      + "the \"ROLE_ADMIN\" role are allowed to get all alerts profiles.")
-  @ApiResponses(value = {@ApiResponse(message = "List of all alerts profiles", code = 200),
-      @ApiResponse(message =
-          "The current user does not have permission to get all alerts profiles", code = 403)})
-  @RequestMapping(value = "/profile/all", method = RequestMethod.GET)
-  ResponseEntity<Iterable<AlertProfile>> findAll() throws RestException {
-    return new ResponseEntity<>(alertService.findAllProfiles(), HttpStatus.OK);
-  }
-
-  @ApiOperation(value = "Creates or updates the current user's alerts profile")
-  @ApiResponses(value = {
-      @ApiResponse(message = "Alerts profile updated. Returns saved alerts profile.", code = 200),
-      @ApiResponse(message = "Alerts profile created. Returns saved alerts profile.", code = 201)})
-  @RequestMapping(value = "/profile", method = RequestMethod.POST)
-  ResponseEntity<AlertProfile> save(@ApiParam(name = "alertsProfile", value =
-      "The alerts profile to be saved", required = true) @RequestBody AlertProfile alertsProfile)
-      throws RestException {
-    if (alertService.getProfile() == null) {
-      return new ResponseEntity<>(alertService.saveProfile(alertsProfile), HttpStatus.CREATED);
-    } else {
-      return new ResponseEntity<>(alertService.saveProfile(alertsProfile), HttpStatus.OK);
-    }
-  }
-
-  @Secured({"ROLE_" + SECURITY_ROLE_ADMIN})
-  @ApiOperation(value = "Deletes a user's alerts profile.  Only users that are part of "
-      + "the \"ROLE_ADMIN\" role are allowed to delete user alerts profiles.")
-  @ApiResponses(value = {@ApiResponse(message = "Alerts profile was deleted", code = 200),
-      @ApiResponse(message = "The current user does not have permission to delete alerts profiles",
-          code = 403),
-      @ApiResponse(message = "Alerts profile could not be found", code = 404)})
-  @RequestMapping(value = "/profile/{user}", method = RequestMethod.DELETE)
-  ResponseEntity<Void> delete(
-      @ApiParam(name = "user", value = "The user whose prolife will be deleted", required = true)
-      @PathVariable String user)
-      throws RestException {
-    if (alertService.deleteProfile(user)) {
-      return new ResponseEntity<>(HttpStatus.OK);
-    } else {
-      return new ResponseEntity<>(HttpStatus.NOT_FOUND);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertsUIController.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertsUIController.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertsUIController.java
new file mode 100644
index 0000000..fe2968f
--- /dev/null
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/AlertsUIController.java
@@ -0,0 +1,124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.metron.rest.controller;
+
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_ADMIN;
+
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import io.swagger.annotations.ApiResponses;
+import org.apache.metron.rest.RestException;
+import org.apache.metron.rest.model.AlertsUIUserSettings;
+import org.apache.metron.rest.service.AlertsUIService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * The API resource that is used for alert-related operations.
+ */
+@RestController
+@RequestMapping("/api/v1/alerts/ui")
+public class AlertsUIController {
+
+  /**
+   * Service used to interact with alerts.
+   */
+  @Autowired
+  private AlertsUIService alertsUIService;
+
+  @ApiOperation(value = "Escalates a list of alerts by producing it to the Kafka escalate topic")
+  @ApiResponse(message = "Alerts were escalated", code = 200)
+  @RequestMapping(value = "/escalate", method = RequestMethod.POST)
+  ResponseEntity<Void> escalate(final @ApiParam(name = "alerts", value = "The alerts to be escalated", required = true) @RequestBody List<Map<String, Object>> alerts) throws RestException {
+    alertsUIService.escalateAlerts(alerts);
+    return new ResponseEntity<>(HttpStatus.OK);
+  }
+
+  @ApiOperation(value = "Retrieves the current user's settings")
+  @ApiResponses(value = {@ApiResponse(message = "User settings", code = 200),
+          @ApiResponse(message = "The current user does not have settings", code = 404)})
+  @RequestMapping(value = "/settings", method = RequestMethod.GET)
+  ResponseEntity<AlertsUIUserSettings> get() throws RestException {
+    Optional<AlertsUIUserSettings> alertUserSettings = alertsUIService.getAlertsUIUserSettings();
+    if (alertUserSettings.isPresent()) {
+      return new ResponseEntity<>(alertUserSettings.get(), HttpStatus.OK);
+    } else {
+      return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+    }
+  }
+
+  @Secured({"ROLE_" + SECURITY_ROLE_ADMIN})
+  @ApiOperation(value = "Retrieves all users' settings.  Only users that are part of "
+          + "the \"ROLE_ADMIN\" role are allowed to get all user settings.")
+  @ApiResponses(value = {@ApiResponse(message = "List of all user settings", code = 200),
+          @ApiResponse(message =
+                  "The current user does not have permission to get all user settings", code = 403)})
+  @RequestMapping(value = "/settings/all", method = RequestMethod.GET)
+  ResponseEntity<Map<String, AlertsUIUserSettings>> findAll() throws RestException {
+    return new ResponseEntity<>(alertsUIService.findAllAlertsUIUserSettings(), HttpStatus.OK);
+  }
+
+  @ApiOperation(value = "Creates or updates the current user's settings")
+  @ApiResponses(value = {
+          @ApiResponse(message = "User settings updated. Returns saved settings.", code = 200),
+          @ApiResponse(message = "User settings created. Returns saved settings.", code = 201)})
+  @RequestMapping(value = "/settings", method = RequestMethod.POST)
+  ResponseEntity<Void> save(@ApiParam(name = "alertsUIUserSettings", value =
+          "The user settings to be saved", required = true) @RequestBody AlertsUIUserSettings alertsUIUserSettings)
+          throws RestException {
+    ResponseEntity<Void> responseEntity;
+    if (alertsUIService.getAlertsUIUserSettings().isPresent()) {
+      responseEntity = new ResponseEntity<>(HttpStatus.OK);
+    } else {
+      responseEntity = new ResponseEntity<>(HttpStatus.CREATED);
+    }
+    alertsUIService.saveAlertsUIUserSettings(alertsUIUserSettings);
+    return responseEntity;
+  }
+
+  @Secured({"ROLE_" + SECURITY_ROLE_ADMIN})
+  @ApiOperation(value = "Deletes a user's settings.  Only users that are part of "
+          + "the \"ROLE_ADMIN\" role are allowed to delete user settings.")
+  @ApiResponses(value = {@ApiResponse(message = "User settings were deleted", code = 200),
+          @ApiResponse(message = "The current user does not have permission to delete user settings",
+                  code = 403),
+          @ApiResponse(message = "User settings could not be found", code = 404)})
+  @RequestMapping(value = "/settings/{user}", method = RequestMethod.DELETE)
+  ResponseEntity<Void> delete(
+          @ApiParam(name = "user", value = "The user whose settings will be deleted", required = true)
+          @PathVariable String user)
+          throws RestException {
+    if (alertsUIService.deleteAlertsUIUserSettings(user)) {
+      return new ResponseEntity<>(HttpStatus.OK);
+    } else {
+      return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java
index 6bca938..b5f7765 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/UserController.java
@@ -26,11 +26,12 @@ import org.springframework.web.bind.annotation.RestController;
 import java.security.Principal;
 
 @RestController
+@RequestMapping("/api/v1/user")
 public class UserController {
 
   @ApiOperation(value = "Retrieves the current user")
   @ApiResponse(message = "Current user", code = 200)
-  @RequestMapping(value = "/api/v1/user", method = RequestMethod.GET)
+  @RequestMapping(method = RequestMethod.GET)
     public String user(Principal user) {
         return user.getName();
     }

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/repository/AlertProfileRepository.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/repository/AlertProfileRepository.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/repository/AlertProfileRepository.java
deleted file mode 100644
index 1466d90..0000000
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/repository/AlertProfileRepository.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.metron.rest.repository;
-
-import org.apache.metron.rest.model.AlertProfile;
-import org.springframework.data.repository.CrudRepository;
-
-public interface AlertProfileRepository extends CrudRepository<AlertProfile, String> {
-}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertService.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertService.java
deleted file mode 100644
index a5f244b..0000000
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertService.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-package org.apache.metron.rest.service;
-
-import java.util.List;
-import java.util.Map;
-import org.apache.metron.rest.RestException;
-import org.apache.metron.rest.model.AlertProfile;
-
-/**
- * This is a set of operations created to interact with alerts.
- */
-public interface AlertService {
-
-  void escalateAlerts(List<Map<String, Object>> alerts) throws RestException;
-
-  AlertProfile getProfile();
-
-  Iterable<AlertProfile> findAllProfiles();
-
-  AlertProfile saveProfile(AlertProfile alertsProfile);
-
-  boolean deleteProfile(String user);
-}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsProfileService.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsProfileService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsProfileService.java
deleted file mode 100644
index 84672b6..0000000
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsProfileService.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.metron.rest.service;
-
-import org.apache.metron.rest.model.AlertProfile;
-
-public interface AlertsProfileService {
-
-  AlertProfile get();
-
-  Iterable<AlertProfile> findAll();
-
-  AlertProfile save(AlertProfile alertsProfile);
-
-  boolean delete(String user);
-}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsUIService.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsUIService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsUIService.java
new file mode 100644
index 0000000..cd9ff9d
--- /dev/null
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/AlertsUIService.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.metron.rest.service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.metron.rest.RestException;
+import org.apache.metron.rest.model.AlertsUIUserSettings;
+
+/**
+ * This is a set of operations created to interact with alerts.
+ */
+public interface AlertsUIService {
+
+  void escalateAlerts(List<Map<String, Object>> alerts) throws RestException;
+
+  Optional<AlertsUIUserSettings> getAlertsUIUserSettings() throws RestException;
+
+  Map<String, AlertsUIUserSettings> findAllAlertsUIUserSettings() throws RestException;
+
+  void saveAlertsUIUserSettings(AlertsUIUserSettings userSettings) throws RestException;
+
+  boolean deleteAlertsUIUserSettings(String user);
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/UserService.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/UserService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/UserService.java
new file mode 100644
index 0000000..5873c80
--- /dev/null
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/UserService.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.metron.rest.service;
+
+import org.apache.metron.rest.RestException;
+
+import java.util.Map;
+
+public interface UserService {
+
+  String getUserSettings(String type) throws RestException;
+
+  Map<String, String> findAllUserSettings(String type) throws RestException;
+
+  void saveUserSettings(String settings, String type) throws RestException;
+
+  boolean deleteUserSettings(String user, String type);
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertServiceImpl.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertServiceImpl.java
deleted file mode 100644
index 73babbe..0000000
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertServiceImpl.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-package org.apache.metron.rest.service.impl;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import java.util.List;
-import java.util.Map;
-import org.apache.metron.common.utils.JSONUtils;
-import org.apache.metron.rest.MetronRestConstants;
-import org.apache.metron.rest.RestException;
-import org.apache.metron.rest.model.AlertProfile;
-import org.apache.metron.rest.repository.AlertProfileRepository;
-import org.apache.metron.rest.security.SecurityUtils;
-import org.apache.metron.rest.service.AlertService;
-import org.apache.metron.rest.service.KafkaService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.env.Environment;
-import org.springframework.dao.EmptyResultDataAccessException;
-import org.springframework.stereotype.Service;
-
-/**
- * The default service layer implementation of {@link AlertService}.
- *
- * @see AlertService
- */
-@Service
-public class AlertServiceImpl implements AlertService {
-
-  private Environment environment;
-  private final KafkaService kafkaService;
-  private AlertProfileRepository alertProfileRepository;
-
-  @Autowired
-  public AlertServiceImpl(final KafkaService kafkaService,
-                          final Environment environment,
-                          final AlertProfileRepository alertsProfileRepository) {
-    this.kafkaService = kafkaService;
-    this.environment = environment;
-    this.alertProfileRepository = alertsProfileRepository;
-  }
-
-  @Override
-  public void escalateAlerts(List<Map<String, Object>> alerts) throws RestException {
-    try {
-      for (Map<String, Object> alert : alerts) {
-        kafkaService.produceMessage(
-            environment.getProperty(MetronRestConstants.KAFKA_TOPICS_ESCALATION_PROPERTY),
-            JSONUtils.INSTANCE.toJSON(alert, false));
-      }
-    } catch (JsonProcessingException e) {
-      throw new RestException(e);
-    }
-  }
-
-  @Override
-  public AlertProfile getProfile() {
-    return alertProfileRepository.findOne(SecurityUtils.getCurrentUser());
-  }
-
-  @Override
-  public Iterable<AlertProfile> findAllProfiles() {
-    return alertProfileRepository.findAll();
-  }
-
-  @Override
-  public AlertProfile saveProfile(AlertProfile alertsProfile) {
-    String user = SecurityUtils.getCurrentUser();
-    alertsProfile.setId(user);
-    return alertProfileRepository.save(alertsProfile);
-  }
-
-  @Override
-  public boolean deleteProfile(String user) {
-    boolean success = true;
-    try {
-      alertProfileRepository.delete(user);
-    } catch (EmptyResultDataAccessException e) {
-      success = false;
-    }
-    return success;
-  }
-}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsProfileServiceImpl.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsProfileServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsProfileServiceImpl.java
deleted file mode 100644
index 239dbdc..0000000
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsProfileServiceImpl.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.metron.rest.service.impl;
-
-import org.apache.metron.rest.model.AlertProfile;
-import org.apache.metron.rest.repository.AlertProfileRepository;
-import org.apache.metron.rest.security.SecurityUtils;
-import org.apache.metron.rest.service.AlertsProfileService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.dao.EmptyResultDataAccessException;
-import org.springframework.stereotype.Service;
-
-@Service
-public class AlertsProfileServiceImpl implements AlertsProfileService {
-
-  private AlertProfileRepository alertsProfileRepository;
-
-  @Autowired
-  public AlertsProfileServiceImpl(AlertProfileRepository alertsProfileRepository) {
-    this.alertsProfileRepository = alertsProfileRepository;
-  }
-
-  @Override
-  public AlertProfile get() {
-    return alertsProfileRepository.findOne(SecurityUtils.getCurrentUser());
-  }
-
-  @Override
-  public Iterable<AlertProfile> findAll() {
-    return alertsProfileRepository.findAll();
-  }
-
-  @Override
-  public AlertProfile save(AlertProfile alertsProfile) {
-    String user = SecurityUtils.getCurrentUser();
-    alertsProfile.setId(user);
-    return alertsProfileRepository.save(alertsProfile);
-  }
-
-  @Override
-  public boolean delete(String user) {
-    boolean success = true;
-    try {
-      alertsProfileRepository.delete(user);
-    } catch (EmptyResultDataAccessException e) {
-      success = false;
-    }
-    return success;
-  }
-}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsUIServiceImpl.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsUIServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsUIServiceImpl.java
new file mode 100644
index 0000000..7d0a8f8
--- /dev/null
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/AlertsUIServiceImpl.java
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.metron.rest.service.impl;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.metron.common.utils.JSONUtils;
+import org.apache.metron.rest.MetronRestConstants;
+import org.apache.metron.rest.RestException;
+import org.apache.metron.rest.model.AlertsUIUserSettings;
+import org.apache.metron.hbase.client.UserSettingsClient;
+import org.apache.metron.rest.security.SecurityUtils;
+import org.apache.metron.rest.service.AlertsUIService;
+import org.apache.metron.rest.service.KafkaService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+
+/**
+ * The default service layer implementation of {@link AlertsUIService}.
+ *
+ * @see AlertsUIService
+ */
+@Service
+public class AlertsUIServiceImpl implements AlertsUIService {
+
+  public static final String ALERT_USER_SETTING_TYPE = "metron-alerts-ui";
+  public static ThreadLocal<ObjectMapper> _mapper = ThreadLocal.withInitial(() ->
+          new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL));
+
+  private Environment environment;
+  private final KafkaService kafkaService;
+  private UserSettingsClient userSettingsClient;
+
+  @Autowired
+  public AlertsUIServiceImpl(final KafkaService kafkaService,
+                             final Environment environment,
+                             final UserSettingsClient userSettingsClient) {
+    this.kafkaService = kafkaService;
+    this.environment = environment;
+    this.userSettingsClient = userSettingsClient;
+  }
+
+  @Override
+  public void escalateAlerts(List<Map<String, Object>> alerts) throws RestException {
+    try {
+      for (Map<String, Object> alert : alerts) {
+        kafkaService.produceMessage(
+            environment.getProperty(MetronRestConstants.KAFKA_TOPICS_ESCALATION_PROPERTY),
+            JSONUtils.INSTANCE.toJSON(alert, false));
+      }
+    } catch (JsonProcessingException e) {
+      throw new RestException(e);
+    }
+  }
+
+  @Override
+  public Optional<AlertsUIUserSettings> getAlertsUIUserSettings() throws RestException {
+    try {
+      Optional<String> alertUserSettings = userSettingsClient.findOne(SecurityUtils.getCurrentUser(), ALERT_USER_SETTING_TYPE);
+      if (alertUserSettings.isPresent()) {
+        return Optional.of(_mapper.get().readValue(alertUserSettings.get(), AlertsUIUserSettings.class));
+      } else {
+        return Optional.empty();
+      }
+    } catch (IOException e) {
+      throw new RestException(e);
+    }
+  }
+
+  @Override
+  public Map<String, AlertsUIUserSettings> findAllAlertsUIUserSettings() throws RestException {
+    Map<String, AlertsUIUserSettings> allAlertUserSettings = new HashMap<>();
+    try {
+      Map<String, Optional<String>> alertUserSettingsStrings = userSettingsClient.findAll(ALERT_USER_SETTING_TYPE);
+      for (Map.Entry<String, Optional<String>> entry: alertUserSettingsStrings.entrySet()) {
+        Optional<String> alertUserSettings = entry.getValue();
+        if (alertUserSettings.isPresent()) {
+          allAlertUserSettings.put(entry.getKey(), _mapper.get().readValue(alertUserSettings.get(), AlertsUIUserSettings.class));
+        }
+      }
+    } catch (IOException e) {
+      throw new RestException(e);
+    }
+    return allAlertUserSettings;
+  }
+
+  @Override
+  public void saveAlertsUIUserSettings(AlertsUIUserSettings alertsUIUserSettings) throws RestException{
+    String user = SecurityUtils.getCurrentUser();
+    try {
+      userSettingsClient.save(user, ALERT_USER_SETTING_TYPE, _mapper.get().writeValueAsString(alertsUIUserSettings));
+    } catch (IOException e) {
+      throw new RestException(e);
+    }
+  }
+
+  @Override
+  public boolean deleteAlertsUIUserSettings(String user) {
+    boolean success = true;
+    try {
+      userSettingsClient.delete(user, ALERT_USER_SETTING_TYPE);
+    } catch (IOException e) {
+      success = false;
+    }
+    return success;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java
index 7cee3cc..e5bab08 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SearchServiceImpl.java
@@ -20,9 +20,11 @@ package org.apache.metron.rest.service.impl;
 import static org.apache.metron.common.Constants.ERROR_TYPE;
 import static org.apache.metron.indexing.dao.MetaAlertDao.METAALERT_TYPE;
 import static org.apache.metron.rest.MetronRestConstants.INDEX_WRITER_NAME;
+import static org.apache.metron.rest.MetronRestConstants.SEARCH_FACET_FIELDS_SPRING_PROPERTY;
 
 import com.google.common.collect.Lists;
 import java.lang.invoke.MethodHandles;
+import java.util.Arrays;
 import org.apache.metron.indexing.dao.IndexDao;
 import org.apache.metron.indexing.dao.search.GetRequest;
 import org.apache.metron.indexing.dao.search.GroupRequest;
@@ -32,6 +34,8 @@ import org.apache.metron.indexing.dao.search.SearchRequest;
 import org.apache.metron.indexing.dao.search.SearchResponse;
 import org.apache.metron.indexing.dao.search.FieldType;
 import org.apache.metron.rest.RestException;
+import org.apache.metron.rest.model.AlertsUIUserSettings;
+import org.apache.metron.rest.service.AlertsUIService;
 import org.apache.metron.rest.service.SearchService;
 import org.apache.metron.rest.service.SensorIndexingConfigService;
 import org.slf4j.Logger;
@@ -53,12 +57,15 @@ public class SearchServiceImpl implements SearchService {
   private IndexDao dao;
   private Environment environment;
   private SensorIndexingConfigService sensorIndexingConfigService;
+  private AlertsUIService alertsUIService;
 
   @Autowired
-  public SearchServiceImpl(IndexDao dao, Environment environment, SensorIndexingConfigService sensorIndexingConfigService) {
+  public SearchServiceImpl(IndexDao dao, Environment environment,
+      SensorIndexingConfigService sensorIndexingConfigService, AlertsUIService alertsUIService) {
     this.dao = dao;
     this.environment = environment;
     this.sensorIndexingConfigService = sensorIndexingConfigService;
+    this.alertsUIService = alertsUIService;
   }
 
   @Override
@@ -70,6 +77,9 @@ public class SearchServiceImpl implements SearchService {
         indices.add(METAALERT_TYPE);
         searchRequest.setIndices(indices);
       }
+      if (searchRequest.getFacetFields() != null && searchRequest.getFacetFields().isEmpty()) {
+        searchRequest.setFacetFields(getDefaultFacetFields());
+      }
       return dao.search(searchRequest);
     }
     catch(InvalidSearchException ise) {
@@ -122,4 +132,14 @@ public class SearchServiceImpl implements SearchService {
     indices.remove(ERROR_TYPE);
     return indices;
   }
+
+  private List<String> getDefaultFacetFields() throws RestException {
+    Optional<AlertsUIUserSettings> alertUserSettings = alertsUIService.getAlertsUIUserSettings();
+    if (!alertUserSettings.isPresent() || alertUserSettings.get().getFacetFields() == null) {
+      String facetFieldsProperty = environment.getProperty(SEARCH_FACET_FIELDS_SPRING_PROPERTY, String.class, "");
+      return Arrays.asList(facetFieldsProperty.split(","));
+    } else {
+      return alertUserSettings.get().getFacetFields();
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/resources/application-test.yml
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/resources/application-test.yml b/metron-interface/metron-rest/src/main/resources/application-test.yml
index 3cca5e0..891f554 100644
--- a/metron-interface/metron-rest/src/main/resources/application-test.yml
+++ b/metron-interface/metron-rest/src/main/resources/application-test.yml
@@ -44,6 +44,8 @@ storm:
 search:
   max:
     results: 100
+  facet:
+    fields: ip_src_addr
 
 index:
   dao:

http://git-wip-us.apache.org/repos/asf/metron/blob/e22479e6/metron-interface/metron-rest/src/main/resources/application.yml
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/main/resources/application.yml b/metron-interface/metron-rest/src/main/resources/application.yml
index 03f4d72..3e75881 100644
--- a/metron-interface/metron-rest/src/main/resources/application.yml
+++ b/metron-interface/metron-rest/src/main/resources/application.yml
@@ -50,6 +50,8 @@ search:
   max:
     results: 1000
     groups: 1000
+  facet:
+    fields: source:type,ip_src_addr,ip_dst_addr,enrichments:geo:ip_dst_addr:country
 
 index:
   dao:
@@ -64,4 +66,9 @@ meta:
   # By default, we use the ElasticsearchMetaAlertDao
     impl: org.apache.metron.elasticsearch.dao.ElasticsearchMetaAlertDao
 
-spring.jpa.generate-ddl: true
\ No newline at end of file
+spring.jpa.generate-ddl: true
+
+user:
+  settings:
+    table: user_settings
+    cf: cf
\ No newline at end of file


Mime
View raw message