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:14 UTC
[38/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/unitofwork/concern/UnitOfWorkDiscardOn.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkDiscardOn.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkDiscardOn.java
new file mode 100644
index 0000000..aec32d4
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkDiscardOn.java
@@ -0,0 +1,73 @@
+/*
+ * 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.unitofwork.concern;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation to denote the unit of work discard policy.
+ * <p>
+ * By default, discard is applied on any method that has {@link UnitOfWorkPropagation} and any exception is thrown.
+ * </p>
+ * <p>
+ * Apply {@code UnitOfWorkDiscardOn} to override the default settings.
+ * </p>
+ * <p>
+ * Usage example:
+ * </p>
+ * <pre>
+ * <code>
+ *
+ * @Concerns( UnitOfWorkConcern.class )
+ * public class MyBusinessServiceMixin implements BusinessService
+ * {
+ * @Structure UnitOfWorkFactory uowf;
+ *
+ * @UnitOfWorkDiscardOn( MyBusinessException.class )
+ * public void myBusinessMethod()
+ * {
+ * // Must invoke current unit of work.
+ * UnitOfWork uow = uowf.currentUnitOfWork();
+ *
+ * // Perform business logic
+ * }
+ * }
+ * </code>
+ * </pre>
+ *
+ * <p>
+ * The unit of work will be discarded iff {@code MyBusinessException} exceptions or its subclass is thrown from within
+ * {@code myBusinessMethod} method.
+ * </p>
+ */
+@Retention( RUNTIME )
+@Target( METHOD )
+@Inherited
+@Documented
+public @interface UnitOfWorkDiscardOn
+{
+ Class<? extends Throwable>[] value() default { Throwable.class };
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkPropagation.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkPropagation.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkPropagation.java
new file mode 100644
index 0000000..b29a355
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkPropagation.java
@@ -0,0 +1,92 @@
+/*
+ * 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.unitofwork.concern;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation to denote the unit of work propagation.
+ * <p>
+ * Usage example:
+ * </p>
+ * <pre>
+ * <code>
+ *
+ * @Concerns( UnitOfWorkConcern.class )
+ * public class MyBusinessServiceMixin implements BusinessService
+ * {
+ * @Structure UnitOfWorkFactory uowf;
+ *
+ * @UnitOfWorkPropagation
+ * public void myBusinessMethod()
+ * {
+ * // Must invoke current unit of work.
+ * UnitOfWork uow = uowf.currentUnitOfWork();
+ *
+ * // Perform business logic
+ * }
+ * }
+ * </code>
+ * </pre>
+ */
+@Retention( RUNTIME )
+@Target( METHOD )
+@Inherited
+@Documented
+public @interface UnitOfWorkPropagation
+{
+ Propagation value() default Propagation.REQUIRED;
+
+ String usecase() default "";
+
+ /**
+ * Propagation behaviors.
+ */
+ enum Propagation
+ {
+ /**
+ * Default propagation behavior.
+ * Behavior: <br>
+ * If no current transaction: creates a new UnitOfWork <br>
+ * If there is a current UnitOfWork: use the current UnitOfWork.
+ */
+ REQUIRED,
+
+ /**
+ * Behavior: <br>
+ * If no current UnitOfWork: throw an exception <br>
+ * If there is a current UnitOfWork: use the current UnitOfWork.
+ */
+ MANDATORY,
+
+ /**
+ * Behavior: <br>
+ * If no current UnitOfWork: creates a new UnitOfWork <br>
+ * If there is a current UnitOfWork: suspend the current UnitOfWork and create a new UnitOfWork.
+ */
+ REQUIRES_NEW
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkRetry.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkRetry.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkRetry.java
new file mode 100644
index 0000000..9f2d481
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkRetry.java
@@ -0,0 +1,81 @@
+/*
+ * 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.unitofwork.concern;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import org.apache.polygene.api.unitofwork.ConcurrentEntityModificationException;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * This annotation describes the retries that should occur in case of
+ * {@link org.apache.polygene.api.unitofwork.ConcurrentEntityModificationException}
+ * occurs.
+ */
+@Retention( RUNTIME )
+@Target( METHOD )
+@Inherited
+@Documented
+public @interface UnitOfWorkRetry
+{
+ /**
+ * Number of times that the UnitOfWork should be tried in total.
+ * The default value is 1, which means that the UnitOfWork will execute only one time. It is also the minimum
+ * value allowed.
+ *
+ * @return Number of times that the UnitOfWork will be executed. Must be 1 or higher. If a value of 0 or lower is
+ * given, the UnitOfWork is still executed one time.
+ */
+ int retries() default 1;
+
+ /**
+ * Number of milliseconds to wait before executing the second UnitOfOfWork.
+ * The default value is 0, which means that there is no delay and it is tried immediately.
+ *
+ * @return Number of milliseconds to wait before executing the second UnitOfOfWork.
+ */
+ long initialDelay() default 0;
+
+ /**
+ * Number of milliseconds to be added for each additional retry, beyond the second one.
+ * The default value is 10.
+ *
+ * The delay is defined as;
+ *
+ * <pre><code>
+ *
+ * Thread.sleep( initialDelay + retry * delayFactor );
+ * </code></pre>
+ * where retry will be 0 after first UnitOfWork had a {@link ConcurrentEntityModificationException} and is 1 after
+ * the first retry and so forth.
+ * <p>
+ * So, with the {@code retries=4, initialDelay=5, delayFactor=20} the 3 delays between the UnitOfWorks will be
+ * {@code 5ms, 25ms, 45ms}
+ * </p>
+ *
+ * @return The number of milliseconds per retry, except the first one, that should be added to the delay between
+ * tries.
+ */
+ long delayFactor() default 10;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/package.html
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/package.html b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/package.html
new file mode 100644
index 0000000..20aa625
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/package.html
@@ -0,0 +1,27 @@
+<!--
+ ~ 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>UnitOfWork Concerns.</h2>
+ <p>
+ UnitOfWork Concerns allow declarative UnitOfWork propagation, discard wrt. exceptions and automatic retry.
+ </p>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/unitofwork/package.html
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/package.html b/core/api/src/main/java/org/apache/polygene/api/unitofwork/package.html
new file mode 100644
index 0000000..70ff9e9
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/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>UnitOfWork 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/usecase/Usecase.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/usecase/Usecase.java b/core/api/src/main/java/org/apache/polygene/api/usecase/Usecase.java
new file mode 100644
index 0000000..c47ce27
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/usecase/Usecase.java
@@ -0,0 +1,75 @@
+/*
+ * 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.usecase;
+
+import java.io.Serializable;
+import org.apache.polygene.api.common.MetaInfo;
+import org.apache.polygene.api.structure.MetaInfoHolder;
+
+/**
+ * A Usecase. A Usecase is used as a model for UnitOfWork, and helps
+ * implementations decide what to do in certain circumstances.
+ */
+public final class Usecase
+ implements Serializable, MetaInfoHolder
+{
+ public static final Usecase DEFAULT = new Usecase( "Default", new MetaInfo() );
+
+ private static final long serialVersionUID = 1L;
+ private final String name;
+ private final MetaInfo metaInfo;
+
+ Usecase( String name, MetaInfo metaInfo )
+ {
+ this.name = name;
+ this.metaInfo = metaInfo;
+ }
+
+ /**
+ * Name of the usecase.
+ *
+ * @return the name
+ */
+ public String name()
+ {
+ return name;
+ }
+
+ /**
+ * Meta-info for the usecase. This can be of any type, and is typically set when creating the usecase
+ * and read during the execution of the usecase.
+ *
+ * @param infoType the MetaInfo type to retrieve.
+ *
+ * @return the previously stored metaInfo of the given type for the usecase.
+ */
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return metaInfo.get( infoType );
+ }
+
+ @Override
+ public String toString()
+ {
+ return name + ", meta info:" + metaInfo;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/usecase/UsecaseBuilder.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/usecase/UsecaseBuilder.java b/core/api/src/main/java/org/apache/polygene/api/usecase/UsecaseBuilder.java
new file mode 100644
index 0000000..ae89aad
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/usecase/UsecaseBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * 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.usecase;
+
+import org.apache.polygene.api.common.MetaInfo;
+
+/**
+ * Builder for Usecases.
+ */
+public final class UsecaseBuilder
+{
+ public static UsecaseBuilder buildUsecase( String aName )
+ {
+ return new UsecaseBuilder( aName );
+ }
+
+ public static Usecase newUsecase( String aName )
+ {
+ return new UsecaseBuilder( aName ).newUsecase();
+ }
+
+ private MetaInfo metaInfo = new MetaInfo();
+
+ private String name;
+
+ private UsecaseBuilder( String name )
+ {
+ this.name = name;
+ }
+
+ public UsecaseBuilder withMetaInfo( Object metaInfo )
+ {
+ this.metaInfo.set( metaInfo );
+ return this;
+ }
+
+ public Usecase newUsecase()
+ {
+ return new Usecase( name, metaInfo );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/usecase/package.html
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/usecase/package.html b/core/api/src/main/java/org/apache/polygene/api/usecase/package.html
new file mode 100644
index 0000000..1d55001
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/usecase/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>Usecase 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/util/Annotations.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Annotations.java b/core/api/src/main/java/org/apache/polygene/api/util/Annotations.java
new file mode 100644
index 0000000..b172945
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/Annotations.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.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.apache.polygene.api.util.Classes.interfacesOf;
+import static org.apache.polygene.api.util.Classes.typeOf;
+
+/**
+ * Useful methods for handling Annotations.
+ */
+public final class Annotations
+{
+ public static final Function<Type, Stream<Annotation>> ANNOTATIONS_OF =
+ Classes.forTypes( type -> Arrays.stream( Classes.RAW_CLASS.apply( type ).getAnnotations() ) );
+
+ public static Predicate<Annotation> typeHasAnnotation( Class<? extends Annotation> annotationType )
+ {
+ return element -> hasAnnotation( annotationType ).test( type().apply( element ) );
+ }
+
+ public static Predicate<AnnotatedElement> hasAnnotation( final Class<? extends Annotation> annotationType )
+ {
+ return element -> element.getAnnotation( annotationType ) != null;
+ }
+
+ public static Function<Annotation, Class<? extends Annotation>> type()
+ {
+ return Annotation::annotationType;
+ }
+
+ public static Predicate<Annotation> isType( final Class<? extends Annotation> annotationType )
+ {
+ return annotation -> annotation.annotationType().equals( annotationType );
+ }
+
+ public static <T extends Annotation> T annotationOn( Type type, Class<T> annotationType )
+ {
+ return annotationType.cast( Classes.RAW_CLASS.apply( type ).getAnnotation( annotationType ) );
+ }
+
+ public static List<Annotation> findAccessorAndTypeAnnotationsIn(AccessibleObject accessor) {
+ Stream<Annotation> stream = Stream.concat(
+ Arrays.stream(accessor.getAnnotations()),
+ interfacesOf(typeOf(accessor)).flatMap(ANNOTATIONS_OF)
+ );
+ Collector<Annotation, ?, List<Annotation>> collector = Collectors.toList();
+ return stream.collect(collector);
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/Classes.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Classes.java b/core/api/src/main/java/org/apache/polygene/api/util/Classes.java
new file mode 100644
index 0000000..175be95
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/Classes.java
@@ -0,0 +1,541 @@
+/*
+ * 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.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.polygene.api.composite.ModelDescriptor;
+
+import static java.util.stream.Stream.concat;
+import static java.util.stream.StreamSupport.stream;
+
+/**
+ * Useful methods for handling Classes.
+ */
+public final class Classes
+{
+ private final static Map<Type, Type> wrapperClasses = new HashMap<>();
+
+ static
+ {
+ wrapperClasses.put( boolean.class, Boolean.class );
+ wrapperClasses.put( byte.class, Byte.class );
+ wrapperClasses.put( short.class, Short.class );
+ wrapperClasses.put( char.class, Character.class );
+ wrapperClasses.put( int.class, Integer.class );
+ wrapperClasses.put( long.class, Long.class );
+ wrapperClasses.put( float.class, Float.class );
+ wrapperClasses.put( double.class, Double.class );
+ }
+
+ private final static Map<Type, Type> primitiveClasses = new HashMap<>();
+
+ static
+ {
+ primitiveClasses.put( boolean.class, Boolean.class );
+ primitiveClasses.put( byte.class, Byte.class );
+ primitiveClasses.put( short.class, Short.class );
+ primitiveClasses.put( char.class, Character.class );
+ primitiveClasses.put( int.class, Integer.class );
+ primitiveClasses.put( long.class, Long.class );
+ primitiveClasses.put( float.class, Float.class );
+ primitiveClasses.put( double.class, Double.class );
+ }
+
+ /**
+ * Convert from primitive class (int, short, double, etc.) to wrapper class (Integer, Short, Double, etc.).
+ * Return the same class if it's not a primitive class. This can therefore safely be used on all types
+ * to ensure that they are not primitives.
+ */
+ private static final Function<Type, Type> WRAPPER_CLASS = clazz -> {
+ Type wrapperClass = wrapperClasses.get( clazz );
+ return wrapperClass == null ? clazz : wrapperClass;
+ };
+
+ /**
+ * Convert from wrapper class (Integer, Short, Double, etc.) to primitive class (int, short, double, etc.).
+ * Return the same class if it's not a wrapper class. This can therefore safely be used on all types
+ * to ensure that they are primitives if possible.
+ */
+ @SuppressWarnings( "UnusedDeclaration" )
+ private static final Function<Type, Type> PRIMITIVE_CLASS = aClass -> {
+ Type primitiveClass = primitiveClasses.get( aClass );
+ return primitiveClass == null ? aClass : primitiveClass;
+ };
+
+ /**
+ * Function that extract the raw class of a type.
+ */
+ public static final Function<Type, Class<?>> RAW_CLASS = genericType -> {
+ // Calculate raw type
+ if( genericType instanceof Class )
+ {
+ return (Class<?>) genericType;
+ }
+ else if( genericType instanceof ParameterizedType )
+ {
+ return (Class<?>) ( (ParameterizedType) genericType ).getRawType();
+ }
+ else if( genericType instanceof TypeVariable )
+ {
+ return (Class<?>) ( (TypeVariable) genericType ).getGenericDeclaration();
+ }
+ else if( genericType instanceof WildcardType )
+ {
+ return (Class<?>) ( (WildcardType) genericType ).getUpperBounds()[ 0 ];
+ }
+ else if( genericType instanceof GenericArrayType )
+ {
+ Object temp = Array.newInstance( (Class<?>) ( (GenericArrayType) genericType ).getGenericComponentType(), 0 );
+ return temp.getClass();
+ }
+ throw new IllegalArgumentException( "Could not extract the raw class of " + genericType );
+ };
+
+ private static final Function<AccessibleObject, Type> TYPE_OF = accessor -> {
+ if( accessor instanceof Method )
+ {
+ return ( (Method) accessor ).getGenericReturnType();
+ }
+ return ( (Field) accessor ).getGenericType();
+ };
+
+ private static final Function<Type, Stream<Class<?>>> CLASS_HIERARCHY = new Function<Type, Stream<Class<?>>>()
+ {
+ @Override
+ public Stream<Class<?>> apply( Type type )
+ {
+ if( type == null )
+ {
+ return Stream.empty();
+ }
+ if( type.equals( Object.class ) )
+ {
+ return Stream.of( (Class<?>) type );
+ }
+ else
+ {
+ type = RAW_CLASS.apply( type );
+ Class superclass = ( (Class) type ).getSuperclass();
+ return concat( Stream.of( (Class<?>) type ), apply( superclass ) );
+ }
+ }
+ };
+
+ @SuppressWarnings( "raw" )
+ private static final Function<Type, Stream<? extends Type>> INTERFACES_OF = new Function<Type, Stream<? extends Type>>()
+ {
+ @Override
+ public Stream<? extends Type> apply( Type type )
+ {
+ Class clazz = RAW_CLASS.apply( type );
+
+ if( clazz.isInterface() )
+ {
+ Stream<? extends Type> genericInterfaces = Arrays.stream( clazz.getGenericInterfaces() );
+ Stream<? extends Type> intfaces = genericInterfaces.flatMap( INTERFACES_OF );
+ return concat( Stream.of( type ), intfaces );
+ }
+ else
+ {
+ if( type.equals( Object.class ) )
+ {
+ return Arrays.stream( clazz.getGenericInterfaces() );
+ }
+ else
+ {
+ return concat( Stream.of( clazz.getGenericInterfaces() ).flatMap( INTERFACES_OF ),
+ Stream.of( clazz.getSuperclass() ).flatMap( INTERFACES_OF ) );
+
+ }
+ }
+ }
+ };
+
+ private static final Function<Type, Stream<? extends Type>> TYPES_OF = type -> {
+ Class clazz = RAW_CLASS.apply( type );
+
+ if( clazz.isInterface() )
+ {
+ Stream<Type> intfaces = Arrays.stream( clazz.getGenericInterfaces() ).flatMap( INTERFACES_OF );
+ return concat( Stream.of( clazz ), intfaces );
+ }
+ else
+ {
+ return concat( Stream.of( clazz ),
+ Stream.of( type ).flatMap( CLASS_HIERARCHY ).flatMap( INTERFACES_OF ) );
+ }
+ };
+
+ public static Type typeOf( AccessibleObject from )
+ {
+ return TYPE_OF.apply( from );
+ }
+
+ public static Stream<Type> typesOf( Stream<? extends Type> types )
+ {
+ return types.flatMap( TYPES_OF );
+ }
+
+ public static Stream<? extends Type> typesOf( Type type )
+ {
+ return TYPES_OF.apply( type );
+ }
+
+ public static Stream<? extends Type> interfacesOf( Stream<? extends Type> types )
+ {
+ return types.flatMap( INTERFACES_OF );
+ }
+
+ public static Stream<? extends Type> interfacesOf( Type type )
+ {
+ return Stream.of( type ).flatMap( INTERFACES_OF );
+ }
+
+ public static Stream<Class<?>> classHierarchy( Class<?> type )
+ {
+ return Stream.of( type ).flatMap( CLASS_HIERARCHY );
+ }
+
+ public static Type wrapperClass( Type type )
+ {
+ return WRAPPER_CLASS.apply( type );
+ }
+
+ public static Predicate<Class<?>> isAssignableFrom( final Class<?> clazz )
+ {
+ return clazz::isAssignableFrom;
+ }
+
+ public static Predicate<Object> instanceOf( final Class<?> clazz )
+ {
+ return clazz::isInstance;
+ }
+
+ public static Predicate<Class<?>> hasModifier( final int classModifier )
+ {
+ return item -> ( item.getModifiers() & classModifier ) != 0;
+ }
+
+ public static <T> Function<Type, Stream<T>> forClassHierarchy( final Function<Class<?>, Stream<T>> function )
+ {
+ return type -> Stream.of( type ).flatMap( CLASS_HIERARCHY ).flatMap( function );
+ }
+
+ public static <T> Function<Type, Stream<T>> forTypes( final Function<Type, Stream<T>> function )
+ {
+ return type -> Stream.of( type ).flatMap( TYPES_OF ).flatMap( function );
+ }
+
+ @SuppressWarnings( "raw" )
+ public static Set<Class<?>> interfacesWithMethods( Set<Class<?>> interfaces )
+ {
+ Set<Class<?>> newSet = new LinkedHashSet<>();
+ for( Class type : interfaces )
+ {
+ if( type.isInterface() && type.getDeclaredMethods().length > 0 )
+ {
+ newSet.add( type );
+ }
+ }
+
+ return newSet;
+ }
+
+ public static String simpleGenericNameOf( Type type )
+ {
+ StringBuilder sb = new StringBuilder();
+ simpleGenericNameOf( sb, type );
+ return sb.toString();
+ }
+
+ @SuppressWarnings( "raw" )
+ private static void simpleGenericNameOf( StringBuilder sb, Type type )
+ {
+ if( type instanceof Class )
+ {
+ sb.append( ( (Class) type ).getSimpleName() );
+ }
+ else if( type instanceof ParameterizedType )
+ {
+ ParameterizedType pt = (ParameterizedType) type;
+ simpleGenericNameOf( sb, pt.getRawType() );
+ sb.append( "<" );
+ boolean atLeastOne = false;
+ for( Type typeArgument : pt.getActualTypeArguments() )
+ {
+ if( atLeastOne )
+ {
+ sb.append( ", " );
+ }
+ simpleGenericNameOf( sb, typeArgument );
+ atLeastOne = true;
+ }
+ sb.append( ">" );
+ }
+ else if( type instanceof GenericArrayType )
+ {
+ GenericArrayType gat = (GenericArrayType) type;
+ simpleGenericNameOf( sb, gat.getGenericComponentType() );
+ sb.append( "[]" );
+ }
+ else if( type instanceof TypeVariable )
+ {
+ TypeVariable tv = (TypeVariable) type;
+ sb.append( tv.getName() );
+ }
+ else if( type instanceof WildcardType )
+ {
+ WildcardType wt = (WildcardType) type;
+ sb.append( "? extends " );
+ boolean atLeastOne = false;
+ for( Type typeArgument : wt.getUpperBounds() )
+ {
+ if( atLeastOne )
+ {
+ sb.append( ", " );
+ }
+ simpleGenericNameOf( sb, typeArgument );
+ atLeastOne = true;
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException( "Don't know how to deal with type:" + type );
+ }
+ }
+
+ @SuppressWarnings( "UnusedDeclaration" )
+ public static <AnnotationType extends Annotation>
+ AnnotationType findAnnotationOfTypeOrAnyOfSuperTypes( Class<?> type, Class<AnnotationType> annotationClass )
+ {
+ return Stream.of( type )
+ .flatMap( TYPES_OF )
+ .map( RAW_CLASS )
+ .map( clazz -> clazz.getAnnotation( annotationClass ) )
+ .filter( Objects::nonNull )
+ .findAny().orElse( null );
+ }
+
+ public static Predicate<Member> memberNamed( final String name )
+ {
+ return item -> item.getName().equals( name );
+ }
+
+ /**
+ * Given a type variable, find what it resolves to given the declaring class where type
+ * variable was found and a top class that extends the declaring class.
+ *
+ * @param name The TypeVariable name.
+ * @param declaringClass The class where the TypeVariable is declared.
+ * @param topClass The top class that extends the declaringClass
+ *
+ * @return The Type instance of the given TypeVariable
+ */
+ @SuppressWarnings( "raw" )
+ public static Type resolveTypeVariable( TypeVariable name, Class declaringClass, Class topClass )
+ {
+ Type type = resolveTypeVariable( name, declaringClass, new HashMap<>(), topClass );
+ if( type == null )
+ {
+ type = Object.class;
+ }
+ return type;
+ }
+
+ private static Type resolveTypeVariable( TypeVariable name,
+ Class declaringClass,
+ Map<TypeVariable, Type> mappings,
+ Class current
+ )
+ {
+ if( current.equals( declaringClass ) )
+ {
+ Type resolvedType = name;
+ while( resolvedType instanceof TypeVariable )
+ {
+ resolvedType = mappings.get( resolvedType );
+ }
+ return resolvedType;
+ }
+
+ Stream<? extends Type> stream = Arrays.stream( current.getGenericInterfaces() )
+ .flatMap( INTERFACES_OF )
+ .distinct();
+
+ Type genericSuperclass = current.getGenericSuperclass();
+ if( genericSuperclass != null )
+ {
+ stream = concat( stream, Stream.of( genericSuperclass ) );
+ }
+ return stream.map( type -> {
+ Class subClass;
+ if( type instanceof ParameterizedType )
+ {
+ subClass = extractTypeVariables( mappings, (ParameterizedType) type );
+ }
+ else
+ {
+ subClass = (Class) type;
+ }
+ return subClass;
+ } )
+ .map( subClass -> resolveTypeVariable( name, declaringClass, mappings, subClass ) )
+ .filter( type -> type != null )
+ .findAny().orElse( null );
+ }
+
+ private static Class extractTypeVariables( Map<TypeVariable, Type> mappings, ParameterizedType type )
+ {
+ Class subClass;
+ Type[] args = type.getActualTypeArguments();
+ Class clazz = (Class) type.getRawType();
+ TypeVariable[] vars = clazz.getTypeParameters();
+ for( int i = 0; i < vars.length; i++ )
+ {
+ TypeVariable var = vars[ i ];
+ Type mappedType = args[ i ];
+ mappings.put( var, mappedType );
+ }
+ subClass = (Class) type.getRawType();
+ return subClass;
+ }
+
+ /**
+ * Get URI for a class.
+ *
+ * @param clazz class
+ *
+ * @return URI
+ *
+ * @throws NullPointerException if clazz is null
+ */
+ @SuppressWarnings( "raw" )
+ public static String toURI( final Class clazz )
+ throws NullPointerException
+ {
+ return toURI( clazz.getName() );
+ }
+
+ /**
+ * Get URI for a class name.
+ * <p>
+ * Example:
+ * </p>
+ * <p>
+ * Class name com.example.Foo$Bar is converted to URI urn:polygene:com.example.Foo-Bar
+ * </p>
+ *
+ * @param className class name
+ *
+ * @return URI
+ *
+ * @throws NullPointerException if className is null
+ */
+ public static String toURI( String className )
+ throws NullPointerException
+ {
+ className = normalizeClassToURI( className );
+ return "urn:polygene:type:" + className;
+ }
+
+ /**
+ * Get class name from a URI
+ *
+ * @param uri URI
+ *
+ * @return class name
+ *
+ * @throws NullPointerException if uri is null
+ */
+ public static String toClassName( String uri )
+ throws NullPointerException
+ {
+ uri = uri.substring( "urn:polygene:type:".length() );
+ uri = denormalizeURIToClass( uri );
+ return uri;
+ }
+
+ public static String normalizeClassToURI( String className )
+ {
+ return className.replace( '$', '-' );
+ }
+
+ public static String denormalizeURIToClass( String uriPart )
+ {
+ return uriPart.replace( '-', '$' );
+ }
+
+ public static Predicate<ModelDescriptor> modelTypeSpecification( final String className )
+ {
+ return item ->
+ stream( item.types().spliterator(), false )
+ .map( Class::getName ).anyMatch( typeName -> typeName.equals( className ) );
+ }
+
+ @SuppressWarnings( "raw" )
+ public static Predicate<ModelDescriptor> exactTypeSpecification( final Class type )
+ {
+ return item -> item.types().anyMatch( clazz -> clazz.equals( type ) );
+ }
+
+ @SuppressWarnings( "raw" )
+ public static Predicate<ModelDescriptor> assignableTypeSpecification( final Class<?> type )
+ {
+ return item ->
+ item.types().anyMatch(
+ itemType -> !type.equals( itemType ) && type.isAssignableFrom( itemType )
+ );
+ }
+
+ @SuppressWarnings( "raw" )
+ public static String toString( Stream<? extends Class> types )
+ {
+ return "[" + types.map( Class::getSimpleName ).collect( Collectors.joining( "," ) ) + "]";
+ }
+
+ public static Function<Type, String> toClassName()
+ {
+ return type -> RAW_CLASS.apply( type ).getName();
+ }
+
+ private Classes()
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java b/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java
new file mode 100644
index 0000000..e419b21
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java
@@ -0,0 +1,105 @@
+/*
+ * 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.util;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collector;
+
+public class Collectors
+{
+ /**
+ * Collect a single element.
+ * @param <T> Element type
+ * @return The single element
+ * @throws IllegalArgumentException if no or more than one element
+ */
+ public static <T>
+ Collector<T, ?, T> single()
+ throws IllegalArgumentException
+ {
+ Supplier<T> thrower = () ->
+ {
+ throw new IllegalArgumentException( "No or more than one element in stream" );
+ };
+ return java.util.stream.Collectors.collectingAndThen( java.util.stream.Collectors.reducing( ( a, b ) -> null ),
+ optional -> optional.orElseGet( thrower ) );
+ }
+
+ /**
+ * Eventually collect a single element.
+ * @param <T> Element type
+ * @return The single element, optional
+ * @throws IllegalArgumentException if more than one element
+ */
+ public static <T>
+ Collector<T, ?, Optional<T>> singleOrEmpty()
+ throws IllegalArgumentException
+ {
+ return java.util.stream.Collectors.reducing(
+ ( left, right ) ->
+ {
+ if( left != null && right != null )
+ {
+ throw new IllegalArgumentException( "More than one element in stream" );
+ }
+ if( left != null )
+ {
+ return left;
+ }
+ return right;
+ } );
+ }
+
+ public static <T, K, U, M extends Map<K, U>>
+ Collector<T, ?, M> toMap( Function<? super T, ? extends K> keyMapper,
+ Function<? super T, ? extends U> valueMapper,
+ Supplier<M> mapSupplier )
+ {
+ return java.util.stream.Collectors.toMap( keyMapper,
+ valueMapper,
+ throwingMerger(),
+ mapSupplier );
+ }
+
+
+ public static <T extends Map.Entry<K, U>, K, U>
+ Collector<T, ?, Map<K, U>> toMap()
+ {
+ return java.util.stream.Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue );
+ }
+
+ public static <T extends Map.Entry<K, U>, K, U, M extends Map<K, U>>
+ Collector<T, ?, M> toMap( Supplier<M> mapSupplier )
+ {
+ return toMap( Map.Entry::getKey, Map.Entry::getValue, mapSupplier );
+ }
+
+ private static <T> BinaryOperator<T> throwingMerger()
+ {
+ return ( left, right ) ->
+ {
+ throw new IllegalStateException( String.format( "Duplicate key %s", left ) );
+ };
+ }
+
+ private Collectors() {}
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/Constructors.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Constructors.java b/core/api/src/main/java/org/apache/polygene/api/util/Constructors.java
new file mode 100644
index 0000000..12f2e01
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/Constructors.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.util;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+/**
+ * Useful methods for handling Constructors.
+ */
+public final class Constructors
+{
+ public static final Function<Type, Stream<Constructor<?>>> CONSTRUCTORS_OF =
+ Classes.forClassHierarchy( type -> Arrays.stream( type.getDeclaredConstructors() ) );
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/Fields.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Fields.java b/core/api/src/main/java/org/apache/polygene/api/util/Fields.java
new file mode 100644
index 0000000..c29c3bf
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/Fields.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.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+/**
+ * Useful methods for handling Fields.
+ */
+public final class Fields
+{
+ public static final Function<Type, Stream<Field>> FIELDS_OF =
+ Classes.forClassHierarchy( type -> Arrays.stream( type.getDeclaredFields() ) );
+
+ public static final BiFunction<Class<?>, String, Field> FIELD_NAMED = ( clazz, name ) ->
+ FIELDS_OF.apply( clazz ).filter( Classes.memberNamed( name ) ).findFirst().orElse( null );
+
+ public static Stream<Field> fieldsOf( Type type )
+ {
+ return Stream.of( type ).flatMap( FIELDS_OF );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/HierarchicalVisitor.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/HierarchicalVisitor.java b/core/api/src/main/java/org/apache/polygene/api/util/HierarchicalVisitor.java
new file mode 100644
index 0000000..33fcb40
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/HierarchicalVisitor.java
@@ -0,0 +1,57 @@
+/*
+ * 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.util;
+
+/**
+ * Visitor to visit hierarchies.
+ */
+public interface HierarchicalVisitor<NODE, LEAF, ThrowableType extends Throwable> extends Visitor<LEAF, ThrowableType>
+{
+ /**
+ * Enter an instance of T
+ *
+ * @param visited the visited instance which is now entered
+ *
+ * @return true if the visitor pattern should continue, false if it should be aborted for this level
+ *
+ * @throws ThrowableType if an exception occurred during processing. Any client call that initiated the visiting should
+ * get the exception in order to handle it properly.
+ */
+ boolean visitEnter( NODE visited )
+ throws ThrowableType;
+
+ /**
+ * Leave an instance of T
+ *
+ * @param visited the visited instance which is now left
+ *
+ * @return true if the visitor pattern should continue, false if it should be aborted for the level of this node
+ *
+ * @throws ThrowableType if an exception occurred during processing. Any client call that initiated the visiting should
+ * get the exception in order to handle it properly.
+ */
+ boolean visitLeave( NODE visited )
+ throws ThrowableType;
+
+ @Override
+ boolean visit( LEAF visited )
+ throws ThrowableType;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/HierarchicalVisitorAdapter.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/HierarchicalVisitorAdapter.java b/core/api/src/main/java/org/apache/polygene/api/util/HierarchicalVisitorAdapter.java
new file mode 100644
index 0000000..4756b3c
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/HierarchicalVisitorAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * 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.util;
+
+/**
+ * Generic Hierarchical Visitor interface.
+ */
+public class HierarchicalVisitorAdapter<NODE, LEAF, ThrowableType extends Throwable>
+ implements HierarchicalVisitor<NODE, LEAF, ThrowableType>
+{
+ @Override
+ public boolean visitEnter( NODE visited )
+ throws ThrowableType
+ {
+ return true;
+ }
+
+ @Override
+ public boolean visitLeave( NODE visited )
+ throws ThrowableType
+ {
+ return true;
+ }
+
+ @Override
+ public boolean visit( LEAF visited )
+ throws ThrowableType
+ {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/ListMap.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/ListMap.java b/core/api/src/main/java/org/apache/polygene/api/util/ListMap.java
new file mode 100644
index 0000000..4cba48e
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/ListMap.java
@@ -0,0 +1,48 @@
+/*
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Map whose values are Lists of things. Create
+ * one ArrayList for each key that is added. The list does not allow
+ * duplicates.
+ */
+public final class ListMap<K, V>
+ extends HashMap<K, List<V>>
+{
+ public void add( K key, V value )
+ {
+ List<V> list = get( key );
+ if( list == null )
+ {
+ list = new ArrayList<V>();
+ put( key, list );
+ }
+ if( !list.contains( value ) )
+ {
+ list.add( value );
+ }
+ }
+}
\ 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/util/Methods.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Methods.java b/core/api/src/main/java/org/apache/polygene/api/util/Methods.java
new file mode 100644
index 0000000..bf0d4dd
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/Methods.java
@@ -0,0 +1,50 @@
+/*
+ * 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.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * Useful methods for handling Methods.
+ */
+public class Methods
+{
+ public static final Predicate<Type> HAS_METHODS =
+ item -> Classes.RAW_CLASS.apply( item ).getDeclaredMethods().length > 0;
+
+ public static final Function<Type, Stream<Method>> METHODS_OF = Classes.forTypes( type ->
+ Stream.of( type ).map( Classes.RAW_CLASS ).flatMap( clazz -> Arrays.stream( clazz.getDeclaredMethods() ) )
+ );
+
+ public static final BiFunction<Class<?>, String, Method> METHOD_NAMED = ( clazz, name ) ->
+ METHODS_OF.apply( clazz ).filter( Classes.memberNamed( name ) ).findFirst().orElse( null );
+
+
+ public static Stream<Method> methodsOf( Type type )
+ {
+ return Stream.of(type).flatMap( METHODS_OF );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/NullArgumentException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/NullArgumentException.java b/core/api/src/main/java/org/apache/polygene/api/util/NullArgumentException.java
new file mode 100644
index 0000000..927a438
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/NullArgumentException.java
@@ -0,0 +1,59 @@
+/*
+ * 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.util;
+
+/**
+ * Thrown if an argument to a method was null, and the method required
+ * it to be non-null.
+ */
+public class NullArgumentException
+ extends IllegalArgumentException
+{
+ private static final long serialVersionUID = 4815431779868729780L;
+
+ private NullArgumentException( String message )
+ {
+ super( message );
+ }
+
+ public static void validateNotNull( String parameterName, Object value )
+ {
+ if( value != null )
+ {
+ return;
+ }
+ String message = parameterName + " was null.";
+ throw new NullArgumentException( message );
+ }
+
+ public static void validateNotEmpty( String parameterName, String value )
+ {
+ if( value == null )
+ {
+ String message = parameterName + " was null.";
+ throw new NullArgumentException( message );
+ }
+ if( value.length() == 0 )
+ {
+ String message = parameterName + " was empty.";
+ throw new NullArgumentException( message );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/Visitable.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Visitable.java b/core/api/src/main/java/org/apache/polygene/api/util/Visitable.java
new file mode 100644
index 0000000..8d163a3
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/Visitable.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.api.util;
+
+/**
+ * Interface that visitable objects should implement.
+ */
+public interface Visitable<T>
+{
+ <ThrowableType extends Throwable> boolean accept( Visitor<? super T, ThrowableType> visitor )
+ throws ThrowableType;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/VisitableHierarchy.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/VisitableHierarchy.java b/core/api/src/main/java/org/apache/polygene/api/util/VisitableHierarchy.java
new file mode 100644
index 0000000..33015db
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/VisitableHierarchy.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.api.util;
+
+/**
+ * Interface that visitable hierarchies of objects should implement.
+ */
+public interface VisitableHierarchy<NODE, LEAF>
+{
+ <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super NODE, ? super LEAF, ThrowableType> visitor )
+ throws ThrowableType;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/Visitor.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Visitor.java b/core/api/src/main/java/org/apache/polygene/api/util/Visitor.java
new file mode 100644
index 0000000..80f45a0
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/Visitor.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.util;
+
+/**
+ * Generic Visitor interface.
+ */
+public interface Visitor<T, ThrowableType extends Throwable>
+{
+ /**
+ * Visit an instance of T
+ *
+ * @param visited the visited instance
+ *
+ * @return true if the visitor pattern should continue, false if it should be aborted
+ *
+ * @throws ThrowableType if an exception occurred during processing. Any client call that initiated the visiting should
+ * get the exception in order to handle it properly.
+ */
+ boolean visit( T visited )
+ throws ThrowableType;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/util/package.html
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/util/package.html b/core/api/src/main/java/org/apache/polygene/api/util/package.html
new file mode 100644
index 0000000..cc0b40b
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/util/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>API Utilities.</h2>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/value/MissingValueSerializationException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/value/MissingValueSerializationException.java b/core/api/src/main/java/org/apache/polygene/api/value/MissingValueSerializationException.java
new file mode 100644
index 0000000..00b1af7
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/value/MissingValueSerializationException.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.value;
+
+public class MissingValueSerializationException extends ValueSerializationException
+{
+ public MissingValueSerializationException()
+ {
+ }
+
+ public MissingValueSerializationException( String message )
+ {
+ super( message );
+ }
+
+ public MissingValueSerializationException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+
+ public MissingValueSerializationException( Throwable cause )
+ {
+ super( cause );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/value/NoSuchValueException.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/value/NoSuchValueException.java b/core/api/src/main/java/org/apache/polygene/api/value/NoSuchValueException.java
new file mode 100644
index 0000000..4e5cb30
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/value/NoSuchValueException.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.value;
+
+import java.util.stream.Collectors;
+import org.apache.polygene.api.composite.NoSuchCompositeException;
+import org.apache.polygene.api.structure.TypeLookup;
+
+/**
+ * Thrown when no visible value of the requested type is found.
+ */
+public class NoSuchValueException
+ extends NoSuchCompositeException
+{
+ public NoSuchValueException( String valueType, String moduleName, TypeLookup typeLookup )
+ {
+ super( "ValueComposite", valueType, moduleName, formatVisibleTypes(typeLookup) );
+ }
+
+ private static String formatVisibleTypes( TypeLookup typeLookup )
+ {
+ return typeLookup.allValues()
+ .map(descriptor -> descriptor.primaryType().getName())
+ .collect( Collectors.joining( "\n", "Visible value types are:\n", "" ) );
+ }
+}
\ 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/value/ValueBuilder.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilder.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilder.java
new file mode 100644
index 0000000..fe7a8e1
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilder.java
@@ -0,0 +1,62 @@
+/*
+ * 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.value;
+
+import org.apache.polygene.api.association.AssociationStateHolder;
+import org.apache.polygene.api.common.ConstructionException;
+
+/**
+ * Builder for Values.
+ */
+public interface ValueBuilder<T>
+{
+ AssociationStateHolder state();
+
+ /**
+ * Get a representation of the state for the new Value.
+ * It is possible to access and update properties and associations,
+ * even immutable ones since the builder represents the initial state.
+ *
+ * @return a mutable instance of the Value type
+ */
+ T prototype();
+
+ /**
+ * Get a representation of the state of the given type for the new ValueComposite.
+ * This is primarily used if you want to provide state for a private mixin type.
+ *
+ * @param mixinType the mixin which you want to provide state for
+ *
+ * @return a proxy implementing the given mixin type
+ */
+ <K> K prototypeFor( Class<K> mixinType );
+
+ /**
+ * Create a new Composite instance.
+ *
+ * @return a new Composite instance
+ *
+ * @throws org.apache.polygene.api.common.ConstructionException
+ * thrown if it was not possible to instantiate the Composite
+ */
+ T newInstance()
+ throws ConstructionException;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilderFactory.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilderFactory.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilderFactory.java
new file mode 100644
index 0000000..b23889c
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilderFactory.java
@@ -0,0 +1,107 @@
+/*
+ * 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.value;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.property.PropertyDescriptor;
+
+/**
+ * Factory for Values and ValueBuilders.
+ */
+public interface ValueBuilderFactory
+{
+
+ /**
+ * Instantiate a Value of the given type.
+ *
+ * @param valueType the Value type to instantiate
+ *
+ * @return a new Value instance
+ *
+ * @throws NoSuchValueException if no value extending the mixinType has been registered
+ * @throws ConstructionException if the value could not be instantiated
+ */
+ <T> T newValue( Class<T> valueType )
+ throws NoSuchValueException, ConstructionException;
+
+ /**
+ * Create a builder for creating new Values that implements the given Value type.
+ * <p>The returned ValueBuilder can be reused to create several Values instances.</p>
+ *
+ * @param valueType an interface that describes the Composite to be instantiated
+ *
+ * @return a ValueBuilder for creation of ValueComposites implementing the interface
+ *
+ * @throws NoSuchValueException if no value extending the mixinType has been registered
+ */
+ <T> ValueBuilder<T> newValueBuilder( Class<T> valueType )
+ throws NoSuchValueException;
+
+ /**
+ * Create a builder for creating a new Value starting with the given prototype.
+ * <p>The returned ValueBuilder can only be used ONCE.</p>
+ *
+ * @param prototype a prototype the builder will use
+ *
+ * @return a ValueBuilder for creation of ValueComposites implementing the interface of the prototype
+ *
+ * @throws NoSuchValueException if no value extending the mixinType has been registered
+ */
+ <T> ValueBuilder<T> newValueBuilderWithPrototype( T prototype );
+
+ /**
+ * Create a builder for creating a new Value starting with the given state.
+ * <p>The returned ValueBuilder can only be used ONCE.</p>
+ *
+ * @param mixinType an interface that describes the Composite to be instantiated
+ * @param propertyFunction a function providing the state of properties
+ * @param associationFunction a function providing the state of associations
+ * @param manyAssociationFunction a function providing the state of many associations
+ * @param namedAssociationFunction a function providing the state of named associations
+ *
+ * @return a ValueBuilder for creation of ValueComposites implementing the interface
+ *
+ * @throws NoSuchValueException if no value extending the mixinType has been registered
+ */
+ <T> ValueBuilder<T> newValueBuilderWithState( Class<T> mixinType,
+ Function<PropertyDescriptor, Object> propertyFunction,
+ Function<AssociationDescriptor, EntityReference> associationFunction,
+ Function<AssociationDescriptor, Stream<EntityReference>> manyAssociationFunction,
+ Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociationFunction );
+
+ /**
+ * Instantiate a Value of the given type using the serialized state given as String.
+ *
+ * @param valueType the Value type to instantiate
+ * @param serializedState the state of the Value
+ *
+ * @return a new Value instance
+ *
+ * @throws NoSuchValueException if no value extending the mixinType has been registered
+ * @throws ConstructionException if the value could not be instantiated
+ */
+ <T> T newValueFromSerializedState( Class<T> valueType, String serializedState );
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilderTemplate.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilderTemplate.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilderTemplate.java
new file mode 100644
index 0000000..59fd667
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilderTemplate.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.value;
+
+import org.apache.polygene.api.structure.ModuleDescriptor;
+
+/**
+ * Builder template for Values.
+ */
+public abstract class ValueBuilderTemplate<T>
+{
+ Class<T> type;
+
+ protected ValueBuilderTemplate( Class<T> type )
+ {
+ this.type = type;
+ }
+
+ protected abstract void build( T prototype );
+
+ public T newInstance( ModuleDescriptor module )
+ {
+ ValueBuilder<T> builder = module.instance().newValueBuilder( type );
+ build( builder.prototype() );
+ return builder.newInstance();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/value/ValueComposite.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueComposite.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueComposite.java
new file mode 100644
index 0000000..be0b54a
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/value/ValueComposite.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+
+package org.apache.polygene.api.value;
+
+import org.apache.polygene.api.association.AssociationMixin;
+import org.apache.polygene.api.association.ManyAssociationMixin;
+import org.apache.polygene.api.association.NamedAssociationMixin;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.mixin.Mixins;
+import org.apache.polygene.api.property.Immutable;
+
+/**
+ * ValueComposites are Composites that has state, and equality is defined from its values and not any reference nor
+ * instance references.
+ *
+ * <ul>
+ * <li>No Identity</li>
+ * <li>No Lifecycle</li>
+ * <li>Immutable</li>
+ * <li>equals()/hashCode() operates on the Properties</li>
+ * <li>Can have property and associations methods.</li>
+ * <li>Can not reference Services</li>
+ * <li>Can not have @Uses</li>
+ * </ul>
+ */
+@Immutable
+@Mixins( { AssociationMixin.class, ManyAssociationMixin.class, NamedAssociationMixin.class } )
+public interface ValueComposite
+ extends Composite
+{
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java
new file mode 100644
index 0000000..b9b3f54
--- /dev/null
+++ b/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java
@@ -0,0 +1,38 @@
+/*
+ * 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.value;
+
+import org.apache.polygene.api.association.AssociationStateDescriptor;
+import org.apache.polygene.api.composite.CompositeDescriptor;
+import org.apache.polygene.api.composite.StatefulCompositeDescriptor;
+import org.apache.polygene.api.type.ValueCompositeType;
+
+/**
+ * Descriptor for ValueComposites.
+ */
+public interface ValueDescriptor
+ extends CompositeDescriptor, StatefulCompositeDescriptor
+{
+ ValueCompositeType valueType();
+
+ @Override
+ AssociationStateDescriptor state();
+}