You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2015/07/31 04:59:25 UTC

[45/81] [abbrv] [partial] zest-java git commit: First round of changes to move to org.apache.zest namespace.

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/QueryExpressions.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/QueryExpressions.java b/core/api/src/main/java/org/apache/zest/api/query/QueryExpressions.java
new file mode 100644
index 0000000..a109310
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/QueryExpressions.java
@@ -0,0 +1,944 @@
+/*
+ * Copyright 2007-2011 Rickard Öberg.
+ * Copyright 2007-2010 Niclas Hedhman.
+ * Copyright 2008 Alin Dreghiciu.
+ * Copyright 2012 Stanislav Muhametsin.
+ * Copyright 2012-2014 Paul Merlin.
+ *
+ * Licensed 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
+ * ied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.query;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collection;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.GenericAssociationInfo;
+import org.apache.zest.api.association.ManyAssociation;
+import org.apache.zest.api.association.NamedAssociation;
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.api.entity.Identity;
+import org.apache.zest.api.injection.scope.State;
+import org.apache.zest.api.property.GenericPropertyInfo;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.api.query.grammar.AndSpecification;
+import org.apache.zest.api.query.grammar.AssociationFunction;
+import org.apache.zest.api.query.grammar.AssociationNotNullSpecification;
+import org.apache.zest.api.query.grammar.AssociationNullSpecification;
+import org.apache.zest.api.query.grammar.ContainsAllSpecification;
+import org.apache.zest.api.query.grammar.ContainsSpecification;
+import org.apache.zest.api.query.grammar.EqSpecification;
+import org.apache.zest.api.query.grammar.GeSpecification;
+import org.apache.zest.api.query.grammar.GtSpecification;
+import org.apache.zest.api.query.grammar.LeSpecification;
+import org.apache.zest.api.query.grammar.LtSpecification;
+import org.apache.zest.api.query.grammar.ManyAssociationContainsSpecification;
+import org.apache.zest.api.query.grammar.ManyAssociationFunction;
+import org.apache.zest.api.query.grammar.MatchesSpecification;
+import org.apache.zest.api.query.grammar.NamedAssociationContainsNameSpecification;
+import org.apache.zest.api.query.grammar.NamedAssociationContainsSpecification;
+import org.apache.zest.api.query.grammar.NamedAssociationFunction;
+import org.apache.zest.api.query.grammar.NeSpecification;
+import org.apache.zest.api.query.grammar.NotSpecification;
+import org.apache.zest.api.query.grammar.OrSpecification;
+import org.apache.zest.api.query.grammar.OrderBy;
+import org.apache.zest.api.query.grammar.PropertyFunction;
+import org.apache.zest.api.query.grammar.PropertyNotNullSpecification;
+import org.apache.zest.api.query.grammar.PropertyNullSpecification;
+import org.apache.zest.api.query.grammar.PropertyReference;
+import org.apache.zest.api.query.grammar.Variable;
+import org.apache.zest.api.util.NullArgumentException;
+import org.apache.zest.functional.Specification;
+
+import static org.apache.zest.functional.Iterables.first;
+import static org.apache.zest.functional.Iterables.prepend;
+
+/**
+ * Static factory methods for query expressions and operators.
+ */
+public final class QueryExpressions
+{
+    // This is used for eq(Association,Composite)
+    private static final Method IDENTITY_METHOD;
+
+    static
+    {
+        try
+        {
+            IDENTITY_METHOD = Identity.class.getMethod( "identity" );
+        }
+        catch( NoSuchMethodException e )
+        {
+            throw new InternalError( "Zest Core API codebase is corrupted. Contact Zest team: QueryExpressions" );
+        }
+    }
+
+    // Templates and variables -----------------------------------------------|
+
+    /**
+     * Create a Query Template using the given type.
+     *
+     * @param <T> the type of the template
+     * @param clazz a class declaring the type of the template
+     *
+     * @return a new Query Template
+     */
+    public static <T> T templateFor( Class<T> clazz )
+    {
+        NullArgumentException.validateNotNull( "Template class", clazz );
+
+        if( clazz.isInterface() )
+        {
+            return clazz.cast( Proxy.newProxyInstance( clazz.getClassLoader(),
+                                                       array( clazz ),
+                                                       new TemplateHandler<T>( null, null, null, null ) ) );
+        }
+        else
+        {
+            try
+            {
+                T mixin = clazz.newInstance();
+                for( Field field : clazz.getFields() )
+                {
+                    if( field.getAnnotation( State.class ) != null )
+                    {
+                        if( field.getType().equals( Property.class ) )
+                        {
+                            field.set( mixin,
+                                       Proxy.newProxyInstance( field.getType().getClassLoader(),
+                                                               array( field.getType() ),
+                                                               new PropertyReferenceHandler<>( new PropertyFunction<T>( null, null, null, null, field ) ) ) );
+                        }
+                        else if( field.getType().equals( Association.class ) )
+                        {
+                            field.set( mixin,
+                                       Proxy.newProxyInstance( field.getType().getClassLoader(),
+                                                               array( field.getType() ),
+                                                               new AssociationReferenceHandler<>( new AssociationFunction<T>( null, null, null, field ) ) ) );
+                        }
+                        else if( field.getType().equals( ManyAssociation.class ) )
+                        {
+                            field.set( mixin,
+                                       Proxy.newProxyInstance( field.getType().getClassLoader(),
+                                                               array( field.getType() ),
+                                                               new ManyAssociationReferenceHandler<>( new ManyAssociationFunction<T>( null, null, null, field ) ) ) );
+                        }
+                        else if( field.getType().equals( NamedAssociation.class ) )
+                        {
+                            field.set( mixin,
+                                       Proxy.newProxyInstance( field.getType().getClassLoader(),
+                                                               array( field.getType() ),
+                                                               new NamedAssociationReferenceHandler<>( new NamedAssociationFunction<T>( null, null, null, field ) ) ) );
+                        }
+                    }
+                }
+                return mixin;
+            }
+            catch( IllegalAccessException | IllegalArgumentException | InstantiationException | SecurityException e )
+            {
+                throw new IllegalArgumentException( "Cannot use class as template", e );
+            }
+        }
+    }
+
+    /**
+     * Create a Query Template using the given mixin class and association.
+     *
+     * @param <T> the type of the template
+     * @param mixinType  a class declaring the type of the template
+     * @param association an association
+     *
+     * @return a new Query Template
+     */
+    public static <T> T templateFor( final Class<T> mixinType, Association<?> association )
+    {
+        NullArgumentException.validateNotNull( "Mixin class", mixinType );
+        NullArgumentException.validateNotNull( "Association", association );
+        return mixinType.cast( Proxy.newProxyInstance( mixinType.getClassLoader(),
+                                                       array( mixinType ),
+                                                       new TemplateHandler<T>( null,
+                                                                               association( association ),
+                                                                               null,
+                                                                               null ) ) );
+    }
+
+    public static <T> T oneOf( final ManyAssociation<T> association )
+    {
+        NullArgumentException.validateNotNull( "Association", association );
+        return association.get( 0 );
+    }
+
+    public static <T> T oneOf( final NamedAssociation<T> association )
+    {
+        NullArgumentException.validateNotNull( "Association", association );
+        return association.get( first( association ) );
+    }
+
+    /**
+     * Create a new Query Variable.
+     *
+     * @param name a name for the Variable
+     *
+     * @return a new Query Variable.
+     */
+    public static Variable variable( String name )
+    {
+        NullArgumentException.validateNotNull( "Variable name", name );
+        return new Variable( name );
+    }
+
+    /**
+     * Create a new Query Template PropertyFunction.
+     *
+     * @param <T> type of the Property
+     * @param property a Property
+     *
+     * @return a new Query Template PropertyFunction
+     */
+    @SuppressWarnings( "unchecked" )
+    public static <T> PropertyFunction<T> property( Property<T> property )
+    {
+        return ( (PropertyReferenceHandler<T>) Proxy.getInvocationHandler( property ) ).property();
+    }
+
+    /**
+     * Create a new Query Property instance.
+     *
+     * @param <T> type of the Property
+     * @param mixinClass mixin of the Property
+     * @param fieldName name of the Property field
+     *
+     * @return a new Query Property instance for the given mixin and property name.
+     */
+    @SuppressWarnings( "unchecked" )
+    public static <T> Property<T> property( Class<?> mixinClass, String fieldName )
+    {
+        try
+        {
+            Field field = mixinClass.getField( fieldName );
+            if( !Property.class.isAssignableFrom( field.getType() ) )
+            {
+                throw new IllegalArgumentException( "Field must be of type Property<?>" );
+            }
+            return (Property<T>) Proxy.newProxyInstance(
+                mixinClass.getClassLoader(),
+                array( field.getType() ),
+                new PropertyReferenceHandler<>( new PropertyFunction<T>( null, null, null, null, field ) ) );
+        }
+        catch( NoSuchFieldException e )
+        {
+            throw new IllegalArgumentException( "No such field '" + fieldName + "' in mixin " + mixinClass.getName() );
+        }
+    }
+
+    /**
+     * Create a new Query Template AssociationFunction.
+     *
+     * @param <T> type of the Association
+     * @param association an Association
+     *
+     * @return a new Query Template AssociationFunction
+     */
+    @SuppressWarnings( "unchecked" )
+    public static <T> AssociationFunction<T> association( Association<T> association )
+    {
+        return ( (AssociationReferenceHandler<T>) Proxy.getInvocationHandler( association ) ).association();
+    }
+
+    /**
+     * Create a new Query Template ManyAssociationFunction.
+     *
+     * @param <T> type of the ManyAssociation
+     * @param association a ManyAssociation
+     *
+     * @return a new Query Template ManyAssociationFunction
+     */
+    @SuppressWarnings( "unchecked" )
+    public static <T> ManyAssociationFunction<T> manyAssociation( ManyAssociation<T> association )
+    {
+        return ( (ManyAssociationReferenceHandler<T>) Proxy.getInvocationHandler( association ) ).manyAssociation();
+    }
+
+    /**
+     * Create a new Query Template NamedAssociationFunction.
+     *
+     * @param <T> type of the NamedAssociation
+     * @param association a NamedAssociation
+     *
+     * @return a new Query Template NamedAssociationFunction
+     */
+    @SuppressWarnings( "unchecked" )
+    public static <T> NamedAssociationFunction<T> namedAssociation( NamedAssociation<T> association )
+    {
+        return ( (NamedAssociationReferenceHandler<T>) Proxy.getInvocationHandler( association ) ).namedAssociation();
+    }
+
+    // And/Or/Not ------------------------------------------------------------|
+    /**
+     * Create a new AND specification.
+     *
+     * @param left first operand
+     * @param right second operand
+     * @param optionalRight optional operands
+     *
+     * @return a new AND specification
+     */
+    @SafeVarargs
+    public static AndSpecification and( Specification<Composite> left,
+                                        Specification<Composite> right,
+                                        Specification<Composite>... optionalRight
+    )
+    {
+        return new AndSpecification( prepend( left, prepend( right, Arrays.asList( optionalRight ) ) ) );
+    }
+
+    /**
+     * Create a new OR specification.
+     *
+     * @param specs operands
+     *
+     * @return a new OR specification
+     */
+    @SafeVarargs
+    public static OrSpecification or( Specification<Composite>... specs )
+    {
+        return new OrSpecification( Arrays.asList( specs ) );
+    }
+
+    /**
+     * Create a new NOT specification.
+     *
+     * @param operand specification to be negated
+     *
+     * @return a new NOT specification
+     */
+    public static NotSpecification not( Specification<Composite> operand )
+    {
+        return new NotSpecification( operand );
+    }
+
+    // Comparisons -----------------------------------------------------------|
+
+    /**
+     * Create a new EQUALS specification for a Property.
+     *
+     * @param property a Property
+     * @param value its value
+     *
+     * @return a new EQUALS specification for a Property.
+     */
+    public static <T> EqSpecification<T> eq( Property<T> property, T value )
+    {
+        return new EqSpecification<>( property( property ), value );
+    }
+
+    /**
+     * Create a new EQUALS specification for a Property using a named Variable.
+     *
+     * @param property a Property
+     * @param variable a Query Variable
+     *
+     * @return a new EQUALS specification for a Property using a named Variable.
+     */
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public static <T> EqSpecification<T> eq( Property<T> property, Variable variable )
+    {
+        return new EqSpecification( property( property ), variable );
+    }
+
+    /**
+     * Create a new EQUALS specification for an Association.
+     *
+     * @param association an Association
+     * @param value its value
+     *
+     * @return a new EQUALS specification for an Association.
+     */
+    public static <T> EqSpecification<String> eq( Association<T> association, T value )
+    {
+        return new EqSpecification<>( new PropertyFunction<String>( null,
+                                                                    association( association ),
+                                                                    null,
+                                                                    null,
+                                                                    IDENTITY_METHOD ),
+                                      value.toString() );
+    }
+
+    /**
+     * Create a new GREATER OR EQUALS specification for a Property.
+     *
+     * @param property a Property
+     * @param value its value
+     *
+     * @return a new GREATER OR EQUALS specification for a Property.
+     */
+    public static <T> GeSpecification<T> ge( Property<T> property, T value )
+    {
+        return new GeSpecification<>( property( property ), value );
+    }
+
+    /**
+     * Create a new GREATER OR EQUALS specification for a Property using a named Variable.
+     *
+     * @param property a Property
+     * @param variable a Query Variable
+     *
+     * @return a new GREATER OR EQUALS specification for a Property using a named Variable.
+     */
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public static <T> GeSpecification<T> ge( Property<T> property, Variable variable )
+    {
+        return new GeSpecification( property( property ), variable );
+    }
+
+    /**
+     * Create a new GREATER THAN specification for a Property.
+     *
+     * @param property a Property
+     * @param value its value
+     *
+     * @return a new GREATER THAN specification for a Property.
+     */
+    public static <T> GtSpecification<T> gt( Property<T> property, T value )
+    {
+        return new GtSpecification<>( property( property ), value );
+    }
+
+    /**
+     * Create a new GREATER THAN specification for a Property using a named Variable.
+     *
+     * @param property a Property
+     * @param variable a Query Variable
+     *
+     * @return a new GREATER THAN specification for a Property using a named Variable.
+     */
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public static <T> GtSpecification<T> gt( Property<T> property, Variable variable )
+    {
+        return new GtSpecification( property( property ), variable );
+    }
+
+    /**
+     * Create a new LESS OR EQUALS specification for a Property.
+     *
+     * @param property a Property
+     * @param value its value
+     *
+     * @return a new LESS OR EQUALS specification for a Property.
+     */
+    public static <T> LeSpecification<T> le( Property<T> property, T value )
+    {
+        return new LeSpecification<>( property( property ), value );
+    }
+
+    /**
+     * Create a new LESS OR EQUALS specification for a Property using a named Variable.
+     *
+     * @param property a Property
+     * @param variable a Query Variable
+     *
+     * @return a new LESS OR EQUALS specification for a Property using a named Variable.
+     */
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public static <T> LeSpecification<T> le( Property<T> property, Variable variable )
+    {
+        return new LeSpecification( property( property ), variable );
+    }
+
+    /**
+     * Create a new LESSER THAN specification for a Property.
+     *
+     * @param property a Property
+     * @param value its value
+     *
+     * @return a new LESSER THAN specification for a Property.
+     */
+    public static <T> LtSpecification<T> lt( Property<T> property, T value )
+    {
+        return new LtSpecification<>( property( property ), value );
+    }
+
+    /**
+     * Create a new LESSER THAN specification for a Property using a named Variable.
+     *
+     * @param property a Property
+     * @param variable a Query Variable
+     *
+     * @return a new LESSER THAN specification for a Property using a named Variable.
+     */
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public static <T> LtSpecification<T> lt( Property<T> property, Variable variable )
+    {
+        return new LtSpecification( property( property ), variable );
+    }
+
+    /**
+     * Create a new NOT EQUALS specification for a Property.
+     *
+     * @param property a Property
+     * @param value its value
+     *
+     * @return a new NOT EQUALS specification for a Property.
+     */
+    public static <T> NeSpecification<T> ne( Property<T> property, T value )
+    {
+        return new NeSpecification<>( property( property ), value );
+    }
+
+    /**
+     * Create a new NOT EQUALS specification for a Property using a named Variable.
+     *
+     * @param property a Property
+     * @param variable a Query Variable
+     *
+     * @return a new NOT EQUALS specification for a Property using a named Variable.
+     */
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public static <T> NeSpecification<T> ne( Property<T> property, Variable variable )
+    {
+        return new NeSpecification( property( property ), variable );
+    }
+
+    /**
+     * Create a new REGULAR EXPRESSION specification for a Property.
+     *
+     * @param property a Property
+     * @param regexp its value
+     *
+     * @return a new REGULAR EXPRESSION specification for a Property.
+     */
+    public static MatchesSpecification matches( Property<String> property, String regexp )
+    {
+        return new MatchesSpecification( property( property ), regexp );
+    }
+
+    /**
+     * Create a new REGULAR EXPRESSION specification for a Property using a named Variable.
+     *
+     * @param property a Property
+     * @param variable a Query Variable
+     *
+     * @return a new REGULAR EXPRESSION specification for a Property using a named Variable.
+     */
+    public static MatchesSpecification matches( Property<String> property, Variable variable )
+    {
+        return new MatchesSpecification( property( property ), variable );
+    }
+
+    // Null checks -----------------------------------------------------------|
+
+    /**
+     * Create a new NOT NULL specification for a Property.
+     *
+     * @param property a Property
+     *
+     * @return a new NOT NULL specification for a Property.
+     */
+    public static <T> PropertyNotNullSpecification<T> isNotNull( Property<T> property )
+    {
+        return new PropertyNotNullSpecification<>( property( property ) );
+    }
+
+    /**
+     * Create a new NULL specification for a Property.
+     *
+     * @param property a Property
+     *
+     * @return a new NULL specification for a Property.
+     */
+    public static <T> PropertyNullSpecification<T> isNull( Property<T> property )
+    {
+        return new PropertyNullSpecification<>( property( property ) );
+    }
+
+    /**
+     * Create a new NOT NULL specification for an Association.
+     *
+     * @param association an Association
+     *
+     * @return a new NOT NULL specification for an Association.
+     */
+    public static <T> AssociationNotNullSpecification<T> isNotNull( Association<T> association )
+    {
+        return new AssociationNotNullSpecification<>( association( association ) );
+    }
+
+    /**
+     * Create a new NULL specification for an Association.
+     *
+     * @param association an Association
+     *
+     * @return a new NULL specification for an Association.
+     */
+    public static <T> AssociationNullSpecification<T> isNull( Association<T> association )
+    {
+        return new AssociationNullSpecification<>( association( association ) );
+    }
+
+    // Collections -----------------------------------------------------------|
+
+    /**
+     * Create a new CONTAINS ALL specification for a Collection Property.
+     *
+     * @param collectionProperty a Collection Property
+     * @param values its values
+     *
+     * @return a new CONTAINS ALL specification for a Collection Property.
+     */
+    public static <T> ContainsAllSpecification<T> containsAll( Property<? extends Collection<T>> collectionProperty,
+                                                               Iterable<T> values )
+    {
+        NullArgumentException.validateNotNull( "Values", values );
+        return new ContainsAllSpecification<>( property( collectionProperty ), values );
+    }
+
+    /**
+     * Create a new CONTAINS ALL specification for a Collection Property using named Variables.
+     *
+     * @param collectionProperty a Collection Property
+     * @param variables named Variables
+     *
+     * @return a new CONTAINS ALL specification for a Collection Property using named Variables.
+     */
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public static <T> ContainsAllSpecification<T> containsAllVariables(
+        Property<? extends Collection<T>> collectionProperty,
+        Iterable<Variable> variables )
+    {
+        NullArgumentException.validateNotNull( "Variables", variables );
+        return new ContainsAllSpecification( property( collectionProperty ), variables );
+    }
+
+    /**
+     * Create a new CONTAINS specification for a Collection Property.
+     *
+     * @param collectionProperty a Collection Property
+     * @param value the value
+     *
+     * @return a new CONTAINS specification for a Collection Property.
+     */
+    public static <T> ContainsSpecification<T> contains( Property<? extends Collection<T>> collectionProperty,
+                                                         T value )
+    {
+        NullArgumentException.validateNotNull( "Value", value );
+        return new ContainsSpecification<>( property( collectionProperty ), value );
+    }
+
+    /**
+     * Create a new CONTAINS specification for a Collection Property using named Variables.
+     *
+     * @param collectionProperty a Collection Property
+     * @param variable named Variable
+     *
+     * @return a new CONTAINS specification for a Collection Property using named Variables.
+     */
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public static <T> ContainsSpecification<T> contains( Property<? extends Collection<T>> collectionProperty,
+                                                         Variable variable )
+    {
+        NullArgumentException.validateNotNull( "Variable", variable );
+        return new ContainsSpecification( property( collectionProperty ), variable );
+    }
+
+    /**
+     * Create a new CONTAINS specification for a ManyAssociation.
+     *
+     * @param manyAssoc  a ManyAssociation
+     * @param value the value
+     *
+     * @return a new CONTAINS specification for a ManyAssociation.
+     */
+    public static <T> ManyAssociationContainsSpecification<T> contains( ManyAssociation<T> manyAssoc, T value )
+    {
+        return new ManyAssociationContainsSpecification<>( manyAssociation( manyAssoc ), value );
+    }
+
+    /**
+     * Create a new CONTAINS specification for a NamedAssociation.
+     *
+     * @param namedAssoc  a NamedAssociation
+     * @param value the value
+     *
+     * @return a new CONTAINS specification for a NamedAssociation.
+     */
+    public static <T> NamedAssociationContainsSpecification<T> contains( NamedAssociation<T> namedAssoc, T value )
+    {
+        return new NamedAssociationContainsSpecification<>( namedAssociation( namedAssoc ), value );
+    }
+
+    /**
+     * Create a new CONTAINS NAME specification for a NamedAssociation.
+     *
+     * @param namedAssoc  a NamedAssociation
+     * @param name the name
+     *
+     * @return a new CONTAINS NAME specification for a NamedAssociation.
+     */
+    public static <T> NamedAssociationContainsNameSpecification<T> containsName( NamedAssociation<T> namedAssoc,
+                                                                                 String name )
+    {
+        return new NamedAssociationContainsNameSpecification<>( namedAssociation( namedAssoc ), name );
+    }
+
+    // Ordering --------------------------------------------------------------|
+    /**
+     * Create a new Query ascending order segment for a Property.
+     *
+     * @param <T> type of the Property
+     * @param property a Property
+     *
+     * @return a new Query ascending order segment for a Property.
+     */
+    public static <T> OrderBy orderBy( final Property<T> property )
+    {
+        return orderBy( property, OrderBy.Order.ASCENDING );
+    }
+
+    /**
+     * Create a new Query ordering segment for a Property.
+     *
+     * @param <T> type of the Property
+     * @param property a Property
+     * @param order ascending or descending
+     *
+     * @return a new Query ordering segment for a Property.
+     */
+    public static <T> OrderBy orderBy( final Property<T> property, final OrderBy.Order order )
+    {
+        return new OrderBy( property( property ), order );
+    }
+
+    // Query Templates InvocationHandlers ------------------------------------|
+
+    private static class TemplateHandler<T>
+        implements InvocationHandler
+    {
+        private final PropertyFunction<?> compositeProperty;
+        private final AssociationFunction<?> compositeAssociation;
+        private final ManyAssociationFunction<?> compositeManyAssociation;
+        private final NamedAssociationFunction<?> compositeNamedAssociation;
+
+        private TemplateHandler( PropertyFunction<?> compositeProperty,
+                                 AssociationFunction<?> compositeAssociation,
+                                 ManyAssociationFunction<?> compositeManyAssociation,
+                                 NamedAssociationFunction<?> compositeNamedAssociation
+        )
+        {
+            this.compositeProperty = compositeProperty;
+            this.compositeAssociation = compositeAssociation;
+            this.compositeManyAssociation = compositeManyAssociation;
+            this.compositeNamedAssociation = compositeNamedAssociation;
+        }
+
+        @Override
+        public Object invoke( Object o, Method method, Object[] objects )
+            throws Throwable
+        {
+            if( Property.class.isAssignableFrom( method.getReturnType() ) )
+            {
+                return Proxy.newProxyInstance(
+                    method.getReturnType().getClassLoader(),
+                    array( method.getReturnType() ),
+                    new PropertyReferenceHandler<>( new PropertyFunction<T>( compositeProperty,
+                                                                             compositeAssociation,
+                                                                             compositeManyAssociation,
+                                                                             compositeNamedAssociation,
+                                                                             method ) ) );
+            }
+            else if( Association.class.isAssignableFrom( method.getReturnType() ) )
+            {
+                return Proxy.newProxyInstance(
+                    method.getReturnType().getClassLoader(),
+                    array( method.getReturnType() ),
+                    new AssociationReferenceHandler<>( new AssociationFunction<T>( compositeAssociation,
+                                                                                   compositeManyAssociation,
+                                                                                   compositeNamedAssociation,
+                                                                                   method ) ) );
+            }
+            else if( ManyAssociation.class.isAssignableFrom( method.getReturnType() ) )
+            {
+                return Proxy.newProxyInstance(
+                    method.getReturnType().getClassLoader(),
+                    array( method.getReturnType() ),
+                    new ManyAssociationReferenceHandler<>( new ManyAssociationFunction<T>( compositeAssociation,
+                                                                                           compositeManyAssociation,
+                                                                                           compositeNamedAssociation,
+                                                                                           method ) ) );
+            }
+            else if( NamedAssociation.class.isAssignableFrom( method.getReturnType() ) )
+            {
+                return Proxy.newProxyInstance(
+                    method.getReturnType().getClassLoader(),
+                    array( method.getReturnType() ),
+                    new NamedAssociationReferenceHandler<>( new NamedAssociationFunction<T>( compositeAssociation,
+                                                                                             compositeManyAssociation,
+                                                                                             compositeNamedAssociation,
+                                                                                             method ) ) );
+            }
+
+            return null;
+        }
+    }
+
+    private static class PropertyReferenceHandler<T>
+        implements InvocationHandler
+    {
+        private final PropertyFunction<T> property;
+
+        private PropertyReferenceHandler( PropertyFunction<T> property )
+        {
+            this.property = property;
+        }
+
+        private PropertyFunction<T> property()
+        {
+            return property;
+        }
+
+        @Override
+        public Object invoke( Object o, final Method method, Object[] objects )
+            throws Throwable
+        {
+            if( method.equals( Property.class.getMethod( "get" ) ) )
+            {
+                Type propertyType = GenericPropertyInfo.propertyTypeOf( property.accessor() );
+                if( propertyType.getClass().equals( Class.class ) )
+                {
+                    return Proxy.newProxyInstance( method.getDeclaringClass().getClassLoader(),
+                                                   array( (Class<?>) propertyType, PropertyReference.class ),
+                                                   new TemplateHandler<T>( property, null, null, null ) );
+                }
+            }
+
+            return null;
+        }
+    }
+
+    private static class AssociationReferenceHandler<T>
+        implements InvocationHandler
+    {
+        private final AssociationFunction<T> association;
+
+        private AssociationReferenceHandler( AssociationFunction<T> association )
+        {
+            this.association = association;
+        }
+
+        private AssociationFunction<T> association()
+        {
+            return association;
+        }
+
+        @Override
+        public Object invoke( Object o, final Method method, Object[] objects )
+            throws Throwable
+        {
+            if( method.equals( Association.class.getMethod( "get" ) ) )
+            {
+                Type associationType = GenericAssociationInfo.associationTypeOf( association.accessor() );
+                if( associationType.getClass().equals( Class.class ) )
+                {
+                    return Proxy.newProxyInstance( method.getDeclaringClass().getClassLoader(),
+                                                   array( (Class) associationType, PropertyReference.class ),
+                                                   new TemplateHandler<T>( null, association, null, null ) );
+                }
+            }
+
+            return null;
+        }
+    }
+
+    private static class ManyAssociationReferenceHandler<T>
+        implements InvocationHandler
+    {
+        private final ManyAssociationFunction<T> manyAssociation;
+
+        private ManyAssociationReferenceHandler( ManyAssociationFunction<T> manyAssociation )
+        {
+            this.manyAssociation = manyAssociation;
+        }
+
+        public ManyAssociationFunction<T> manyAssociation()
+        {
+            return manyAssociation;
+        }
+
+        @Override
+        public Object invoke( Object o, final Method method, Object[] objects )
+            throws Throwable
+        {
+            if( method.equals( ManyAssociation.class.getMethod( "get", Integer.TYPE ) ) )
+            {
+                Type manyAssociationType = GenericAssociationInfo.associationTypeOf( manyAssociation.accessor() );
+                if( manyAssociationType.getClass().equals( Class.class ) )
+                {
+                    return Proxy.newProxyInstance( method.getDeclaringClass().getClassLoader(),
+                                                   array( (Class) manyAssociationType, PropertyReference.class ),
+                                                   new TemplateHandler<T>( null, null, manyAssociation, null ) );
+                }
+            }
+
+            return null;
+        }
+    }
+
+    private static class NamedAssociationReferenceHandler<T>
+        implements InvocationHandler
+    {
+        private final NamedAssociationFunction<T> namedAssociation;
+
+        private NamedAssociationReferenceHandler( NamedAssociationFunction<T> namedAssociation )
+        {
+            this.namedAssociation = namedAssociation;
+        }
+
+        public NamedAssociationFunction<T> namedAssociation()
+        {
+            return namedAssociation;
+        }
+
+        @Override
+        public Object invoke( Object o, final Method method, Object[] objects )
+            throws Throwable
+        {
+            if( method.equals( NamedAssociation.class.getMethod( "get", String.class ) ) )
+            {
+                Type namedAssociationType = GenericAssociationInfo.associationTypeOf( namedAssociation.accessor() );
+                if( namedAssociationType.getClass().equals( Class.class ) )
+                {
+                    return Proxy.newProxyInstance( method.getDeclaringClass().getClassLoader(),
+                                                   array( (Class) namedAssociationType, PropertyReference.class ),
+                                                   new TemplateHandler<T>( null, null, null, namedAssociation ) );
+                }
+            }
+
+            return null;
+        }
+    }
+
+    @SafeVarargs
+    private static <T> T[] array( T... array )
+    {
+        return array;
+    }
+
+    private QueryExpressions()
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/AndSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/AndSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/AndSpecification.java
new file mode 100644
index 0000000..3d710ad
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/AndSpecification.java
@@ -0,0 +1,56 @@
+/*
+ * 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.zest.api.query.grammar;
+
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.functional.Specification;
+import org.apache.zest.functional.Specifications;
+
+/**
+ * AND Specification.
+ */
+public class AndSpecification
+    extends BinarySpecification
+{
+
+    public AndSpecification( Iterable<Specification<Composite>> operands )
+    {
+        super( operands );
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        return Specifications.and( operands ).satisfiedBy( item );
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder( "(" );
+        String and = "";
+        for( Specification<Composite> operand : operands )
+        {
+            sb.append( and ).append( operand );
+            and = " and ";
+        }
+        return sb.append( ")" ).toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationFunction.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationFunction.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationFunction.java
new file mode 100644
index 0000000..8355114
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationFunction.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2007-2011 Rickard Öberg.
+ * Copyright 2007-2010 Niclas Hedhman.
+ *
+ * Licensed 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
+ * ied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.query.grammar;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Member;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.AssociationStateHolder;
+import org.apache.zest.api.association.GenericAssociationInfo;
+import org.apache.zest.api.association.ManyAssociation;
+import org.apache.zest.api.association.NamedAssociation;
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.api.composite.CompositeInstance;
+import org.apache.zest.api.query.QueryExpressionException;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.functional.Function;
+
+import static org.apache.zest.api.util.Classes.typeOf;
+
+/**
+ * Function to get Entity Associations
+ */
+public class AssociationFunction<T>
+    implements Function<Composite, Association<T>>
+{
+    private final AssociationFunction<?> traversedAssociation;
+    private final ManyAssociationFunction<?> traversedManyAssociation;
+    private final NamedAssociationFunction<?> traversedNamedAssociation;
+    private final AccessibleObject accessor;
+
+    public AssociationFunction( AssociationFunction<?> traversedAssociation,
+                                ManyAssociationFunction<?> traversedManyAssociation,
+                                NamedAssociationFunction<?> traversedNamedAssociation,
+                                AccessibleObject accessor
+    )
+    {
+        this.traversedAssociation = traversedAssociation;
+        this.traversedManyAssociation = traversedManyAssociation;
+        this.traversedNamedAssociation = traversedNamedAssociation;
+        this.accessor = accessor;
+
+        Type returnType = typeOf( accessor );
+        if( !Association.class.isAssignableFrom( Classes.RAW_CLASS.map( returnType ) )
+            && !ManyAssociation.class.isAssignableFrom( Classes.RAW_CLASS.map( returnType ) )
+            && !NamedAssociation.class.isAssignableFrom( Classes.RAW_CLASS.map( returnType ) ) )
+        {
+            throw new QueryExpressionException( "Unsupported association type:" + returnType );
+        }
+        Type associationTypeAsType = GenericAssociationInfo.toAssociationType( returnType );
+        if( !( associationTypeAsType instanceof Class ) )
+        {
+            throw new QueryExpressionException( "Unsupported association type:" + associationTypeAsType );
+        }
+    }
+
+    public AssociationFunction<?> traversedAssociation()
+    {
+        return traversedAssociation;
+    }
+
+    public ManyAssociationFunction<?> traversedManyAssociation()
+    {
+        return traversedManyAssociation;
+    }
+
+    public NamedAssociationFunction<?> traversedNamedAssociation()
+    {
+        return traversedNamedAssociation;
+    }
+
+    public AccessibleObject accessor()
+    {
+        return accessor;
+    }
+
+    @Override
+    public Association<T> map( Composite entity )
+    {
+        try
+        {
+            Object target = entity;
+            if( traversedAssociation != null )
+            {
+                Association<?> association = traversedAssociation.map( entity );
+                if( association == null )
+                {
+                    return null;
+                }
+                target = association.get();
+            }
+            else if( traversedManyAssociation != null )
+            {
+                throw new IllegalArgumentException( "Cannot evaluate a ManyAssociation" );
+            }
+            else if( traversedNamedAssociation != null )
+            {
+                throw new IllegalArgumentException( "Cannot evaluate a NamedAssociation" );
+            }
+
+            if( target == null )
+            {
+                return null;
+            }
+
+            CompositeInstance handler = (CompositeInstance) Proxy.getInvocationHandler( target );
+            return ( (AssociationStateHolder) handler.state() ).associationFor( accessor );
+        }
+        catch( IllegalArgumentException e )
+        {
+            throw e;
+        }
+        catch( Throwable e )
+        {
+            throw new IllegalArgumentException( e );
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        if( traversedAssociation != null )
+        {
+            return traversedAssociation.toString() + "." + ( (Member) accessor ).getName();
+        }
+        else
+        {
+            return ( (Member) accessor ).getName();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationNotNullSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationNotNullSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationNotNullSpecification.java
new file mode 100644
index 0000000..1376029
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationNotNullSpecification.java
@@ -0,0 +1,67 @@
+/*
+ * 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.zest.api.query.grammar;
+
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.composite.Composite;
+
+/**
+ * Association not null Specification.
+ */
+public class AssociationNotNullSpecification<T>
+    extends ExpressionSpecification
+{
+    private AssociationFunction<T> association;
+
+    public AssociationNotNullSpecification( AssociationFunction<T> association )
+    {
+        this.association = association;
+    }
+
+    public AssociationFunction<T> association()
+    {
+        return association;
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        try
+        {
+            Association<T> assoc = association.map( item );
+
+            if( assoc == null )
+            {
+                return false;
+            }
+
+            return assoc.get() != null;
+        }
+        catch( IllegalArgumentException e )
+        {
+            return false;
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return association.toString() + "is not null";
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationNullSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationNullSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationNullSpecification.java
new file mode 100644
index 0000000..7dd72b2
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/AssociationNullSpecification.java
@@ -0,0 +1,67 @@
+/*
+ * 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.zest.api.query.grammar;
+
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.composite.Composite;
+
+/**
+ * Association null Specification.
+ */
+public class AssociationNullSpecification<T>
+    extends ExpressionSpecification
+{
+    private AssociationFunction<T> association;
+
+    public AssociationNullSpecification( AssociationFunction<T> association )
+    {
+        this.association = association;
+    }
+
+    public AssociationFunction<T> association()
+    {
+        return association;
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        try
+        {
+            Association<T> assoc = association.map( item );
+
+            if( assoc == null )
+            {
+                return true;
+            }
+
+            return assoc.get() == null;
+        }
+        catch( IllegalArgumentException e )
+        {
+            return true;
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return association.toString() + "is null";
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/BinarySpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/BinarySpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/BinarySpecification.java
new file mode 100644
index 0000000..177caf0
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/BinarySpecification.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.zest.api.query.grammar;
+
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.functional.Specification;
+
+/**
+ * Base binary Specification, used for AND and OR Specifications..
+ */
+public abstract class BinarySpecification
+    extends ExpressionSpecification
+{
+    protected final Iterable<Specification<Composite>> operands;
+
+    protected BinarySpecification( Iterable<Specification<Composite>> operands )
+    {
+        this.operands = operands;
+    }
+
+    public Iterable<Specification<Composite>> operands()
+    {
+        return operands;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/ComparisonSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/ComparisonSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/ComparisonSpecification.java
new file mode 100644
index 0000000..c53fe00
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/ComparisonSpecification.java
@@ -0,0 +1,76 @@
+/*
+ * 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.zest.api.query.grammar;
+
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.api.property.Property;
+
+/**
+ * Base comparison Specification.
+ */
+public abstract class ComparisonSpecification<T>
+    extends ExpressionSpecification
+{
+    protected final PropertyFunction<T> property;
+    protected final T value;
+
+    public ComparisonSpecification( PropertyFunction<T> property, T value )
+    {
+        this.property = property;
+        this.value = value;
+    }
+
+    public PropertyFunction<T> property()
+    {
+        return property;
+    }
+
+    @Override
+    public final boolean satisfiedBy( Composite item )
+    {
+        try
+        {
+            Property<T> prop = property.map( item );
+
+            if( prop == null )
+            {
+                return false;
+            }
+
+            T propValue = prop.get();
+            if( propValue == null )
+            {
+                return false;
+            }
+
+            return compare( propValue );
+        }
+        catch( IllegalArgumentException e )
+        {
+            return false;
+        }
+    }
+
+    protected abstract boolean compare( T value );
+
+    public T value()
+    {
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/ContainsAllSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/ContainsAllSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/ContainsAllSpecification.java
new file mode 100644
index 0000000..c5221d2
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/ContainsAllSpecification.java
@@ -0,0 +1,78 @@
+/*
+ * 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.zest.api.query.grammar;
+
+import java.util.Collection;
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.functional.Iterables;
+
+/**
+ * Contains All Specification.
+ */
+public class ContainsAllSpecification<T>
+    extends ExpressionSpecification
+{
+    private PropertyFunction<? extends Collection<T>> collectionProperty;
+    private Iterable<T> valueCollection;
+
+    public ContainsAllSpecification( PropertyFunction<? extends Collection<T>> collectionProperty,
+                                     Iterable<T> valueCollection
+    )
+    {
+        this.collectionProperty = collectionProperty;
+        this.valueCollection = valueCollection;
+    }
+
+    public PropertyFunction<? extends Collection<T>> collectionProperty()
+    {
+        return collectionProperty;
+    }
+
+    public Iterable<T> containedValues()
+    {
+        return valueCollection;
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        Collection<T> collection = collectionProperty.map( item ).get();
+
+        if( collection == null )
+        {
+            return false;
+        }
+
+        for( T value : valueCollection )
+        {
+            if( !collection.contains( value ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public String toString()
+    {
+        return collectionProperty + " contains " + Iterables.toList( valueCollection );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/ContainsSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/ContainsSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/ContainsSpecification.java
new file mode 100644
index 0000000..4f05aac
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/ContainsSpecification.java
@@ -0,0 +1,67 @@
+/*
+ * 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.zest.api.query.grammar;
+
+import java.util.Collection;
+import org.apache.zest.api.composite.Composite;
+
+/**
+ * Contains Specification.
+ */
+public class ContainsSpecification<T>
+    extends ExpressionSpecification
+{
+    private PropertyFunction<? extends Collection<T>> collectionProperty;
+    private T value;
+
+    public ContainsSpecification( PropertyFunction<? extends Collection<T>> collectionProperty, T value )
+    {
+        this.collectionProperty = collectionProperty;
+        this.value = value;
+    }
+
+    public PropertyFunction<? extends Collection<T>> collectionProperty()
+    {
+        return collectionProperty;
+    }
+
+    public T value()
+    {
+        return value;
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        Collection<T> collection = collectionProperty.map( item ).get();
+
+        if( collection == null )
+        {
+            return false;
+        }
+
+        return collection.contains( value );
+    }
+
+    @Override
+    public String toString()
+    {
+        return collectionProperty + " contains " + value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/EqSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/EqSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/EqSpecification.java
new file mode 100644
index 0000000..b7ed03c
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/EqSpecification.java
@@ -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.zest.api.query.grammar;
+
+/**
+ * Equals Specification.
+ */
+public class EqSpecification<T>
+    extends ComparisonSpecification<T>
+{
+    public EqSpecification( PropertyFunction<T> property, T value )
+    {
+        super( property, value );
+    }
+
+    @Override
+    protected boolean compare( T value )
+    {
+        return value.equals( this.value );
+    }
+
+    @Override
+    public String toString()
+    {
+        return property.toString() + "=" + value.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/ExpressionSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/ExpressionSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/ExpressionSpecification.java
new file mode 100644
index 0000000..f0dd6b2
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/ExpressionSpecification.java
@@ -0,0 +1,60 @@
+/*
+ * 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.zest.api.query.grammar;
+
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.functional.Specification;
+
+import static org.apache.zest.functional.Iterables.append;
+import static org.apache.zest.functional.Iterables.iterable;
+
+/**
+ * Base expression Specification.
+ */
+public abstract class ExpressionSpecification
+    implements Specification<Composite>
+{
+
+    @SuppressWarnings( "unchecked" )
+    public AndSpecification and( Specification<Composite> specification )
+    {
+        if( this instanceof AndSpecification )
+        {
+            return new AndSpecification( append( specification, ( (AndSpecification) this ).operands() ) );
+        }
+        else
+        {
+            return new AndSpecification( iterable( this, specification ) );
+        }
+    }
+
+    @SuppressWarnings( "unchecked" )
+    public OrSpecification or( Specification<Composite> specification )
+    {
+        if( this instanceof OrSpecification )
+        {
+            return new OrSpecification( append( specification, ( (OrSpecification) this ).operands() ) );
+        }
+        else
+        {
+            return new OrSpecification( iterable( this, specification ) );
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/GeSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/GeSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/GeSpecification.java
new file mode 100644
index 0000000..f012293
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/GeSpecification.java
@@ -0,0 +1,44 @@
+/*
+ * 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.zest.api.query.grammar;
+
+/**
+ * Greater or equals Specification.
+ */
+public class GeSpecification<T>
+    extends ComparisonSpecification<T>
+{
+    public GeSpecification( PropertyFunction<T> property, T value )
+    {
+        super( property, value );
+    }
+
+    @Override
+    @SuppressWarnings( "unchecked" )
+    protected boolean compare( T value )
+    {
+        return ( (Comparable) value ).compareTo( this.value ) >= 0;
+    }
+
+    @Override
+    public String toString()
+    {
+        return property.toString() + ">=" + value.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/GtSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/GtSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/GtSpecification.java
new file mode 100644
index 0000000..880fb67
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/GtSpecification.java
@@ -0,0 +1,44 @@
+/*
+ * 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.zest.api.query.grammar;
+
+/**
+ * Greater than Specification.
+ */
+public class GtSpecification<T>
+    extends ComparisonSpecification<T>
+{
+    public GtSpecification( PropertyFunction<T> property, T value )
+    {
+        super( property, value );
+    }
+
+    @Override
+    @SuppressWarnings( "unchecked" )
+    protected boolean compare( T value )
+    {
+        return ( (Comparable) value ).compareTo( this.value ) > 0;
+    }
+
+    @Override
+    public String toString()
+    {
+        return property.toString() + ">" + value.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/LeSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/LeSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/LeSpecification.java
new file mode 100644
index 0000000..3a28f16
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/LeSpecification.java
@@ -0,0 +1,44 @@
+/*
+ * 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.zest.api.query.grammar;
+
+/**
+ * Less or equals Specification.
+ */
+public class LeSpecification<T>
+    extends ComparisonSpecification<T>
+{
+    public LeSpecification( PropertyFunction<T> property, T value )
+    {
+        super( property, value );
+    }
+
+    @Override
+    @SuppressWarnings( "unchecked" )
+    protected boolean compare( T value )
+    {
+        return ( (Comparable) value ).compareTo( this.value ) <= 0;
+    }
+
+    @Override
+    public String toString()
+    {
+        return property.toString() + "<=" + value.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/LtSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/LtSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/LtSpecification.java
new file mode 100644
index 0000000..8f476c3
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/LtSpecification.java
@@ -0,0 +1,44 @@
+/*
+ * 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.zest.api.query.grammar;
+
+/**
+ * Lesser than Specification.
+ */
+public class LtSpecification<T>
+    extends ComparisonSpecification<T>
+{
+    public LtSpecification( PropertyFunction<T> property, T value )
+    {
+        super( property, value );
+    }
+
+    @Override
+    @SuppressWarnings( "unchecked" )
+    protected boolean compare( T value )
+    {
+        return ( (Comparable) value ).compareTo( this.value ) < 0;
+    }
+
+    @Override
+    public String toString()
+    {
+        return property.toString() + "<" + value.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/ManyAssociationContainsSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/ManyAssociationContainsSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/ManyAssociationContainsSpecification.java
new file mode 100644
index 0000000..a15bdb0
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/ManyAssociationContainsSpecification.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2007-2011 Rickard Öberg.
+ * Copyright 2007-2010 Niclas Hedhman.
+ *
+ * Licensed 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
+ * ied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.query.grammar;
+
+import org.apache.zest.api.association.ManyAssociation;
+import org.apache.zest.api.composite.Composite;
+
+/**
+ * ManyAssociation Contains Specification.
+ */
+public class ManyAssociationContainsSpecification<T>
+    extends ExpressionSpecification
+{
+    private final ManyAssociationFunction<T> manyAssociationFunction;
+    private final T value;
+
+    public ManyAssociationContainsSpecification( ManyAssociationFunction<T> manyAssociationFunction, T value )
+    {
+        this.manyAssociationFunction = manyAssociationFunction;
+        this.value = value;
+    }
+
+    public ManyAssociationFunction<T> manyAssociation()
+    {
+        return manyAssociationFunction;
+    }
+
+    public T value()
+    {
+        return value;
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        ManyAssociation<T> collection = manyAssociationFunction.map( item );
+        if( collection == null )
+        {
+            return false;
+        }
+        return collection.contains( value );
+    }
+
+    @Override
+    public String toString()
+    {
+        return manyAssociationFunction + " contains:" + value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/ManyAssociationFunction.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/ManyAssociationFunction.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/ManyAssociationFunction.java
new file mode 100644
index 0000000..540a901
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/ManyAssociationFunction.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2007-2011 Rickard Öberg.
+ * Copyright 2007-2010 Niclas Hedhman.
+ *
+ * Licensed 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
+ * ied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.query.grammar;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Member;
+import java.lang.reflect.Proxy;
+import org.apache.zest.api.association.AssociationStateHolder;
+import org.apache.zest.api.association.ManyAssociation;
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.api.composite.CompositeInstance;
+import org.apache.zest.functional.Function;
+
+/**
+ * Function to get Entity ManyAssociations.
+ */
+public class ManyAssociationFunction<T>
+    implements Function<Composite, ManyAssociation<T>>
+{
+    private final AssociationFunction<?> traversedAssociation;
+    private final ManyAssociationFunction<?> traversedManyAssociation;
+    private final NamedAssociationFunction<?> traversedNamedAssociation;
+    private final AccessibleObject accessor;
+
+    public ManyAssociationFunction( AssociationFunction<?> traversedAssociation,
+                                    ManyAssociationFunction<?> traversedManyAssociation,
+                                    NamedAssociationFunction<?> traversedNamedAssociation,
+                                    AccessibleObject accessor
+    )
+    {
+        this.traversedAssociation = traversedAssociation;
+        this.traversedManyAssociation = traversedManyAssociation;
+        this.traversedNamedAssociation = traversedNamedAssociation;
+        this.accessor = accessor;
+    }
+
+    public AssociationFunction<?> traversedAssociation()
+    {
+        return traversedAssociation;
+    }
+
+    public ManyAssociationFunction<?> traversedManyAssociation()
+    {
+        return traversedManyAssociation;
+    }
+
+    public NamedAssociationFunction<?> traversedNamedAssociation()
+    {
+        return traversedNamedAssociation;
+    }
+
+    public AccessibleObject accessor()
+    {
+        return accessor;
+    }
+
+    @Override
+    public ManyAssociation<T> map( Composite entity )
+    {
+        try
+        {
+            Object target = entity;
+            if( traversedAssociation != null )
+            {
+                target = traversedAssociation.map( entity ).get();
+            }
+            if( traversedManyAssociation != null )
+            {
+                throw new IllegalArgumentException( "Cannot traverse ManyAssociations" );
+            }
+            if( traversedNamedAssociation != null )
+            {
+                throw new IllegalArgumentException( "Cannot traverse NamedAssociations" );
+            }
+
+            CompositeInstance handler = (CompositeInstance) Proxy.getInvocationHandler( target );
+            return ( (AssociationStateHolder) handler.state() ).manyAssociationFor( accessor );
+        }
+        catch( IllegalArgumentException e )
+        {
+            throw e;
+        }
+        catch( Throwable e )
+        {
+            throw new IllegalArgumentException( e );
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        if( traversedAssociation != null )
+        {
+            return traversedAssociation.toString() + "." + ( (Member) accessor ).getName();
+        }
+        else
+        {
+            return ( (Member) accessor ).getName();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/MatchesSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/MatchesSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/MatchesSpecification.java
new file mode 100644
index 0000000..4f54a47
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/MatchesSpecification.java
@@ -0,0 +1,93 @@
+/*
+ * 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.zest.api.query.grammar;
+
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.api.property.Property;
+
+/**
+ * Regular expression match Specification.
+ */
+public class MatchesSpecification
+    extends ExpressionSpecification
+{
+    private PropertyFunction<String> property;
+    private Object value;
+
+    public MatchesSpecification( PropertyFunction<String> property, String regexp )
+    {
+        this.property = property;
+        this.value = regexp;
+    }
+
+    public MatchesSpecification( PropertyFunction<String> property, Variable variable )
+    {
+        this.property = property;
+        this.value = variable;
+    }
+
+    public PropertyFunction<String> property()
+    {
+        return property;
+    }
+
+    public Object value()
+    {
+        return value;
+    }
+
+    public String regexp()
+    {
+        return ( String ) value;
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        Property<String> prop = property.map( item );
+
+        if( prop == null )
+        {
+            return false;
+        }
+
+        String val = prop.get();
+
+        if( val == null )
+        {
+            return false;
+        }
+
+        return val.matches( ( String ) value );
+    }
+
+    @Override
+    public String toString()
+    {
+        return new StringBuilder()
+            .append( "( " )
+            .append( property )
+            .append( " matches " )
+            .append( "\"" )
+            .append( value )
+            .append( "\"" )
+            .append( " )" )
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/NamedAssociationContainsNameSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/NamedAssociationContainsNameSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/NamedAssociationContainsNameSpecification.java
new file mode 100644
index 0000000..5af9a51
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/NamedAssociationContainsNameSpecification.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011-2012 Niclas Hedhman.
+ * Copyright 2014 Paul Merlin.
+ *
+ * Licensed 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
+ * ied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.query.grammar;
+
+import org.apache.zest.api.association.NamedAssociation;
+import org.apache.zest.api.composite.Composite;
+
+/**
+ * NamedAssociation Contains Specification.
+ */
+public class NamedAssociationContainsNameSpecification<T>
+    extends ExpressionSpecification
+{
+    private final NamedAssociationFunction<T> namedAssociationFunction;
+    private final String name;
+
+    public NamedAssociationContainsNameSpecification( NamedAssociationFunction<T> namedAssociationFunction, String name )
+    {
+        this.namedAssociationFunction = namedAssociationFunction;
+        this.name = name;
+    }
+
+    public NamedAssociationFunction<T> namedAssociation()
+    {
+        return namedAssociationFunction;
+    }
+
+    public String name()
+    {
+        return name;
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        NamedAssociation<T> collection = namedAssociationFunction.map( item );
+        if( collection == null )
+        {
+            return false;
+        }
+        return collection.containsName( name );
+    }
+
+    @Override
+    public String toString()
+    {
+        return namedAssociationFunction + " contains name:" + name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/api/src/main/java/org/apache/zest/api/query/grammar/NamedAssociationContainsSpecification.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/zest/api/query/grammar/NamedAssociationContainsSpecification.java b/core/api/src/main/java/org/apache/zest/api/query/grammar/NamedAssociationContainsSpecification.java
new file mode 100644
index 0000000..e4e4f7b
--- /dev/null
+++ b/core/api/src/main/java/org/apache/zest/api/query/grammar/NamedAssociationContainsSpecification.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011-2012 Niclas Hedhman.
+ * Copyright 2014 Paul Merlin.
+ *
+ * Licensed 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
+ * ied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.api.query.grammar;
+
+import org.apache.zest.api.association.NamedAssociation;
+import org.apache.zest.api.composite.Composite;
+
+/**
+ * NamedAssociation Contains Specification.
+ */
+public class NamedAssociationContainsSpecification<T>
+    extends ExpressionSpecification
+{
+    private final NamedAssociationFunction<T> namedAssociationFunction;
+    private final T value;
+
+    public NamedAssociationContainsSpecification( NamedAssociationFunction<T> namedAssociationFunction, T value )
+    {
+        this.namedAssociationFunction = namedAssociationFunction;
+        this.value = value;
+    }
+
+    public NamedAssociationFunction<T> namedAssociation()
+    {
+        return namedAssociationFunction;
+    }
+
+    public T value()
+    {
+        return value;
+    }
+
+    @Override
+    public boolean satisfiedBy( Composite item )
+    {
+        NamedAssociation<T> collection = namedAssociationFunction.map( item );
+        if( collection == null )
+        {
+            return false;
+        }
+        return collection.nameOf( value ) != null;
+    }
+
+    @Override
+    public String toString()
+    {
+        return namedAssociationFunction + " contains:" + value;
+    }
+}