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(); +}
