You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2017/09/22 02:10:29 UTC

[1/7] atlas git commit: ATLAS-2158: good coding practices

Repository: atlas
Updated Branches:
  refs/heads/branch-0.8 3aeba233d -> 2d0bc3c62


ATLAS-2158: good coding practices

Signed-off-by: Madhan Neethiraj <ma...@apache.org>


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

Branch: refs/heads/branch-0.8
Commit: 2d0bc3c62022ccdd52ff930b60aefe6200f22d71
Parents: 43ab507
Author: Ashutosh Mestry <am...@apache.org>
Authored: Thu Sep 21 14:45:59 2017 -0700
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Sep 21 19:10:04 2017 -0700

----------------------------------------------------------------------
 .../atlas/repository/impexp/ZipFileResourceTestUtils.java | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/2d0bc3c6/repository/src/test/java/org/apache/atlas/repository/impexp/ZipFileResourceTestUtils.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/impexp/ZipFileResourceTestUtils.java b/repository/src/test/java/org/apache/atlas/repository/impexp/ZipFileResourceTestUtils.java
index f0dab47..be8c004 100644
--- a/repository/src/test/java/org/apache/atlas/repository/impexp/ZipFileResourceTestUtils.java
+++ b/repository/src/test/java/org/apache/atlas/repository/impexp/ZipFileResourceTestUtils.java
@@ -75,6 +75,9 @@ public class ZipFileResourceTestUtils {
         File f = new File(filePath);
         String s = FileUtils.readFileToString(f);
         assertFalse(StringUtils.isEmpty(s), "Model file read correctly!");
+        if(StringUtils.isEmpty(s)) {
+            throw new IOException("Unable to read file: " + fileName);
+        }
 
         return s;
     }
@@ -138,9 +141,12 @@ public class ZipFileResourceTestUtils {
     }
 
     private static void createTypesAsNeeded(AtlasTypesDef typesFromJson, AtlasTypeDefStore typeDefStore, AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
-        AtlasTypesDef typesToCreate = AtlasTypeDefStoreInitializer.getTypesToCreate(typesFromJson, typeRegistry);
+        if(typesFromJson == null) {
+            return;
+        }
 
-        if (!typesToCreate.isEmpty()) {
+        AtlasTypesDef typesToCreate = AtlasTypeDefStoreInitializer.getTypesToCreate(typesFromJson, typeRegistry);
+        if (typesToCreate != null && !typesToCreate.isEmpty()) {
             typeDefStore.createTypesDef(typesToCreate);
         }
     }


[4/7] atlas git commit: ATLAS-2100: UserProfile & SavedSearch API implementation. Fixed accidentally deleted type.

Posted by ma...@apache.org.
ATLAS-2100: UserProfile & SavedSearch API implementation. Fixed accidentally deleted type.


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

Branch: refs/heads/branch-0.8
Commit: 2e138da48861f213fb415bf19af026b9821f5022
Parents: 3aeba23
Author: ashutoshm <am...@hortonworks.com>
Authored: Mon Sep 18 16:52:14 2017 -0700
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Sep 21 19:10:04 2017 -0700

----------------------------------------------------------------------
 addons/models/0010-base_model.json | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/2e138da4/addons/models/0010-base_model.json
----------------------------------------------------------------------
diff --git a/addons/models/0010-base_model.json b/addons/models/0010-base_model.json
index db95d7e..8f38f59 100644
--- a/addons/models/0010-base_model.json
+++ b/addons/models/0010-base_model.json
@@ -1,7 +1,23 @@
 {
   "enumDefs": [],
   "structDefs": [],
-  "classificationDefs": [],
+  "classificationDefs": [
+    {
+      "name": "TaxonomyTerm",
+      "superTypes": [],
+      "typeVersion": "1.0",
+      "attributeDefs": [
+        {
+          "name": "atlas.taxonomy",
+          "typeName": "string",
+          "cardinality": "SINGLE",
+          "isIndexable": false,
+          "isOptional": true,
+          "isUnique": false
+        }
+      ]
+    }
+  ],
   "entityDefs": [
     {
       "name": "Referenceable",


[2/7] atlas git commit: ATLAS-2150: UI to support search-history and favorites

Posted by ma...@apache.org.
ATLAS-2150: UI to support search-history and favorites

Signed-off-by: Madhan Neethiraj <ma...@apache.org>


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

Branch: refs/heads/branch-0.8
Commit: d0343f1048a4cd3de8e9440c1536bef5f82a6273
Parents: 466703f
Author: kevalbhatt <kb...@apache.org>
Authored: Wed Sep 20 23:50:42 2017 +0530
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Sep 21 19:10:04 2017 -0700

----------------------------------------------------------------------
 dashboardv2/public/css/scss/loader.scss         |   7 +
 dashboardv2/public/css/scss/tag.scss            |   5 +
 dashboardv2/public/css/scss/theme.scss          |  18 +-
 .../detail_page/DetailPageLayoutView_tmpl.html  |  26 +--
 .../entity/CreateEntityLayoutView_tmpl.html     |   8 +-
 .../profile/ProfileColumnLayoutView_tmpl.html   |   2 +-
 .../templates/search/SaveAsLayoutView_tmpl.html |  24 +++
 .../search/SaveSearchItemView_tmpl.html         |  28 ++++
 .../js/templates/search/SaveSearch_tmpl.html    |  29 ++++
 .../templates/search/SearchLayoutView_tmpl.html |   8 +-
 .../public/js/utils/CommonViewFunction.js       | 164 +++++++++++++++++--
 dashboardv2/public/js/utils/Enums.js            |  11 ++
 dashboardv2/public/js/utils/Messages.js         |  12 +-
 dashboardv2/public/js/utils/Overrides.js        |   7 +
 dashboardv2/public/js/utils/UrlLinks.js         |  10 +-
 .../public/js/views/search/QueryBuilderView.js  |   4 +-
 .../public/js/views/search/SaveAsLayoutView.js  |  97 +++++++++++
 .../js/views/search/SaveSearchItemView.js       | 127 ++++++++++++++
 .../public/js/views/search/SaveSearchView.js    | 143 ++++++++++++++++
 .../public/js/views/search/SearchLayoutView.js  | 100 ++++++++++-
 20 files changed, 778 insertions(+), 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/css/scss/loader.scss
----------------------------------------------------------------------
diff --git a/dashboardv2/public/css/scss/loader.scss b/dashboardv2/public/css/scss/loader.scss
index 43f15fd..d323212 100644
--- a/dashboardv2/public/css/scss/loader.scss
+++ b/dashboardv2/public/css/scss/loader.scss
@@ -63,6 +63,13 @@
     display: none;
 }
 
+.fontLoader-relative {
+    @extend .fontLoader;
+    position: relative;
+    left: 0%;
+    text-align: center;
+}
+
 .initialLoading {
     display: block;
     position: absolute;

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/css/scss/tag.scss
----------------------------------------------------------------------
diff --git a/dashboardv2/public/css/scss/tag.scss b/dashboardv2/public/css/scss/tag.scss
index 6556784..8b5e6e2 100644
--- a/dashboardv2/public/css/scss/tag.scss
+++ b/dashboardv2/public/css/scss/tag.scss
@@ -19,6 +19,10 @@
 //tag.scss
 .tag-tree {
     padding: 0; // overflow: auto;
+    &.saveSearchList {
+        height: 150px;
+        overflow-y: auto;
+    }
     >li {
         list-style: none;
         cursor: pointer;
@@ -52,6 +56,7 @@
                 display: none;
                 position: absolute;
                 right: 0;
+                color: $white;
                 padding: 5px 10px;
             }
         }

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/css/scss/theme.scss
----------------------------------------------------------------------
diff --git a/dashboardv2/public/css/scss/theme.scss b/dashboardv2/public/css/scss/theme.scss
index 26e507f..dc56148 100644
--- a/dashboardv2/public/css/scss/theme.scss
+++ b/dashboardv2/public/css/scss/theme.scss
@@ -84,6 +84,10 @@ header {
 #sideNav-wrapper {
     color: $white;
     font-size: 16px !important;
+    .well {
+        background-color: $color_tuna_approx;
+        border: 1px solid #666363;
+    }
 }
 
 .page-title {
@@ -272,17 +276,6 @@ hr[size="10"] {
     margin-right: 0px !important;
 }
 
-.backButton {
-    display: block;
-    margin: 0px 13px;
-    &:hover {
-        color: $color_jungle_green_approx;
-    }
-    &:active {
-        color: $color_jungle_green_approx;
-    }
-}
-
 .position-relative {
     position: relative;
 }
@@ -308,7 +301,8 @@ hr[size="10"] {
 
 .add-seperator {
     margin-bottom: 10px;
-    border-bottom: 1px solid $color_mirage_approx
+    border-bottom: 1px solid $color_mirage_approx;
+    padding-bottom: 10px;
 }
 
 .legend-sm {

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
index 21931e5..8acd8e4 100644
--- a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
@@ -20,7 +20,7 @@
     </div>
     <div class="entityDetail form-horizontal col-md-12">
         <div class="row">
-            <a href="javascript:void(0);" class="backButton" data-id="backButton"><i class="fa fa-chevron-left"></i>  Back To Results</a>
+            <a href="javascript:void(0);" data-id="backButton"><i class="fa fa-chevron-left"></i>  Back To Results</a>
         </div>
         <h1 class="form-group"><span  data-id="title"></span></h1> {{#if entityUpdate}}
         <div data-id="editButtonContainer" class="pull-right"></div>
@@ -95,43 +95,43 @@
                     </div>
                     <div class="tab-content">
                         <div id="tab-details" role="properties" class="tab-pane active">
-                            <div id="r_entityDetailTableLayoutView" style="position: relative;">
-                                <div class="fontLoader">
+                            <div id="r_entityDetailTableLayoutView">
+                                <div class="fontLoader-relative">
                                     <i class="fa fa-refresh fa-spin-custom"></i>
                                 </div>
                             </div>
                         </div>
                         <div id="tab-tagTable" role="tags" class="tab-pane fade">
-                            <div id="r_tagTableLayoutView" style="position: relative;">
-                                <div class="fontLoader">
+                            <div id="r_tagTableLayoutView">
+                                <div class="fontLoader-relative">
                                     <i class="fa fa-refresh fa-spin-custom"></i>
                                 </div>
                             </div>
                         </div>
                         <div id="tab-termTable" role="terms" class="tab-pane">
-                            <div id="r_termTableLayoutView" style="position: relative;">
-                                <div class="fontLoader">
+                            <div id="r_termTableLayoutView">
+                                <div class="fontLoader-relative">
                                     <i class="fa fa-refresh fa-spin-custom"></i>
                                 </div>
                             </div>
                         </div>
                         <div id="tab-audit" role="audits" class="tab-pane">
-                            <div id="r_auditTableLayoutView" style="position: relative;">
-                                <div class="fontLoader">
+                            <div id="r_auditTableLayoutView">
+                                <div class="fontLoader-relative">
                                     <i class="fa fa-refresh fa-spin-custom"></i>
                                 </div>
                             </div>
                         </div>
                         <div id="tab-schema" role="schema" class="tab-pane">
-                            <div id="r_schemaTableLayoutView" style="position: relative;">
-                                <div class="fontLoader">
+                            <div id="r_schemaTableLayoutView">
+                                <div class="fontLoader-relative">
                                     <i class="fa fa-refresh fa-spin-custom"></i>
                                 </div>
                             </div>
                         </div>
                         <div id="tab-profile" role="profile" class="tab-pane">
-                            <div id="r_profileLayoutView" style="position: relative;">
-                                <div class="fontLoader">
+                            <div id="r_profileLayoutView">
+                                <div class="fontLoader-relative">
                                     <i class="fa fa-refresh fa-spin-custom"></i>
                                 </div>
                             </div>

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/templates/entity/CreateEntityLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/templates/entity/CreateEntityLayoutView_tmpl.html b/dashboardv2/public/js/templates/entity/CreateEntityLayoutView_tmpl.html
index ef99f2d..55f70a1 100644
--- a/dashboardv2/public/js/templates/entity/CreateEntityLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/entity/CreateEntityLayoutView_tmpl.html
@@ -40,8 +40,6 @@
         <div class="col-md-12 entityInputData" data-id="entityInputData"></div>
     </div>
 </form>
-<div class="" style="position: relative;height: 8px;">
-    <div class="fontLoader entityLoader" style="display:none">
-        <i class="fa fa-refresh fa-spin-custom"></i>
-    </div>
-</div>
+<div class="fontLoader-relative entityLoader" style="display:none">
+    <i class="fa fa-refresh fa-spin-custom"></i>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/templates/profile/ProfileColumnLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/templates/profile/ProfileColumnLayoutView_tmpl.html b/dashboardv2/public/js/templates/profile/ProfileColumnLayoutView_tmpl.html
index 5215254..5903afb 100644
--- a/dashboardv2/public/js/templates/profile/ProfileColumnLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/profile/ProfileColumnLayoutView_tmpl.html
@@ -35,7 +35,7 @@
     <h4 class="col-md-12">{{typeObject.label}}</h4>
 </div>
 <div class="row">
-    <a href="javascript:void(0);" class="backButton" data-id="backToYear" style="display: none"><i class="fa fa-chevron-left"></i>  Back To Year</a>
+    <a href="javascript:void(0);" data-id="backToYear" style="display: none"><i class="fa fa-chevron-left"></i>  Back To Year</a>
 </div>
 </br>
 <div class="row">

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/templates/search/SaveAsLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/templates/search/SaveAsLayoutView_tmpl.html b/dashboardv2/public/js/templates/search/SaveAsLayoutView_tmpl.html
new file mode 100644
index 0000000..fd87d28
--- /dev/null
+++ b/dashboardv2/public/js/templates/search/SaveAsLayoutView_tmpl.html
@@ -0,0 +1,24 @@
+<!--
+ * 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.
+-->
+<form name="saveAsform" class="form-horizontal" data-id="">
+    <div class="form-group">
+        <label class="control-label col-sm-2 required" for="name">Name</label>
+        <div class="col-sm-10">
+            <input class="form-control" data-id="saveAsName" placeholder="Name(required)" autofocus/>
+        </div>
+    </div>
+</form>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/templates/search/SaveSearchItemView_tmpl.html
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/templates/search/SaveSearchItemView_tmpl.html b/dashboardv2/public/js/templates/search/SaveSearchItemView_tmpl.html
new file mode 100644
index 0000000..d84a2ef
--- /dev/null
+++ b/dashboardv2/public/js/templates/search/SaveSearchItemView_tmpl.html
@@ -0,0 +1,28 @@
+<!--
+ * 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.
+-->
+<!-- <div class="row">
+    <div class="col-md-10"><span>{{name}}</span></div>
+    <div class="col-md-2">
+        <button type="button" class="btn btn-danger btn-sm closeInput" data-id="close"><i class="fa fa-times"></i></button>
+    </div>
+</div> -->
+<div data-id="{{guid}}" class="item">
+    <div class="tools">
+        <i class="fa fa-ellipsis-h tagPopover" data-original-title="" title="" data-id=""></i>
+    </div>
+    <a href="javascript:void(0)">{{name}}</a>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/templates/search/SaveSearch_tmpl.html
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/templates/search/SaveSearch_tmpl.html b/dashboardv2/public/js/templates/search/SaveSearch_tmpl.html
new file mode 100644
index 0000000..0b20eb4
--- /dev/null
+++ b/dashboardv2/public/js/templates/search/SaveSearch_tmpl.html
@@ -0,0 +1,29 @@
+<!--
+ * 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.
+-->
+<div class="inline-content add-seperator">
+    <div class="inline">
+        <h4>Favorite Search</h4></div>
+    <div class="pull-right">
+        <button type="button" class="btn btn-action btn-sm" disabled="disabled" data-id="saveBtn">Save</button>
+        <button type="button" class="btn btn-action btn-sm" data-id="saveAsBtn">Save As</button>
+    </div>
+</div>
+<ul data-id="itemViewContent" class="tag-tree saveSearchList gray-text">
+    <div class="fontLoader-relative" style="display: block;">
+        <i class="fa fa-refresh fa-spin-custom"></i>
+    </div>
+</ul>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html b/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html
index cca5f27..9aa6e8d 100644
--- a/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html
@@ -31,7 +31,7 @@
             </div>
         </div>
     </div>
-    <div class="col-sm-12">
+    <div class="col-sm-12 form-group">
         <div class="form-group">
             <div class="srchType clearfix">
                 <span class="srchTitle">Search By Type</span>
@@ -64,4 +64,10 @@
         <button type="button" class="btn btn-atlas pull-right" data-id="searchBtn" disabled="disabled">Search</button>
     </div>
     <div id="searchResult"></div>
+    <div class="col-md-12">
+        <div class="col-md-12 well basicSaveSearch" data-id="r_saveSearchBasic"></div>
+    </div>
+    <div class="col-md-12">
+        <div class="col-md-12 well advanceSaveSearch" data-id="r_saveSearchAdvance" style="display: none"></div>
+    </div>
 </div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/utils/CommonViewFunction.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/CommonViewFunction.js b/dashboardv2/public/js/utils/CommonViewFunction.js
index dd7e360..0fa8506 100644
--- a/dashboardv2/public/js/utils/CommonViewFunction.js
+++ b/dashboardv2/public/js/utils/CommonViewFunction.js
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enums'], function(require, Utils, Modal, Messages, Enums) {
+define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enums', 'moment'], function(require, Utils, Modal, Messages, Enums, moment) {
     'use strict';
 
     var CommonViewFunction = {};
@@ -436,12 +436,110 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
             });
         })
     }
+    CommonViewFunction.generateObjectForSaveSearchApi = function(options) {
+        var obj = {
+            name: options.name,
+            searchParameters: {
+                excludeDeletedEntities: true
+            }
+        };
+        var value = options.value;
+        if (value) {
+            _.each(Enums.extractFromUrlForSearch, function(v, k) {
+                var val = value[k];
+                if (!_.isUndefinedNull(val)) {
+                    if (k == "attributes") {
+                        val = val.split(',');
+                    } else if (k == "tagFilters") {
+                        val = CommonViewFunction.attributeFilter.generateAPIObj(val);
+                    } else if (k == "entityFilters") {
+                        val = CommonViewFunction.attributeFilter.generateAPIObj(val);
+                    } else if (k == "includeDE") {
+                        if (val) {
+                            val = false;
+                        } else {
+                            val = true;
+                        }
+                    }
+                }
+                obj.searchParameters[v] = val;
+            });
+            return obj;
+        }
+    }
+    CommonViewFunction.generateUrlFromSaveSearchObject = function(options) {
+        var value = options.value,
+            classificationDefCollection = options.classificationDefCollection,
+            entityDefCollection = options.entityDefCollection,
+            obj = {};
+        if (value) {
+            _.each(Enums.extractFromUrlForSearch, function(v, k) {
+                var val = value[v];
+                if (!_.isUndefinedNull(val)) {
+                    if (k == "attributes") {
+                        val = val.join(',');
+                    } else if (k == "tagFilters") {
+                        if (classificationDefCollection) {
+                            var classificationDef = classificationDefCollection.fullCollection.findWhere({ 'name': value.classification })
+                            attributeDefs = Utils.getNestedSuperTypeObj({
+                                collection: classificationDefCollection,
+                                attrMerge: true,
+                                data: classificationDef.toJSON()
+                            });
+                            _.each(val.criterion, function(obj) {
+                                var attributeDef = _.findWhere(attributeDefs, { 'name': obj.attributeName });
+                                if (attributeDef) {
+                                    if (attributeDef.typeName == "date") {
+                                        obj.attributeValue = moment(parseInt(obj.attributeValue)).format('MM/DD/YYYY h:mm A');
+                                    }
+                                    obj['attributeType'] = attributeDef.typeName;
+                                }
+                            });
+                        }
+                        val = CommonViewFunction.attributeFilter.generateUrl(val.criterion);
+                    } else if (k == "entityFilters") {
+                        if (entityDefCollection) {
+                            var entityDef = entityDefCollection.fullCollection.findWhere({ 'name': value.typeName }),
+                                attributeDefs = Utils.getNestedSuperTypeObj({
+                                    collection: entityDefCollection,
+                                    attrMerge: true,
+                                    data: entityDef.toJSON()
+                                });
+                            _.each(val.criterion, function(obj) {
+                                var attributeDef = _.findWhere(attributeDefs, { 'name': obj.attributeName });
+                                if (attributeDef) {
+                                    if (attributeDef.typeName == "date") {
+                                        obj.attributeValue = moment(parseInt(obj.attributeValue)).format('MM/DD/YYYY h:mm A');
+                                    }
+                                    obj['attributeType'] = attributeDef.typeName;
+                                }
+                            });
+                        }
+                        val = CommonViewFunction.attributeFilter.generateUrl(val.criterion);
+                    } else if (k == "includeDE") {
+                        if (val) {
+                            val = false;
+                        } else {
+                            val = true;
+                        }
+                    }
+                }
+                obj[k] = val;
+            });
+            return obj;
+        }
+    }
     CommonViewFunction.attributeFilter = {
         generateUrl: function(attrObj) {
             var attrQuery = [];
             if (attrObj) {
                 _.each(attrObj, function(obj) {
-                    attrQuery.push(obj.id + "::" + obj.operator + "::" + obj.value + "::" + obj.type);
+                    var url = [(obj.id || obj.attributeName), mapApiOperatorToUI(obj.operator), (obj.value || obj.attributeValue)],
+                        type = (obj.type || obj.attributeType);
+                    if (type) {
+                        url.push(type);
+                    }
+                    attrQuery.push(url.join("::"));
                 });
                 if (attrQuery.length) {
                     return attrQuery.join();
@@ -451,13 +549,40 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
             } else {
                 return null;
             }
+
+            function mapApiOperatorToUI(oper) {
+                if (oper == "eq") {
+                    return "=";
+                } else if (oper == "neq") {
+                    return "!=";
+                } else if (oper == "lt") {
+                    return "<";
+                } else if (oper == "lte") {
+                    return "<=";
+                } else if (oper == "gt") {
+                    return ">";
+                } else if (oper == "gte") {
+                    return ">=";
+                } else if (oper == "startsWith") {
+                    return "begins_with";
+                } else if (oper == "endsWith") {
+                    return "ends_with";
+                } else if (oper == "contains") {
+                    return "contains";
+                }
+                return oper;
+            }
         },
         extractUrl: function(urlObj) {
             var attrObj = [];
             if (urlObj && urlObj.length) {
                 _.each(urlObj.split(","), function(obj) {
                     var temp = obj.split("::");
-                    attrObj.push({ id: temp[0], operator: temp[1], value: temp[2], type: temp[3] });
+                    var finalObj = { id: temp[0], operator: temp[1], value: temp[2] }
+                    if (temp[3]) {
+                        finalObj['type'] = temp[3];
+                    }
+                    attrObj.push(finalObj);
                 });
                 return attrObj;
             } else {
@@ -479,23 +604,38 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
                 var convertObj = [];
                 _.each(rules, function(rulObj) {
                     var tempObj = {};
-                    // For nested 
-                    // if (rulObj.rules) {
-                    //     tempObj = {
-                    //         "condition": "AND",
-                    //         "criterion": convertKeyAndExtractObj(rulObj.rules)
-                    //     }
-                    // } else {
-                    // }
                     tempObj = {
                         "attributeName": rulObj.id,
-                        "operator": rulObj.operator,
+                        "operator": mapUiOperatorToAPI(rulObj.operator),
                         "attributeValue": (rulObj.type === "date" ? Date.parse(rulObj.value) : rulObj.value)
                     }
                     convertObj.push(tempObj);
                 });
                 return convertObj;
             }
+
+            function mapUiOperatorToAPI(oper) {
+                if (oper == "=") {
+                    return "eq";
+                } else if (oper == "!=") {
+                    return "neq";
+                } else if (oper == "<") {
+                    return "lt";
+                } else if (oper == "<=") {
+                    return "lte";
+                } else if (oper == ">") {
+                    return "gt";
+                } else if (oper == ">=") {
+                    return "gte";
+                } else if (oper == "begins_with") {
+                    return "startsWith";
+                } else if (oper == "ends_with") {
+                    return "endsWith";
+                } else if (oper == "contains") {
+                    return "contains";
+                }
+                return oper;
+            }
         }
     }
     CommonViewFunction.addRestCsrfCustomHeader = function(xhr, settings) {

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/utils/Enums.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/Enums.js b/dashboardv2/public/js/utils/Enums.js
index db2c46c..78445e1 100644
--- a/dashboardv2/public/js/utils/Enums.js
+++ b/dashboardv2/public/js/utils/Enums.js
@@ -56,6 +56,17 @@ define(['require'], function(require) {
         'decile-frequency': "Decile Frequency Distribution",
         'annual': "Annual Distribution"
     }
+    Enums.extractFromUrlForSearch = {
+        "pageLimit": "limit",
+        "type": "typeName",
+        "tag": "classification",
+        "query": "query",
+        "pageOffset": "offset",
+        "includeDE": "excludeDeletedEntities",
+        "tagFilters": "tagFilters",
+        "entityFilters": "entityFilters",
+        "attributes": "attributes"
+    }
 
     return Enums;
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/utils/Messages.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/Messages.js b/dashboardv2/public/js/utils/Messages.js
index b91f940..feccdc0 100644
--- a/dashboardv2/public/js/utils/Messages.js
+++ b/dashboardv2/public/js/utils/Messages.js
@@ -33,14 +33,22 @@ define(['require'], function(require) {
         removeErrorMessage: " could not be removed",
         editSuccessMessage: " has been updated successfully",
         assignDeletedEntity: " is deleted, tag cannot be assigned",
+        conformation: {
+            deleteMessage: "Are you sure you want to delete "
+        },
         search: {
             noRecordForPage: "No record found at ",
-            onSamePage : "You are on the same page!"
+            onSamePage: "You are on the same page!",
+            favoriteSearch: {
+                save: "Do you want to overwrite ",
+                notSelectedFavoriteElement: "Please select any one favorite search",
+                notSelectedSearchFilter:"Please select at least one filter"
+            }
         },
         tag: {
             addAttributeSuccessMessage: "Tag attribute is added successfully",
             updateTagDescriptionMessage: "Tag description is updated successfully",
-            updateTermDescriptionMessage: "Term description is updated successfully",
+            updateTermDescriptionMessage: "Term description is updated successfully"
         }
     };
     return Messages;

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/utils/Overrides.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/Overrides.js b/dashboardv2/public/js/utils/Overrides.js
index 0be9a83..bdc15db 100644
--- a/dashboardv2/public/js/utils/Overrides.js
+++ b/dashboardv2/public/js/utils/Overrides.js
@@ -47,6 +47,13 @@ define(['require', 'utils/Utils', 'marionette', 'backgrid', 'asBreadcrumbs', 'jq
             } else {
                 return false;
             }
+        },
+        isUndefinedNull: function(val) {
+            if (_.isUndefined(val) || _.isNull(val)) {
+                return true
+            } else {
+                return false;
+            }
         }
     });
     var getPopoverEl = function(e) {

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/utils/UrlLinks.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/UrlLinks.js b/dashboardv2/public/js/utils/UrlLinks.js
index df20cf1..913df24 100644
--- a/dashboardv2/public/js/utils/UrlLinks.js
+++ b/dashboardv2/public/js/utils/UrlLinks.js
@@ -107,6 +107,14 @@ define(['require', 'utils/Enums'], function(require, Enums) {
                 return searchUrl;
             }
         },
+        saveSearchApiUrl: function(saveSearchType) {
+            var saveSearchUrl = this.searchApiUrl() + "/saved";
+            if (saveSearchType) {
+                return saveSearchUrl + '/' + saveSearchType;
+            } else {
+                return saveSearchUrl;
+            }
+        },
         versionApiUrl: function() {
             return this.baseUrl + '/admin/version';
         },
@@ -117,4 +125,4 @@ define(['require', 'utils/Enums'], function(require, Enums) {
     };
 
     return UrlLinks;
-});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/views/search/QueryBuilderView.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/views/search/QueryBuilderView.js b/dashboardv2/public/js/views/search/QueryBuilderView.js
index e94c05d..a6a1e3a 100644
--- a/dashboardv2/public/js/views/search/QueryBuilderView.js
+++ b/dashboardv2/public/js/views/search/QueryBuilderView.js
@@ -153,8 +153,8 @@ define(['require',
                         allow_groups: false,
                         allow_empty: true,
                         operators: [
-                            { type: '=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
-                            { type: '!=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+                            { type: '=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+                            { type: '!=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
                             { type: '>', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
                             { type: '<', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
                             { type: '>=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/views/search/SaveAsLayoutView.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/views/search/SaveAsLayoutView.js b/dashboardv2/public/js/views/search/SaveAsLayoutView.js
new file mode 100644
index 0000000..f4f4c68
--- /dev/null
+++ b/dashboardv2/public/js/views/search/SaveAsLayoutView.js
@@ -0,0 +1,97 @@
+/**
+ * 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.
+ */
+
+define(['require',
+    'backbone',
+    'hbs!tmpl/search/SaveAsLayoutView_tmpl',
+    'utils/Utils',
+    'modules/Modal',
+    'utils/UrlLinks',
+    'platform',
+    'models/VSearch',
+    'utils/CommonViewFunction',
+    'utils/Messages'
+], function(require, Backbone, SaveAsLayoutViewTmpl, Utils, Modal, UrlLinks, platform, VSearch, CommonViewFunction, Messages) {
+
+
+    var SaveAsLayoutView = Backbone.Marionette.LayoutView.extend({
+        _viewName: 'SaveAsLayoutView',
+        template: SaveAsLayoutViewTmpl,
+        regions: {},
+        ui: {
+            saveAsName: "[data-id='saveAsName']"
+        },
+        events: function() {
+            var events = {};
+            return events;
+        },
+        initialize: function(options) {
+            var that = this;
+            _.extend(this, _.pick(options, 'value', 'collection', 'searchVent', 'typeHeaders', 'fetchFavioriteCollection', 'getValue', 'isBasic'));
+
+            this.model = new VSearch();
+            var modal = new Modal({
+                title: 'Enter your search name',
+                content: this,
+                cancelText: "Cancel",
+                okCloses: false,
+                okText: 'Create',
+                allowCancel: true
+            }).open();
+            modal.$el.find('button.ok').attr("disabled", "true");
+            this.ui.saveAsName.on('keyup', function(e) {
+                modal.$el.find('button.ok').removeAttr("disabled");
+            });
+            this.ui.saveAsName.on('keyup', function(e) {
+                if ((e.keyCode == 8 || e.keyCode == 32 || e.keyCode == 46) && e.currentTarget.value.trim() == "") {
+                    modal.$el.find('button.ok').attr("disabled", "true");
+                }
+            });
+            modal.on('ok', function() {
+                modal.$el.find('button.ok').attr("disabled", "true");
+                that.onCreateButton(modal);
+            });
+            modal.on('closeModal', function() {
+                modal.trigger('cancel');
+            });
+        },
+        onCreateButton: function(modal) {
+            var that = this,
+                obj = { value: this.getValue(), name: this.ui.saveAsName.val() },
+                saveObj = CommonViewFunction.generateObjectForSaveSearchApi(obj);
+            if (this.isBasic) {
+                saveObj['searchType'] = "BASIC";
+            } else {
+                saveObj['searchType'] = "ADVANCED";
+            }
+            that.model.urlRoot = UrlLinks.saveSearchApiUrl();
+            that.model.save(saveObj, {
+                success: function(model, data) {
+                    if (that.collection) {
+                        that.collection.add(data);
+                    }
+                    Utils.notifySuccess({
+                        content: obj.name + Messages.addSuccessMessage
+                    });
+                }
+            });
+            modal.trigger('cancel');
+        }
+    });
+    return SaveAsLayoutView;
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/views/search/SaveSearchItemView.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/views/search/SaveSearchItemView.js b/dashboardv2/public/js/views/search/SaveSearchItemView.js
new file mode 100644
index 0000000..46704a9
--- /dev/null
+++ b/dashboardv2/public/js/views/search/SaveSearchItemView.js
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+define(['require',
+    'backbone',
+    'hbs!tmpl/search/SaveSearchItemView_tmpl',
+    'utils/UrlLinks',
+    'utils/Utils',
+    'utils/CommonViewFunction',
+    'utils/Messages'
+], function(require, Backbone, SaveSearchItemView_tmpl, UrlLinks, Utils, CommonViewFunction, Messages) {
+    'use strict';
+    return Backbone.Marionette.ItemView.extend({
+        template: SaveSearchItemView_tmpl,
+        tagName: 'li',
+        className: 'parent-node',
+        ui: {
+            stateChange: '.item',
+            tools: '.tools'
+        },
+        events: function() {
+            var events = {};
+            events['click ' + this.ui.stateChange] = 'stateChange';
+            events['click ' + this.ui.tools] = function(e) {
+                e.stopPropagation();
+            };
+            return events;
+        },
+        initialize: function(options) {
+            _.extend(this, _.pick(options, 'collection', 'typeHeaders', 'applyValue', 'fetchFavioriteCollection', 'isBasic', 'classificationDefCollection', 'entityDefCollection'));
+            this.model.id = this.model.get('guid');
+            this.model.idAttribute = 'guid';
+            this.searchTypeObj = {
+                'searchType': 'dsl',
+                'dslChecked': 'true'
+            }
+            if (this.isBasic) {
+                this.searchTypeObj.dslChecked = false;
+                this.searchTypeObj.searchType = 'basic';
+            }
+        },
+        onRender: function() {
+            this.showToolTip();
+        },
+        stateChange: function() {
+            this.applyValue(this.model, this.searchTypeObj);
+            this.trigger('item:clicked');
+            this.ui.stateChange.parent('li').addClass('active').siblings().removeClass('active');
+        },
+        showToolTip: function(e) {
+            var that = this;
+            Utils.generatePopover({
+                el: this.$('.tagPopover'),
+                container: this.$el,
+                popoverOptions: {
+                    content: function() {
+                        return "<ul class='saveSearchPopoverList'>" +
+                            "<li class='th' ><i class='fa fa-search'></i> <a href='javascript:void(0)' data-fn='onSearch'>Search </a></li>" +
+                            "<li class='listTerm' ><i class='fa fa-trash-o'></i> <a href='javascript:void(0)' data-fn='onDelete'>Delete</a></li>" +
+                            "</ul>";
+                    }
+                }
+            }).parent('div.tools').on('click', 'li', function(e) {
+                e.stopPropagation();
+                that.$('.tagPopover').popover('hide');
+                that[$(this).find('a').data('fn')](e)
+            });
+        },
+        onSearch: function() {
+            var searchParameters = this.model.toJSON().searchParameters,
+                params = CommonViewFunction.generateUrlFromSaveSearchObject({
+                    value: searchParameters,
+                    classificationDefCollection: this.classificationDefCollection,
+                    entityDefCollection: this.entityDefCollection
+                });
+            Utils.setUrl({
+                url: '#!/search/searchResult',
+                urlParams: _.extend(params, this.searchTypeObj),
+                mergeBrowserUrl: false,
+                trigger: true,
+                updateTabState: true
+            });
+        },
+        onDelete: function() {
+            var that = this;
+            var notifyObj = {
+                modal: true,
+                html: true,
+                text: Messages.conformation.deleteMessage + "<b>" + this.model.get('name') + "</b>" + " ?",
+                ok: function(argument) {
+                    that.onDeleteNotifyOk();
+                },
+                cancel: function(argument) {}
+            }
+            Utils.notifyConfirm(notifyObj);
+        },
+        onDeleteNotifyOk: function() {
+            var that = this;
+            this.model.urlRoot = UrlLinks.saveSearchApiUrl();
+            this.model.destroy({
+                wait: true,
+                success: function(model, data) {
+                    if (that.collection) {
+                        that.collection.remove(data);
+                    }
+                    Utils.notifySuccess({
+                        content: that.model.get('name') + Messages.deleteSuccessMessage
+                    });
+                }
+            });
+        }
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/views/search/SaveSearchView.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/views/search/SaveSearchView.js b/dashboardv2/public/js/views/search/SaveSearchView.js
new file mode 100644
index 0000000..aed8714
--- /dev/null
+++ b/dashboardv2/public/js/views/search/SaveSearchView.js
@@ -0,0 +1,143 @@
+/**
+ * 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.
+ */
+
+define(['require',
+    'backbone',
+    'hbs!tmpl/search/SaveSearch_tmpl',
+    'views/search/SaveSearchItemView',
+    'collection/VSearchList',
+    'utils/Utils',
+    'utils/UrlLinks',
+    'utils/CommonViewFunction',
+    'utils/Messages'
+], function(require, Backbone, SaveSearch_Tmpl, SaveSearchItemView, VSearchList, Utils, UrlLinks, CommonViewFunction, Messages) {
+    'use strict';
+
+    return Backbone.Marionette.CompositeView.extend({
+        template: SaveSearch_Tmpl,
+        childView: SaveSearchItemView,
+        childViewContainer: "[data-id='itemViewContent']",
+        ui: {
+            saveAs: "[data-id='saveAsBtn']",
+            save: "[data-id='saveBtn']"
+        },
+        childViewOptions: function() {
+            return {
+                collection: this.collection,
+                typeHeaders: this.typeHeaders,
+                applyValue: this.applyValue,
+                isBasic: this.isBasic,
+                classificationDefCollection: this.classificationDefCollection,
+                entityDefCollection: this.entityDefCollection,
+                fetchFavioriteCollection: this.fetchCollection.bind(this)
+            };
+        },
+        childEvents: function() {
+            return {
+                "item:clicked": function() {
+                    this.ui.save.attr('disabled', false);
+                }
+            }
+        },
+        events: function() {
+            var events = {};
+            events['click ' + this.ui.saveAs] = "saveAs";
+            events['click ' + this.ui.save] = "save";
+            return events;
+        },
+        initialize: function(options) {
+            var that = this;
+            _.extend(this, _.pick(options, 'collection', 'value', 'searchVent', 'typeHeaders', 'applyValue', 'getValue', 'isBasic', 'fetchCollection', 'classificationDefCollection', 'entityDefCollection'));
+        },
+        onRender: function() {
+            this.bindEvents();
+        },
+        bindEvents: function() {
+            this.listenTo(this.collection, "reset error", function(model, response) {
+                this.$('.fontLoader-relative').hide();
+                if (model && model.length) {
+                    this.$("[data-id='itemViewContent']").text("");
+                } else {
+                    this.$("[data-id='itemViewContent']").text("You don't have any favorite search.")
+                }
+            }, this);
+        },
+        saveAs: function(e) {
+            var that = this,
+                value = this.getValue();
+            if (value && (value.type || value.tag || value.query)) {
+                require([
+                    'views/search/SaveAsLayoutView'
+                ], function(SaveAsLayoutView) {
+                    new SaveAsLayoutView({ 'value': that.value, 'searchVent': that.searchVent, 'collection': that.collection, 'getValue': that.getValue, 'isBasic': that.isBasic });
+                });
+            } else {
+                Utils.notifyInfo({
+                    content: Messages.search.favoriteSearch.notSelectedSearchFilter
+                })
+            }
+        },
+        save: function() {
+            var that = this,
+                obj = {},
+                notifyObj = {
+                    modal: true,
+                    html: true,
+                    ok: function(argument) {
+                        that.onSaveNotifyOk(obj);
+                    },
+                    cancel: function(argument) {}
+                },
+                selectedEl = this.$('.saveSearchList li.active').find('div.item');
+            obj.name = selectedEl.find('a').text();
+            obj.id = selectedEl.data('id');
+            if (selectedEl && selectedEl.length) {
+                notifyObj['text'] = Messages.search.favoriteSearch.save + " <b>" + obj.name + "</b> ?";
+                Utils.notifyConfirm(notifyObj);
+            } else {
+                Utils.notifyInfo({
+                    content: Messages.search.favoriteSearch.notSelectedElement
+                })
+            }
+        },
+        onSaveNotifyOk: function(obj) {
+            var that = this
+            if (obj && obj.id) {
+                var model = new this.collection.model();
+                obj.value = this.getValue();
+                var saveObj = CommonViewFunction.generateObjectForSaveSearchApi(obj);
+                saveObj['guid'] = obj.id;
+                model.urlRoot = UrlLinks.saveSearchApiUrl();
+                model.save(saveObj, {
+                    type: 'PUT',
+                    success: function(model, data) {
+                        if (that.collection) {
+                            var collectionRef = that.collection.find({ guid: data.guid });
+                            if (collectionRef) {
+                                collectionRef.set(data);
+                            }
+                        }
+                        Utils.notifySuccess({
+                            content: obj.name + Messages.editSuccessMessage
+                        });
+                    }
+                });
+            }
+        }
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/d0343f10/dashboardv2/public/js/views/search/SearchLayoutView.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/views/search/SearchLayoutView.js b/dashboardv2/public/js/views/search/SearchLayoutView.js
index 602ecf8..6b839cd 100644
--- a/dashboardv2/public/js/views/search/SearchLayoutView.js
+++ b/dashboardv2/public/js/views/search/SearchLayoutView.js
@@ -22,8 +22,9 @@ define(['require',
     'utils/Utils',
     'utils/UrlLinks',
     'utils/Globals',
+    'collection/VSearchList',
     'utils/CommonViewFunction'
-], function(require, Backbone, SearchLayoutViewTmpl, Utils, UrlLinks, Globals, CommonViewFunction) {
+], function(require, Backbone, SearchLayoutViewTmpl, Utils, UrlLinks, Globals, VSearchList, CommonViewFunction) {
     'use strict';
 
     var SearchLayoutView = Backbone.Marionette.LayoutView.extend(
@@ -34,7 +35,10 @@ define(['require',
             template: SearchLayoutViewTmpl,
 
             /** Layout sub regions */
-            regions: {},
+            regions: {
+                RSaveSearchBasic: "[data-id='r_saveSearchBasic']",
+                RSaveSearchAdvance: "[data-id='r_saveSearchAdvance']"
+            },
 
             /** ui selector cache */
             ui: {
@@ -56,6 +60,8 @@ define(['require',
                     that = this;
                 events["keyup " + this.ui.searchInput] = function(e) {
                     var code = e.which;
+                    this.value.query = e.currentTarget.value;
+                    this.query[this.type].query = this.value.query;
                     if (code == 13) {
                         that.findSearchResult();
                     }
@@ -111,6 +117,69 @@ define(['require',
                 }
                 this.bindEvents();
             },
+            renderSaveSearch: function() {
+                var that = this;
+                require(['views/search/SaveSearchView'], function(SaveSearchView) {
+                    var saveSearchBaiscCollection = new VSearchList(),
+                        saveSearchAdvanceCollection = new VSearchList(),
+                        saveSearchCollection = new VSearchList();
+                    saveSearchCollection.url = UrlLinks.saveSearchApiUrl();
+                    var obj = {
+                        value: that.value,
+                        searchVent: that.searchVent,
+                        typeHeaders: that.typeHeaders,
+                        fetchCollection: fetchSaveSearchCollection,
+                        classificationDefCollection: that.classificationDefCollection,
+                        entityDefCollection: that.entityDefCollection,
+                        getValue: function() {
+                            var queryObj = that.query[that.type],
+                                entityObj = that.searchTableFilters['entityFilters'],
+                                tagObj = that.searchTableFilters['tagFilters'],
+                                urlObj = Utils.getUrlState.getQueryParams();
+                            if (urlObj) {
+                                if (urlObj.includeDE == "true") {
+                                    urlObj.includeDE = true;
+                                } else {
+                                    urlObj.includeDE = false;
+                                }
+                            }
+                            return _.extend({}, queryObj, urlObj, {
+                                'entityFilters': entityObj ? entityObj[queryObj.type] : null,
+                                'tagFilters': tagObj ? tagObj[queryObj.tag] : null,
+                                'type': queryObj.type,
+                                'query': queryObj.query,
+                                'tag': queryObj.tag
+                            })
+                        },
+                        applyValue: function(model, searchType) {
+                            that.manualRender(_.extend(searchType, CommonViewFunction.generateUrlFromSaveSearchObject({
+                                value: model.get('searchParameters'),
+                                classificationDefCollection: that.classificationDefCollection,
+                                entityDefCollection: that.entityDefCollection
+                            })));
+                        }
+                    }
+                    that.RSaveSearchBasic.show(new SaveSearchView(_.extend(obj, {
+                        isBasic: true,
+                        collection: saveSearchBaiscCollection
+                    })));
+                    that.RSaveSearchAdvance.show(new SaveSearchView(_.extend(obj, {
+                        isBasic: false,
+                        collection: saveSearchAdvanceCollection
+                    })));
+
+                    function fetchSaveSearchCollection() {
+                        saveSearchCollection.fetch({
+                            success: function(collection, data) {
+                                saveSearchAdvanceCollection.reset(_.where(data, { "searchType": "ADVANCED" }));
+                                saveSearchBaiscCollection.reset(_.where(data, { "searchType": "BASIC" }));
+                            },
+                            silent: true
+                        });
+                    }
+                    fetchSaveSearchCollection();
+                });
+            },
             bindEvents: function(param) {
                 this.listenTo(this.typeHeaders, "reset", function(value) {
                     this.renderTypeTagList();
@@ -189,12 +258,26 @@ define(['require',
                                 _.extend(this.value, temp);
                                 // on change of type/tag change the offset.
                                 this.query[this.type].pageOffset = 0;
+                                _.extend(this.query[this.type], temp);
                             } else {
                                 // Initial loading handle.
                                 var filterObj = this.searchTableFilters[filterType];
                                 if (filterObj && this.value[key]) {
                                     this.searchTableFilters[filterType][this.value[key]] = this.value[filterType] ? this.value[filterType] : null;
                                 }
+                                if (this.value.type) {
+                                    if (this.value.attributes) {
+                                        var attributes = _.sortBy(this.value.attributes.split(',')),
+                                            tableColumn = this.searchTableColumns[this.value.type];
+                                        if (_.isEmpty(this.searchTableColumns) || !tableColumn) {
+                                            this.searchTableColumns[this.value.type] = attributes
+                                        } else if (tableColumn.join(",") !== attributes.join(",")) {
+                                            this.searchTableColumns[this.value.type] = attributes;
+                                        }
+                                    } else if (this.searchTableColumns[this.value.type]) {
+                                        this.searchTableColumns[this.value.type] = undefined;
+                                    }
+                                }
                             }
                             this.makeFilterButtonActive(filterType);
                         } else {
@@ -229,6 +312,7 @@ define(['require',
                     placeholder: "Select",
                     allowClear: true
                 });
+                this.renderSaveSearch();
             },
             updateQueryObject: function(param) {
                 if (param && param.searchType) {
@@ -427,7 +511,7 @@ define(['require',
                     this.query[this.type].pageLimit = this.value.pageLimit;
                 }
                 if (this.value.pageOffset) {
-                    if (this.query[this.type].query != value) {
+                    if (this.query[this.type].query && this.query[this.type].query != value) {
                         this.query[this.type].pageOffset = 0;
                     } else {
                         this.query[this.type].pageOffset = this.value.pageOffset;
@@ -455,11 +539,15 @@ define(['require',
                     this.$('.temFilterBtn').hide();
                     this.$('.temFilter').addClass('col-sm-12');
                     this.$('.temFilter').removeClass('col-sm-10');
+                    this.$('.basicSaveSearch').hide();
+                    this.$('.advanceSaveSearch').show();
                 } else {
                     this.$('.temFilter').addClass('col-sm-10');
                     this.$('.temFilter').removeClass('col-sm-12');
                     this.$('.temFilterBtn').show();
                     this.$('.tagBox').show();
+                    this.$('.basicSaveSearch').show();
+                    this.$('.advanceSaveSearch').hide();
                     this.dsl = false;
                     this.type = "basic";
                 }
@@ -485,6 +573,12 @@ define(['require',
                 this.ui.typeLov.val("").trigger("change");
                 this.ui.tagLov.val("").trigger("change");
                 this.ui.searchInput.val("");
+                var type = "basicSaveSearch";
+                if (this.type == "dsl") {
+                    type = "advanceSaveSearch";
+                }
+                this.$('.' + type + ' .saveSearchList').find('li.active').removeClass('active');
+                this.$('.' + type + ' [data-id="saveBtn"]').attr('disabled', true);
                 if (!this.dsl) {
                     this.searchTableFilters.tagFilters = {};
                     this.searchTableFilters.entityFilters = {};


[6/7] atlas git commit: ATLAS-2157: HiveHook fix to handle getTable() error for temproray tables

Posted by ma...@apache.org.
ATLAS-2157: HiveHook fix to handle getTable() error for temproray tables

(cherry picked from commit baccd1d8d768cc9e4650c3b39383c304e936e503)


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

Branch: refs/heads/branch-0.8
Commit: 43ab507b35a1d4c4ee49a7c40ddf1e08a44130ab
Parents: d0343f1
Author: Madhan Neethiraj <ma...@apache.org>
Authored: Wed Sep 20 16:12:23 2017 -0700
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Sep 21 19:10:04 2017 -0700

----------------------------------------------------------------------
 .../org/apache/atlas/hive/hook/HiveHook.java    | 93 +++++++++++++-------
 1 file changed, 63 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/43ab507b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/HiveHook.java
----------------------------------------------------------------------
diff --git a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/HiveHook.java b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/HiveHook.java
index 7dc2e2f..aca5645 100755
--- a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/HiveHook.java
+++ b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/HiveHook.java
@@ -526,12 +526,14 @@ public class HiveHook extends AtlasHook implements ExecuteWithHookContext {
             Database db = null;
             Table table = null;
             Partition partition = null;
-            LinkedHashMap<Type, Referenceable> result = new LinkedHashMap<>();
-            List<Referenceable> entities = new ArrayList<>();
 
             switch (entity.getType()) {
                 case DATABASE:
                     db = entity.getDatabase();
+
+                    if (db != null) {
+                        db = dgiBridge.hiveClient.getDatabase(db.getName());
+                    }
                     break;
 
                 case TABLE:
@@ -549,40 +551,47 @@ public class HiveHook extends AtlasHook implements ExecuteWithHookContext {
                     LOG.info("{}: entity-type not handled by Atlas hook. Ignored", entity.getType());
             }
 
-            if (db != null) {
-                db = dgiBridge.hiveClient.getDatabase(db.getName());
-            }
+            Referenceable dbEntity    = null;
+            Referenceable tableEntity = null;
 
             if (db != null) {
-                Referenceable dbEntity = dgiBridge.createDBInstance(db);
-
-                entities.add(dbEntity);
-                result.put(Type.DATABASE, dbEntity);
+                dbEntity = dgiBridge.createDBInstance(db);
+            }
 
-                Referenceable tableEntity = null;
+            if (db != null && table != null) {
+                if (existTable != null) {
+                    table = existTable;
+                } else {
+                    table = refreshTable(dgiBridge, table.getDbName(), table.getTableName());
+                }
 
                 if (table != null) {
-                    if (existTable != null) {
-                        table = existTable;
-                    } else {
-                        table = dgiBridge.hiveClient.getTable(table.getDbName(), table.getTableName());
-                    }
-                    //If its an external table, even though the temp table skip flag is on,
-                    // we create the table since we need the HDFS path to temp table lineage.
-                    if (skipTempTables &&
-                            table.isTemporary() &&
-                            !TableType.EXTERNAL_TABLE.equals(table.getTableType())) {
-                        LOG.debug("Skipping temporary table registration {} since it is not an external table {} ", table.getTableName(), table.getTableType().name());
-
+                    // If its an external table, even though the temp table skip flag is on, we create the table since we need the HDFS path to temp table lineage.
+                    if (skipTempTables && table.isTemporary() && !TableType.EXTERNAL_TABLE.equals(table.getTableType())) {
+                        LOG.warn("Skipping temporary table registration {} since it is not an external table {} ", table.getTableName(), table.getTableType().name());
                     } else {
                         tableEntity = dgiBridge.createTableInstance(dbEntity, table);
-                        entities.add(tableEntity);
-                        result.put(Type.TABLE, tableEntity);
                     }
                 }
+            }
+
+            LinkedHashMap<Type, Referenceable> result   = new LinkedHashMap<>();
+            List<Referenceable>                entities = new ArrayList<>();
+
+            if (dbEntity != null) {
+                result.put(Type.DATABASE, dbEntity);
+                entities.add(dbEntity);
+            }
 
+            if (tableEntity != null) {
+                result.put(Type.TABLE, tableEntity);
+                entities.add(tableEntity);
+            }
+
+            if (!entities.isEmpty()) {
                 event.addMessage(new HookNotification.EntityUpdateRequest(event.getUser(), entities));
             }
+
             return result;
         }
         catch(Exception e) {
@@ -709,7 +718,11 @@ public class HiveHook extends AtlasHook implements ExecuteWithHookContext {
                 final String tblQFName = HiveMetaStoreBridge.getTableQualifiedName(dgiBridge.getClusterName(), entity.getTable());
                 if (!dataSetsProcessed.contains(tblQFName)) {
                     LinkedHashMap<Type, Referenceable> result = createOrUpdateEntities(dgiBridge, event, entity, false);
-                    dataSets.put(entity, result.get(Type.TABLE));
+
+                    if (result.get(Type.TABLE) != null) {
+                        dataSets.put(entity, result.get(Type.TABLE));
+                    }
+
                     dataSetsProcessed.add(tblQFName);
                     entities.addAll(result.values());
                 }
@@ -760,7 +773,7 @@ public class HiveHook extends AtlasHook implements ExecuteWithHookContext {
 
         //Refresh to get the correct location
         if(hiveTable != null) {
-            hiveTable = dgiBridge.hiveClient.getTable(hiveTable.getDbName(), hiveTable.getTableName());
+            hiveTable = refreshTable(dgiBridge, hiveTable.getDbName(), hiveTable.getTableName());
         }
 
         if (hiveTable != null && TableType.EXTERNAL_TABLE.equals(hiveTable.getTableType())) {
@@ -951,12 +964,17 @@ public class HiveHook extends AtlasHook implements ExecuteWithHookContext {
                             LOG.debug("Skipping dfs dir input addition to process qualified name {} ", input.getName());
                         } else if (refs.containsKey(input)) {
                             if ( input.getType() == Type.PARTITION || input.getType() == Type.TABLE) {
-                                final Date createTime = HiveMetaStoreBridge.getTableCreatedTime(hiveBridge.hiveClient.getTable(input.getTable().getDbName(), input.getTable().getTableName()));
-                                addDataset(buffer, refs.get(input), createTime.getTime());
+                                Table inputTable = refreshTable(hiveBridge, input.getTable().getDbName(), input.getTable().getTableName());
+
+                                if (inputTable != null) {
+                                    final Date createTime = HiveMetaStoreBridge.getTableCreatedTime(inputTable);
+                                    addDataset(buffer, refs.get(input), createTime.getTime());
+                                }
                             } else {
                                 addDataset(buffer, refs.get(input));
                             }
                         }
+
                         dataSetsProcessed.add(input.getName().toLowerCase());
                     }
                 }
@@ -995,12 +1013,17 @@ public class HiveHook extends AtlasHook implements ExecuteWithHookContext {
                             LOG.debug("Skipping dfs dir output addition to process qualified name {} ", output.getName());
                         } else if (refs.containsKey(output)) {
                             if ( output.getType() == Type.PARTITION || output.getType() == Type.TABLE) {
-                                final Date createTime = HiveMetaStoreBridge.getTableCreatedTime(hiveBridge.hiveClient.getTable(output.getTable().getDbName(), output.getTable().getTableName()));
-                                addDataset(buffer, refs.get(output), createTime.getTime());
+                                Table outputTable = refreshTable(hiveBridge, output.getTable().getDbName(), output.getTable().getTableName());
+
+                                if (outputTable != null) {
+                                    final Date createTime = HiveMetaStoreBridge.getTableCreatedTime(outputTable);
+                                    addDataset(buffer, refs.get(output), createTime.getTime());
+                                }
                             } else {
                                 addDataset(buffer, refs.get(output));
                             }
                         }
+
                         dataSetsProcessed.add(output.getName().toLowerCase());
                     }
                 }
@@ -1008,6 +1031,16 @@ public class HiveHook extends AtlasHook implements ExecuteWithHookContext {
         }
     }
 
+    private static Table refreshTable(HiveMetaStoreBridge dgiBridge, String dbName, String tableName) {
+        try {
+            return dgiBridge.hiveClient.getTable(dbName, tableName);
+        } catch (HiveException excp) { // this might be the case for temp tables
+            LOG.warn("failed to get details for table {}.{}. Ignoring. {}: {}", dbName, tableName, excp.getClass().getCanonicalName(), excp.getMessage());
+        }
+
+        return null;
+    }
+
     private static boolean addQueryType(HiveOperation op, WriteEntity entity) {
         if (entity.getWriteType() != null && HiveOperation.QUERY.equals(op)) {
             switch (entity.getWriteType()) {


[7/7] atlas git commit: ATLAS-2121: basic-search update to use case-sensitive filter for type-name / tag-name

Posted by ma...@apache.org.
ATLAS-2121: basic-search update to use case-sensitive filter for type-name / tag-name

Signed-off-by: Madhan Neethiraj <ma...@apache.org>
(cherry picked from commit c0f0abc13037a9d05499dbce2d0e1b65beb9d656)


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

Branch: refs/heads/branch-0.8
Commit: 466703fe86df3db0f203cbda5847dfbfc160b5af
Parents: 4f1129b
Author: apoorvnaik <ap...@apache.org>
Authored: Tue Sep 19 11:57:01 2017 -0700
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Sep 21 19:10:04 2017 -0700

----------------------------------------------------------------------
 .../discovery/ClassificationSearchProcessor.java   | 10 +++++++++-
 .../atlas/discovery/EntitySearchProcessor.java     | 17 +++++++++--------
 2 files changed, 18 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/466703fe/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java b/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java
index 1d4815d..776f5bf 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java
@@ -34,6 +34,7 @@ import org.apache.atlas.util.SearchPredicateUtil;
 import org.apache.atlas.utils.AtlasPerfTracer;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.Predicate;
+import org.apache.commons.collections.PredicateUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -93,7 +94,14 @@ public class ClassificationSearchProcessor extends SearchProcessor {
 
             this.indexQuery = graph.indexQuery(Constants.VERTEX_INDEX, indexQueryString);
 
-            inMemoryPredicate = constructInMemoryPredicate(classificationType, filterCriteria, indexAttributes);
+            Predicate typeNamePredicate  = SearchPredicateUtil.getINPredicateGenerator()
+                                                              .generatePredicate(Constants.TYPE_NAME_PROPERTY_KEY, typeAndSubTypes, String.class);
+            Predicate attributePredicate = constructInMemoryPredicate(classificationType, filterCriteria, indexAttributes);
+            if (attributePredicate != null) {
+                inMemoryPredicate = PredicateUtils.andPredicate(typeNamePredicate, attributePredicate);
+            } else {
+                inMemoryPredicate = typeNamePredicate;
+            }
         } else {
             indexQuery = null;
         }

http://git-wip-us.apache.org/repos/asf/atlas/blob/466703fe/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java b/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java
index 970cd28..87efed7 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java
@@ -80,12 +80,20 @@ public class EntitySearchProcessor extends SearchProcessor {
 
         if (typeSearchByIndex) {
             constructTypeTestQuery(indexQuery, typeAndSubTypesQryStr);
+
+            // TypeName check to be done in-memory as well to address ATLAS-2121 (case sensitivity)
+            inMemoryPredicate = typeNamePredicate;
         }
 
         if (attrSearchByIndex) {
             constructFilterQuery(indexQuery, entityType, filterCriteria, indexAttributes);
 
-            inMemoryPredicate = constructInMemoryPredicate(entityType, filterCriteria, indexAttributes);
+            Predicate attributePredicate = constructInMemoryPredicate(entityType, filterCriteria, indexAttributes);
+            if (inMemoryPredicate != null) {
+                inMemoryPredicate = PredicateUtils.andPredicate(inMemoryPredicate, attributePredicate);
+            } else {
+                inMemoryPredicate = attributePredicate;
+            }
         } else {
             graphAttributes.addAll(indexAttributes);
         }
@@ -110,13 +118,6 @@ public class EntitySearchProcessor extends SearchProcessor {
 
             if (!typeSearchByIndex) {
                 query.in(Constants.TYPE_NAME_PROPERTY_KEY, typeAndSubTypes);
-
-                // Construct a parallel in-memory predicate
-                if (graphQueryPredicate != null) {
-                    graphQueryPredicate = PredicateUtils.andPredicate(graphQueryPredicate, typeNamePredicate);
-                } else {
-                    graphQueryPredicate = typeNamePredicate;
-                }
             }
 
             // If we need to filter on the trait names then we need to build the query and equivalent in-memory predicate


[5/7] atlas git commit: ATLAS-2148: saved-search API enhancement to support searchType

Posted by ma...@apache.org.
ATLAS-2148: saved-search API enhancement to support searchType

Signed-off-by: Madhan Neethiraj <ma...@apache.org>


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

Branch: refs/heads/branch-0.8
Commit: 4f1129bdb70bb143db7fbc2f09b0f914db3c43d9
Parents: ceb5c0c
Author: ashutoshm <am...@hortonworks.com>
Authored: Tue Sep 19 16:20:52 2017 -0700
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Sep 21 19:10:04 2017 -0700

----------------------------------------------------------------------
 addons/models/0010-base_model.json              |   8 ++
 .../model/profile/AtlasUserSavedSearch.java     |  35 +++++-
 .../atlas/discovery/AtlasDiscoveryService.java  |  15 ++-
 .../atlas/discovery/EntityDiscoveryService.java |  23 +++-
 .../repository/ogm/AtlasSavedSearchDTO.java     |   5 +-
 .../apache/atlas/repository/ogm/DataAccess.java |   2 +-
 .../userprofile/UserProfileService.java         |  23 ++--
 .../userprofile/UserProfileServiceTest.java     |  47 ++++---
 .../apache/atlas/web/rest/DiscoveryREST.java    | 126 ++++++++++++++-----
 9 files changed, 215 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/addons/models/0010-base_model.json
----------------------------------------------------------------------
diff --git a/addons/models/0010-base_model.json b/addons/models/0010-base_model.json
index 8f38f59..0a0244c 100644
--- a/addons/models/0010-base_model.json
+++ b/addons/models/0010-base_model.json
@@ -185,6 +185,14 @@
           "isUnique": true
         },
         {
+          "name": "searchType",
+          "typeName": "string",
+          "cardinality": "SINGLE",
+          "isIndexable": true,
+          "isOptional": false,
+          "isUnique": false
+        },
+        {
           "name": "searchParameters",
           "typeName": "string",
           "cardinality": "SINGLE",

http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/intg/src/main/java/org/apache/atlas/model/profile/AtlasUserSavedSearch.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/model/profile/AtlasUserSavedSearch.java b/intg/src/main/java/org/apache/atlas/model/profile/AtlasUserSavedSearch.java
index b0698fc..8ecd52d 100644
--- a/intg/src/main/java/org/apache/atlas/model/profile/AtlasUserSavedSearch.java
+++ b/intg/src/main/java/org/apache/atlas/model/profile/AtlasUserSavedSearch.java
@@ -34,26 +34,41 @@ import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.PUBLIC_ONL
 public class AtlasUserSavedSearch extends AtlasBaseModelObject implements Serializable {
     private static final long serialVersionUID = 1L;
 
+    public enum SavedSearchType {
+        BASIC,
+        ADVANCED;
+
+        public static SavedSearchType to(String val) {
+            return SavedSearchType.ADVANCED.name().equalsIgnoreCase(val) ? SavedSearchType.ADVANCED : SavedSearchType.BASIC;
+        }
+    }
+
     private String           ownerName;
     private String           name;
+    private SavedSearchType  searchType;
     private SearchParameters searchParameters;
 
 
     public AtlasUserSavedSearch() {
-        this(null, null, null);
+        this(null, null, SavedSearchType.BASIC, null);
     }
 
-    public AtlasUserSavedSearch(String name, SearchParameters searchParameters) {
-        this(null, name, searchParameters);
+    public AtlasUserSavedSearch(String name, SavedSearchType searchType, SearchParameters searchParameters) {
+        this(null, name, searchType, searchParameters);
     }
 
     public AtlasUserSavedSearch(String ownerName, String name) {
-        this(ownerName, name, null);
+        this(ownerName, name, SavedSearchType.BASIC, null);
+    }
+
+    public AtlasUserSavedSearch(String ownerName, String name, SavedSearchType searchType) {
+        this(ownerName, name, searchType, null);
     }
 
-    public AtlasUserSavedSearch(String ownerName, String name, SearchParameters searchParameters) {
+    public AtlasUserSavedSearch(String ownerName, String name, SavedSearchType savedSearchType, SearchParameters searchParameters) {
         setOwnerName(ownerName);
         setName(name);
+        setSearchType(savedSearchType);
         setSearchParameters(searchParameters);
     }
 
@@ -74,6 +89,14 @@ public class AtlasUserSavedSearch extends AtlasBaseModelObject implements Serial
         this.name = name;
     }
 
+    public SavedSearchType getSearchType() {
+        return searchType;
+    }
+
+    public void setSearchType(SavedSearchType searchType) {
+        this.searchType = searchType;
+    }
+
     public SearchParameters getSearchParameters() {
         return searchParameters;
     }
@@ -82,11 +105,11 @@ public class AtlasUserSavedSearch extends AtlasBaseModelObject implements Serial
         this.searchParameters = searchParameters;
     }
 
-
     @Override
     public StringBuilder toString(StringBuilder sb) {
         sb.append(", ownerName=").append(ownerName);
         sb.append(", name=").append(name);
+        sb.append(", searchType=").append(searchType);
         sb.append(", searchParameters=");
         if (searchParameters == null) {
             sb.append("null");

http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java b/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java
index baaee85..630e776 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java
@@ -24,6 +24,7 @@ import org.apache.atlas.exception.AtlasBaseException;
 import org.apache.atlas.model.discovery.AtlasSearchResult;
 import org.apache.atlas.model.discovery.SearchParameters;
 import org.apache.atlas.model.profile.AtlasUserSavedSearch;
+import org.apache.atlas.model.profile.AtlasUserSavedSearch.SavedSearchType;
 
 import java.util.List;
 
@@ -89,14 +90,14 @@ public interface AtlasDiscoveryService {
      * @param savedSearch Search to be saved
      * @throws AtlasBaseException
      */
-    void addSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException;
+    AtlasUserSavedSearch addSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException;
 
     /**
      *
      * @param savedSearch Search to be saved
      * @throws AtlasBaseException
      */
-    void updateSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException;
+    AtlasUserSavedSearch updateSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException;
 
     /**
      *
@@ -108,12 +109,20 @@ public interface AtlasDiscoveryService {
 
     /**
      *
+     * @param guid Guid for the saved search
+     * @return Search object identified by the guid
+     * @throws AtlasBaseException
+     */
+    AtlasUserSavedSearch getSavedSearch(String guid) throws AtlasBaseException;
+
+    /**
+     *
      * @param userName Name of the user who the search belongs
      * @param searchName Name of the search to be retrieved
      * @return Search object identified by the name
      * @throws AtlasBaseException
      */
-    AtlasUserSavedSearch getSavedSearch(String userName, String searchName) throws AtlasBaseException;
+    AtlasUserSavedSearch getSavedSearch(String userName, String searchName, SavedSearchType searchType) throws AtlasBaseException;
 
     /**
      * @param guid Guid for the saved search

http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
index ad21ee4..e701dff 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
@@ -33,6 +33,7 @@ import org.apache.atlas.model.discovery.SearchParameters;
 import org.apache.atlas.model.instance.AtlasEntityHeader;
 import org.apache.atlas.model.instance.AtlasObjectId;
 import org.apache.atlas.model.profile.AtlasUserSavedSearch;
+import org.apache.atlas.model.profile.AtlasUserSavedSearch.SavedSearchType;
 import org.apache.atlas.query.Expressions.AliasExpression;
 import org.apache.atlas.query.Expressions.Expression;
 import org.apache.atlas.query.Expressions.SelectExpression;
@@ -804,9 +805,9 @@ public class EntityDiscoveryService implements AtlasDiscoveryService {
 
 
     @Override
-    public void addSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
+    public AtlasUserSavedSearch addSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
         try {
-            userProfileService.addSavedSearch(savedSearch);
+            return userProfileService.addSavedSearch(savedSearch);
         } catch (AtlasBaseException e) {
             LOG.error("addSavedSearch({})", savedSearch, e);
             throw e;
@@ -815,9 +816,9 @@ public class EntityDiscoveryService implements AtlasDiscoveryService {
 
 
     @Override
-    public void updateSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
+    public AtlasUserSavedSearch updateSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
         try {
-            userProfileService.updateSavedSearch(savedSearch);
+            return userProfileService.updateSavedSearch(savedSearch);
         } catch (AtlasBaseException e) {
             LOG.error("updateSavedSearch({})", savedSearch, e);
             throw e;
@@ -835,9 +836,19 @@ public class EntityDiscoveryService implements AtlasDiscoveryService {
     }
 
     @Override
-    public AtlasUserSavedSearch getSavedSearch(String userName, String searchName) throws AtlasBaseException {
+    public AtlasUserSavedSearch getSavedSearch(String guid) throws AtlasBaseException {
         try {
-            return userProfileService.getSavedSearch(userName, searchName);
+            return userProfileService.getSavedSearch(guid);
+        } catch (AtlasBaseException e) {
+            LOG.error("getSavedSearch({})", guid, e);
+            throw e;
+        }
+    }
+
+    @Override
+    public AtlasUserSavedSearch getSavedSearch(String userName, String searchName, SavedSearchType searchType) throws AtlasBaseException {
+        try {
+            return userProfileService.getSavedSearch(userName, searchName, searchType);
         } catch (AtlasBaseException e) {
             LOG.error("getSavedSearch({}, {})", userName, searchName, e);
             throw e;

http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java b/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java
index 26eee20..aa8fc39 100644
--- a/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java
+++ b/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java
@@ -35,6 +35,7 @@ public class AtlasSavedSearchDTO extends AbstractDataTransferObject<AtlasUserSav
     private static final String PROPERTY_OWNER_NAME        = "ownerName";
     private static final String PROPERTY_SEARCH_PARAMETERS = "searchParameters";
     private static final String PROPERTY_UNIQUE_NAME       = "uniqueName";
+    private static final String PROPERTY_SEARCH_TYPE       = "searchType";
 
     public AtlasSavedSearchDTO(AtlasTypeRegistry typeRegistry) {
         super(typeRegistry, AtlasUserSavedSearch.class);
@@ -47,6 +48,7 @@ public class AtlasSavedSearchDTO extends AbstractDataTransferObject<AtlasUserSav
         savedSearch.setGuid(entity.getGuid());
         savedSearch.setName((String) entity.getAttribute(PROPERTY_NAME));
         savedSearch.setOwnerName((String) entity.getAttribute(PROPERTY_OWNER_NAME));
+        savedSearch.setSearchType(AtlasUserSavedSearch.SavedSearchType.to((String) entity.getAttribute(PROPERTY_SEARCH_TYPE)));
 
         String jsonSearchParams = (String) entity.getAttribute(PROPERTY_SEARCH_PARAMETERS);
 
@@ -68,6 +70,7 @@ public class AtlasSavedSearchDTO extends AbstractDataTransferObject<AtlasUserSav
 
         entity.setAttribute(PROPERTY_NAME, obj.getName());
         entity.setAttribute(PROPERTY_OWNER_NAME, obj.getOwnerName());
+        entity.setAttribute(PROPERTY_SEARCH_TYPE, obj.getSearchType());
         entity.setAttribute(PROPERTY_UNIQUE_NAME, getUniqueValue(obj));
 
         if (obj.getSearchParameters() != null) {
@@ -92,6 +95,6 @@ public class AtlasSavedSearchDTO extends AbstractDataTransferObject<AtlasUserSav
     }
 
     private String getUniqueValue(AtlasUserSavedSearch obj) {
-        return obj.getOwnerName() + ":" + obj.getName();
+        return String.format("%s:%s:%s", obj.getOwnerName(), obj.getName(), obj.getSearchType()) ;
     }
 }

http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java b/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java
index bc93cc6..c99d2f8 100644
--- a/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java
+++ b/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java
@@ -51,7 +51,7 @@ public class DataAccess {
             throw new AtlasBaseException(AtlasErrorCode.DATA_ACCESS_SAVE_FAILED, obj.toString());
         }
 
-        return obj;
+        return this.load(obj);
     }
 
     public <T extends AtlasBaseModelObject> T load(T obj) throws AtlasBaseException {

http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/repository/src/main/java/org/apache/atlas/repository/userprofile/UserProfileService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/userprofile/UserProfileService.java b/repository/src/main/java/org/apache/atlas/repository/userprofile/UserProfileService.java
index 766d1c7..99d13af 100644
--- a/repository/src/main/java/org/apache/atlas/repository/userprofile/UserProfileService.java
+++ b/repository/src/main/java/org/apache/atlas/repository/userprofile/UserProfileService.java
@@ -22,6 +22,7 @@ import org.apache.atlas.annotation.AtlasService;
 import org.apache.atlas.exception.AtlasBaseException;
 import org.apache.atlas.model.profile.AtlasUserProfile;
 import org.apache.atlas.model.profile.AtlasUserSavedSearch;
+import org.apache.atlas.model.profile.AtlasUserSavedSearch.SavedSearchType;
 import org.apache.atlas.repository.ogm.DataAccess;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -41,8 +42,8 @@ public class UserProfileService {
         this.dataAccess = dataAccess;
     }
 
-    public void saveUserProfile(AtlasUserProfile profile) throws AtlasBaseException {
-        dataAccess.save(profile);
+    public AtlasUserProfile saveUserProfile(AtlasUserProfile profile) throws AtlasBaseException {
+        return dataAccess.save(profile);
     }
 
     public AtlasUserProfile getUserProfile(String userName) throws AtlasBaseException {
@@ -51,7 +52,7 @@ public class UserProfileService {
         return dataAccess.load(profile);
     }
 
-    public AtlasUserProfile addSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
+    public AtlasUserSavedSearch addSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
         String userName = savedSearch.getOwnerName();
         AtlasUserProfile userProfile = null;
 
@@ -67,13 +68,21 @@ public class UserProfileService {
 
         checkIfQueryAlreadyExists(savedSearch, userProfile);
         userProfile.getSavedSearches().add(savedSearch);
-        return dataAccess.save(userProfile);
+        userProfile = dataAccess.save(userProfile);
+        for (AtlasUserSavedSearch s : userProfile.getSavedSearches()) {
+            if(s.getName().equals(savedSearch.getName()) && s.getSearchType().equals(savedSearch.getSearchType())) {
+                return s;
+            }
+        }
+
+        return savedSearch;
     }
 
     private void checkIfQueryAlreadyExists(AtlasUserSavedSearch savedSearch, AtlasUserProfile userProfile) throws AtlasBaseException {
         for (AtlasUserSavedSearch exisingSearch : userProfile.getSavedSearches()) {
             if (StringUtils.equals(exisingSearch.getOwnerName(), savedSearch.getOwnerName()) &&
-                    StringUtils.equals(exisingSearch.getName(), savedSearch.getName())) {
+                StringUtils.equals(exisingSearch.getName(), savedSearch.getName()) &&
+                exisingSearch.getSearchType().equals(savedSearch.getSearchType())) {
                 throw new AtlasBaseException(AtlasErrorCode.SAVED_SEARCH_ALREADY_EXISTS, savedSearch.getName(), savedSearch.getOwnerName());
             }
         }
@@ -120,8 +129,8 @@ public class UserProfileService {
         return (profile != null) ? profile.getSavedSearches() : null;
     }
 
-    public AtlasUserSavedSearch getSavedSearch(String userName, String searchName) throws AtlasBaseException {
-        AtlasUserSavedSearch ss = new AtlasUserSavedSearch(userName, searchName);
+    public AtlasUserSavedSearch getSavedSearch(String userName, String searchName, SavedSearchType searchType) throws AtlasBaseException {
+        AtlasUserSavedSearch ss = new AtlasUserSavedSearch(userName, searchName, searchType);
 
         return dataAccess.load(ss);
     }

http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java b/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java
index 4e83296..713dade 100644
--- a/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java
+++ b/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java
@@ -37,6 +37,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.apache.atlas.model.profile.AtlasUserSavedSearch.SavedSearchType.BASIC;
 import static org.apache.atlas.repository.impexp.ZipFileResourceTestUtils.loadModelFromJson;
 import static org.testng.Assert.*;
 
@@ -77,7 +78,7 @@ public class UserProfileServiceTest {
     }
 
     @Test(dependsOnMethods = { "createsNewProfile", "savesQueryForAnNonExistentUser" }, expectedExceptions = AtlasBaseException.class)
-    public void savesAlreadyExistingQueryForAnExistingUser() throws AtlasBaseException {
+    public void atteptsToAddAlreadyExistingQueryForAnExistingUser() throws AtlasBaseException {
         SearchParameters expectedSearchParameter = getActualSearchParameters();
 
         for (int i = 0; i < 2; i++) {
@@ -85,13 +86,20 @@ public class UserProfileServiceTest {
 
             for (int j = 0; j < max_searches; j++) {
                 String queryName = getIndexBasedQueryName(j);
-                AtlasUserProfile actual = userProfileService.addSavedSearch(new AtlasUserSavedSearch(userName, queryName, expectedSearchParameter));
+                AtlasUserSavedSearch expected = getDefaultSavedSearch(userName, queryName, expectedSearchParameter);
+                AtlasUserSavedSearch actual = userProfileService.addSavedSearch(expected);
+
                 assertNotNull(actual);
+                assertNotNull(actual.getGuid());
+                assertEquals(actual.getOwnerName(), expected.getOwnerName());
+                assertEquals(actual.getName(), expected.getName());
+                assertEquals(actual.getSearchType(), expected.getSearchType());
+                assertEquals(actual.getSearchParameters(), expected.getSearchParameters());
             }
         }
     }
 
-    @Test(dependsOnMethods = { "createsNewProfile", "savesQueryForAnNonExistentUser", "savesAlreadyExistingQueryForAnExistingUser" })
+    @Test(dependsOnMethods = { "createsNewProfile", "savesQueryForAnNonExistentUser", "atteptsToAddAlreadyExistingQueryForAnExistingUser" })
     public void savesExistingQueryForAnExistingUser() throws AtlasBaseException {
         SearchParameters expectedSearchParameter = getActualSearchParameters();
 
@@ -100,10 +108,10 @@ public class UserProfileServiceTest {
 
             for (int j = 4; j < max_searches + 6; j++) {
                 String queryName = getIndexBasedQueryName(j);
-                AtlasUserProfile actual = userProfileService.addSavedSearch(new AtlasUserSavedSearch(userName, queryName, expectedSearchParameter));
+                AtlasUserSavedSearch actual = userProfileService.addSavedSearch(getDefaultSavedSearch(userName, queryName, expectedSearchParameter));
                 assertNotNull(actual);
 
-                AtlasUserSavedSearch savedSearch = userProfileService.getSavedSearch(userName, queryName);
+                AtlasUserSavedSearch savedSearch = userProfileService.getSavedSearch(userName, queryName, BASIC);
                 assertNotNull(savedSearch);
                 assertEquals(savedSearch.getSearchParameters(), expectedSearchParameter);
             }
@@ -122,14 +130,19 @@ public class UserProfileServiceTest {
 
     @Test(dependsOnMethods = "createsNewProfile")
     public void savesQueryForAnNonExistentUser() throws AtlasBaseException {
-        String expectedUserName = "firstXYZ";
+        String expectedUserName = getIndexBasedUserName(0);
         String expectedQueryName = "testQuery";
         SearchParameters expectedSearchParam = getActualSearchParameters();
+        AtlasUserSavedSearch expectedSavedSearch = getDefaultSavedSearch(expectedUserName, expectedQueryName, expectedSearchParam);
+
+        AtlasUserSavedSearch actual = userProfileService.addSavedSearch(expectedSavedSearch);
+        assertEquals(actual.getOwnerName(), expectedUserName);
+        assertEquals(actual.getName(), expectedQueryName);
+    }
 
-        AtlasUserProfile actual = userProfileService.addSavedSearch(new AtlasUserSavedSearch(expectedUserName, expectedQueryName, expectedSearchParam));
-        assertEquals(actual.getName(), expectedUserName);
-        assertEquals(actual.getSavedSearches().size(), 1);
-        assertEquals(actual.getSavedSearches().get(0).getName(), expectedQueryName);
+    private AtlasUserSavedSearch getDefaultSavedSearch(String userName, String queryName, SearchParameters expectedSearchParam) {
+        return new AtlasUserSavedSearch(userName, queryName,
+                BASIC, expectedSearchParam);
     }
 
     @Test(dependsOnMethods = "createsNewProfile")
@@ -143,7 +156,7 @@ public class UserProfileServiceTest {
 
         saveQueries(userName, actualSearchParameter);
         for (int i = 0; i < max_searches; i++) {
-            AtlasUserSavedSearch savedSearch = userProfileService.getSavedSearch(userName, getIndexBasedQueryName(i));
+            AtlasUserSavedSearch savedSearch = userProfileService.getSavedSearch(userName, getIndexBasedQueryName(i), BASIC);
             assertEquals(savedSearch.getName(), getIndexBasedQueryName(i));
             assertEquals(savedSearch.getSearchParameters(), actualSearchParameter);
         }
@@ -151,7 +164,7 @@ public class UserProfileServiceTest {
 
     private void saveQueries(String userName, SearchParameters sp) throws AtlasBaseException {
         for (int i = 0; i < max_searches; i++) {
-            userProfileService.addSavedSearch(new AtlasUserSavedSearch(userName, getIndexBasedQueryName(i), sp));
+            userProfileService.addSavedSearch(getDefaultSavedSearch(userName, getIndexBasedQueryName(i), sp));
         }
     }
 
@@ -181,7 +194,7 @@ public class UserProfileServiceTest {
     public void updateSearch() throws AtlasBaseException {
         final String queryName = getIndexBasedQueryName(0);
         String userName = getIndexBasedUserName(0);
-        AtlasUserSavedSearch expected = userProfileService.getSavedSearch(userName, queryName);
+        AtlasUserSavedSearch expected = userProfileService.getSavedSearch(userName, queryName, BASIC);
         assertNotNull(expected);
 
         SearchParameters sp = expected.getSearchParameters();
@@ -199,11 +212,11 @@ public class UserProfileServiceTest {
         final String queryName = getIndexBasedQueryName(1);
         String userName = getIndexBasedUserName(0);
 
-        AtlasUserSavedSearch expected = userProfileService.getSavedSearch(userName, queryName);
+        AtlasUserSavedSearch expected = userProfileService.getSavedSearch(userName, queryName, BASIC);
         assertNotNull(expected);
 
         userProfileService.deleteSavedSearch(expected.getGuid());
-        userProfileService.getSavedSearch(userName, queryName);
+        userProfileService.getSavedSearch(userName, queryName, BASIC);
     }
 
     @Test(dependsOnMethods = {"createsNewProfile", "savesMultipleQueriesForUser", "verifyQueryNameListForUser"})
@@ -236,12 +249,12 @@ public class UserProfileServiceTest {
     private void assertSaveLoadUserProfile(int i) throws AtlasBaseException {
         String s = String.valueOf(i);
         AtlasUserProfile expected = getAtlasUserProfile(i);
-        userProfileService.saveUserProfile(expected);
 
-        AtlasUserProfile actual = userProfileService.getUserProfile(expected.getName());
+        AtlasUserProfile actual = userProfileService.saveUserProfile(expected);
         assertNotNull(actual);
         assertEquals(expected.getName(), actual.getName());
         assertEquals(expected.getFullName(), actual.getFullName());
+        assertNotNull(actual.getGuid());
     }
 
     public static AtlasUserProfile getAtlasUserProfile(Integer s) {

http://git-wip-us.apache.org/repos/asf/atlas/blob/4f1129bd/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
index ad595c8..aed82ae 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
@@ -24,6 +24,7 @@ import org.apache.atlas.exception.AtlasBaseException;
 import org.apache.atlas.model.discovery.AtlasSearchResult;
 import org.apache.atlas.model.discovery.SearchParameters;
 import org.apache.atlas.model.profile.AtlasUserSavedSearch;
+import org.apache.atlas.model.profile.AtlasUserSavedSearch.SavedSearchType;
 import org.apache.atlas.utils.AtlasPerfTracer;
 import org.apache.atlas.web.util.Servlets;
 import org.apache.commons.collections.CollectionUtils;
@@ -321,25 +322,9 @@ public class DiscoveryREST {
         }
     }
 
-    private boolean isEmpty(SearchParameters.FilterCriteria filterCriteria) {
-        return filterCriteria == null ||
-                (StringUtils.isEmpty(filterCriteria.getAttributeName()) && CollectionUtils.isEmpty(filterCriteria.getCriterion()));
-    }
-
-    private String escapeTypeName(String typeName) {
-        String ret;
-
-        if (StringUtils.startsWith(typeName, "`") && StringUtils.endsWith(typeName, "`")) {
-            ret = typeName;
-        } else {
-            ret = String.format("`%s`", typeName);
-        }
-
-        return ret;
-    }
-
     /**
      * @param savedSearch
+     * @return the saved search-object
      * @throws AtlasBaseException
      * @throws IOException
      */
@@ -347,36 +332,75 @@ public class DiscoveryREST {
     @Path("saved")
     @Consumes(Servlets.JSON_MEDIA_TYPE)
     @Produces(Servlets.JSON_MEDIA_TYPE)
-    public void createSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException, IOException {
+    public AtlasUserSavedSearch createSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException, IOException {
         savedSearch.setOwnerName(Servlets.getUserName(httpServletRequest));
 
-        atlasDiscoveryService.addSavedSearch(savedSearch);
+        AtlasPerfTracer perf = null;
+
+        try {
+            if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DiscoveryREST.createSavedSearch(ownerName=" + savedSearch.getOwnerName() + ", name=" + savedSearch.getName() + ", searchType=" + savedSearch.getSearchType() + ")");
+            }
+
+            return atlasDiscoveryService.addSavedSearch(savedSearch);
+        } finally {
+            AtlasPerfTracer.log(perf);
+        }
     }
 
-    /**
+    /***
+     *
      * @param savedSearch
+     * @return the updated search-object
      * @throws AtlasBaseException
-     * @throws IOException
      */
     @PUT
     @Path("saved")
     @Consumes(Servlets.JSON_MEDIA_TYPE)
     @Produces(Servlets.JSON_MEDIA_TYPE)
-    public void updateSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
-        atlasDiscoveryService.updateSavedSearch(savedSearch);
+    public AtlasUserSavedSearch updateSavedSearch(AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
+        savedSearch.setOwnerName(Servlets.getUserName(httpServletRequest));
+
+        AtlasPerfTracer perf = null;
+
+        try {
+            if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DiscoveryREST.updateSavedSearch(ownerName=" + savedSearch.getOwnerName() + ", name=" + savedSearch.getName() + ", searchType=" + savedSearch.getSearchType() + ")");
+            }
+
+            return atlasDiscoveryService.updateSavedSearch(savedSearch);
+        } finally {
+            AtlasPerfTracer.log(perf);
+        }
     }
 
     /**
+     *
+     * @param userName User for whom the search is retrieved
      * @param searchName Name of the saved search
      * @return
+     * @throws AtlasBaseException
      */
     @GET
-    @Path("saved/{name}")
+    @Path("saved/{type}/{name}")
     @Consumes(Servlets.JSON_MEDIA_TYPE)
     @Produces(Servlets.JSON_MEDIA_TYPE)
-    public AtlasUserSavedSearch getSavedSearch(@QueryParam("user") String userName, @PathParam("name") String searchName) throws AtlasBaseException {
+    public AtlasUserSavedSearch getSavedSearch(@PathParam("type") String searchType,
+                                               @PathParam("name") String searchName,
+                                               @QueryParam("user") String userName) throws AtlasBaseException {
         userName = StringUtils.isBlank(userName) ? Servlets.getUserName(httpServletRequest) : userName;
-        return atlasDiscoveryService.getSavedSearch(userName, searchName);
+
+        AtlasPerfTracer perf = null;
+
+        try {
+            if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DiscoveryREST.getSavedSearch(user=" + userName + ", name=" + searchName + ", type=" + searchType + ")");
+            }
+
+            return atlasDiscoveryService.getSavedSearch(userName, searchName, SavedSearchType.to(searchType));
+        } finally {
+            AtlasPerfTracer.log(perf);
+        }
     }
 
     /**
@@ -388,7 +412,18 @@ public class DiscoveryREST {
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public List<AtlasUserSavedSearch> getSavedSearches(@QueryParam("user") String userName) throws AtlasBaseException {
         userName = StringUtils.isBlank(userName) ? Servlets.getUserName(httpServletRequest) : userName;
-        return atlasDiscoveryService.getSavedSearches(userName);
+
+        AtlasPerfTracer perf = null;
+
+        try {
+            if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DiscoveryREST.getSavedSearches(user=" + userName + ")");
+            }
+
+            return atlasDiscoveryService.getSavedSearches(userName);
+        } finally {
+            AtlasPerfTracer.log(perf);
+        }
     }
 
     /**
@@ -399,6 +434,41 @@ public class DiscoveryREST {
     @Consumes(Servlets.JSON_MEDIA_TYPE)
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public void deleteSavedSearch(@PathParam("guid") String guid) throws AtlasBaseException {
-        atlasDiscoveryService.deleteSavedSearch(guid);
+        AtlasPerfTracer perf = null;
+
+        try {
+            if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DiscoveryREST.deleteSavedSearch(guid=" + guid + ")");
+            }
+
+            AtlasUserSavedSearch savedSearch = atlasDiscoveryService.getSavedSearch(guid);
+
+            // block attempt to delete another user's saved-search
+            if (!StringUtils.equals(savedSearch.getOwnerName(), Servlets.getUserName(httpServletRequest))) {
+                throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "invalid data");
+            }
+
+            atlasDiscoveryService.deleteSavedSearch(guid);
+        } finally {
+            AtlasPerfTracer.log(perf);
+        }
+    }
+
+
+    private boolean isEmpty(SearchParameters.FilterCriteria filterCriteria) {
+        return filterCriteria == null ||
+                (StringUtils.isEmpty(filterCriteria.getAttributeName()) && CollectionUtils.isEmpty(filterCriteria.getCriterion()));
+    }
+
+    private String escapeTypeName(String typeName) {
+        String ret;
+
+        if (StringUtils.startsWith(typeName, "`") && StringUtils.endsWith(typeName, "`")) {
+            ret = typeName;
+        } else {
+            ret = String.format("`%s`", typeName);
+        }
+
+        return ret;
     }
 }


[3/7] atlas git commit: ATLAS-2132: incorrect error for invalid file path/unreadable file provided during import

Posted by ma...@apache.org.
ATLAS-2132: incorrect error for invalid file path/unreadable file provided during import

Signed-off-by: Madhan Neethiraj <ma...@apache.org>
(cherry picked from commit 67c04c63e1126791ab8537e2a8e8411f0b9e6897)


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

Branch: refs/heads/branch-0.8
Commit: ceb5c0cd90aa94d6836bb5f14154e5c5934e7ed2
Parents: 2e138da
Author: Ashutosh Mestry <am...@apache.org>
Authored: Mon Sep 18 22:22:15 2017 -0700
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Sep 21 19:10:04 2017 -0700

----------------------------------------------------------------------
 .../atlas/repository/impexp/ImportService.java  |  8 ++-
 .../repository/impexp/ImportServiceTest.java    | 55 +++++++++++++++++---
 2 files changed, 53 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/ceb5c0cd/repository/src/main/java/org/apache/atlas/repository/impexp/ImportService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/impexp/ImportService.java b/repository/src/main/java/org/apache/atlas/repository/impexp/ImportService.java
index 650741e..c976c59 100644
--- a/repository/src/main/java/org/apache/atlas/repository/impexp/ImportService.java
+++ b/repository/src/main/java/org/apache/atlas/repository/impexp/ImportService.java
@@ -36,6 +36,7 @@ import javax.inject.Inject;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 
 @Component
 public class ImportService {
@@ -108,7 +109,7 @@ public class ImportService {
 
     public AtlasImportResult run(AtlasImportRequest request, String userName, String hostName, String requestingIP)
             throws AtlasBaseException {
-        String fileName = (String) request.getFileName();
+        String fileName = request.getFileName();
 
         if (StringUtils.isBlank(fileName)) {
             throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "FILENAME parameter not found");
@@ -122,7 +123,6 @@ public class ImportService {
             String transforms = MapUtils.isNotEmpty(request.getOptions()) ? request.getOptions().get(AtlasImportRequest.TRANSFORMS_KEY) : null;
             File file = new File(fileName);
             ZipSource source = new ZipSource(new ByteArrayInputStream(FileUtils.readFileToByteArray(file)), ImportTransforms.fromJson(transforms));
-
             result = run(source, request, userName, hostName, requestingIP);
         } catch (AtlasBaseException excp) {
             LOG.error("import(user={}, from={}, fileName={}): failed", userName, requestingIP, excp);
@@ -132,6 +132,10 @@ public class ImportService {
             LOG.error("import(user={}, from={}, fileName={}): file not found", userName, requestingIP, excp);
 
             throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, fileName + ": file not found");
+        } catch (IOException excp) {
+            LOG.error("import(user={}, from={}, fileName={}): cannot read file", userName, requestingIP, excp);
+
+            throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, fileName + ": cannot read file");
         } catch (Exception excp) {
             LOG.error("import(user={}, from={}, fileName={}): failed", userName, requestingIP, excp);
 

http://git-wip-us.apache.org/repos/asf/atlas/blob/ceb5c0cd/repository/src/test/java/org/apache/atlas/repository/impexp/ImportServiceTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/impexp/ImportServiceTest.java b/repository/src/test/java/org/apache/atlas/repository/impexp/ImportServiceTest.java
index 923b681..035ddac 100644
--- a/repository/src/test/java/org/apache/atlas/repository/impexp/ImportServiceTest.java
+++ b/repository/src/test/java/org/apache/atlas/repository/impexp/ImportServiceTest.java
@@ -27,6 +27,8 @@ import org.apache.atlas.model.impexp.AtlasImportRequest;
 import org.apache.atlas.store.AtlasTypeDefStore;
 import org.apache.atlas.type.AtlasClassificationType;
 import org.apache.atlas.type.AtlasTypeRegistry;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.ITestContext;
@@ -40,6 +42,8 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static org.apache.atlas.repository.impexp.ZipFileResourceTestUtils.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
@@ -72,7 +76,7 @@ public class ImportServiceTest {
 
     @Test(dataProvider = "sales")
     public void importDB1(ZipSource zipSource) throws AtlasBaseException, IOException {
-        loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
+        loadBaseModel();
         runAndVerifyQuickStart_v1_Import(importService, zipSource);
     }
 
@@ -83,7 +87,7 @@ public class ImportServiceTest {
 
     @Test(dataProvider = "reporting")
     public void importDB2(ZipSource zipSource) throws AtlasBaseException, IOException {
-        loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
+        loadBaseModel();
         runAndVerifyQuickStart_v1_Import(importService, zipSource);
     }
 
@@ -94,7 +98,7 @@ public class ImportServiceTest {
 
     @Test(dataProvider = "logging")
     public void importDB3(ZipSource zipSource) throws AtlasBaseException, IOException {
-        loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
+        loadBaseModel();
         runAndVerifyQuickStart_v1_Import(importService, zipSource);
     }
 
@@ -105,7 +109,7 @@ public class ImportServiceTest {
 
     @Test(dataProvider = "salesNewTypeAttrs", dependsOnMethods = "importDB1")
     public void importDB4(ZipSource zipSource) throws AtlasBaseException, IOException {
-        loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
+        loadBaseModel();
         runImportWithParameters(importService, getDefaultImportRequest(), zipSource);
     }
 
@@ -154,8 +158,8 @@ public class ImportServiceTest {
 
     @Test(dataProvider = "ctas")
     public void importCTAS(ZipSource zipSource) throws IOException, AtlasBaseException {
-        loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
-        loadModelFromJson("0030-hive_model.json", typeDefStore, typeRegistry);
+        loadBaseModel();
+        loadHiveModel();
 
         runImportWithNoParameters(importService, zipSource);
     }
@@ -168,8 +172,8 @@ public class ImportServiceTest {
 
     @Test(dataProvider = "hdfs_path1", expectedExceptions = AtlasBaseException.class)
     public void importHdfs_path1(ZipSource zipSource) throws IOException, AtlasBaseException {
-        loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
-        loadModelFromJson("0020-fs_model.json", typeDefStore, typeRegistry);
+        loadBaseModel();
+        loadFsModel();
         loadModelFromResourcesJson("tag1.json", typeDefStore, typeRegistry);
 
         try {
@@ -182,4 +186,39 @@ public class ImportServiceTest {
             throw e;
         }
     }
+
+    @Test
+    public void importServiceProcessesIOException() {
+        ImportService importService = new ImportService(typeDefStore, typeRegistry, null);
+        AtlasImportRequest req = mock(AtlasImportRequest.class);
+
+        Answer<Map> answer = new Answer<Map>() {
+            @Override
+            public Map answer(InvocationOnMock invocationOnMock) throws Throwable {
+                throw new IOException("file is read only");
+            }
+        };
+
+        when(req.getFileName()).thenReturn("some-file.zip");
+        when(req.getOptions()).thenAnswer(answer);
+
+        try {
+            importService.run(req, "a", "b", "c");
+        }
+        catch (AtlasBaseException ex) {
+            assertEquals(ex.getAtlasErrorCode().getErrorCode(), AtlasErrorCode.INVALID_PARAMETERS.getErrorCode());
+        }
+    }
+
+    private void loadBaseModel() throws IOException, AtlasBaseException {
+        loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
+    }
+
+    private void loadFsModel() throws IOException, AtlasBaseException {
+        loadModelFromJson("0020-fs_model.json", typeDefStore, typeRegistry);
+    }
+
+    private void loadHiveModel() throws IOException, AtlasBaseException {
+        loadModelFromJson("0030-hive_model.json", typeDefStore, typeRegistry);
+    }
 }