You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2013/03/20 21:44:50 UTC

svn commit: r1459041 [3/18] - in /incubator/ambari/branches/branch-1.2: ./ ambari-agent/ ambari-agent/conf/unix/ ambari-agent/src/main/puppet/modules/hdp-ganglia/files/ ambari-agent/src/main/puppet/modules/hdp-ganglia/manifests/ ambari-agent/src/main/p...

Modified: incubator/ambari/branches/branch-1.2/ambari-server/docs/api/v1/services-service.md
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/docs/api/v1/services-service.md?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/docs/api/v1/services-service.md (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/docs/api/v1/services-service.md Wed Mar 20 20:44:43 2013
@@ -28,43 +28,45 @@ Refers to a specific service identified 
 
     200 OK
     {
-    "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services/HDFS",
-    "ServiceInfo" : {
-      "cluster_name" : "MyCluster",
-      "service_name" : "HDFS"
-      },
-    "components" : [
-      {
-      "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services/HDFS/components/NAMENODE",
-      "ServiceComponentInfo" : {
-        "cluster_name" : "MyCluster",
-        "component_name" : "NAMENODE",
-        "service_name" : "HDFS"
-        }
-      },
-      {
-      "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services/HDFS/components/DATANODE",
-      "ServiceComponentInfo" : {
-        "cluster_name" : "MyCluster",
-        "component_name" : "DATANODE",
-        "service_name" : "HDFS"
-        }
-      },
-      {
-      "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services/HDFS/components/HDFS_CLIENT",
-      "ServiceComponentInfo" : {
-        "cluster_name" : "MyCluster",
-        "component_name" : "HDFS_CLIENT",
-        "service_name" : "HDFS"
-        }
-      },
-      {
-      "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services/HDFS/components/SECONDARY_NAMENODE",
-      "ServiceComponentInfo" : {
-        "cluster_name" : "MyCluster",
-        "component_name" : "SECONDARY_NAMENODE",
-        "service_name" : "HDFS"
-        }
-      } ]
+    	"href" : "http://your.ambari.server/api/v1/clusters/c1/services/HDFS",
+    	"ServiceInfo" : {
+      		"cluster_name" : "c1",
+      		"service_name" : "HDFS",
+      		"state" : "STARTED"      		
+      	},
+    	"components" : [
+      		{
+      			"href" : "http://your.ambari.server/api/v1/clusters/c1/services/HDFS/components/NAMENODE",
+      			"ServiceComponentInfo" : {
+        			"cluster_name" : "c1",
+        			"component_name" : "NAMENODE",
+        			"service_name" : "HDFS"
+       			}
+      		},
+      		{
+      			"href" : "http://your.ambari.server/api/v1/clusters/c1/services/HDFS/components/DATANODE",
+      			"ServiceComponentInfo" : {
+        			"cluster_name" : "c1",
+        			"component_name" : "DATANODE",
+        			"service_name" : "HDFS"
+        		}
+      		},
+      		{
+      			"href" : "http://your.ambari.server/api/v1/clusters/c1/services/HDFS/components/HDFS_CLIENT",
+      			"ServiceComponentInfo" : {
+        			"cluster_name" : "c1",
+        			"component_name" : "HDFS_CLIENT",
+        			"service_name" : "HDFS"
+        		}
+      		},
+      		{
+      			"href" : "http://your.ambari.server/api/v1/clusters/c1/services/HDFS/components/SECONDARY_NAMENODE",
+     			"ServiceComponentInfo" : {
+        			"cluster_name" : "c1",
+        			"component_name" : "SECONDARY_NAMENODE",
+        			"service_name" : "HDFS"
+        		}
+      		}
+      	]
     }
 

Modified: incubator/ambari/branches/branch-1.2/ambari-server/docs/api/v1/services.md
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/docs/api/v1/services.md?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/docs/api/v1/services.md (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/docs/api/v1/services.md Wed Mar 20 20:44:43 2013
@@ -28,28 +28,28 @@ Returns a collection of the services in 
 
     200 OK
     {
-    "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services",
-    "items" : [
-        {
-        "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services/NAGIOS",
-        "ServiceInfo" : {
-          "cluster_name" : "MyCluster",
-          "service_name" : "NAGIOS"
-          }
-        },
-        {
-        "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services/HCATALOG",
-        "ServiceInfo" : {
-          "cluster_name" : "MyCluster",
-          "service_name" : "HCATALOG"
-          }
-        },
-        {
-        "href" : "http://your.ambari.server/api/v1/clusters/MyCluster/services/PIG",
-        "ServiceInfo" : {
-          "cluster_name" : "MyCluster",
-          "service_name" : "PIG"
-          }
-        }
-      ]
-    }
+    	"href" : "http://your.ambari.server/api/v1/clusters/c1/services",
+    	"items" : [
+    		{
+        		"href" : "http://your.ambari.server/api/v1/clusters/c1/services/NAGIOS",
+        		"ServiceInfo" : {
+          			"cluster_name" : "c1",
+          			"service_name" : "NAGIOS"
+          		}
+        	},
+        	{
+        		"href" : "http://your.ambari.server/api/v1/clusters/c1/services/HCATALOG",
+        		"ServiceInfo" : {
+        	  		"cluster_name" : "c1",
+        	  		"service_name" : "HCATALOG"
+        	  	}
+        	},
+        	{
+        		"href" : "http://your.ambari.server/api/v1/clusters/c1/services/PIG",
+        		"ServiceInfo" : {
+        	  		"cluster_name" : "c1",
+        	  		"service_name" : "PIG"
+        	  	}	
+        	}
+        ]
+    }    
\ No newline at end of file

Modified: incubator/ambari/branches/branch-1.2/ambari-server/pom.xml
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/pom.xml?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/pom.xml (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/pom.xml Wed Mar 20 20:44:43 2013
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.apache.ambari</groupId>
     <artifactId>ambari-project</artifactId>
-    <version>1.2.1-SNAPSHOT</version>
+    <version>1.2.2-SNAPSHOT</version>
     <relativePath>../ambari-project</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -24,14 +24,19 @@
   <artifactId>ambari-server</artifactId>
   <packaging>jar</packaging>
   <name>Ambari Server</name>
-  <version>1.2.1-SNAPSHOT</version>
+  <version>1.2.2-SNAPSHOT</version>
   <description>Ambari Server</description>
   <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <python.ver>python &gt;= 2.6</python.ver>
   </properties>
   <build>
     <plugins>
       <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.0</version>
+      </plugin>
+      <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
         <configuration>
           <descriptors>
@@ -248,7 +253,24 @@
               <groupname>root</groupname>
               <sources>
                 <source>
-                  <location>src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.2.1.sql</location>
+                  <location>src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.2.2.sql</location>
+                </source>
+                <source>
+                  <location>src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.2.2.Fix.sql</location>
+                </source>
+                <source>
+                  <location>src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.2.2.Check.sql</location>
+                </source>
+              </sources>
+            </mapping>
+            <mapping>
+              <directory>/var/lib/ambari-server/resources/upgrade/dml</directory>
+              <filemode>755</filemode>
+              <username>root</username>
+              <groupname>root</groupname>
+              <sources>
+                <source>
+                  <location>src/main/resources/upgrade/dml/Ambari-DML-Postgres-UPGRADE_STACK.sql</location>
                 </source>
               </sources>
             </mapping>

Modified: incubator/ambari/branches/branch-1.2/ambari-server/sbin/ambari-server
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/sbin/ambari-server?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/sbin/ambari-server (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/sbin/ambari-server Wed Mar 20 20:44:43 2013
@@ -77,6 +77,10 @@ case "$1" in
         echo -e "Upgrading ambari-server"
         $PYTHON /usr/sbin/ambari-server.py $@
         ;;
+  upgradestack)
+        echo -e "Upgrading stack of ambari-server"
+        $PYTHON /usr/sbin/ambari-server.py $@
+        ;;
   setup)
         echo -e "Run postgresql initdb"
         initdb_res=`/sbin/service postgresql initdb`
@@ -89,7 +93,7 @@ case "$1" in
         $PYTHON /usr/sbin/ambari-server.py $@
         ;;
   *)
-        echo "Usage: /usr/sbin/ambari-server {start|stop|restart|setup|upgrade} [options]"
+        echo "Usage: /usr/sbin/ambari-server {start|stop|restart|setup|upgrade|upgradestack} [options]"
         exit 1
 esac
 

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java Wed Mar 20 20:44:43 2013
@@ -181,6 +181,8 @@ public class ActionDBAccessorImpl implem
         hostRoleCommand.setTaskId(hostRoleCommandEntity.getTaskId());
         ExecutionCommandEntity executionCommandEntity = hostRoleCommand.constructExecutionCommandEntity();
         executionCommandEntity.setHostRoleCommand(hostRoleCommandEntity);
+
+        executionCommandEntity.setTaskId(hostRoleCommandEntity.getTaskId());
         hostRoleCommandEntity.setExecutionCommand(executionCommandEntity);
 
         executionCommandDAO.create(hostRoleCommandEntity.getExecutionCommand());

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java Wed Mar 20 20:44:43 2013
@@ -17,11 +17,9 @@
  */
 package org.apache.ambari.server.actionmanager;
 
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
-
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
 import org.apache.ambari.server.agent.ActionQueue;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.controller.HostsMap;
@@ -30,9 +28,10 @@ import org.apache.ambari.server.utils.St
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
 
 
 /**
@@ -75,6 +74,9 @@ public class ActionManager {
       LOG.info("Persisting stage into db: " + s.toString());
     }
     db.persistActions(stages);
+
+    // Now scheduler should process actions
+    scheduler.awake();
   }
 
   public List<Stage> getRequestStatus(long requestId) {

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java Wed Mar 20 20:44:43 2013
@@ -17,32 +17,25 @@
  */
 package org.apache.ambari.server.actionmanager;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.Role;
 import org.apache.ambari.server.ServiceComponentNotFoundException;
 import org.apache.ambari.server.agent.ActionQueue;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.controller.HostsMap;
-import org.apache.ambari.server.state.Cluster;
-import org.apache.ambari.server.state.Clusters;
-import org.apache.ambari.server.state.Service;
-import org.apache.ambari.server.state.ServiceComponent;
-import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.*;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpFailedEvent;
-import org.apache.ambari.server.utils.StageUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-//This class encapsulates the action scheduler thread.
-//Action schedule frequently looks at action database and determines if
-//there is an action that can be scheduled.
+import java.util.*;
+
+/**
+ * This class encapsulates the action scheduler thread.
+ * Action schedule frequently looks at action database and determines if
+ * there is an action that can be scheduled.
+ */
 class ActionScheduler implements Runnable {
 
   private static Logger LOG = LoggerFactory.getLogger(ActionScheduler.class);
@@ -56,6 +49,14 @@ class ActionScheduler implements Runnabl
   private final Clusters fsmObject;
   private boolean taskTimeoutAdjustment = true;
   private final HostsMap hostsMap;
+  private final Object wakeupSyncObject = new Object();
+
+  /**
+   * true if scheduler should run ASAP.
+   * We need this flag to avoid sleep in situations, when
+   * we receive awake() request during running a scheduler iteration.
+   */
+  private boolean activeAwakeRequest = false;
 
   public ActionScheduler(long sleepTimeMilliSec, long actionTimeoutMilliSec,
       ActionDBAccessor db, ActionQueue actionQueue, Clusters fsmObject,
@@ -79,11 +80,28 @@ class ActionScheduler implements Runnabl
     schedulerThread.interrupt();
   }
 
+  /**
+   * Should be called from another thread when we want scheduler to
+   * make a run ASAP (for example, to process desired configs of SCHs).
+   * The method is guaranteed to return quickly.
+   */
+  public void awake() {
+    synchronized (wakeupSyncObject) {
+      activeAwakeRequest = true;
+      wakeupSyncObject.notify();
+    }
+  }
+
   @Override
   public void run() {
     while (shouldRun) {
       try {
-        Thread.sleep(sleepTime);
+        synchronized (wakeupSyncObject) {
+          if (!activeAwakeRequest) {
+              wakeupSyncObject.wait(sleepTime);
+          }
+          activeAwakeRequest = false;
+        }
         doWork();
       } catch (InterruptedException ex) {
         LOG.warn("Scheduler thread is interrupted going to stop", ex);

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java Wed Mar 20 20:44:43 2013
@@ -223,13 +223,9 @@ public class HeartBeatHandler {
               if (prevState.equals(State.INSTALLED)
                   || prevState.equals(State.START_FAILED)
                   || prevState.equals(State.STARTED)
+                  || prevState.equals(State.STARTING)
+                  || prevState.equals(State.STOPPING)
                   || prevState.equals(State.STOP_FAILED)) {
-                if (prevState == State.START_FAILED
-                        && liveState == State.INSTALLED) {
-                  LOG.info("Ignoring INSTALLED state update for " +
-                          "START_FAILED component");
-                  continue;
-                }
                 scHost.setState(liveState);
                 if (!prevState.equals(liveState)) {
                   LOG.info("State of service component " + componentName

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java Wed Mar 20 20:44:43 2013
@@ -18,10 +18,12 @@
 
 package org.apache.ambari.server.api.handlers;
 
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.Request;
 import org.apache.ambari.server.api.services.Result;
 import org.apache.ambari.server.api.services.ResultImpl;
+import org.apache.ambari.server.api.services.ResultStatus;
 import org.apache.ambari.server.api.services.persistence.PersistenceManager;
 import org.apache.ambari.server.api.services.persistence.PersistenceManagerImpl;
 import org.apache.ambari.server.api.util.TreeNode;
@@ -57,7 +59,13 @@ public abstract class BaseManagementHand
 
   public Result handleRequest(Request request) {
     ResourceInstance resource = request.getResource();
-    Predicate queryPredicate = request.getQueryPredicate();
+    Predicate queryPredicate;
+    try {
+      queryPredicate = request.getQueryPredicate();
+    } catch (InvalidQueryException e) {
+      return new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST,
+          "Invalid Request: " + e.getMessage()));
+    }
     if (queryPredicate != null) {
       resource.getQuery().setUserPredicate(queryPredicate);
     }

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/ReadHandler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/ReadHandler.java?rev=1459041&r1=1459040&r2=1459041&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/ReadHandler.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/ReadHandler.java Wed Mar 20 20:44:43 2013
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.api.handlers;
 
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
 import org.apache.ambari.server.api.services.Request;
 import org.apache.ambari.server.api.services.ResultImpl;
 import org.apache.ambari.server.api.services.ResultStatus;
@@ -51,9 +52,12 @@ public class ReadHandler implements Requ
       return new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage()));
     }
 
-    query.setUserPredicate(request.getQueryPredicate());
     Result result;
+    Predicate p = null;
     try {
+      p = request.getQueryPredicate();
+      query.setUserPredicate(p);
+
       result = query.execute();
       result.setResultStatus(new ResultStatus(ResultStatus.STATUS.OK));
     } catch (SystemException e) {
@@ -63,7 +67,7 @@ public class ReadHandler implements Requ
     } catch (UnsupportedPropertyException e) {
       result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage()));
     } catch (NoSuchResourceException e) {
-      if (request.getQueryPredicate() == null) {
+      if (p == null) {
         // no predicate specified, resource requested by id
         result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e.getMessage()));
       } else {
@@ -74,6 +78,9 @@ public class ReadHandler implements Requ
     } catch (IllegalArgumentException e) {
       result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST,
           "Invalid Request: " + e.getMessage()));
+    } catch (InvalidQueryException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST,
+          "Invalid Request: " + e.getMessage()));
     } catch (RuntimeException e) {
       if (LOG.isErrorEnabled()) {
         LOG.error("Caught a runtime exception executing a query", e);

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/InvalidQueryException.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/InvalidQueryException.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/InvalidQueryException.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/InvalidQueryException.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate;
+
+/**
+ * Exception indicating that a query compilation error occurred.
+ */
+public class InvalidQueryException extends Exception {
+  /**
+   * Constructor.
+   *
+   * @param msg msg
+   */
+  public InvalidQueryException(String msg) {
+    super(msg);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param msg        msg
+   * @param throwable  root cause
+   */
+  public InvalidQueryException(String msg, Throwable throwable) {
+    super(msg, throwable);
+  }
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/PredicateCompiler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/PredicateCompiler.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/PredicateCompiler.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/PredicateCompiler.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate;
+
+import org.apache.ambari.server.controller.spi.Predicate;
+
+/**
+ * Compiler which takes a query expression as input and produces a predicate instance as output.
+ */
+public class PredicateCompiler {
+
+  /**
+   * Lexer instance used to translate expressions into stream of tokens.
+   */
+  private QueryLexer lexer = new QueryLexer();
+
+  /**
+   * Parser instance used to produce a predicate instance from a stream of tokens.
+   */
+  private QueryParser parser = new QueryParser();
+
+  /**
+   * Generate a predicate from a query expression.
+   *
+   * @param exp  query expression
+   *
+   * @return a predicate instance
+   * @throws InvalidQueryException if unable to compile the expression
+   */
+  public Predicate compile(String exp) throws InvalidQueryException {
+    return parser.parse(lexer.tokens(exp));
+  }
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,501 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Scans a query expression and generates an array of tokens.
+ * Each token contains type and value information.
+ *
+ * First, the query expression is broken down into string tokens using
+ * a regular expression which splits on a set of deliminators which includes
+ * operators and brackets.
+ *
+ * Second, each string token is converted into a Token with type and value information.
+ */
+public class QueryLexer {
+  /**
+   * All valid deliminators.
+   */
+  private static final String[] ALL_DELIMS =
+      {".in\\(",".isEmpty\\(","<=",">=","!=","=","<",">","&","|","!","(", ")"};
+
+  /**
+   * Map of token type to list of valid handlers for next token.
+   */
+  private static final Map<Token.TYPE, List<TokenHandler>> TOKEN_HANDLERS =
+      new HashMap<Token.TYPE, List<TokenHandler>>();
+
+  /**
+   * Set of property names to ignore.
+   */
+  private static final Set<String> SET_IGNORE = new HashSet<String>();
+
+  /**
+   * Constructor.
+   * Register token handlers.
+   */
+  public QueryLexer() {
+    //todo: refactor handler registration
+    List<TokenHandler> listHandlers = new ArrayList<TokenHandler>();
+    listHandlers.add(new LogicalUnaryOperatorTokenHandler());
+    listHandlers.add(new OpenBracketTokenHandler());
+    listHandlers.add(new PropertyOperandTokenHandler());
+
+    TOKEN_HANDLERS.put(Token.TYPE.BRACKET_OPEN, listHandlers);
+    TOKEN_HANDLERS.put(Token.TYPE.LOGICAL_OPERATOR, listHandlers);
+    TOKEN_HANDLERS.put(Token.TYPE.LOGICAL_UNARY_OPERATOR, listHandlers);
+
+    listHandlers= new ArrayList<TokenHandler>();
+    listHandlers.add(new RelationalOperatorTokenHandler());
+    listHandlers.add(new RelationalOperatorFuncTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.PROPERTY_OPERAND, listHandlers);
+
+    listHandlers = new ArrayList<TokenHandler>();
+    listHandlers.add(new ValueOperandTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.RELATIONAL_OPERATOR, listHandlers);
+
+    listHandlers = new ArrayList<TokenHandler>();
+    listHandlers.add(new CloseBracketTokenHandler());
+    listHandlers.add(new ValueOperandTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.RELATIONAL_OPERATOR_FUNC, listHandlers);
+
+    listHandlers = new ArrayList<TokenHandler>();
+    listHandlers.add(new CloseBracketTokenHandler());
+    listHandlers.add(new LogicalOperatorTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.VALUE_OPERAND, listHandlers);
+    TOKEN_HANDLERS.put(Token.TYPE.BRACKET_CLOSE, listHandlers);
+  }
+
+
+  /**
+   * Scan the provided query and generate a token stream to be used by the query parser.
+   *
+   * @param exp  the query expression to scan
+   *
+   * @return an array of tokens
+   * @throws InvalidQueryException if the query is invalid
+   */
+  public Token[] tokens(String exp) throws InvalidQueryException {
+
+    ScanContext ctx = new ScanContext();
+    for (String tok : parseStringTokens(exp)) {
+      List<TokenHandler> listHandlers = TOKEN_HANDLERS.get(ctx.getLastTokenType());
+      boolean            processed    = false;
+      int                idx          = 0;
+
+      while (!processed && idx < listHandlers.size()) {
+        processed = listHandlers.get(idx++).handleToken(tok, ctx);
+      }
+
+      if (! processed) {
+        throw new InvalidQueryException("Invalid Query Token: token='" +
+            tok + "\', previous token type=" + ctx.getLastTokenType());
+      }
+    }
+    return ctx.getTokenList().toArray(new Token[ctx.getTokenList().size()]);
+  }
+
+  /**
+   * Uses a regular expression to scan a query expression and produce a list of string tokens.
+   * These tokens are the exact strings that exist in the original syntax.
+   *
+   * @param exp  the query expression
+   *
+   * @return list of string tokens from the query expression
+   */
+  private List<String> parseStringTokens(String exp) {
+    Pattern      pattern       = generatePattern();
+    Matcher      matcher       = pattern.matcher(exp);
+    List<String> listStrTokens = new ArrayList<String>();
+    int pos = 0;
+
+    while (matcher.find()) { // while there's a delimiter in the string
+      if (pos != matcher.start()) {
+        // add anything between the current and previous delimiter to the tokens list
+        listStrTokens.add(exp.substring(pos, matcher.start()));
+      }
+      listStrTokens.add(matcher.group()); // add the delimiter
+      pos = matcher.end(); // Remember end of delimiter
+    }
+    if (pos != exp.length()) {
+      // Add any chars remaining in the string after last delimiter
+      listStrTokens.add(exp.substring(pos));
+    }
+    return listStrTokens;
+  }
+
+  /**
+   * Generate the regex pattern to tokenize the query expression.
+   *
+   * @return the regex pattern
+   */
+  private Pattern generatePattern() {
+    StringBuilder sb = new StringBuilder();
+    sb.append('(');
+    for (String delim : ALL_DELIMS) { // For each delimiter
+      if (sb.length() != 1) sb.append('|');
+      sb.append('\\');
+      sb.append(delim);
+    }
+    sb.append(')');
+
+    return Pattern.compile(sb.toString());
+  }
+
+  /**
+   * Add property names that the lexer should ignore.
+   */
+  static {
+    // ignore values
+    SET_IGNORE.add("fields");
+    SET_IGNORE.add("_");
+  }
+
+  /**
+   * Scan context.  Provides contextual information related to the current scan.
+   */
+  private class ScanContext {
+    /**
+     * The last token type scanned.
+     */
+    private Token.TYPE m_lastType;
+
+    /**
+     * The last property operand value
+     */
+    private String m_propertyName;
+
+    /**
+     * List of tokens generated by the scan
+     */
+    private List<Token> m_listTokens = new ArrayList<Token>();
+
+    /**
+     * Whether the current expression should be ignored.
+     * This is used to ignore portions of the query string that are
+     * not query specific.
+     */
+    private boolean m_ignore = false;
+
+    /**
+     * Constructor.
+     */
+    private ScanContext() {
+      //init last type to the logical op type
+      m_lastType = Token.TYPE.LOGICAL_OPERATOR;
+    }
+
+    /**
+     * Set the ignore tokens flag.
+     *
+     * @param ignore  true to ignore tokens; false otherwise
+     */
+    public void setIgnoreTokens(boolean ignore) {
+      m_ignore = ignore;
+    }
+
+    /**
+     * Get the type of the last token.
+     *
+     * @return the type of the last token
+     */
+    public Token.TYPE getLastTokenType() {
+      return m_lastType;
+    }
+
+    /**
+     * Set the type of the last token.
+     *
+     * @param lastType  the type of the last token
+     */
+    public void setLastTokenType(Token.TYPE lastType) {
+      m_lastType = lastType;
+    }
+
+    /**
+     * Get the current property operand value.
+     * This is used to hold the property operand name until it is added since,
+     * the following relational operator token is added first.
+     *
+     * @return the current property operand value
+     */
+    public String getPropertyOperand() {
+      return m_propertyName;
+    }
+
+    /**
+     * Set the current property operand value.
+     * This is used to hold the property operand name until it is added since,
+     * the following relational operator token is added first.
+     */
+    public void setPropertyOperand(String prop) {
+      m_propertyName = prop;
+    }
+
+    /**
+     * Add a token.
+     *
+     * @param token  the token to add
+     */
+    public void addToken(Token token) {
+      if (! m_ignore) {
+        m_listTokens.add(token);
+      }
+    }
+
+    /**
+     * Get the list of generated tokens.
+     *
+     * @return the list of generated tokens
+     */
+    public List<Token> getTokenList() {
+      return m_listTokens;
+    }
+  }
+
+  /**
+   * Token handler base class.
+   * Token handlers are responsible for processing specific token type.
+   */
+  private abstract class TokenHandler {
+    /**
+     * Provides base token handler functionality then delegates to the individual concrete handlers.
+     *
+     * @param token   the token to process
+     * @param ctx     the scan context
+     *
+     * @return true if this handler processed the token; false otherwise
+     * @throws InvalidQueryException  if an invalid token is encountered
+     */
+    public boolean handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      if (handles(token, ctx.getLastTokenType())) {
+        _handleToken(token, ctx);
+        ctx.setLastTokenType(getType());
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    /**
+     * Process a token.
+     *
+     * @param token  the token to process
+     * @param ctx    the current scan context
+     * @throws InvalidQueryException if an invalid token is encountered
+     */
+    public abstract void _handleToken(String token, ScanContext ctx) throws InvalidQueryException;
+
+    /**
+     * Get the token handler type.
+     *
+     * @return the token handler type
+     */
+    public abstract Token.TYPE getType();
+
+    /**
+     * Determine if a handler handles a specific token type.
+     *
+     * @param token              the token type
+     * @param previousTokenType  the previous token type
+     *
+     * @return true if the handler handles the specified type; false otherwise
+     */
+    public abstract boolean handles(String token, Token.TYPE previousTokenType);
+  }
+
+  /**
+   * Property Operand token handler.
+   */
+  private class PropertyOperandTokenHandler extends TokenHandler {
+
+    @Override
+    public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      //don't add prop name token until after operator token
+      if (! SET_IGNORE.contains(token)) {
+        ctx.setPropertyOperand(token);
+      } else {
+        ctx.setIgnoreTokens(true);
+        if (!ctx.getTokenList().isEmpty()) {
+        // remove '&' token that separates ignored token and query
+          ctx.getTokenList().remove(ctx.getTokenList().size() -1);
+        }
+      }
+    }
+
+    @Override
+    public Token.TYPE getType() {
+      return Token.TYPE.PROPERTY_OPERAND;
+    }
+
+    @Override
+    public boolean handles(String token, Token.TYPE previousTokenType) {
+      return token.matches("[^!&\\|<=|>=|!=|=|<|>\\(\\)]+");
+    }
+  }
+
+  /**
+   * Value Operand token handler.
+   */
+  private class ValueOperandTokenHandler extends TokenHandler {
+    @Override
+    public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      ctx.addToken(new Token(Token.TYPE.VALUE_OPERAND, token));
+    }
+
+    @Override
+    public Token.TYPE getType() {
+      return Token.TYPE.VALUE_OPERAND;
+    }
+
+    @Override
+    public boolean handles(String token, Token.TYPE previousTokenType) {
+      return token.matches("[^!&\\|<=|>=|!=|=|<|>]+");
+    }
+  }
+
+  /**
+   * Open Bracket token handler.
+   */
+  private class OpenBracketTokenHandler extends TokenHandler {
+    @Override
+    public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      ctx.addToken(new Token(Token.TYPE.BRACKET_OPEN, token));
+    }
+
+    @Override
+    public Token.TYPE getType() {
+      return Token.TYPE.BRACKET_OPEN;
+    }
+
+    @Override
+    public boolean handles(String token, Token.TYPE previousTokenType) {
+      return token.matches("\\(");
+    }
+  }
+
+  /**
+   * Close Bracket token handler.
+   */
+  private class CloseBracketTokenHandler extends TokenHandler {
+    @Override
+    public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      ctx.addToken(new Token(Token.TYPE.BRACKET_CLOSE, token));
+    }
+
+    @Override
+    public Token.TYPE getType() {
+      return Token.TYPE.BRACKET_CLOSE;
+    }
+
+    @Override
+    public boolean handles(String token, Token.TYPE previousTokenType) {
+      return token.matches("\\)");
+    }
+  }
+
+  /**
+   * Relational Operator token handler.
+   */
+  private class RelationalOperatorTokenHandler extends TokenHandler {
+    @Override
+    public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      ctx.addToken(new Token(Token.TYPE.RELATIONAL_OPERATOR, token));
+      ctx.addToken(new Token(Token.TYPE.PROPERTY_OPERAND, ctx.getPropertyOperand()));
+    }
+
+    @Override
+    public Token.TYPE getType() {
+      return Token.TYPE.RELATIONAL_OPERATOR;
+    }
+
+    @Override
+    public boolean handles(String token, Token.TYPE previousTokenType) {
+      return token.matches("<=|>=|!=|=|<|>");
+    }
+  }
+
+  /**
+   * Relational Operator function token handler.
+   */
+  private class RelationalOperatorFuncTokenHandler extends TokenHandler {
+    @Override
+    public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      ctx.addToken(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, token));
+      ctx.addToken(new Token(Token.TYPE.PROPERTY_OPERAND, ctx.getPropertyOperand()));
+    }
+
+    @Override
+    public Token.TYPE getType() {
+      return Token.TYPE.RELATIONAL_OPERATOR_FUNC;
+    }
+
+    //todo: add a unary relational operator func
+    @Override
+    public boolean handles(String token, Token.TYPE previousTokenType) {
+      return token.matches("\\.[a-zA-Z]+\\(");
+    }
+  }
+
+
+  /**
+   * Logical Operator token handler.
+   */
+  private class LogicalOperatorTokenHandler extends TokenHandler {
+    @Override
+    public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      ctx.addToken(new Token(Token.TYPE.LOGICAL_OPERATOR, token));
+      ctx.setIgnoreTokens(false);
+    }
+
+    @Override
+    public Token.TYPE getType() {
+      return Token.TYPE.LOGICAL_OPERATOR;
+    }
+
+    @Override
+    public boolean handles(String token, Token.TYPE previousTokenType) {
+      return token.matches("[!&\\|]");
+    }
+  }
+
+  /**
+   * Logical Unary Operator token handler.
+   */
+  private class LogicalUnaryOperatorTokenHandler extends TokenHandler {
+    @Override
+    public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
+      ctx.addToken(new Token(Token.TYPE.LOGICAL_UNARY_OPERATOR, token));
+    }
+
+    @Override
+    public Token.TYPE getType() {
+      return Token.TYPE.LOGICAL_UNARY_OPERATOR;
+    }
+
+    @Override
+    public boolean handles(String token, Token.TYPE previousTokenType) {
+      return "!".equals(token);
+    }
+  }
+}
\ No newline at end of file

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,514 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate;
+
+import org.apache.ambari.server.api.predicate.expressions.Expression;
+import org.apache.ambari.server.api.predicate.expressions.LogicalExpressionFactory;
+import org.apache.ambari.server.api.predicate.expressions.RelationalExpression;
+import org.apache.ambari.server.api.predicate.operators.*;
+import org.apache.ambari.server.controller.spi.Predicate;
+
+import java.util.*;
+
+/**
+ * Parser which produces a predicate instance from an array of tokens,
+ * which is generated by the lexer.
+ */
+public class QueryParser {
+
+  /**
+   * Map of token type to token handlers.
+   */
+  private static final Map<Token.TYPE, TokenHandler> TOKEN_HANDLERS =
+      new HashMap<Token.TYPE, TokenHandler>();
+
+  /**
+   * Constructor.
+   * Register token handlers.
+   *
+   */
+  public QueryParser() {
+    TOKEN_HANDLERS.put(Token.TYPE.BRACKET_OPEN, new BracketOpenTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.BRACKET_CLOSE, new BracketCloseTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.RELATIONAL_OPERATOR, new RelationalOperatorTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.LOGICAL_OPERATOR, new LogicalOperatorTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.LOGICAL_UNARY_OPERATOR, new LogicalUnaryOperatorTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.PROPERTY_OPERAND, new PropertyOperandTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.VALUE_OPERAND, new ValueOperandTokenHandler());
+    TOKEN_HANDLERS.put(Token.TYPE.RELATIONAL_OPERATOR_FUNC, new RelationalOperatorFuncTokenHandler());
+  }
+
+  /**
+   * Generate a Predicate instance from an array of tokens.
+   * Each input token contains a type and a value.
+   *
+   * Based on the token type and location, the tokens are first translated into a list of
+   * expressions, both relational and logical.  These expressions are then merged into a tree
+   * of expressions with a single root following operator precedence and explicit grouping rules.
+   * Depending on the query, this merging of expressions into a tree of expressions may occur in
+   * several passes, one pass per level of precedence starting at the highest level of precedence.
+   *
+   *  The predicate is built by traversing the expression tree in-order with each node expressing itself
+   *  as a predicate.
+   *
+   * @param tokens  an array of tokens which represent the query,
+   *                each token contains type and value information
+   *
+   * @return a new predicate instance based on the supplied tokens
+   * @throws InvalidQueryException if unable to parse the tokens and produce a predicate
+   */
+  public Predicate parse(Token[] tokens) throws InvalidQueryException {
+    ParseContext ctx = parseExpressions(tokens);
+
+    List<Expression> listExpressions       = ctx.getExpressions();
+    List<Expression> listMergedExpressions = mergeExpressions(listExpressions, ctx.getMaxPrecedence());
+
+    return listMergedExpressions.isEmpty() ? null :
+        listMergedExpressions.get(0).toPredicate();
+  }
+
+  /**
+   * Create parse context from an array of tokens. The parse context contains a list of expressions
+   * and other information about the expressions an parsed tokens.
+   *
+   * @param tokens  an array of tokens which represent the query,
+   *                each token contains type and value information
+   *
+   * @return a parse context which contains a list of expressions
+   * @throws InvalidQueryException if unable to properly parse the tokens into a parse context
+   */
+  private ParseContext parseExpressions(Token[] tokens) throws InvalidQueryException {
+    ParseContext ctx = new ParseContext(tokens);
+
+    while (ctx.getCurrentTokensIndex() < tokens.length) {
+      TOKEN_HANDLERS.get(tokens[ctx.getCurrentTokensIndex()].getType()).handleToken(ctx);
+    }
+
+    if (ctx.getPrecedenceLevel() != 0) {
+      throw new InvalidQueryException("Invalid query string: mismatched parentheses.");
+    }
+
+    return ctx;
+  }
+
+  /**
+   * Merge list of expressions into a tree of logical/relational expressions.
+   * This is done recursively in several passes, one per level of precedence starting at the
+   * highest precedence level. Recursion exits when a single expression remains.
+   *
+   * @param listExpressions  list of expressions to merge
+   * @param precedenceLevel  the precedence level that is to be merged
+   *
+   * @return  tree of expressions with a single root expression
+   */
+  private List<Expression> mergeExpressions(List<Expression> listExpressions, int precedenceLevel) {
+    if (listExpressions.size() > 1) {
+      Stack<Expression> stack = new Stack<Expression>();
+
+      stack.push(listExpressions.remove(0));
+      while (! listExpressions.isEmpty()) {
+        Expression exp = stack.pop();
+        Expression left = stack.empty() ? null : stack.pop();
+        Expression right = listExpressions.remove(0);
+        stack.addAll(exp.merge(left, right, precedenceLevel));
+      }
+      return mergeExpressions(new ArrayList<Expression>(stack), precedenceLevel - 1);
+    }
+    return listExpressions;
+  }
+
+  /**
+   * A parse context which contains information related to parsing the provided tokens into expressions.
+   */
+  private class ParseContext {
+    /**
+     * The current context precedence level.  This is dictated by bracket tokens.
+     */
+    private int m_precedence = 0;
+
+    /**
+     * Current position in tokens array
+     */
+    private int m_tokensIdx = 0;
+
+    /**
+     * Tokens
+     */
+    private Token[] m_tokens;
+
+    /**
+     * The type of the previous token used in validation.
+     */
+    private Token.TYPE m_previousTokenType = null;
+
+    /**
+     * The list of expressions which are generated from the tokens.
+     */
+    private List<Expression> m_listExpressions = new ArrayList<Expression>();
+
+    /**
+     * Highest precedence level in expression.
+     */
+    int m_maxPrecedence = 0;
+
+    public ParseContext(Token[] tokens) {
+      m_tokens = tokens;
+    }
+
+    /**
+     * Get array of all tokens.
+     * @return token array
+     */
+    public Token[] getTokens() {
+      return m_tokens;
+    }
+
+    /**
+     * Get the current position in the tokens array.
+     * @return the current tokens index
+     */
+    public int getCurrentTokensIndex() {
+      return m_tokensIdx;
+    }
+
+    /**
+     * Set the current position in the tokens array.
+     * Each handler should set this value after processing a token(s).
+     * @param idx  current tokens index
+     */
+    public void setCurrentTokensIndex(int idx) {
+      m_tokensIdx = idx;
+    }
+
+    /**
+     * Increment the context precedence level.
+     *
+     * @param val  how much the level is increased by
+     */
+    public void incPrecedenceLevel(int val) {
+      m_precedence += val;
+    }
+
+    /**
+     * Decrement the context precedence level.
+     *
+     * @param val  how much the level is decremented by
+     * @throws InvalidQueryException if the level is decremented below 0
+     */
+    public void decPrecedenceLevel(int val) throws InvalidQueryException {
+      m_precedence -= val;
+      if (m_precedence < 0) {
+        throw new InvalidQueryException("Invalid query string: mismatched parentheses.");
+      }
+    }
+
+    /**
+     * Get the current context precedence level.
+     *
+     * @return current context precedence level
+     */
+    public int getPrecedenceLevel() {
+      return m_precedence;
+    }
+
+    /**
+     * Get the list of generated expressions.
+     *
+     * @return the list of generated expressions
+     */
+    public List<Expression> getExpressions() {
+      return m_listExpressions;
+    }
+
+    /**
+     * Get the last expression.
+     *
+     * @return the last expression
+     */
+    public Expression getPrecedingExpression() {
+      return m_listExpressions == null ? null :
+          m_listExpressions.get(m_listExpressions.size() - 1);
+    }
+
+    /**
+     * Get the highest operator precedence in the list of generated expressions.
+     *
+     * @return the max operator precedence
+     */
+    public int getMaxPrecedence() {
+      return m_maxPrecedence;
+    }
+
+    /**
+     * Update the max precedence level.
+     * The max precedence level is only updated if the provided level > the current level.
+     *
+     * @param precedenceLevel the new value
+     */
+    public void updateMaxPrecedence(int precedenceLevel) {
+      if (precedenceLevel > m_maxPrecedence) {
+        m_maxPrecedence = precedenceLevel;
+      }
+    }
+
+    /**
+     * Add a generated expression.
+     *
+     * @param exp  the expression to add
+     */
+    public void addExpression(Expression exp) {
+      m_listExpressions.add(exp);
+    }
+
+    /**
+     * Set the token type of the current token
+     *
+     * @param type  type of the current token
+     */
+    private void setTokenType(Token.TYPE type) {
+      m_previousTokenType = type;
+    }
+
+    /**
+     * Get the last token type set.
+     *
+     * @return the last token type set
+     */
+    public Token.TYPE getPreviousTokenType() {
+      return m_previousTokenType;
+    }
+  }
+
+
+  /**
+   * Base token handler.
+   * Token handlers are responsible for handling the processing of a specific token type.
+   */
+  private abstract class TokenHandler {
+    /**
+     * Process a token. Handles common token processing functionality then delegates to the individual
+     * concrete handlers.
+     *
+     * @param ctx    the current parse context
+     * @throws InvalidQueryException if unable to process the token
+     */
+    public void handleToken(ParseContext ctx) throws InvalidQueryException {
+      Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
+      if (! validate(ctx.getPreviousTokenType())) {
+        throw new InvalidQueryException("Unexpected token encountered in query string. Last Token Type=" +
+            ctx.getPreviousTokenType() + ", Current Token[type=" + token.getType() +
+            ", value='" + token.getValue() + "']");
+      }
+      ctx.setTokenType(token.getType());
+
+      int idxIncrement = _handleToken(ctx);
+      ctx.setCurrentTokensIndex(ctx.getCurrentTokensIndex() + idxIncrement);
+    }
+
+    /**
+     * Process a token.
+     *
+     * @param ctx    the current parse context
+     * @throws InvalidQueryException if unable to process the token
+     */
+    public abstract int _handleToken(ParseContext ctx) throws InvalidQueryException;
+
+    /**
+     * Validate the token based on the previous token.
+     *
+     * @param previousTokenType  the type of the previous token
+     * @return true if validation is successful, false otherwise
+     */
+    public abstract boolean validate(Token.TYPE previousTokenType);
+  }
+
+  /**
+   * Open Bracket token handler.
+   */
+  private class BracketOpenTokenHandler extends TokenHandler {
+
+    @Override
+    public int _handleToken(ParseContext ctx) {
+      ctx.incPrecedenceLevel(Operator.MAX_OP_PRECEDENCE);
+      return 1;
+    }
+
+    @Override
+    public boolean validate(Token.TYPE previousTokenType) {
+     return previousTokenType == null                        ||
+            previousTokenType == Token.TYPE.BRACKET_OPEN     ||
+            previousTokenType == Token.TYPE.LOGICAL_OPERATOR ||
+            previousTokenType == Token.TYPE.LOGICAL_UNARY_OPERATOR;
+    }
+  }
+
+  /**
+   * Close Bracket token handler
+   */
+  private class BracketCloseTokenHandler extends TokenHandler {
+    @Override
+    public int _handleToken(ParseContext ctx) throws InvalidQueryException{
+      ctx.decPrecedenceLevel(Operator.MAX_OP_PRECEDENCE);
+
+      return 1;
+    }
+
+    @Override
+    public boolean validate(Token.TYPE previousTokenType) {
+      return previousTokenType == Token.TYPE.VALUE_OPERAND ||
+             previousTokenType == Token.TYPE.BRACKET_CLOSE;
+    }
+  }
+
+  /**
+   * Relational Operator token handler
+   */
+  private class RelationalOperatorTokenHandler extends TokenHandler {
+    @Override
+    public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+      Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
+      RelationalOperator relationalOp = RelationalOperatorFactory.createOperator(token.getValue());
+      //todo: use factory to create expression
+      ctx.addExpression(new RelationalExpression(relationalOp));
+
+      return 1;
+    }
+
+    @Override
+    public boolean validate(Token.TYPE previousTokenType) {
+      return previousTokenType == null                     ||
+          previousTokenType == Token.TYPE.BRACKET_OPEN     ||
+          previousTokenType == Token.TYPE.LOGICAL_OPERATOR ||
+          previousTokenType == Token.TYPE.LOGICAL_UNARY_OPERATOR;
+    }
+  }
+
+  /**
+   * Relational Operator function token handler
+   */
+  private class RelationalOperatorFuncTokenHandler extends TokenHandler {
+    @Override
+    public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+      Token[]            tokens       = ctx.getTokens();
+      int                idx          = ctx.getCurrentTokensIndex();
+      Token              token        = tokens[idx];
+      RelationalOperator relationalOp = RelationalOperatorFactory.createOperator(token.getValue());
+
+      ctx.addExpression(new RelationalExpression(relationalOp));
+      ctx.setCurrentTokensIndex(++idx);
+
+      TokenHandler propertyHandler = new PropertyOperandTokenHandler();
+      propertyHandler.handleToken(ctx);
+
+      // handle right operand if applicable to operator
+      idx = ctx.getCurrentTokensIndex();
+      if (ctx.getCurrentTokensIndex() < tokens.length &&
+          tokens[idx].getType().equals(Token.TYPE.VALUE_OPERAND)) {
+        TokenHandler valueHandler = new ValueOperandTokenHandler();
+        valueHandler.handleToken(ctx);
+      }
+
+      // skip closing bracket
+      idx = ctx.getCurrentTokensIndex();
+      if (idx >= tokens.length || tokens[idx].getType() != Token.TYPE.BRACKET_CLOSE) {
+        throw new InvalidQueryException("Missing closing bracket for in expression.") ;
+      }
+      return 1;
+    }
+
+    @Override
+    public boolean validate(Token.TYPE previousTokenType) {
+      return previousTokenType == null                     ||
+          previousTokenType == Token.TYPE.BRACKET_OPEN     ||
+          previousTokenType == Token.TYPE.LOGICAL_OPERATOR ||
+          previousTokenType == Token.TYPE.LOGICAL_UNARY_OPERATOR;
+    }
+  }
+
+  /**
+   * Logical Operator token handler
+   */
+  private class LogicalOperatorTokenHandler extends TokenHandler {
+    @Override
+    public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+      Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
+      LogicalOperator logicalOp = LogicalOperatorFactory.createOperator(token.getValue(), ctx.getPrecedenceLevel());
+      ctx.updateMaxPrecedence(logicalOp.getPrecedence());
+      ctx.addExpression(LogicalExpressionFactory.createLogicalExpression(logicalOp));
+
+      return 1;
+    }
+
+    @Override
+    public boolean validate(Token.TYPE previousTokenType) {
+      return previousTokenType == Token.TYPE.VALUE_OPERAND ||
+             previousTokenType == Token.TYPE.BRACKET_CLOSE;
+    }
+  }
+
+  /**
+   * Logical Unary Operator token handler
+   */
+  private class LogicalUnaryOperatorTokenHandler extends LogicalOperatorTokenHandler {
+    @Override
+    public boolean validate(Token.TYPE previousTokenType) {
+      return previousTokenType == null                 ||
+          previousTokenType == Token.TYPE.BRACKET_OPEN ||
+          previousTokenType == Token.TYPE.LOGICAL_OPERATOR;
+    }
+  }
+
+  /**
+   * Property Operand token handler
+   */
+  private class PropertyOperandTokenHandler extends TokenHandler {
+    @Override
+    public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+      Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
+      ctx.getPrecedingExpression().setLeftOperand(token.getValue());
+
+      return 1;
+    }
+
+    @Override
+    public boolean validate(Token.TYPE previousTokenType) {
+      return previousTokenType == Token.TYPE.RELATIONAL_OPERATOR ||
+          previousTokenType == Token.TYPE.RELATIONAL_OPERATOR_FUNC;
+    }
+  }
+
+  /**
+   * Value Operand token handler
+   */
+  private class ValueOperandTokenHandler extends TokenHandler {
+    @Override
+    public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+      Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
+      ctx.getPrecedingExpression().setRightOperand(token.getValue());
+
+      return 1;
+    }
+
+    @Override
+    public boolean validate(Token.TYPE previousTokenType) {
+      return previousTokenType == Token.TYPE.PROPERTY_OPERAND;
+    }
+  }
+}
+

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate;
+
+/**
+ * Token representation which is generated by the lexer.
+ * Contains type and value information.
+ */
+public class Token {
+
+  /**
+   * Token types.
+   */
+  public enum TYPE {
+    /** Property name operand.  This is the left operand in relational expressions. */
+    PROPERTY_OPERAND,
+    /** Value operand.  This is the right operand in relational expressions. */
+    VALUE_OPERAND,
+    /** Relational operator */
+    RELATIONAL_OPERATOR,
+    /** Relational operator function */
+    RELATIONAL_OPERATOR_FUNC,
+    /** Logical operator */
+    LOGICAL_OPERATOR,
+    /** Logical unary operator such as !*/
+    LOGICAL_UNARY_OPERATOR,
+    /** Opening bracket */
+    BRACKET_OPEN,
+    /** Closing bracket */
+    BRACKET_CLOSE
+  }
+
+  /**
+   * Token type.
+   */
+  private TYPE m_type;
+
+  /**
+   * Token value.
+   */
+  private String m_value;
+
+
+  /**
+   * Constructor.
+   *
+   * @param type   type
+   * @param value  value
+   */
+  public Token(TYPE type, String value) {
+    m_type = type;
+    m_value = value;
+  }
+
+  /**
+   * Get the token type.
+   * @return token type
+   */
+  public TYPE getType() {
+    return m_type;
+  }
+
+  /**
+   * Get the token value.
+   * @return token value
+   */
+  public String getValue() {
+    return m_value;
+  }
+
+  @Override
+  public String toString() {
+    return "Token{ type=" + m_type + ", value='" + m_value + "' }";
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    Token token = (Token) o;
+
+    return m_type == token.m_type &&
+        (m_value == null ? token.m_value == null : m_value.equals(token.m_value));
+  }
+
+  @Override
+  public int hashCode() {
+    int result = m_type.hashCode();
+    result = 31 * result + (m_value != null ? m_value.hashCode() : 0);
+
+    return result;
+  }
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/AbstractExpression.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/AbstractExpression.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/AbstractExpression.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/AbstractExpression.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate.expressions;
+
+import org.apache.ambari.server.api.predicate.operators.Operator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for expressions.
+ */
+public abstract class AbstractExpression<T> implements Expression<T> {
+
+  /**
+   * The operator.
+   */
+  private final Operator m_op;
+
+  /**
+   * The left operand.
+   * */
+  private T m_left = null;
+
+  /**
+   * The right operand.
+   */
+  private T m_right = null;
+
+  /**
+   * Constructor.
+   *
+   * @param op  the expressions operator
+   */
+  protected AbstractExpression(Operator op) {
+    m_op = op;
+  }
+
+  @Override
+  public void setLeftOperand(T left) {
+    m_left = left;
+  }
+
+  @Override
+  public void setRightOperand(T right) {
+    m_right = right;
+  }
+
+  @Override
+  public T getLeftOperand() {
+    return m_left;
+  }
+
+  @Override
+  public T getRightOperand() {
+    return m_right;
+  }
+
+  @Override
+  public Operator getOperator() {
+    return m_op;
+  }
+
+  @Override
+  public List<Expression> merge(Expression left, Expression right, int precedence) {
+    return defaultMerge(left, right);
+  }
+
+  /**
+   * Base merge implementation.
+   * No merge is done, simply returns the left expression, this and the right expression.
+   *
+   * @param left   the expression to the left of this expression
+   * @param right  the expression to the right of this expression
+   *
+   * @return a list containing the un-merged left expression, this and right expression
+   */
+  protected List<Expression> defaultMerge(Expression left, Expression right) {
+    List<Expression> listExpressions = new ArrayList<Expression>();
+    if (left != null) {
+      listExpressions.add(left);
+    }
+    listExpressions.add(this);
+    if (right != null) {
+      listExpressions.add(right);
+    }
+
+    return listExpressions;
+  }
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate.expressions;
+
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.api.predicate.operators.Operator;
+import org.apache.ambari.server.controller.spi.Predicate;
+
+import java.util.List;
+
+/**
+ * Expression representation.
+ * There are two types of expressions, relational and logical.
+ * Each expression has an operator and either 2 operands for binary
+ * expressions or 1 operand for unary expressions.
+ */
+public interface Expression<T> {
+
+  /**
+   * Merge expression with surrounding expressions.
+   *
+   * @param left        the preceding expression
+   * @param right       the following expression
+   * @param precedence  the precedence level being merged.  Only expressions at this precedence level
+   *                    should be merged. Others should simply return the left expression, themselves and
+   *                    the right expression in that order.
+   *
+   * @return a list of expressions after merging.  Do not return any null elements.
+   */
+  public List<Expression> merge(Expression left, Expression right, int precedence);
+
+
+  /**
+   * Get the predicate representation of the expression.
+   * @return a predicate instance for the expression
+   */
+  public Predicate toPredicate() throws InvalidQueryException;
+
+  /**
+   * Set the expressions left operand.
+   *
+   * @param left  the left operand
+   */
+  public void setLeftOperand(T left);
+
+  /**
+   * Set the expressions right operand.
+   *
+   * @param right  the right operand
+   */
+  public void setRightOperand(T right);
+
+  /**
+   * Get the left operand expression.
+   *
+   * @return the left operand
+   */
+  public T getLeftOperand();
+
+  /**
+   * Get the right operand expression.
+   *
+   * @return the right operand.
+   */
+  public T getRightOperand();
+
+  /**
+   * Get the expression operator.
+   *
+   * @return the logical operator for the expression
+   */
+  public Operator getOperator();
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate.expressions;
+
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.api.predicate.operators.LogicalOperator;
+import org.apache.ambari.server.controller.spi.Predicate;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Logical expression implementation.
+ * Always a binary expression that consists of a logical operator and
+ * expressions for the left and right operands.
+ */
+public class LogicalExpression extends AbstractExpression<Expression> {
+
+  /**
+   * Constructor.
+   *
+   * @param op  the logical operator of the expression
+   */
+  public LogicalExpression(LogicalOperator op) {
+    super(op);
+  }
+
+
+  @Override
+  public Predicate toPredicate() throws InvalidQueryException {
+    return ((LogicalOperator) getOperator()).
+        toPredicate(getLeftOperand().toPredicate(), getRightOperand().toPredicate());
+  }
+
+  @Override
+  public List<Expression> merge(Expression left, Expression right, int precedence) {
+    if (getOperator().getPrecedence() == precedence && getLeftOperand() == null) {
+      setLeftOperand(left);
+      setRightOperand(right);
+      return Collections.<Expression>singletonList(this);
+    } else {
+      return defaultMerge(left, right);
+    }
+  }
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpressionFactory.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpressionFactory.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpressionFactory.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpressionFactory.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate.expressions;
+
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.api.predicate.operators.LogicalOperator;
+
+/**
+ * Factory of logical expression instances.
+ */
+public class LogicalExpressionFactory {
+  /**
+   * Create a logical expression instance.
+   *
+   * @param op  the logical operator
+   *
+   * @return a new logical expression instance
+   * @throws InvalidQueryException
+   */
+  public static LogicalExpression createLogicalExpression(LogicalOperator op) throws InvalidQueryException {
+    switch (op.getType()) {
+      case AND:
+      case OR:
+        return new LogicalExpression(op);
+      case NOT :
+        return new NotLogicalExpression(op);
+      default:
+        throw new RuntimeException("An invalid logical operator type was encountered: " + op);
+    }
+  }
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate.expressions;
+
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.api.predicate.operators.LogicalOperator;
+import org.apache.ambari.server.controller.predicate.BasePredicate;
+import org.apache.ambari.server.controller.predicate.NotPredicate;
+import org.apache.ambari.server.controller.spi.Predicate;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A 'NOT' logical expression representation.
+ * Negates a corresponding right operand.
+ */
+public class NotLogicalExpression extends LogicalExpression {
+  /**
+   * Constructor.
+   *
+   * @param op  the logical operator
+   */
+  public NotLogicalExpression(LogicalOperator op) {
+    super(op);
+  }
+
+  @Override
+  public List<Expression> merge(Expression left, Expression right, int precedence) {
+    if (getOperator().getPrecedence() == precedence && getRightOperand() == null) {
+      List<Expression> listExpressions = new ArrayList<Expression>();
+      if (left != null) {
+        listExpressions.add(left);
+      }
+      setRightOperand(right);
+      listExpressions.add(this);
+      return listExpressions;
+    } else {
+      // do nothing, already merged
+      return defaultMerge(left, right);
+    }
+  }
+
+  @Override
+  public Predicate toPredicate() throws InvalidQueryException {
+    //todo: remove need to down cast to BasePredicate
+    return new NotPredicate((BasePredicate) getRightOperand().toPredicate());
+  }
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate.expressions;
+
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.api.predicate.operators.RelationalOperator;
+import org.apache.ambari.server.controller.spi.Predicate;
+
+/**
+ * Relational Expression.
+ * Consists of a property name for the left operand, a relational operator
+ * and a value as the right operand.
+ */
+public class RelationalExpression extends AbstractExpression<String> {
+
+  /**
+   * Constructor.
+   *
+   * @param op  relational operator
+   */
+  public RelationalExpression(RelationalOperator op) {
+    super(op);
+  }
+
+  @Override
+  public Predicate toPredicate() throws InvalidQueryException {
+    return ((RelationalOperator) getOperator()).
+        toPredicate(getLeftOperand(), getRightOperand());
+  }
+
+  @Override
+  public String toString() {
+    return "RelationalExpression{ property='" + getLeftOperand() + "\', value='"
+        + getRightOperand() + "\', op=" + getOperator() + " }";
+  }
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/AbstractOperator.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/AbstractOperator.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/AbstractOperator.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/AbstractOperator.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate.operators;
+
+/**
+ * Base operator implementation.
+ */
+public abstract class AbstractOperator implements Operator {
+  /**
+   * The precedence value for the current context.
+   */
+  private final int m_ctxPrecedence;
+
+
+  /**
+   * Constructor.
+   *
+   * @param ctxPrecedence  the context precedence value
+   */
+  protected AbstractOperator(int ctxPrecedence) {
+    m_ctxPrecedence = ctxPrecedence;
+  }
+
+  /**
+   * Return the base precedence for this operator.
+   * This is the value that is specific to the operator
+   * type and doesn't take context into account.
+   *
+   * @return the base precedence for this operator type
+   */
+  public int getBasePrecedence() {
+    // this value is used for all relational operators
+    // logical operators override this value
+    return -1;
+  }
+
+  @Override
+  public int getPrecedence() {
+    return getBasePrecedence() + m_ctxPrecedence;
+  }
+
+  @Override
+  public String toString() {
+    return getName();
+  }
+
+  /**
+   * Get the name of the operator.
+   *
+   * @return the operator name
+   */
+  public abstract String getName();
+}

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/AndOperator.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/AndOperator.java?rev=1459041&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/AndOperator.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/AndOperator.java Wed Mar 20 20:44:43 2013
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.predicate.operators;
+
+import org.apache.ambari.server.controller.predicate.AndPredicate;
+import org.apache.ambari.server.controller.predicate.BasePredicate;
+import org.apache.ambari.server.controller.spi.Predicate;
+
+/**
+ * And operator implementation.
+ */
+public class AndOperator extends AbstractOperator implements LogicalOperator {
+
+  /**
+   * Constructor.
+   *
+   * @param ctxPrecedence  precedence value for the current context
+   */
+  public AndOperator(int ctxPrecedence) {
+    super(ctxPrecedence);
+  }
+
+  @Override
+  public TYPE getType() {
+    return TYPE.AND;
+  }
+
+  @Override
+  public String getName() {
+    return "AndOperator";
+  }
+
+  @Override
+  public int getBasePrecedence() {
+    return 2;
+  }
+
+  @Override
+  public Predicate toPredicate(Predicate left, Predicate right) {
+    //todo: refactor to not need down casts
+    return new AndPredicate((BasePredicate) left, (BasePredicate) right);
+  }
+
+  @Override
+  public String toString() {
+    return getName() + "[precedence=" + getPrecedence() + "]";
+  }
+}