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 2016/12/17 10:28:18 UTC
[42/81] [abbrv] [partial] zest-java git commit: ZEST-195 ;
Replace all "zest" with "polygene"
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/property/StateHolder.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/property/StateHolder.java b/core/api/src/main/java/org/apache/polygene/api/property/StateHolder.java
new file mode 100644
index 0000000..28c3620
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/property/StateHolder.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.polygene.api.property;
+
+import java.lang.reflect.AccessibleObject;
+import java.util.stream.Stream;
+
+/**
+ * This represents the state of a composite (properties).
+ */
+public interface StateHolder
+{
+ /**
+ * Get a property for a specific accessor
+ *
+ * @param accessor of the property
+ *
+ * @return the property
+ *
+ * @throws IllegalArgumentException if no property for given accessor exists
+ */
+ <T> Property<T> propertyFor( AccessibleObject accessor )
+ throws IllegalArgumentException;
+
+ Stream<? extends Property<?>> properties();
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/property/package.html
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/property/package.html b/core/api/src/main/java/org/apache/polygene/api/property/package.html
new file mode 100644
index 0000000..95d7f77
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/property/package.html
@@ -0,0 +1,24 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ ~
+ -->
+<html>
+ <body>
+ <h2>Property API.</h2>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/MissingIndexingSystemException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/MissingIndexingSystemException.java b/core/api/src/main/java/org/apache/polygene/api/query/MissingIndexingSystemException.java
new file mode 100644
index 0000000..e15cbee
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/MissingIndexingSystemException.java
@@ -0,0 +1,35 @@
+/*
+ * 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.polygene.api.query;
+
+/**
+ * This Exception is thrown in <code>QueryBuilderFactory.newQueryBuilder()</code> method if
+ * no indexing subsystem has been declared in the assembly.
+ */
+public final class MissingIndexingSystemException
+ extends QueryException
+{
+ private static final long serialVersionUID = 5147421865890379209L;
+
+ public MissingIndexingSystemException()
+ {
+ super( "No EntityFinder has been declared in the assembly of the application." );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/NotQueryableException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/NotQueryableException.java b/core/api/src/main/java/org/apache/polygene/api/query/NotQueryableException.java
new file mode 100644
index 0000000..75dd611
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/NotQueryableException.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.api.query;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Member;
+import org.apache.polygene.api.entity.Queryable;
+import org.apache.polygene.api.property.GenericPropertyInfo;
+import org.apache.polygene.api.util.Classes;
+
+/**
+ * Thrown in case that a non queryable type or accessor (marked with @Queriable(false)) is used during query building,
+ * or when non-Property, non-Associations are trying to be queried (possibly can not happen).
+ */
+public class NotQueryableException
+ extends QueryException
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor.
+ *
+ * @param message exception message
+ */
+ public NotQueryableException( final String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Verify that the provided accessor method has not been marked with a Queryable(false).
+ *
+ * @param accessor accessor method
+ *
+ * @throws NotQueryableException - If accessor method has been marked as not queryable
+ */
+ public static void throwIfNotQueryable( final AccessibleObject accessor )
+ {
+ Queryable queryable = accessor.getAnnotation( Queryable.class );
+ if( queryable != null && !queryable.value() )
+ {
+ throw new NotQueryableException(
+ String.format(
+ "%1$s \"%2$s\" (%3$s) is not queryable as has been marked with @Queryable(false)",
+ Classes.RAW_CLASS.apply( GenericPropertyInfo.propertyTypeOf( accessor ) ).getSimpleName(),
+ ( (Member) accessor ).getName(),
+ ( (Member) accessor ).getDeclaringClass().getName()
+ )
+ );
+ }
+ }
+
+ /**
+ * Verify that the provided type has not been marked with a Queryable(false).
+ *
+ * @param type a type
+ *
+ * @throws NotQueryableException - If type has been marked as not queryable
+ */
+ public static void throwIfNotQueryable( final Class<?> type )
+ {
+ Queryable queryable = type.getAnnotation( Queryable.class );
+ if( queryable != null && !queryable.value() )
+ {
+ throw new NotQueryableException(
+ String.format(
+ "Type \"%1$s\" is not queryable as has been marked with @Queryable(false)",
+ type.getName()
+ )
+ );
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/Query.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/Query.java b/core/api/src/main/java/org/apache/polygene/api/query/Query.java
new file mode 100644
index 0000000..dda526d
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/Query.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.api.query;
+
+import java.io.Serializable;
+import java.util.stream.Stream;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.query.grammar.OrderBy;
+
+/**
+ * This represents a Query in an indexing system. It is created from a
+ * {@link QueryBuilder}, which decides the "where" clause in the query.
+ * <p>
+ * Additional limitations, such as paging, ordering, and variables, can be set on
+ * a Query before it is executed by calling one of find(), iterator(),
+ * or count().
+ * </p>
+ * <p>
+ * DDD tip: typically Queries are created in the Domain Model and passed to the UI,
+ * which sets the order and paging before executing it.
+ * </p>
+ */
+public interface Query<T>
+ extends Iterable<T>, Serializable
+{
+ /**
+ * Set the ordering rules. If many segments are used for ordering
+ * then they will be applied in order.
+ *
+ * @param segments the segments to order by
+ *
+ * @return the Query
+ */
+ Query<T> orderBy( OrderBy... segments );
+
+ /**
+ * Append an ordering rule to the existing segments.
+ *
+ * @param property the property to order by
+ * @param order the order to apply
+ *
+ * @return the Query
+ */
+ Query<T> orderBy( final Property<?> property, final OrderBy.Order order );
+
+ /**
+ * Append an ascending ordering rule to the existing segments.
+ *
+ * @param property the property to order by
+ *
+ * @return the Query
+ */
+ Query<T> orderBy( Property<?> property );
+
+ /**
+ * Set the index of the first result. Default is 0 (zero).
+ *
+ * @param firstResult which index to use as the first one
+ *
+ * @return the Query
+ */
+ Query<T> firstResult( int firstResult );
+
+ /**
+ * Set how many results should be returned. Default is that
+ * there is no limit set.
+ *
+ * @param maxResults that shouldbe returned
+ *
+ * @return the query
+ */
+ Query<T> maxResults( int maxResults );
+
+ /**
+ * Get the first Entity that matches the criteria. This
+ * executes the Query.
+ *
+ * @return the first found Entity or null if none were found
+ *
+ * @throws QueryExecutionException if the query fails
+ */
+ T find()
+ throws QueryExecutionException;
+
+ /**
+ * Set the value of a named variable.
+ *
+ * @param name of the variable
+ * @param value of the variable
+ *
+ * @return the query
+ */
+ Query<T> setVariable( String name, Object value );
+
+ /**
+ * Get the value of a named variable.
+ *
+ * @param name of the variable
+ *
+ * @return value of the variable
+ */
+ <V> V getVariable( String name );
+
+ /**
+ * Get the result type of this Query
+ *
+ * @return the result type
+ */
+ Class<T> resultType();
+
+ /**
+ * Count how many results would be returned by this Query.
+ * This executes the Query.
+ *
+ * @return result count
+ *
+ * @throws QueryExecutionException if the query fails
+ */
+ long count()
+ throws QueryExecutionException;
+
+ /**
+ * @return Stream results
+ */
+ Stream<T> stream();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/QueryBuilder.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/QueryBuilder.java b/core/api/src/main/java/org/apache/polygene/api/query/QueryBuilder.java
new file mode 100644
index 0000000..cd65e39
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/QueryBuilder.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.polygene.api.query;
+
+import java.util.function.Predicate;
+import org.apache.polygene.api.composite.Composite;
+
+/**
+ * QueryBuilders are used to create {@link Query} instances.
+ * Iteratively add where() clauses to the query, and then use
+ * {@link org.apache.polygene.api.unitofwork.UnitOfWork#newQuery(QueryBuilder)} to instantiate the Query.
+ * QueryBuilders are immutable, so when adding new where-clauses you get new instances. This
+ *
+ * DDD tip: Query objects are not executed immediately, so they
+ * should be constructed in the domain model and handed over to
+ * the UI, which can then further constrain it before actual
+ * execution.
+ */
+public interface QueryBuilder<T>
+{
+ /**
+ * Add a where-clause to the Query. Use {@link QueryExpressions}
+ * to create the expression.
+ *
+ * @param specification the where clause
+ *
+ * @return a new builder with the added where-clause
+ */
+ QueryBuilder<T> where( Predicate<Composite> specification );
+
+ /**
+ * Create a new query with the declared where-clauses that will be evaluated against the iterable entries.
+ *
+ * @param iterable collection of objects (composites?)
+ *
+ * @return a new Query instance
+ */
+ Query<T> newQuery( Iterable<T> iterable );
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/QueryBuilderFactory.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/QueryBuilderFactory.java b/core/api/src/main/java/org/apache/polygene/api/query/QueryBuilderFactory.java
new file mode 100644
index 0000000..be2666d
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/QueryBuilderFactory.java
@@ -0,0 +1,40 @@
+/*
+ * 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.polygene.api.query;
+
+/**
+ * This is used to create QueryBuilders.
+ *
+ * @see QueryBuilder
+ */
+public interface QueryBuilderFactory
+{
+ /**
+ * Create a new QueryBuilder.
+ *
+ * @param resultType the type of the result that you want
+ *
+ * @return a QueryBuilder
+ *
+ * @throws MissingIndexingSystemException if there is no EntityFinder service available
+ */
+ <T> QueryBuilder<T> newQueryBuilder( Class<T> resultType )
+ throws MissingIndexingSystemException;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/QueryException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/QueryException.java b/core/api/src/main/java/org/apache/polygene/api/query/QueryException.java
new file mode 100644
index 0000000..6a52120
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/QueryException.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.polygene.api.query;
+
+/**
+ * Base class for Query exceptions.
+ */
+public abstract class QueryException
+ extends RuntimeException
+{
+ private static final long serialVersionUID = -3602596752342902060L;
+
+ public QueryException()
+ {
+ }
+
+ public QueryException( final String message )
+ {
+ super( message );
+ }
+
+ public QueryException( final String message, final Throwable cause )
+ {
+ super( message, cause );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/QueryExecutionException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/QueryExecutionException.java b/core/api/src/main/java/org/apache/polygene/api/query/QueryExecutionException.java
new file mode 100644
index 0000000..bbed7f7
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/QueryExecutionException.java
@@ -0,0 +1,39 @@
+/*
+ * 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.polygene.api.query;
+
+/**
+ * Throw this exception if a query could not be executed
+ */
+public final class QueryExecutionException
+ extends QueryException
+{
+ private static final long serialVersionUID = 5147421865890379209L;
+
+ public QueryExecutionException( String message )
+ {
+ super( message );
+ }
+
+ public QueryExecutionException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/QueryExpressionException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/QueryExpressionException.java b/core/api/src/main/java/org/apache/polygene/api/query/QueryExpressionException.java
new file mode 100644
index 0000000..ed665ee
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/QueryExpressionException.java
@@ -0,0 +1,36 @@
+/*
+ * 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.polygene.api.query;
+
+/**
+ * Throw this exception if a QueryExpression is invalid.
+ */
+public class QueryExpressionException
+ extends QueryException
+{
+
+ private static final long serialVersionUID = 1L;
+
+ public QueryExpressionException( String message )
+ {
+ super( message );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/QueryExpressions.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/QueryExpressions.java b/core/api/src/main/java/org/apache/polygene/api/query/QueryExpressions.java
new file mode 100644
index 0000000..ca83940
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/QueryExpressions.java
@@ -0,0 +1,940 @@
+/*
+ * 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.polygene.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.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Predicate;
+import org.apache.polygene.api.association.Association;
+import org.apache.polygene.api.association.GenericAssociationInfo;
+import org.apache.polygene.api.association.ManyAssociation;
+import org.apache.polygene.api.association.NamedAssociation;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.identity.HasIdentity;
+import org.apache.polygene.api.identity.Identity;
+import org.apache.polygene.api.injection.scope.State;
+import org.apache.polygene.api.property.GenericPropertyInfo;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.query.grammar.AndPredicate;
+import org.apache.polygene.api.query.grammar.AssociationFunction;
+import org.apache.polygene.api.query.grammar.AssociationNotNullPredicate;
+import org.apache.polygene.api.query.grammar.AssociationNullPredicate;
+import org.apache.polygene.api.query.grammar.ContainsAllPredicate;
+import org.apache.polygene.api.query.grammar.ContainsPredicate;
+import org.apache.polygene.api.query.grammar.EqPredicate;
+import org.apache.polygene.api.query.grammar.GePredicate;
+import org.apache.polygene.api.query.grammar.GtPredicate;
+import org.apache.polygene.api.query.grammar.LePredicate;
+import org.apache.polygene.api.query.grammar.LtPredicate;
+import org.apache.polygene.api.query.grammar.ManyAssociationContainsPredicate;
+import org.apache.polygene.api.query.grammar.ManyAssociationFunction;
+import org.apache.polygene.api.query.grammar.MatchesPredicate;
+import org.apache.polygene.api.query.grammar.NamedAssociationContainsNamePredicate;
+import org.apache.polygene.api.query.grammar.NamedAssociationContainsPredicate;
+import org.apache.polygene.api.query.grammar.NamedAssociationFunction;
+import org.apache.polygene.api.query.grammar.NePredicate;
+import org.apache.polygene.api.query.grammar.Notpredicate;
+import org.apache.polygene.api.query.grammar.OrPredicate;
+import org.apache.polygene.api.query.grammar.OrderBy;
+import org.apache.polygene.api.query.grammar.PropertyFunction;
+import org.apache.polygene.api.query.grammar.PropertyNotNullPredicate;
+import org.apache.polygene.api.query.grammar.PropertyNullPredicate;
+import org.apache.polygene.api.query.grammar.PropertyReference;
+import org.apache.polygene.api.query.grammar.Variable;
+import org.apache.polygene.api.util.NullArgumentException;
+
+import static org.apache.polygene.api.identity.HasIdentity.IDENTITY_METHOD;
+
+/**
+ * Static factory methods for query expressions and operators.
+ */
+public final class QueryExpressions
+{
+ // This is used for eq(Association,Composite)
+
+ // 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 );
+ Iterator<String> iterator = association.iterator();
+ return association.get( iterator.hasNext() ? iterator.next() : null );
+ }
+
+ /**
+ * 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 AndPredicate and( Predicate<Composite> left,
+ Predicate<Composite> right,
+ Predicate<Composite>... optionalRight
+ )
+ {
+ List<Predicate<Composite>> predicates = new ArrayList<>( 2 + optionalRight.length );
+ predicates.add( left );
+ predicates.add( right );
+ Collections.addAll( predicates, optionalRight );
+ return new AndPredicate( predicates );
+ }
+
+ /**
+ * Create a new OR specification.
+ *
+ * @param specs operands
+ *
+ * @return a new OR specification
+ */
+ @SafeVarargs
+ public static OrPredicate or( Predicate<Composite>... specs )
+ {
+ return new OrPredicate( Arrays.asList( specs ) );
+ }
+
+ /**
+ * Create a new NOT specification.
+ *
+ * @param operand specification to be negated
+ *
+ * @return a new NOT specification
+ */
+ public static Notpredicate not( Predicate<Composite> operand )
+ {
+ return new Notpredicate( 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> EqPredicate<T> eq( Property<T> property, T value )
+ {
+ return new EqPredicate<>( 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> EqPredicate<T> eq( Property<T> property, Variable variable )
+ {
+ return new EqPredicate( 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> EqPredicate<Identity> eq( Association<T> association, T value )
+ {
+ return new EqPredicate<>(
+ new PropertyFunction<>(
+ null,
+ association(association),
+ null,
+ null,
+ IDENTITY_METHOD),
+ ((HasIdentity) value).identity().get());
+ }
+
+ /**
+ * 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> GePredicate<T> ge( Property<T> property, T value )
+ {
+ return new GePredicate<>( 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> GePredicate<T> ge( Property<T> property, Variable variable )
+ {
+ return new GePredicate( 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> GtPredicate<T> gt( Property<T> property, T value )
+ {
+ return new GtPredicate<>( 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> GtPredicate<T> gt( Property<T> property, Variable variable )
+ {
+ return new GtPredicate( 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> LePredicate<T> le( Property<T> property, T value )
+ {
+ return new LePredicate<>( 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> LePredicate<T> le( Property<T> property, Variable variable )
+ {
+ return new LePredicate( 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> LtPredicate<T> lt( Property<T> property, T value )
+ {
+ return new LtPredicate<>( 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> LtPredicate<T> lt( Property<T> property, Variable variable )
+ {
+ return new LtPredicate( 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> NePredicate<T> ne( Property<T> property, T value )
+ {
+ return new NePredicate<>( 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> NePredicate<T> ne( Property<T> property, Variable variable )
+ {
+ return new NePredicate( 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 MatchesPredicate matches( Property<String> property, String regexp )
+ {
+ return new MatchesPredicate( 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 MatchesPredicate matches( Property<String> property, Variable variable )
+ {
+ return new MatchesPredicate( 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> PropertyNotNullPredicate<T> isNotNull( Property<T> property )
+ {
+ return new PropertyNotNullPredicate<>( 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> PropertyNullPredicate<T> isNull( Property<T> property )
+ {
+ return new PropertyNullPredicate<>( 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> AssociationNotNullPredicate<T> isNotNull( Association<T> association )
+ {
+ return new AssociationNotNullPredicate<>( 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> AssociationNullPredicate<T> isNull( Association<T> association )
+ {
+ return new AssociationNullPredicate<>( 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> ContainsAllPredicate<T> containsAll( Property<? extends Collection<T>> collectionProperty,
+ Collection<T> values )
+ {
+ NullArgumentException.validateNotNull( "Values", values );
+ return new ContainsAllPredicate<>( 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> ContainsAllPredicate<T> containsAllVariables(
+ Property<? extends Collection<T>> collectionProperty,
+ Collection<Variable> variables )
+ {
+ NullArgumentException.validateNotNull( "Variables", variables );
+ return new ContainsAllPredicate( 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> ContainsPredicate<T> contains( Property<? extends Collection<T>> collectionProperty,
+ T value )
+ {
+ NullArgumentException.validateNotNull( "Value", value );
+ return new ContainsPredicate<>( 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> ContainsPredicate<T> contains( Property<? extends Collection<T>> collectionProperty,
+ Variable variable )
+ {
+ NullArgumentException.validateNotNull( "Variable", variable );
+ return new ContainsPredicate( 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> ManyAssociationContainsPredicate<T> contains( ManyAssociation<T> manyAssoc, T value )
+ {
+ return new ManyAssociationContainsPredicate<>( 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> NamedAssociationContainsPredicate<T> contains( NamedAssociation<T> namedAssoc, T value )
+ {
+ return new NamedAssociationContainsPredicate<>( 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> NamedAssociationContainsNamePredicate<T> containsName( NamedAssociation<T> namedAssoc,
+ String name )
+ {
+ return new NamedAssociationContainsNamePredicate<>( 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/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/AndPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/AndPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/AndPredicate.java
new file mode 100644
index 0000000..5e9c0bf
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/AndPredicate.java
@@ -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.polygene.api.query.grammar;
+
+import java.util.Collection;
+import java.util.function.Predicate;
+import org.apache.polygene.api.composite.Composite;
+
+/**
+ * AND Specification.
+ */
+public class AndPredicate
+ extends BinaryPredicate
+{
+ public AndPredicate( Collection<Predicate<Composite>> operands )
+ {
+ super( operands );
+ }
+
+ @Override
+ public boolean test( Composite item )
+ {
+ Predicate<Composite> master = t -> true;
+ for( Predicate<Composite> p : operands )
+ {
+ master = master.and( p );
+ }
+ return master.test( item );
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder( "(" );
+ String and = "";
+ for( Predicate<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/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationFunction.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationFunction.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationFunction.java
new file mode 100644
index 0000000..1a77c69
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationFunction.java
@@ -0,0 +1,149 @@
+/*
+ * 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.polygene.api.query.grammar;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Member;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.function.Function;
+import org.apache.polygene.api.association.Association;
+import org.apache.polygene.api.association.AssociationStateHolder;
+import org.apache.polygene.api.association.GenericAssociationInfo;
+import org.apache.polygene.api.association.ManyAssociation;
+import org.apache.polygene.api.association.NamedAssociation;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.composite.CompositeInstance;
+import org.apache.polygene.api.query.QueryExpressionException;
+import org.apache.polygene.api.util.Classes;
+
+import static org.apache.polygene.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.apply( returnType ) )
+ && !ManyAssociation.class.isAssignableFrom( Classes.RAW_CLASS.apply( returnType ) )
+ && !NamedAssociation.class.isAssignableFrom( Classes.RAW_CLASS.apply( 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> apply( Composite entity )
+ {
+ try
+ {
+ Object target = entity;
+ if( traversedAssociation != null )
+ {
+ Association<?> association = traversedAssociation.apply( 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/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationNotNullPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationNotNullPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationNotNullPredicate.java
new file mode 100644
index 0000000..b4f1f64
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationNotNullPredicate.java
@@ -0,0 +1,68 @@
+/*
+ * 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.polygene.api.query.grammar;
+
+import org.apache.polygene.api.association.Association;
+import org.apache.polygene.api.composite.Composite;
+
+/**
+ * Association not null Specification.
+ */
+public class AssociationNotNullPredicate<T>
+ extends ExpressionPredicate
+{
+ private AssociationFunction<T> association;
+
+ public AssociationNotNullPredicate( AssociationFunction<T> association )
+ {
+ this.association = association;
+ }
+
+ public AssociationFunction<T> association()
+ {
+ return association;
+ }
+
+ @Override
+ public boolean test( Composite item )
+ {
+ try
+ {
+ Association<T> assoc = association.apply( 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/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationNullPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationNullPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationNullPredicate.java
new file mode 100644
index 0000000..ba1ec40
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/AssociationNullPredicate.java
@@ -0,0 +1,68 @@
+/*
+ * 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.polygene.api.query.grammar;
+
+import org.apache.polygene.api.association.Association;
+import org.apache.polygene.api.composite.Composite;
+
+/**
+ * Association null Specification.
+ */
+public class AssociationNullPredicate<T>
+ extends ExpressionPredicate
+{
+ private AssociationFunction<T> association;
+
+ public AssociationNullPredicate( AssociationFunction<T> association )
+ {
+ this.association = association;
+ }
+
+ public AssociationFunction<T> association()
+ {
+ return association;
+ }
+
+ @Override
+ public boolean test( Composite item )
+ {
+ try
+ {
+ Association<T> assoc = association.apply( 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/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/BinaryPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/BinaryPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/BinaryPredicate.java
new file mode 100644
index 0000000..cdc6919
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/BinaryPredicate.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.polygene.api.query.grammar;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.function.Predicate;
+import org.apache.polygene.api.composite.Composite;
+
+/**
+ * Base binary Specification, used for AND and OR Specifications..
+ */
+public abstract class BinaryPredicate
+ extends ExpressionPredicate
+{
+ protected final Collection<Predicate<Composite>> operands;
+
+ protected BinaryPredicate( Collection<Predicate<Composite>> operands )
+ {
+ this.operands = Collections.unmodifiableCollection( operands );
+ }
+
+ public Collection<Predicate<Composite>> operands()
+ {
+ return operands;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/ComparisonPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/ComparisonPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/ComparisonPredicate.java
new file mode 100644
index 0000000..955f3ae
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/ComparisonPredicate.java
@@ -0,0 +1,77 @@
+/*
+ * 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.polygene.api.query.grammar;
+
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.property.Property;
+
+/**
+ * Base comparison Specification.
+ */
+public abstract class ComparisonPredicate<T>
+ extends ExpressionPredicate
+{
+ protected final PropertyFunction<T> property;
+ protected final T value;
+
+ public ComparisonPredicate( PropertyFunction<T> property, T value )
+ {
+ this.property = property;
+ this.value = value;
+ }
+
+ public PropertyFunction<T> property()
+ {
+ return property;
+ }
+
+ @Override
+ public final boolean test( Composite item )
+ {
+ try
+ {
+ Property<T> prop = property.apply( 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/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/ContainsAllPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/ContainsAllPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/ContainsAllPredicate.java
new file mode 100644
index 0000000..b06c6f8
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/ContainsAllPredicate.java
@@ -0,0 +1,79 @@
+/*
+ * 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.polygene.api.query.grammar;
+
+import java.util.Collection;
+import java.util.Collections;
+import org.apache.polygene.api.composite.Composite;
+
+/**
+ * Contains All Specification.
+ */
+public class ContainsAllPredicate<T>
+ extends ExpressionPredicate
+{
+ private PropertyFunction<? extends Collection<T>> collectionProperty;
+ private Collection<T> valueCollection;
+
+ public ContainsAllPredicate( PropertyFunction<? extends Collection<T>> collectionProperty,
+ Collection<T> valueCollection
+ )
+ {
+ this.collectionProperty = collectionProperty;
+ this.valueCollection = Collections.unmodifiableCollection( valueCollection );
+ }
+
+ public PropertyFunction<? extends Collection<T>> collectionProperty()
+ {
+ return collectionProperty;
+ }
+
+ public Collection<T> containedValues()
+ {
+ return valueCollection;
+ }
+
+ @Override
+ public boolean test( Composite item )
+ {
+ Collection<T> collection = collectionProperty.apply( 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 " + valueCollection;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/ContainsPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/ContainsPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/ContainsPredicate.java
new file mode 100644
index 0000000..a277307
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/ContainsPredicate.java
@@ -0,0 +1,68 @@
+/*
+ * 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.polygene.api.query.grammar;
+
+import java.util.Collection;
+import org.apache.polygene.api.composite.Composite;
+
+/**
+ * Contains Specification.
+ */
+public class ContainsPredicate<T>
+ extends ExpressionPredicate
+{
+ private PropertyFunction<? extends Collection<T>> collectionProperty;
+ private T value;
+
+ public ContainsPredicate( 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 test( Composite item )
+ {
+ Collection<T> collection = collectionProperty.apply( 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/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/EqPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/EqPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/EqPredicate.java
new file mode 100644
index 0000000..84eb77a
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/EqPredicate.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.polygene.api.query.grammar;
+
+/**
+ * Equals Specification.
+ */
+public class EqPredicate<T>
+ extends ComparisonPredicate<T>
+{
+ public EqPredicate( 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/1c722f44/core/api/src/main/java/org/apache/polygene/api/query/grammar/ExpressionPredicate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/query/grammar/ExpressionPredicate.java b/core/api/src/main/java/org/apache/polygene/api/query/grammar/ExpressionPredicate.java
new file mode 100644
index 0000000..94ec810
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/query/grammar/ExpressionPredicate.java
@@ -0,0 +1,31 @@
+/*
+ * 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.polygene.api.query.grammar;
+
+import java.util.function.Predicate;
+import org.apache.polygene.api.composite.Composite;
+
+/**
+ * Base expression Specification.
+ */
+public abstract class ExpressionPredicate
+ implements Predicate<Composite>
+{
+}