falcon-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sowmya...@apache.org
Subject falcon git commit: FALCON-1121 Backend support for free-text entity search. Contributed by Ying Zheng
Date Tue, 02 Jun 2015 21:04:09 GMT
Repository: falcon
Updated Branches:
  refs/heads/master cc3b343bd -> 1bae2a6f2


FALCON-1121 Backend support for free-text entity search. Contributed by Ying Zheng


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

Branch: refs/heads/master
Commit: 1bae2a6f20dd751f9115cbdd4c7f0f8ead20d594
Parents: cc3b343
Author: Sowmya Ramesh <sramesh@hortonworks.com>
Authored: Tue Jun 2 14:04:00 2015 -0700
Committer: Sowmya Ramesh <sramesh@hortonworks.com>
Committed: Tue Jun 2 14:04:00 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/falcon/cli/FalconCLI.java   |  32 ++-
 .../org/apache/falcon/client/FalconClient.java  |  60 +++---
 .../org/apache/falcon/entity/v0/Entity.java     |   2 +
 .../org/apache/falcon/resource/EntityList.java  |  24 ++-
 .../falcon/entity/store/ConfigurationStore.java |   3 +
 docs/src/site/twiki/FalconCLI.twiki             |   8 +-
 docs/src/site/twiki/restapi/EntityList.twiki    |  50 ++++-
 .../falcon/resource/AbstractEntityManager.java  | 208 ++++++++++++-------
 .../AbstractSchedulableEntityManager.java       |  16 +-
 .../proxy/SchedulableEntityManagerProxy.java    |  17 +-
 .../falcon/resource/EntityManagerTest.java      |  71 ++++---
 .../resource/SchedulableEntityManager.java      |  16 +-
 .../java/org/apache/falcon/cli/FalconCLIIT.java |   9 +-
 .../org/apache/falcon/cli/FalconCLISmokeIT.java |   4 +
 .../falcon/resource/EntityManagerJerseyIT.java  |  26 +++
 15 files changed, 365 insertions(+), 181 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/FalconCLI.java b/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
index 7d56b01..a5e3728 100644
--- a/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
+++ b/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
@@ -98,6 +98,7 @@ public class FalconCLI {
     public static final String NUM_RESULTS_OPT = "numResults";
     public static final String NUM_INSTANCES_OPT = "numInstances";
     public static final String NAMESEQ_OPT = "nameseq";
+    public static final String TAGKEYS_OPT = "tagkeys";
     public static final String FORCE_RERUN_FLAG = "force";
 
     public static final String INSTANCE_CMD = "instance";
@@ -393,15 +394,29 @@ public class FalconCLI {
         String sortOrder = commandLine.getOptionValue(SORT_ORDER_OPT);
         String filterBy = commandLine.getOptionValue(FILTER_BY_OPT);
         String filterTags = commandLine.getOptionValue(TAGS_OPT);
-        String nameseq = commandLine.getOptionValue(NAMESEQ_OPT);
+        String nameSubsequence = commandLine.getOptionValue(NAMESEQ_OPT);
+        String tagKeywords = commandLine.getOptionValue(TAGKEYS_OPT);
         String fields = commandLine.getOptionValue(FIELDS_OPT);
         String feedInstancePath = commandLine.getOptionValue(PATH_OPT);
         Integer offset = parseIntegerInput(commandLine.getOptionValue(OFFSET_OPT), 0, "offset");
         Integer numResults = parseIntegerInput(commandLine.getOptionValue(NUM_RESULTS_OPT),
                 FalconClient.DEFAULT_NUM_RESULTS, "numResults");
         Integer numInstances = parseIntegerInput(commandLine.getOptionValue(NUM_INSTANCES_OPT), 7, "numInstances");
-        validateNotEmpty(entityType, ENTITY_TYPE_OPT);
-        EntityType entityTypeEnum = EntityType.getEnum(entityType);
+        EntityType entityTypeEnum = null;
+        if (optionsList.contains(LIST_OPT)) {
+            if (entityType == null) {
+                entityType = "";
+            }
+            if (StringUtils.isNotEmpty(entityType)) {
+                String[] types = entityType.split(",");
+                for (String type : types) {
+                    EntityType.getEnum(type);
+                }
+            }
+        } else {
+            validateNotEmpty(entityType, ENTITY_TYPE_OPT);
+            entityTypeEnum = EntityType.getEnum(entityType);
+        }
         validateSortOrder(sortOrder);
         String entityAction = "entity";
 
@@ -462,8 +477,8 @@ public class FalconCLI {
             validateEntityFields(fields);
             validateOrderBy(orderBy, entityAction);
             validateFilterBy(filterBy, entityAction);
-            EntityList entityList = client.getEntityList(entityType, fields, filterBy,
-                    filterTags, orderBy, sortOrder, offset, numResults, nameseq);
+            EntityList entityList = client.getEntityList(entityType, fields, nameSubsequence, tagKeywords,
+                    filterBy, filterTags, orderBy, sortOrder, offset, numResults);
             result = entityList != null ? entityList.toString() : "No entity of type (" + entityType + ") found.";
         }  else if (optionsList.contains(SUMMARY_OPT)) {
             validateEntityTypeForSummary(entityType);
@@ -668,7 +683,6 @@ public class FalconCLI {
         Option url = new Option(URL_OPTION, true, "Falcon URL");
         Option entityType = new Option(ENTITY_TYPE_OPT, true,
                 "Entity type, can be cluster, feed or process xml");
-        entityType.setRequired(true);
         Option filePath = new Option(FILE_PATH_OPT, true,
                 "Path to entity xml file");
         Option entityName = new Option(ENTITY_NAME_OPT, true,
@@ -681,8 +695,9 @@ public class FalconCLI {
         Option fields = new Option(FIELDS_OPT, true, "Entity fields to show for a request");
         Option filterBy = new Option(FILTER_BY_OPT, true,
                 "Filter returned entities by the specified status");
-        Option nameseq = new Option(NAMESEQ_OPT, true, "Subsequence of entity name");
         Option filterTags = new Option(TAGS_OPT, true, "Filter returned entities by the specified tags");
+        Option nameSubsequence = new Option(NAMESEQ_OPT, true, "Subsequence of entity name");
+        Option tagKeywords = new Option(TAGKEYS_OPT, true, "Keywords in tags");
         Option orderBy = new Option(ORDER_BY_OPT, true,
                 "Order returned entities by this field");
         Option sortOrder = new Option(SORT_ORDER_OPT, true, "asc or desc order for results");
@@ -706,8 +721,9 @@ public class FalconCLI {
         entityOptions.addOption(end);
         entityOptions.addOption(fields);
         entityOptions.addOption(filterBy);
-        entityOptions.addOption(nameseq);
         entityOptions.addOption(filterTags);
+        entityOptions.addOption(nameSubsequence);
+        entityOptions.addOption(tagKeywords);
         entityOptions.addOption(orderBy);
         entityOptions.addOption(sortOrder);
         entityOptions.addOption(offset);

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/client/src/main/java/org/apache/falcon/client/FalconClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/client/FalconClient.java b/client/src/main/java/org/apache/falcon/client/FalconClient.java
index fedcea6..786e0a0 100644
--- a/client/src/main/java/org/apache/falcon/client/FalconClient.java
+++ b/client/src/main/java/org/apache/falcon/client/FalconClient.java
@@ -368,11 +368,11 @@ public class FalconClient {
 
     //SUSPEND CHECKSTYLE CHECK ParameterNumberCheck
 
-    public EntityList getEntityList(String entityType, String fields, String filterBy, String filterTags,
-                                    String orderBy, String sortOrder, Integer offset,
-                                    Integer numResults, String nameseq) throws FalconCLIException {
-        return sendListRequest(Entities.LIST, entityType, fields, filterBy,
-                filterTags, orderBy, sortOrder, offset, numResults, nameseq);
+    public EntityList getEntityList(String entityType, String fields, String nameSubsequence, String tagKeywords,
+                                    String filterBy, String filterTags, String orderBy, String sortOrder,
+                                    Integer offset, Integer numResults) throws FalconCLIException {
+        return sendListRequest(Entities.LIST, entityType, fields, nameSubsequence, tagKeywords, filterBy,
+                filterTags, orderBy, sortOrder, offset, numResults);
     }
 
     public EntitySummaryResult getEntitySummary(String entityType, String cluster, String start, String end,
@@ -606,30 +606,34 @@ public class FalconClient {
 
     private WebResource addParamsToResource(WebResource resource,
                                             String start, String end, String runId, String colo,
-                                            String fields, String filterBy, String tags,
-                                            String orderBy, String sortOrder, Integer offset,
-                                            Integer numResults, Integer numInstances, String nameseq,
-                                            Boolean isForced) {
-
-        if (!StringUtils.isEmpty(fields)) {
+                                            String fields, String nameSubsequence, String tagKeywords, String filterBy,
+                                            String tags, String orderBy, String sortOrder, Integer offset,
+                                            Integer numResults, Integer numInstances, Boolean isForced) {
+        if (StringUtils.isNotEmpty(fields)) {
             resource = resource.queryParam("fields", fields);
         }
-        if (!StringUtils.isEmpty(tags)) {
+        if (StringUtils.isNotEmpty(nameSubsequence)) {
+            resource = resource.queryParam("nameseq", nameSubsequence);
+        }
+        if (StringUtils.isNotEmpty(tagKeywords)) {
+            resource = resource.queryParam("tagkeys", tagKeywords);
+        }
+        if (StringUtils.isNotEmpty(tags)) {
             resource = resource.queryParam("tags", tags);
         }
-        if (!StringUtils.isEmpty(filterBy)) {
+        if (StringUtils.isNotEmpty(filterBy)) {
             resource = resource.queryParam("filterBy", filterBy);
         }
-        if (!StringUtils.isEmpty(orderBy)) {
+        if (StringUtils.isNotEmpty(orderBy)) {
             resource = resource.queryParam("orderBy", orderBy);
         }
-        if (!StringUtils.isEmpty(sortOrder)) {
+        if (StringUtils.isNotEmpty(sortOrder)) {
             resource = resource.queryParam("sortOrder", sortOrder);
         }
-        if (!StringUtils.isEmpty(start)) {
+        if (StringUtils.isNotEmpty(start)) {
             resource = resource.queryParam("start", start);
         }
-        if (!StringUtils.isEmpty(end)) {
+        if (StringUtils.isNotEmpty(end)) {
             resource = resource.queryParam("end", end);
         }
         if (runId != null) {
@@ -647,10 +651,6 @@ public class FalconClient {
         if (numInstances != null) {
             resource = resource.queryParam("numInstances", numInstances.toString());
         }
-
-        if (!StringUtils.isEmpty(nameseq)) {
-            resource = resource.queryParam("nameseq", nameseq);
-        }
         if (isForced != null) {
             resource = resource.queryParam("force", String.valueOf(isForced));
         }
@@ -664,14 +664,14 @@ public class FalconClient {
                                             String orderBy, String sortOrder, Integer offset, Integer numResults,
                                             Integer numInstances) throws FalconCLIException {
         WebResource resource = service.path(entities.path).path(entityType);
-        if (!StringUtils.isEmpty(cluster)) {
+        if (StringUtils.isNotEmpty(cluster)) {
             resource = resource.queryParam("cluster", cluster);
         }
 
         resource = addParamsToResource(resource, start, end, null, null,
-                fields, filterBy, filterTags,
+                fields, null, null, filterBy, filterTags,
                 orderBy, sortOrder,
-                offset, numResults, numInstances, null, null);
+                offset, numResults, numInstances, null);
 
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
@@ -780,7 +780,7 @@ public class FalconClient {
                 .path(entity);
 
         resource = addParamsToResource(resource, start, end, runid, colo,
-                null, filterBy, null, orderBy, sortOrder, offset, numResults, null, null, isForced);
+                null, null, null, filterBy, null, orderBy, sortOrder, offset, numResults, null, isForced);
 
         if (lifeCycles != null) {
             checkLifeCycleOption(lifeCycles, type);
@@ -831,13 +831,13 @@ public class FalconClient {
     }
 
     //SUSPEND CHECKSTYLE CHECK ParameterNumberCheck
-    private EntityList sendListRequest(Entities entities, String entityType, String fields, String filterBy,
-                                       String filterTags, String orderBy, String sortOrder, Integer offset,
-                                       Integer numResults, String nameseq) throws FalconCLIException {
+    private EntityList sendListRequest(Entities entities, String entityType, String fields, String nameSubsequence,
+                                       String tagKeywords, String filterBy, String filterTags, String orderBy,
+                                       String sortOrder, Integer offset, Integer numResults) throws FalconCLIException {
         WebResource resource = service.path(entities.path)
                 .path(entityType);
-        resource = addParamsToResource(resource, null, null, null, null, fields, filterBy, filterTags,
-                orderBy, sortOrder, offset, numResults, null, nameseq, null);
+        resource = addParamsToResource(resource, null, null, null, null, fields, nameSubsequence, tagKeywords,
+                filterBy, filterTags, orderBy, sortOrder, offset, numResults, null, null);
 
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/client/src/main/java/org/apache/falcon/entity/v0/Entity.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/entity/v0/Entity.java b/client/src/main/java/org/apache/falcon/entity/v0/Entity.java
index 7fb271d..ba6f2e5 100644
--- a/client/src/main/java/org/apache/falcon/entity/v0/Entity.java
+++ b/client/src/main/java/org/apache/falcon/entity/v0/Entity.java
@@ -29,6 +29,8 @@ import java.io.StringWriter;
 public abstract class Entity {
     public abstract String getName();
 
+    public abstract String getTags();
+
     public abstract AccessControlList getACL();
 
     public EntityType getEntityType() {

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/client/src/main/java/org/apache/falcon/resource/EntityList.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/resource/EntityList.java b/client/src/main/java/org/apache/falcon/resource/EntityList.java
index 4c96195..ee33234 100644
--- a/client/src/main/java/org/apache/falcon/resource/EntityList.java
+++ b/client/src/main/java/org/apache/falcon/resource/EntityList.java
@@ -37,6 +37,9 @@ import java.util.List;
 @edu.umd.cs.findbugs.annotations.SuppressWarnings({"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
 public class EntityList {
 
+    @XmlElement
+    private int totalResults;
+
     @XmlElement(name = "entity")
     private final EntityElement[] elements;
 
@@ -44,14 +47,14 @@ public class EntityList {
      * List of fields returned by RestAPI.
      */
     public static enum EntityFieldList {
-        TYPE, NAME, STATUS, TAGS, PIPELINES
+        TYPE, NAME, STATUS, TAGS, PIPELINES, CLUSTERS
     }
 
     /**
      * Filter by these Fields is supported by RestAPI.
      */
     public static enum EntityFilterByFields {
-        TYPE, NAME, STATUS, PIPELINES, CLUSTER
+        TYPE, NAME, STATUS, PIPELINES, CLUSTER, TAGS
     }
 
     /**
@@ -69,6 +72,9 @@ public class EntityList {
         public List<String> tag;
         @XmlElementWrapper(name = "pipelines")
         public List<String> pipeline;
+        @XmlElementWrapper(name = "clusters")
+        public List<String> cluster;
+
         //RESUME CHECKSTYLE CHECK VisibilityModifierCheck
 
         @Override
@@ -85,6 +91,11 @@ public class EntityList {
             if (pipeline != null && !pipeline.isEmpty()) {
                 outString += " - " + pipeline.toString();
             }
+
+            if (cluster != null && !cluster.isEmpty()) {
+                outString += " - " + cluster.toString();
+            }
+
             outString += "\n";
             return outString;
         }
@@ -93,13 +104,16 @@ public class EntityList {
     //For JAXB
     public EntityList() {
         this.elements = null;
+        this.totalResults = 0;
     }
 
-    public EntityList(EntityElement[] elements) {
+    public EntityList(EntityElement[] elements, int totalResults) {
+        this.totalResults = totalResults;
         this.elements = elements;
     }
 
-    public EntityList(Entity[] elements) {
+    public EntityList(Entity[] elements, int totalResults) {
+        this.totalResults = totalResults;
         int len = elements.length;
         EntityElement[] items = new EntityElement[len];
         for (int i = 0; i < len; i++) {
@@ -115,6 +129,7 @@ public class EntityList {
         element.status = null;
         element.tag = new ArrayList<String>();
         element.pipeline = new ArrayList<String>();
+        element.cluster = new ArrayList<String>();
         return element;
     }
 
@@ -140,6 +155,7 @@ public class EntityList {
     @Override
     public String toString() {
         StringBuilder buffer = new StringBuilder();
+        buffer.append(totalResults + "\n");
         for (EntityElement element : elements) {
             buffer.append(element.toString());
         }

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/common/src/main/java/org/apache/falcon/entity/store/ConfigurationStore.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/falcon/entity/store/ConfigurationStore.java b/common/src/main/java/org/apache/falcon/entity/store/ConfigurationStore.java
index b84371f..b5f531a 100644
--- a/common/src/main/java/org/apache/falcon/entity/store/ConfigurationStore.java
+++ b/common/src/main/java/org/apache/falcon/entity/store/ConfigurationStore.java
@@ -79,6 +79,9 @@ public final class ConfigurationStore implements FalconService {
         }
 
         @Override
+        public String getTags() { return null; }
+
+        @Override
         public AccessControlList getACL() {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/docs/src/site/twiki/FalconCLI.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/FalconCLI.twiki b/docs/src/site/twiki/FalconCLI.twiki
index 0e42ae2..3b428f3 100644
--- a/docs/src/site/twiki/FalconCLI.twiki
+++ b/docs/src/site/twiki/FalconCLI.twiki
@@ -49,10 +49,12 @@ $FALCON_HOME/bin/falcon entity  -type [cluster|feed|process] -name <<name>> -del
 Entities of a particular type can be listed with list sub-command.
 
 Usage:
-$FALCON_HOME/bin/falcon entity -type [cluster|feed|process] -list
+$FALCON_HOME/bin/falcon entity -list
 
-Optional Args : -fields <<field1,field2>> -filterBy <<field1:value1,field2:value2>>
--tags <<tagkey=tagvalue,tagkey=tagvalue>> -nameseq <<namesubsequence>>
+Optional Args : -fields <<field1,field2>>
+-type <<[cluster|feed|process],[cluster|feed|process]>>
+-nameseq <<namesubsequence>> -tagkey <<tagkeyword1,tagkeyword2>>
+-filterBy <<field1:value1,field2:value2>> -tags <<tagkey=tagvalue,tagkey=tagvalue>>
 -orderBy <<field>> -sortOrder <<sortOrder>> -offset 0 -numResults 10
 
 <a href="./Restapi/EntityList.html">Optional params described here.</a>

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/docs/src/site/twiki/restapi/EntityList.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityList.twiki b/docs/src/site/twiki/restapi/EntityList.twiki
index 08dd304..8957fda 100644
--- a/docs/src/site/twiki/restapi/EntityList.twiki
+++ b/docs/src/site/twiki/restapi/EntityList.twiki
@@ -8,13 +8,15 @@
 Get list of the entities.
 
 ---++ Parameters
-   * :entity-type Valid options are cluster, feed or process.
+   * :entity-type Comma-separated entity types. Can be empty. Valid entity types are cluster, feed or process.
    * fields <optional param> Fields of entity that the user wants to view, separated by commas.
-      * Valid options are STATUS, TAGS, PIPELINES.
+      * Valid options are STATUS, TAGS, PIPELINES, CLUSTERS.
    * nameseq <optional param> Subsequence of entity name. Not case sensitive.
       * The entity name needs to contain all the characters in the subsequence in the same order.
       * Example 1: "sample1" will match the entity named "SampleFeed1-2".
       * Example 2: "mhs" will match the entity named "New-My-Hourly-Summary".
+   * tagkey <optional param> Keywords in tags, separated by comma. Not case sensitive.
+      * The returned entities will have tags that match all the tag keywords.
    * filterBy <optional param> Filter results by list of field:value pairs. Example: filterBy=STATUS:RUNNING,PIPELINES:clickLogs
       * Supported filter fields are NAME, STATUS, PIPELINES, CLUSTER.
       * Query will do an AND among filterBy fields.
@@ -25,9 +27,12 @@ Get list of the entities.
    * sortOrder <optional param> Valid options are "asc" and "desc"
    * offset <optional param> Show results from the offset, used for pagination. Defaults to 0.
    * numResults <optional param> Number of results to show per request, used for pagination. Only integers > 0 are valid, Default is 10.
+   * Note:
+      * We have two filtering parameters for entity tags: "tags" and "tagkey". "tags" does the exact match in key=value fashion, while "tagkey" finds all the entities with the given key as a substring in the tags. This "tagkey" filter is introduced for the user who doesn't remember the exact tag but some keywords in the tag. It also helps users to save the time of typing long tags.
+      * The returned entities will match all the filtering criteria.
 
 ---++ Results
-List of the entities.
+Total number of results and a list of entities.
 
 ---++ Examples
 ---+++ Rest Call
@@ -37,6 +42,7 @@ GET http://localhost:15000/api/entities/list/feed
 ---+++ Result
 <verbatim>
 {
+    "totalResults":"2”,
     "entity": [
         {
             "name": "SampleOutput",
@@ -52,11 +58,41 @@ GET http://localhost:15000/api/entities/list/feed
 
 ---+++ Rest Call
 <verbatim>
+GET http://localhost:15000/api/entities/list
+</verbatim>
+---+++ Result
+<verbatim>
+{
+    "totalResults":"4”,
+    "entity": [
+        {
+            "name"  : "SampleCluster1",
+            "type"  : "cluster"
+        }
+        {
+            "name"  : "SampleOutput",
+            "type"  : "feed"
+        },
+        {
+            "name"  : "SampleInput",
+            "type"  : "feed"
+        }
+        {
+            "name"  : "SampleProcess1",
+            "type"  : "process"
+        }
+    ]
+}
+</verbatim>
+
+---+++ Rest Call
+<verbatim>
 GET http://localhost:15000/api/entities/list/feed?fields=status
 </verbatim>
 ---+++ Result
 <verbatim>
 {
+    "totalResults":"2”,
     "entity": [
         {
             "name"  : "SampleOutput",
@@ -79,6 +115,7 @@ GET http://localhost:15000/api/entities/list/process?filterBy=STATUS:RUNNING,PIP
 ---+++ Result
 <verbatim>
 {
+    "totalResults":"10”,
     "entity": [
         {
             "name"  : "SampleProcess1",
@@ -100,11 +137,12 @@ GET http://localhost:15000/api/entities/list/process?filterBy=STATUS:RUNNING,PIP
 
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/entities/list/feed?nameseq=samplebill&numResults=2&offset=1&fields=status,clusters,tags
+GET http://localhost:15000/api/entities/list/feed,process?nameseq=samplebill&tagkey=billing,healthcare&numResults=2&offset=1&fields=status,clusters,tags
 </verbatim>
 ---+++ Result
 <verbatim>
 {
+    "totalResults":"4”,
     "entity”:[
         {
             "type":"FEED”,
@@ -114,7 +152,7 @@ GET http://localhost:15000/api/entities/list/feed?nameseq=samplebill&numResults=
             "clusters": {"cluster":["SampleCluster1","primaryCluster”]}
         },
         {
-            "type":"FEED”,
+            "type":"PROCESS”,
             "name":"SampleHealthBill”,
             "status":"SUBMITTED”,
             "tags”: {"tag":["related=healthcare","department=billingDepartment"]},
@@ -122,4 +160,4 @@ GET http://localhost:15000/api/entities/list/feed?nameseq=samplebill&numResults=
         }
     ]
 }
-</verbatim>
\ No newline at end of file
+</verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java b/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
index 25cb312..678235e 100644
--- a/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
+++ b/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
@@ -564,39 +564,79 @@ public abstract class AbstractEntityManager {
 
     //SUSPEND CHECKSTYLE CHECK ParameterNumberCheck
     /**
-     * Returns the list of entities registered of a given type.
+     * Returns the list of filtered entities as well as the total number of results.
      *
-     * @param type           Only return entities of this type
-     * @param fieldStr       fields that the query is interested in, separated by comma
-     * @param filterBy       filter by a specific field.
-     * @param filterTags     filter by these tags.
-     * @param orderBy        order result by these fields.
-     * @param offset         Pagination offset.
-     * @param resultsPerPage Number of results that should be returned starting at the offset.
+     * @param fieldStr         Fields that the query is interested in, separated by comma
+     * @param nameSubsequence  Name subsequence to match
+     * @param tagKeywords      Tag keywords to match, separated by commma
+     * @param filterType       Only return entities of this type
+     * @param filterTags       Full tag matching, separated by comma
+     * @param filterBy         Specific fields to match (i.e. TYPE, NAME, STATUS, PIPELINES, CLUSTER)
+     * @param orderBy          Order result by these fields.
+     * @param sortOrder        Valid options are "asc" and “desc”
+     * @param offset           Pagination offset.
+     * @param resultsPerPage   Number of results that should be returned starting at the offset.
      * @return EntityList
      */
-    public EntityList getEntityList(String type, String fieldStr, String filterBy, String filterTags,
-                                    String orderBy, String sortOrder, Integer offset, Integer resultsPerPage,
-                                    String nameseq) {
+    public EntityList getEntityList(String fieldStr, String nameSubsequence, String tagKeywords,
+                                    String filterType, String filterTags, String filterBy,
+                                    String orderBy, String sortOrder, Integer offset, Integer resultsPerPage) {
+
+        HashSet<String> fields = new HashSet<String>(Arrays.asList(fieldStr.toUpperCase().split(",")));
+        Map<String, String> filterByFieldsValues = getFilterByFieldsValues(filterBy);
+        validateEntityFilterByClause(filterByFieldsValues);
+        if (StringUtils.isNotEmpty(filterTags)) {
+            filterByFieldsValues.put(EntityList.EntityFilterByFields.TAGS.name(), filterTags);
+        }
 
-        HashSet<String> fields = new HashSet<String>(Arrays.asList(fieldStr.toLowerCase().split(",")));
-        validateEntityFilterByClause(filterBy);
-        List<Entity> entities;
+        // get filtered entities
+        List<Entity> entities = new ArrayList<Entity>();
         try {
-            entities = getEntities(type, "", "", "", filterBy, filterTags, orderBy, sortOrder, offset,
-                    resultsPerPage, nameseq);
+            if (StringUtils.isEmpty(filterType)) {
+                // return entities of all types if no entity type specified
+                for (EntityType entityType : EntityType.values()) {
+                    entities.addAll(getFilteredEntities(
+                            entityType, nameSubsequence, tagKeywords, filterByFieldsValues, "", "", ""));
+                }
+            } else {
+                String[] types = filterType.split(",");
+                for (String type : types) {
+                    EntityType entityType = EntityType.getEnum(type);
+                    entities.addAll(getFilteredEntities(
+                            entityType, nameSubsequence, tagKeywords, filterByFieldsValues, "", "", ""));
+                }
+            }
         } catch (Exception e) {
             LOG.error("Failed to get entity list", e);
             throw FalconWebException.newException(e, Response.Status.BAD_REQUEST);
         }
 
-        return entities.size() == 0
-                ? new EntityList(new Entity[]{})
-                : new EntityList(buildEntityElements(fields, entities));
+        // sort entities and pagination
+        List<Entity> entitiesReturn = sortEntitiesPagination(entities, orderBy, sortOrder, offset, resultsPerPage);
+
+        // add total number of results
+        EntityList entityList = entitiesReturn.size() == 0
+                ? new EntityList(new Entity[]{}, 0)
+                : new EntityList(buildEntityElements(new HashSet<String>(fields), entitiesReturn), entities.size());
+        return entityList;
     }
 
-    protected void validateEntityFilterByClause(String entityFilterByClause) {
-        Map<String, String> filterByFieldsValues = getFilterByFieldsValues(entityFilterByClause);
+    protected List<Entity> sortEntitiesPagination(List<Entity> entities, String orderBy, String sortOrder,
+                                                  Integer offset, Integer resultsPerPage) {
+        // sort entities
+        entities = sortEntities(entities, orderBy, sortOrder);
+
+        // pagination
+        int pageCount = getRequiredNumberOfResults(entities.size(), offset, resultsPerPage);
+        List<Entity> entitiesReturn = new ArrayList<Entity>();
+        if (pageCount > 0) {
+            entitiesReturn.addAll(entities.subList(offset, (offset + pageCount)));
+        }
+
+        return entitiesReturn;
+    }
+
+    protected Map<String, String> validateEntityFilterByClause(Map<String, String> filterByFieldsValues) {
         for (Map.Entry<String, String> entry : filterByFieldsValues.entrySet()) {
             try {
                 EntityList.EntityFilterByFields.valueOf(entry.getKey().toUpperCase());
@@ -605,21 +645,25 @@ public abstract class AbstractEntityManager {
                         "Invalid filter key: " + entry.getKey(), Response.Status.BAD_REQUEST);
             }
         }
+        return filterByFieldsValues;
     }
 
-    protected List<Entity> getEntities(String type, String startDate, String endDate, String cluster,
-                                       String filterBy, String filterTags, String orderBy, String sortOrder, int offset,
-                                       int resultsPerPage, String nameseq) throws FalconException, IOException {
-        final Map<String, String> filterByFieldsValues = getFilterByFieldsValues(filterBy);
-        final List<String> filterByTags = getFilterByTags(filterTags);
+    protected Map<String, String> validateEntityFilterByClause(String entityFilterByClause) {
+        Map<String, String> filterByFieldsValues = getFilterByFieldsValues(entityFilterByClause);
+        return validateEntityFilterByClause(filterByFieldsValues);
+    }
 
-        EntityType entityType = EntityType.getEnum(type);
+    protected List<Entity> getFilteredEntities(
+            EntityType entityType, String nameSubsequence, String tagKeywords, Map<String, String> filterByFieldsValues,
+            String startDate, String endDate, String cluster) throws FalconException, IOException {
         Collection<String> entityNames = configStore.getEntities(entityType);
         if (entityNames.isEmpty()) {
             return Collections.emptyList();
         }
 
         List<Entity> entities = new ArrayList<Entity>();
+        char[] subsequence = nameSubsequence.toLowerCase().toCharArray();
+        final List<String> tagKeywordsList = getFilterByTags(tagKeywords.toLowerCase());
         for (String entityName : entityNames) {
             Entity entity;
             try {
@@ -628,60 +672,76 @@ public abstract class AbstractEntityManager {
                     continue;
                 }
             } catch (FalconException e1) {
-                LOG.error("Unable to get list for entities for ({})", type, e1);
+                LOG.error("Unable to get list for entities for ({})", entityType.getEntityClass().getSimpleName(), e1);
                 throw FalconWebException.newException(e1, Response.Status.BAD_REQUEST);
             }
 
-            if (SecurityUtil.isAuthorizationEnabled() && !isEntityAuthorized(entity)
-                || filterEntityByDatesAndCluster(entity, startDate, endDate, cluster)) {
+            if (SecurityUtil.isAuthorizationEnabled() && !isEntityAuthorized(entity)) {
                 // the user who requested list query has no permission to access this entity. Skip this entity
                 continue;
             }
+            if (isFilteredByDatesAndCluster(entity, startDate, endDate, cluster)) {
+                // this is for entity summary
+                continue;
+            }
             SecurityUtil.tryProxy(entity);
 
-            List<String> tags = EntityUtil.getTags(entity);
-            List<String> pipelines = EntityUtil.getPipelines(entity);
-            String entityStatus = getStatusString(entity);
+            // filter by fields
+            if (isFilteredByFields(entity, filterByFieldsValues)) {
+                continue;
+            }
 
-            if (filterEntity(entity, entityStatus,
-                    filterByFieldsValues, filterByTags, tags, pipelines)) {
+            // filter by subsequence of name
+            if (subsequence.length > 0 && !matchesNameSubsequence(subsequence, entityName.toLowerCase())) {
                 continue;
             }
 
-            if (StringUtils.isNotBlank(nameseq) && !fuzzySearch(entity.getName(), nameseq)) {
+            // filter by tag keywords
+            if (!matchTagKeywords(tagKeywordsList, entity.getTags())) {
                 continue;
             }
-            entities.add(entity);
-        }
-        // Sort entities before returning a subset of entity elements.
-        entities = sortEntities(entities, orderBy, sortOrder);
 
-        int pageCount = getRequiredNumberOfResults(entities.size(), offset, resultsPerPage);
-        if (pageCount == 0) {  // handle pagination
-            return new ArrayList<Entity>();
+            entities.add(entity);
         }
 
-        return new ArrayList<Entity>(entities.subList(offset, (offset + pageCount)));
+        return entities;
     }
-    //RESUME CHECKSTYLE CHECK ParameterNumberCheck
 
-    boolean fuzzySearch(String enityName, String nameseq) {
-        int currentIndex = 0; // current index in name subsequence which is to be matched
-        char[] nameseqArray = nameseq.toLowerCase().toCharArray();
-        String name = enityName.toLowerCase();
+    //RESUME CHECKSTYLE CHECK ParameterNumberCheck
 
+    private boolean matchesNameSubsequence(char[] subsequence, String name) {
+        int currentIndex = 0; // current index in pattern which is to be matched
         for (Character c : name.toCharArray()) {
-            if (currentIndex < nameseqArray.length && c == nameseqArray[currentIndex]) {
+            if (currentIndex < subsequence.length && c == subsequence[currentIndex]) {
                 currentIndex++;
             }
-            if (currentIndex == nameseqArray.length) {
+            if (currentIndex == subsequence.length) {
                 return true;
             }
         }
         return false;
     }
 
-    private boolean filterEntityByDatesAndCluster(Entity entity, String startDate, String endDate, String cluster)
+    private boolean matchTagKeywords(List<String> tagKeywords, String tags) {
+        if (tagKeywords.isEmpty()) {
+            return true;
+        }
+
+        if (StringUtils.isEmpty(tags)) {
+            return false;
+        }
+
+        tags = tags.toLowerCase();
+        for (String keyword : tagKeywords) {
+            if (tags.indexOf(keyword) == -1) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private boolean isFilteredByDatesAndCluster(Entity entity, String startDate, String endDate, String cluster)
         throws FalconException {
         if (StringUtils.isEmpty(cluster)) {
             return false; // no filtering necessary on cluster
@@ -691,13 +751,13 @@ public abstract class AbstractEntityManager {
             return true; // entity does not have this cluster
         }
 
-        if (!StringUtils.isEmpty(startDate)) {
+        if (StringUtils.isNotEmpty(startDate)) {
             Date parsedDate = EntityUtil.parseDateUTC(startDate);
             if (parsedDate.after(EntityUtil.getEndTime(entity, cluster))) {
                 return true;
             }
         }
-        if (!StringUtils.isEmpty(endDate)) {
+        if (StringUtils.isNotEmpty(endDate)) {
             Date parseDate = EntityUtil.parseDateUTC(endDate);
             if (parseDate.before(EntityUtil.getStartTime(entity, cluster))) {
                 return true;
@@ -710,7 +770,7 @@ public abstract class AbstractEntityManager {
     protected static Map<String, String> getFilterByFieldsValues(String filterBy) {
         // Filter the results by specific field:value, eliminate empty values
         Map<String, String> filterByFieldValues = new HashMap<String, String>();
-        if (!StringUtils.isEmpty(filterBy)) {
+        if (StringUtils.isNotEmpty(filterBy)) {
             String[] fieldValueArray = filterBy.split(",");
             for (String fieldValue : fieldValueArray) {
                 String[] splits = fieldValue.split(":", 2);
@@ -726,7 +786,7 @@ public abstract class AbstractEntityManager {
 
     private static List<String> getFilterByTags(String filterTags) {
         ArrayList<String> filterTagsList = new ArrayList<String>();
-        if (!StringUtils.isEmpty(filterTags)) {
+        if (StringUtils.isNotEmpty(filterTags)) {
             String[] splits = filterTags.split(",");
             for (String tag : splits) {
                 filterTagsList.add(tag.trim());
@@ -746,13 +806,6 @@ public abstract class AbstractEntityManager {
         return statusString;
     }
 
-    private boolean filterEntity(Entity entity, String entityStatus,
-                                 Map<String, String> filterByFieldsValues, List<String> filterByTags,
-                                 List<String> tags, List<String> pipelines) {
-        return filterEntityByTags(filterByTags, tags)
-                || filterEntityByFields(entity, filterByFieldsValues, entityStatus, pipelines);
-    }
-
     protected boolean isEntityAuthorized(Entity entity) {
         try {
             SecurityUtil.getAuthorizationProvider().authorizeEntity(entity.getName(),
@@ -767,7 +820,7 @@ public abstract class AbstractEntityManager {
         return true;
     }
 
-    private boolean filterEntityByTags(List<String> filterTagsList, List<String> tags) {
+    private boolean isFilteredByTags(List<String> filterTagsList, List<String> tags) {
         if (filterTagsList.isEmpty()) {
             return false;
         } else if (tags.isEmpty()) {
@@ -783,8 +836,7 @@ public abstract class AbstractEntityManager {
         return false;
     }
 
-    private boolean filterEntityByFields(Entity entity, Map<String, String> filterKeyVals,
-                                         String status, List<String> pipelines) {
+    private boolean isFilteredByFields(Entity entity, Map<String, String> filterKeyVals) {
         if (filterKeyVals.isEmpty()) {
             return false;
         }
@@ -792,7 +844,7 @@ public abstract class AbstractEntityManager {
         for (Map.Entry<String, String> pair : filterKeyVals.entrySet()) {
             EntityList.EntityFilterByFields filter =
                     EntityList.EntityFilterByFields.valueOf(pair.getKey().toUpperCase());
-            if (isEntityFiltered(entity, filter, pair, status, pipelines)) {
+            if (isEntityFiltered(entity, filter, pair)) {
                 return true;
             }
         }
@@ -801,8 +853,7 @@ public abstract class AbstractEntityManager {
     }
 
     private boolean isEntityFiltered(Entity entity, EntityList.EntityFilterByFields filter,
-                                     Map.Entry<String, String> pair,
-                                     String status, List<String> pipelines) {
+                                     Map.Entry<String, String> pair) {
         switch (filter) {
         case TYPE:
             return !entity.getEntityType().toString().equalsIgnoreCase(pair.getValue());
@@ -811,7 +862,7 @@ public abstract class AbstractEntityManager {
             return !entity.getName().equalsIgnoreCase(pair.getValue());
 
         case STATUS:
-            return !status.equalsIgnoreCase(pair.getValue());
+            return !getStatusString(entity).equalsIgnoreCase(pair.getValue());
 
         case PIPELINES:
             if (!entity.getEntityType().equals(EntityType.PROCESS)) {
@@ -819,11 +870,14 @@ public abstract class AbstractEntityManager {
                         "Invalid filterBy key for non process entities " + pair.getKey(),
                         Response.Status.BAD_REQUEST);
             }
-            return !pipelines.contains(pair.getValue());
+            return !EntityUtil.getPipelines(entity).contains(pair.getValue());
 
         case CLUSTER:
             return !EntityUtil.getClustersDefined(entity).contains(pair.getValue());
 
+        case TAGS:
+            return isFilteredByTags(getFilterByTags(pair.getValue()), EntityUtil.getTags(entity));
+
         default:
             return false;
         }
@@ -831,7 +885,7 @@ public abstract class AbstractEntityManager {
 
     private List<Entity> sortEntities(List<Entity> entities, String orderBy, String sortOrder) {
         // Sort the ArrayList using orderBy param
-        if (!StringUtils.isEmpty(orderBy)) {
+        if (!entities.isEmpty() && StringUtils.isNotEmpty(orderBy)) {
             EntityList.EntityFieldList orderByField = EntityList.EntityFieldList.valueOf(orderBy.toUpperCase());
             final String order = getValidSortOrder(sortOrder, orderBy);
             switch (orderByField) {
@@ -910,16 +964,18 @@ public abstract class AbstractEntityManager {
         EntityElement elem = new EntityElement();
         elem.type = entity.getEntityType().toString();
         elem.name = entity.getName();
-        if (fields.contains("status")) {
+        if (fields.contains(EntityList.EntityFieldList.STATUS.name())) {
             elem.status = getStatusString(entity);
         }
-        if (fields.contains("pipelines")) {
+        if (fields.contains(EntityList.EntityFieldList.PIPELINES.name())) {
             elem.pipeline = EntityUtil.getPipelines(entity);
         }
-        if (fields.contains("tags")) {
+        if (fields.contains(EntityList.EntityFieldList.TAGS.name())) {
             elem.tag = EntityUtil.getTags(entity);
         }
-
+        if (fields.contains(EntityList.EntityFieldList.CLUSTERS.name())) {
+            elem.cluster = new ArrayList<String>(EntityUtil.getClustersDefined(entity));
+        }
         return elem;
     }
 

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java b/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java
index 6198c74..e9a2491 100644
--- a/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java
+++ b/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java
@@ -196,16 +196,22 @@ public abstract class AbstractSchedulableEntityManager extends AbstractInstanceM
                                                 Integer resultsPerPage, Integer numInstances) {
         HashSet<String> fieldSet = new HashSet<String>(Arrays.asList(fields.toLowerCase().split(",")));
         Pair<Date, Date> startAndEndDates = getStartEndDatesForSummary(startDate, endDate);
-        validateEntityFilterByClause(filterBy);
         validateTypeForEntitySummary(type);
+        Map<String, String> filterByFieldsValues = getFilterByFieldsValues(filterBy);
+        validateEntityFilterByClause(filterByFieldsValues);
+        if (StringUtils.isNotEmpty(filterTags)) {
+            filterByFieldsValues.put(EntityList.EntityFilterByFields.TAGS.name(), filterTags);
+        }
 
         List<Entity> entities;
         String colo;
         try {
-            entities = getEntities(type,
-                    SchemaHelper.getDateFormat().format(startAndEndDates.first),
-                    SchemaHelper.getDateFormat().format(startAndEndDates.second),
-                    cluster, filterBy, filterTags, orderBy, sortOrder, offset, resultsPerPage, "");
+            entities = sortEntitiesPagination(
+                    getFilteredEntities(EntityType.valueOf(type.toUpperCase()), "", "", filterByFieldsValues,
+                            SchemaHelper.getDateFormat().format(startAndEndDates.first),
+                            SchemaHelper.getDateFormat().format(startAndEndDates.second),
+                            cluster),
+                    orderBy, sortOrder, offset, resultsPerPage);
             colo = ((Cluster) configStore.get(EntityType.CLUSTER, cluster)).getColo();
         } catch (Exception e) {
             LOG.error("Failed to get entities", e);

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java b/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
index 2dcf779..27e2476 100644
--- a/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
+++ b/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
@@ -18,6 +18,7 @@
 
 package org.apache.falcon.resource.proxy;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.falcon.FalconException;
 import org.apache.falcon.FalconRuntimException;
 import org.apache.falcon.FalconWebException;
@@ -449,20 +450,26 @@ public class SchedulableEntityManagerProxy extends AbstractSchedulableEntityMana
 
     //SUSPEND CHECKSTYLE CHECK ParameterNumberCheck
     @GET
-    @Path("list/{type}")
+    @Path("list{type : (/[^/]+)?}")
     @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_JSON})
+    @Monitored(event = "list")
     @Override
     public EntityList getEntityList(@PathParam("type") String type,
                                     @DefaultValue("") @QueryParam("fields") String fields,
-                                    @DefaultValue("") @QueryParam("filterBy") String filterBy,
+                                    @DefaultValue("") @QueryParam("nameseq") String nameSubsequence,
+                                    @DefaultValue("") @QueryParam("tagkeys") String tagKeywords,
                                     @DefaultValue("") @QueryParam("tags") String tags,
+                                    @DefaultValue("") @QueryParam("filterBy") String filterBy,
                                     @DefaultValue("") @QueryParam("orderBy") String orderBy,
                                     @DefaultValue("asc") @QueryParam("sortOrder") String sortOrder,
                                     @DefaultValue("0") @QueryParam("offset") Integer offset,
                                     @DefaultValue(DEFAULT_NUM_RESULTS)
-                                    @QueryParam("numResults") Integer resultsPerPage,
-                                    @QueryParam("nameseq") String nameseq) {
-        return super.getEntityList(type, fields, filterBy, tags, orderBy, sortOrder, offset, resultsPerPage, nameseq);
+                                    @QueryParam("numResults") Integer resultsPerPage) {
+        if (StringUtils.isNotEmpty(type)) {
+            type = type.substring(1);
+        }
+        return super.getEntityList(fields, nameSubsequence, tagKeywords, type, tags, filterBy,
+                orderBy, sortOrder, offset, resultsPerPage);
     }
 
     @GET

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java
----------------------------------------------------------------------
diff --git a/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java b/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java
index 9b0dec5..c37da40 100644
--- a/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java
+++ b/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java
@@ -18,7 +18,6 @@
 package org.apache.falcon.resource;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.falcon.FalconException;
 import org.apache.falcon.FalconWebException;
 import org.apache.falcon.entity.store.FeedLocationStore;
 import org.apache.falcon.entity.v0.Entity;
@@ -134,7 +133,7 @@ public class EntityManagerTest extends AbstractEntityManager {
          * Only one entity should be returned when the auth is enabled.
          */
         try {
-            getEntityList("process", "", "", "", "", "", 0, 10, "");
+            getEntityList("", "", "", "process", "", "", "", "", 0, 10);
             Assert.fail();
         } catch (Throwable ignore) {
             // do nothing
@@ -151,7 +150,7 @@ public class EntityManagerTest extends AbstractEntityManager {
         Entity process2 = buildProcess("processAuthUser", System.getProperty("user.name"), "", "");
         configStore.publish(EntityType.PROCESS, process2);
 
-        EntityList entityList = this.getEntityList("process", "", "", "", "", "asc", 0, 10, "");
+        EntityList entityList = this.getEntityList("", "", "", "process", "", "", "", "asc", 0, 10);
         Assert.assertNotNull(entityList.getElements());
         Assert.assertEquals(entityList.getElements().length, 1);
 
@@ -160,7 +159,7 @@ public class EntityManagerTest extends AbstractEntityManager {
          */
         StartupProperties.get().setProperty("falcon.security.authorization.enabled", "true");
         CurrentUser.authenticate(System.getProperty("user.name"));
-        entityList = this.getEntityList("process", "", "", "", "", "desc", 0, 10, "");
+        entityList = this.getEntityList("", "", "", "process", "", "", "", "desc", 0, 10);
         Assert.assertNotNull(entityList.getElements());
         Assert.assertEquals(entityList.getElements().length, 1);
 
@@ -196,8 +195,8 @@ public class EntityManagerTest extends AbstractEntityManager {
         Entity process4 = buildProcess("process4", user, "owner=producer@xyz.com", "");
         configStore.publish(EntityType.PROCESS, process4);
 
-        EntityList entityList = this.getEntityList("process", "tags", "PIPELINES:dataReplicationPipeline",
-                "", "name", "desc", 1, 1, "");
+        EntityList entityList = this.getEntityList("tags", "", "", "process", "", "PIPELINES:dataReplicationPipeline",
+                "name", "desc", 1, 1);
         Assert.assertNotNull(entityList.getElements());
         Assert.assertEquals(entityList.getElements().length, 1);
         Assert.assertEquals(entityList.getElements()[0].name, "process1");
@@ -206,8 +205,8 @@ public class EntityManagerTest extends AbstractEntityManager {
         Assert.assertEquals(entityList.getElements()[0].status, null);
 
 
-        entityList = this.getEntityList("process", "pipelines", "",
-                "consumer=consumer@xyz.com, owner=producer@xyz.com", "name", "", 0, 2, "");
+        entityList = this.getEntityList("pipelines", "", "", "process",
+                "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "", 0, 2);
         Assert.assertNotNull(entityList.getElements());
         Assert.assertEquals(entityList.getElements().length, 2);
         Assert.assertEquals(entityList.getElements()[1].name, "process2");
@@ -215,18 +214,18 @@ public class EntityManagerTest extends AbstractEntityManager {
         Assert.assertEquals(entityList.getElements()[1].pipeline.get(0), "testPipeline");
         Assert.assertEquals(entityList.getElements()[0].tag, null);
 
-        entityList = this.getEntityList("process", "pipelines", "",
-                "consumer=consumer@xyz.com, owner=producer@xyz.com", "name", "", 10, 2, "");
+        entityList = this.getEntityList("pipelines", "", "", "process",
+                "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "", 10, 2);
         Assert.assertEquals(entityList.getElements().length, 0);
 
-        entityList = this.getEntityList("process", "pipelines", "",
-                "owner=producer@xyz.com", "name", "", 1, 2, "");
+        entityList = this.getEntityList("pipelines", "", "", "process",
+                "owner=producer@xyz.com", "", "name", "", 1, 2);
         Assert.assertEquals(entityList.getElements().length, 2);
 
         // Test negative value for numResults, should throw an exception.
         try {
-            this.getEntityList("process", "pipelines", "",
-                    "consumer=consumer@xyz.com, owner=producer@xyz.com", "name", "", 10, -1, "");
+            this.getEntityList("pipelines", "", "", "process",
+                    "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "", 10, -1);
             Assert.assertTrue(false);
         } catch (Throwable e) {
             Assert.assertTrue(true);
@@ -234,8 +233,8 @@ public class EntityManagerTest extends AbstractEntityManager {
 
         // Test invalid entry for sortOrder
         try {
-            this.getEntityList("process", "pipelines", "",
-                    "consumer=consumer@xyz.com, owner=producer@xyz.com", "name", "invalid", 10, 2, "");
+            this.getEntityList("pipelines", "", "", "process",
+                    "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "invalid", 10, 2);
             Assert.assertTrue(false);
         } catch (Throwable e) {
             Assert.assertTrue(true);
@@ -243,37 +242,41 @@ public class EntityManagerTest extends AbstractEntityManager {
     }
 
     @Test
-    public void testSearch() throws FalconException {
-        Assert.assertTrue(fuzzySearch("My-Hourly-Summary", "mhs"));
-        Assert.assertTrue(fuzzySearch("New-My-Hourly-Summary", "MHs"));
-        Assert.assertFalse(fuzzySearch("My-Hourly-Summary", "moh"));
-    }
-
-    @Test
-    public void testGetEntityListWithPattern() throws FalconException {
+    public void testGetEntityListKeywordSearch() throws Exception {
         String user = System.getProperty("user.name");
 
-        Entity process1 = buildProcess("New-My-Hourly-Summary", user,
-                "consumer=consumer@xyz.com, owner=producer@xyz.com",
-                "testPipeline,dataReplicationPipeline");
+        Entity process1 = buildProcess("SampleProcess1", user, "related=healthcare,department=billingDepartment", "");
         configStore.publish(EntityType.PROCESS, process1);
 
-        Entity process2 = buildProcess("Random-Summary-Generator", user,
-                "consumer=consumer@xyz.com, owner=producer@xyz.com",
-                "testPipeline,dataReplicationPipeline");
+        Entity process2 = buildProcess("SampleProcess2", user,
+                "category=usHealthcarePlans,department=billingDepartment", "");
         configStore.publish(EntityType.PROCESS, process2);
 
-        Entity process3 = buildProcess("My-Hourly-Summary", user, "", "testPipeline");
+        Entity process3 = buildProcess("SampleProcess3", user, "", "");
         configStore.publish(EntityType.PROCESS, process3);
 
-        Entity process4 = buildProcess("sample-process4", user, "owner=producer@xyz.com", "");
+        Entity process4 = buildProcess("SampleProcess4", user, "department=billingDepartment", "");
         configStore.publish(EntityType.PROCESS, process4);
 
-        EntityList entityList = this.getEntityList("process", "tags", "PIPELINES:dataReplicationPipeline",
-                "", "name", "desc", 0, 10, "mhs");
+        Entity process5 = buildProcess("Process5", user, "category=usHealthcarePlans,department=billingDepartment", "");
+        configStore.publish(EntityType.PROCESS, process5);
+
+        EntityList entityList = this.getEntityList("", "sample", "health,billing", "", "", "", "name", "", 0, 10);
+        Assert.assertNotNull(entityList.getElements());
+        Assert.assertEquals(entityList.getElements().length, 2);
+        Assert.assertEquals(entityList.getElements()[0].name, "SampleProcess1");
+        Assert.assertEquals(entityList.getElements()[1].name, "SampleProcess2");
+
+        entityList = this.getEntityList("", "sample4", "", "", "", "", "", "", 0, 10);
         Assert.assertNotNull(entityList.getElements());
         Assert.assertEquals(entityList.getElements().length, 1);
+        Assert.assertEquals(entityList.getElements()[0].name, "SampleProcess4");
 
+        entityList = this.getEntityList("", "", "health,us", "", "", "", "name", "", 0, 10);
+        Assert.assertNotNull(entityList.getElements());
+        Assert.assertEquals(entityList.getElements().length, 2);
+        Assert.assertEquals(entityList.getElements()[0].name, "Process5");
+        Assert.assertEquals(entityList.getElements()[1].name, "SampleProcess2");
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java b/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java
index 82a622c..fa04add 100644
--- a/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java
+++ b/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java
@@ -18,6 +18,7 @@
 
 package org.apache.falcon.resource;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.falcon.monitors.Dimension;
 import org.apache.falcon.monitors.Monitored;
 
@@ -55,21 +56,26 @@ public class SchedulableEntityManager extends AbstractSchedulableEntityManager {
 
     //SUSPEND CHECKSTYLE CHECK ParameterNumberCheck
     @GET
-    @Path("list/{type}")
+    @Path("list{type : (/[^/]+)?}")
     @Produces({MediaType.TEXT_XML, MediaType.APPLICATION_JSON})
     @Monitored(event = "list")
     @Override
     public EntityList getEntityList(@Dimension("type") @PathParam("type") String type,
                                     @DefaultValue("") @QueryParam("fields") String fields,
-                                    @DefaultValue("") @QueryParam("filterBy") String filterBy,
+                                    @DefaultValue("") @QueryParam("nameseq") String nameSubsequence,
+                                    @DefaultValue("") @QueryParam("tagkeys") String tagKeywords,
                                     @DefaultValue("") @QueryParam("tags") String tags,
+                                    @DefaultValue("") @QueryParam("filterBy") String filterBy,
                                     @DefaultValue("") @QueryParam("orderBy") String orderBy,
                                     @DefaultValue("asc") @QueryParam("sortOrder") String sortOrder,
                                     @DefaultValue("0") @QueryParam("offset") Integer offset,
                                     @DefaultValue(DEFAULT_NUM_RESULTS)
-                                    @QueryParam("numResults") Integer resultsPerPage,
-                                    @QueryParam("nameseq") String nameseq) {
-        return super.getEntityList(type, fields, filterBy, tags, orderBy, sortOrder, offset, resultsPerPage, nameseq);
+                                    @QueryParam("numResults") Integer resultsPerPage) {
+        if (StringUtils.isNotEmpty(type)) {
+            type = type.substring(1);
+        }
+        return super.getEntityList(fields, nameSubsequence, tagKeywords, type, tags, filterBy,
+                orderBy, sortOrder, offset, resultsPerPage);
     }
 
     @GET

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java b/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java
index dd14e9c..797b595 100644
--- a/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java
+++ b/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java
@@ -554,12 +554,11 @@ public class FalconCLIIT {
         OozieTestUtils.waitForProcessWFtoStart(context);
 
         // test entity List cli
+        Assert.assertEquals(executeWithURL("entity -list -offset 0 -numResults 1"), 0);
+        Assert.assertEquals(executeWithURL("entity -list -type feed,process -offset 0 -numResults 1"), 0);
+        Assert.assertEquals(executeWithURL("entity -list -type feed,process -offset 0 -numResults 1 "
+                + "-nameseq abc -tagkeys abc"), 0);
         Assert.assertEquals(executeWithURL("entity -list -type cluster" + " -offset 0 -numResults 1"), 0);
-
-        Assert.assertEquals(executeWithURL("entity -list -type process -fields status "
-                + " -filterBy STATUS:SUBMITTED,TYPE:process -orderBy name "
-                + " -sortOrder asc -offset 1 -numResults 1 -nameseq abc"), 0);
-
         Assert.assertEquals(executeWithURL("entity -list -type process -fields status "
                 + " -filterBy STATUS:SUBMITTED,TYPE:process -orderBy name "
                 + " -sortOrder asc -offset 1 -numResults 1"), 0);

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/webapp/src/test/java/org/apache/falcon/cli/FalconCLISmokeIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/falcon/cli/FalconCLISmokeIT.java b/webapp/src/test/java/org/apache/falcon/cli/FalconCLISmokeIT.java
index ee5534a..7c1a42e 100644
--- a/webapp/src/test/java/org/apache/falcon/cli/FalconCLISmokeIT.java
+++ b/webapp/src/test/java/org/apache/falcon/cli/FalconCLISmokeIT.java
@@ -80,6 +80,10 @@ public class FalconCLISmokeIT {
         OozieTestUtils.waitForProcessWFtoStart(context);
 
         // test entity List cli
+        Assert.assertEquals(executeWithURL("entity -list -offset 0 -numResults 1"), 0);
+        Assert.assertEquals(executeWithURL("entity -list -type feed,process -offset 0 -numResults 1"), 0);
+        Assert.assertEquals(executeWithURL("entity -list -type feed,process -offset 0 -numResults 1 "
+                + "-nameseq abc -tagkeys abc"), 0);
         Assert.assertEquals(executeWithURL("entity -list -type cluster -offset 0 -numResults 1"), 0);
         Assert.assertEquals(executeWithURL("entity -list -type process -fields status "
                         + " -filterBy STATUS:SUBMITTED,TYPE:process -orderBy name -offset 1 -numResults 1"), 0);

http://git-wip-us.apache.org/repos/asf/falcon/blob/1bae2a6f/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java b/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java
index 280253d..47b51fe 100644
--- a/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java
+++ b/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java
@@ -814,6 +814,32 @@ public class EntityManagerJerseyIT {
         for (EntityList.EntityElement entityElement : result.getElements()) {
             Assert.assertNull(entityElement.status); // status is null
         }
+
+        response = context.service
+                .path("api/entities/list/feed,process/")
+                .header("Cookie", context.getAuthenticationToken())
+                .type(MediaType.TEXT_XML)
+                .accept(MediaType.TEXT_XML)
+                .get(ClientResponse.class);
+        Assert.assertEquals(response.getStatus(), 200);
+        result = response.getEntity(EntityList.class);
+        Assert.assertNotNull(result);
+        for (EntityList.EntityElement entityElement : result.getElements()) {
+            Assert.assertNull(entityElement.status); // status is null
+        }
+
+        response = context.service
+                .path("api/entities/list/")
+                .header("Cookie", context.getAuthenticationToken())
+                .type(MediaType.TEXT_XML)
+                .accept(MediaType.TEXT_XML)
+                .get(ClientResponse.class);
+        Assert.assertEquals(response.getStatus(), 200);
+        result = response.getEntity(EntityList.class);
+        Assert.assertNotNull(result);
+        for (EntityList.EntityElement entityElement : result.getElements()) {
+            Assert.assertNull(entityElement.status); // status is null
+        }
     }
 
     @Test


Mime
View raw message