polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nic...@apache.org
Subject [06/81] [abbrv] [partial] zest-java git commit: ZEST-195 ; Replace all "zest" with "polygene"
Date Sat, 17 Dec 2016 10:27:42 GMT
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/UsedLayersInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/UsedLayersInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/UsedLayersInstance.java
new file mode 100644
index 0000000..e4d3880
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/UsedLayersInstance.java
@@ -0,0 +1,74 @@
+/*
+ *  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.runtime.structure;
+
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.composite.ModelDescriptor;
+import org.apache.polygene.api.composite.TransientDescriptor;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.object.ObjectDescriptor;
+import org.apache.polygene.api.structure.LayerDescriptor;
+import org.apache.polygene.api.value.ValueDescriptor;
+
+/**
+ * JAVADOC
+ */
+public final class UsedLayersInstance
+{
+    private final List<LayerDescriptor> usedLayerInstances;
+
+    public UsedLayersInstance( List<LayerDescriptor> usedLayerInstances )
+    {
+        this.usedLayerInstances = usedLayerInstances;
+    }
+
+    Stream<? extends ObjectDescriptor> visibleObjects()
+    {
+        return usedLayerInstances.stream()
+            .flatMap( layerInstance -> layerInstance.visibleObjects( Visibility.application ) );
+    }
+
+    Stream<? extends TransientDescriptor> visibleTransients()
+    {
+        return usedLayerInstances.stream()
+            .flatMap( layerInstance -> layerInstance.visibleTransients( Visibility.application ) );
+    }
+
+    Stream<? extends EntityDescriptor> visibleEntities()
+    {
+        return usedLayerInstances.stream()
+            .flatMap( layerInstance -> layerInstance.visibleEntities( Visibility.application ) );
+    }
+
+    Stream<? extends ValueDescriptor> visibleValues()
+    {
+        return usedLayerInstances.stream()
+            .flatMap( layerInstance -> layerInstance.visibleValues( Visibility.application ) );
+    }
+
+    Stream<? extends ModelDescriptor> visibleServices()
+    {
+        return usedLayerInstances.stream()
+            .flatMap( layerInstance -> layerInstance.visibleServices( Visibility.application ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/UsedLayersModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/UsedLayersModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/UsedLayersModel.java
new file mode 100644
index 0000000..c5bcd1a
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/UsedLayersModel.java
@@ -0,0 +1,71 @@
+/*
+ *  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.runtime.structure;
+
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.structure.LayerDescriptor;
+import org.apache.polygene.api.structure.UsedLayersDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+
+/**
+ * JAVADOC
+ */
+public final class UsedLayersModel
+    implements UsedLayersDescriptor, VisitableHierarchy<Object, Object>
+{
+    private final List<LayerModel> usedLayers;
+
+    public UsedLayersModel( List<LayerModel> usedLayers )
+    {
+        this.usedLayers = usedLayers;
+    }
+
+    @Override
+    public Stream<? extends LayerDescriptor> layers()
+    {
+        return usedLayers.stream();
+    }
+
+    @Override
+    public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+        throws ThrowableType
+    {
+        if( visitor.visitEnter( this ) )
+        {
+            for( LayerModel usedLayer : usedLayers )
+            {
+                if( !usedLayer.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+
+        return visitor.visitLeave( this );
+    }
+
+    public UsedLayersInstance newInstance( List<LayerDescriptor> usedLayerInstances )
+    {
+        return new UsedLayersInstance( usedLayerInstances );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/Visibilitypredicate.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/Visibilitypredicate.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/Visibilitypredicate.java
new file mode 100644
index 0000000..df013c3
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/Visibilitypredicate.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.runtime.structure;
+
+import java.util.function.Predicate;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.composite.ModelDescriptor;
+
+/**
+ * TODO
+ */
+public class Visibilitypredicate
+    implements Predicate<ModelDescriptor>
+{
+    public static final Predicate<ModelDescriptor> MODULE = new Visibilitypredicate( Visibility.module );
+    public static final Predicate<ModelDescriptor> LAYER = new Visibilitypredicate( Visibility.layer );
+    public static final Predicate<ModelDescriptor> APPLICATION = new Visibilitypredicate( Visibility.application );
+
+    private final Visibility visibility;
+
+    public Visibilitypredicate( Visibility visibility )
+    {
+        this.visibility = visibility;
+    }
+
+    @Override
+    public boolean test( ModelDescriptor item )
+    {
+        return item.visibility().ordinal() >= visibility.ordinal();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/types/ValueTypeFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/types/ValueTypeFactory.java b/core/runtime/src/main/java/org/apache/polygene/runtime/types/ValueTypeFactory.java
new file mode 100644
index 0000000..a3538c0
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/types/ValueTypeFactory.java
@@ -0,0 +1,233 @@
+/*
+ *  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.runtime.types;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.polygene.api.common.InvalidApplicationException;
+import org.apache.polygene.api.common.MetaInfo;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.type.CollectionType;
+import org.apache.polygene.api.type.EnumType;
+import org.apache.polygene.api.type.MapType;
+import org.apache.polygene.api.type.Serialization;
+import org.apache.polygene.api.type.ValueCompositeType;
+import org.apache.polygene.api.type.ValueType;
+import org.apache.polygene.api.util.Classes;
+import org.apache.polygene.api.util.HierarchicalVisitorAdapter;
+import org.apache.polygene.api.value.ValueComposite;
+import org.apache.polygene.runtime.association.AssociationsModel;
+import org.apache.polygene.runtime.association.ManyAssociationsModel;
+import org.apache.polygene.runtime.association.NamedAssociationsModel;
+import org.apache.polygene.runtime.composite.CompositeMethodsModel;
+import org.apache.polygene.runtime.composite.MixinsModel;
+import org.apache.polygene.runtime.property.PropertiesModel;
+import org.apache.polygene.runtime.structure.LayerModel;
+import org.apache.polygene.runtime.structure.ModuleModel;
+import org.apache.polygene.runtime.structure.UsedLayersModel;
+import org.apache.polygene.runtime.value.ValueModel;
+import org.apache.polygene.runtime.value.ValueStateModel;
+import org.apache.polygene.runtime.value.ValuesModel;
+
+public class ValueTypeFactory
+{
+    private static final ValueTypeFactory instance = new ValueTypeFactory();
+
+    public static ValueTypeFactory instance()
+    {
+        return instance;
+    }
+
+    @SuppressWarnings( { "raw", "unchecked" } )
+    public ValueType newValueType( Type type,
+                                   Class declaringClass,
+                                   Class compositeType,
+                                   LayerModel layer,
+                                   ModuleModel module,
+                                   Serialization.Variant variant
+    )
+    {
+        ValueType valueType;
+        if( CollectionType.isCollection( type ) )
+        {
+            if( type instanceof ParameterizedType )
+            {
+                ParameterizedType pt = (ParameterizedType) type;
+                Type collectionType = pt.getActualTypeArguments()[ 0 ];
+                if( collectionType instanceof TypeVariable )
+                {
+                    TypeVariable collectionTypeVariable = (TypeVariable) collectionType;
+                    collectionType = Classes.resolveTypeVariable( collectionTypeVariable, declaringClass, compositeType );
+                }
+                ValueType collectedType = newValueType( collectionType, declaringClass, compositeType, layer, module, variant );
+                valueType = new CollectionType( Classes.RAW_CLASS.apply( type ), collectedType );
+            }
+            else
+            {
+                ValueType collectedType = newValueType( Object.class, declaringClass, compositeType, layer, module, variant );
+                valueType = new CollectionType( Classes.RAW_CLASS.apply( type ), collectedType );
+            }
+        }
+        else if( MapType.isMap( type ) )
+        {
+            if( type instanceof ParameterizedType )
+            {
+                ParameterizedType pt = (ParameterizedType) type;
+                Type keyType = pt.getActualTypeArguments()[ 0 ];
+                if( keyType instanceof TypeVariable )
+                {
+                    TypeVariable keyTypeVariable = (TypeVariable) keyType;
+                    keyType = Classes.resolveTypeVariable( keyTypeVariable, declaringClass, compositeType );
+                }
+                ValueType keyedType = newValueType( keyType, declaringClass, compositeType, layer, module, variant );
+                Type valType = pt.getActualTypeArguments()[ 1 ];
+                if( valType instanceof TypeVariable )
+                {
+                    TypeVariable valueTypeVariable = (TypeVariable) valType;
+                    valType = Classes.resolveTypeVariable( valueTypeVariable, declaringClass, compositeType );
+                }
+                ValueType valuedType = newValueType( valType, declaringClass, compositeType, layer, module, variant );
+                valueType = new MapType( Classes.RAW_CLASS.apply( type ), keyedType, valuedType, variant );
+            }
+            else
+            {
+                ValueType keyType = newValueType( Object.class, declaringClass, compositeType, layer, module, variant );
+                ValueType valuesType = newValueType( Object.class, declaringClass, compositeType, layer, module, variant );
+                valueType = new MapType( Classes.RAW_CLASS.apply( type ), keyType, valuesType, variant );
+            }
+        }
+        else if( ValueCompositeType.isValueComposite( type ) )
+        {
+            // Find ValueModel in module/layer/used layers
+            ValueModel model = new ValueFinder( layer, module, Classes.RAW_CLASS.apply( type ) ).getFoundModel();
+
+            if( model == null )
+            {
+                if( type.equals( ValueComposite.class ) )
+                {
+                    // Create default model
+                    MixinsModel mixinsModel = new MixinsModel();
+                    List<Class<?>> valueComposite = new ArrayList<>();
+                    valueComposite.add( ValueComposite.class );
+                    ValueStateModel valueStateModel = new ValueStateModel( new PropertiesModel(),
+                                                                           new AssociationsModel(),
+                                                                           new ManyAssociationsModel(),
+                                                                           new NamedAssociationsModel() );
+                    model = new ValueModel( module, valueComposite, Visibility.application, new MetaInfo(),
+                                            mixinsModel, valueStateModel, new CompositeMethodsModel( mixinsModel ) );
+                }
+                else
+                {
+                    throw new InvalidApplicationException( "[" + module.name() + "] Could not find ValueComposite of type " + type );
+                }
+            }
+
+            return model.valueType();
+        }
+        else if( EnumType.isEnum( type ) )
+        {
+            valueType = new EnumType( Classes.RAW_CLASS.apply( type ) );
+        }
+        else
+        {
+            valueType = new ValueType( Classes.RAW_CLASS.apply( type ) );
+        }
+
+        return valueType;
+    }
+
+    @SuppressWarnings( "raw" )
+    private static class ValueFinder
+        extends HierarchicalVisitorAdapter<Object, Object, RuntimeException>
+    {
+        private Class<?> type;
+        private ValueModel foundModel;
+        private Visibility visibility;
+
+        private ValueFinder( LayerModel layer, ModuleModel module, Class type )
+        {
+            this.type = type;
+
+            visibility = Visibility.module;
+            module.accept( this );
+
+            if( foundModel == null )
+            {
+                visibility = Visibility.layer;
+                layer.accept( this );
+
+                if( foundModel == null )
+                {
+                    visibility = Visibility.application;
+                    layer.usedLayers().accept( this );
+                }
+            }
+        }
+
+        public ValueModel getFoundModel()
+        {
+            return foundModel;
+        }
+
+        @Override
+        public boolean visitEnter( Object visited )
+            throws RuntimeException
+        {
+            if( visited instanceof ValuesModel )
+            {
+                return true;
+            }
+            else if( visited instanceof ModuleModel )
+            {
+                return true;
+            }
+            else if( visited instanceof LayerModel )
+            {
+                return true;
+            }
+            else if( visited instanceof UsedLayersModel )
+            {
+                return true;
+            }
+            else if( visited instanceof ValueModel )
+            {
+                ValueModel valueModel = (ValueModel) visited;
+                boolean typeEquality = valueModel.types().anyMatch( t -> t.equals( type ) );
+                if( typeEquality && valueModel.visibility().ordinal() >= visibility.ordinal() )
+                {
+                    foundModel = valueModel;
+                }
+            }
+
+            return false;
+        }
+
+        @Override
+        public boolean visitLeave( Object visited )
+            throws RuntimeException
+        {
+            return foundModel == null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderEntityState.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderEntityState.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderEntityState.java
new file mode 100644
index 0000000..c8739c5
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderEntityState.java
@@ -0,0 +1,173 @@
+/*
+ *  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.runtime.unitofwork;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.polygene.api.common.QualifiedName;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.util.Classes;
+import org.apache.polygene.spi.entity.EntityState;
+import org.apache.polygene.spi.entity.EntityStatus;
+import org.apache.polygene.spi.entity.ManyAssociationState;
+import org.apache.polygene.spi.entity.NamedAssociationState;
+
+/**
+ * Implementation of EntityState for use through EntityBuilder.
+ */
+public final class BuilderEntityState
+    implements EntityState
+{
+    private final EntityDescriptor entityType;
+    private final EntityReference reference;
+    private final Map<QualifiedName, Object> properties = new HashMap<>();
+    private final Map<QualifiedName, EntityReference> associations = new HashMap<>();
+    private final Map<QualifiedName, ManyAssociationState> manyAssociations = new HashMap<>();
+    private final Map<QualifiedName, NamedAssociationState> namedAssociations = new HashMap<>();
+
+    public BuilderEntityState( EntityDescriptor type, EntityReference reference )
+    {
+        this.entityType = type;
+        this.reference = reference;
+    }
+
+    @Override
+    public EntityReference entityReference()
+    {
+        return reference;
+    }
+
+    @Override
+    public String version()
+    {
+        return "";
+    }
+
+    @Override
+    public Instant lastModified()
+    {
+        return Instant.MIN;
+    }
+
+    @Override
+    public void remove()
+    {
+    }
+
+    @Override
+    public EntityStatus status()
+    {
+        return EntityStatus.NEW;
+    }
+
+    @Override
+    public boolean isAssignableTo( Class<?> type )
+    {
+        return Classes.exactTypeSpecification( type ).test( entityType );
+    }
+
+    @Override
+    public EntityDescriptor entityDescriptor()
+    {
+        return entityType;
+    }
+
+    @Override
+    public Object propertyValueOf( QualifiedName stateName )
+    {
+        return properties.get( stateName );
+    }
+
+    @Override
+    public EntityReference associationValueOf( QualifiedName stateName )
+    {
+        return associations.get( stateName );
+    }
+
+    @Override
+    public void setPropertyValue( QualifiedName stateName, Object newValue )
+    {
+        properties.put( stateName, newValue );
+    }
+
+    @Override
+    public void setAssociationValue( QualifiedName stateName, EntityReference newEntity )
+    {
+        associations.put( stateName, newEntity );
+    }
+
+    @Override
+    public ManyAssociationState manyAssociationValueOf( QualifiedName stateName )
+    {
+        ManyAssociationState state = manyAssociations.get( stateName );
+        if( state == null )
+        {
+            state = new BuilderManyAssociationState();
+            manyAssociations.put( stateName, state );
+        }
+        return state;
+    }
+
+    @Override
+    public NamedAssociationState namedAssociationValueOf( QualifiedName stateName )
+    {
+        NamedAssociationState state = namedAssociations.get( stateName );
+        if( state == null )
+        {
+            state = new BuilderNamedAssociationState();
+            namedAssociations.put( stateName, state );
+        }
+        return state;
+    }
+
+    public void copyTo( EntityState newEntityState )
+    {
+        for( Map.Entry<QualifiedName, Object> fromPropertyEntry : properties.entrySet() )
+        {
+            newEntityState.setPropertyValue( fromPropertyEntry.getKey(), fromPropertyEntry.getValue() );
+        }
+        for( Map.Entry<QualifiedName, EntityReference> fromAssociationEntry : associations.entrySet() )
+        {
+            newEntityState.setAssociationValue( fromAssociationEntry.getKey(), fromAssociationEntry.getValue() );
+        }
+        for( Map.Entry<QualifiedName, ManyAssociationState> fromManyAssociationEntry : manyAssociations.entrySet() )
+        {
+            QualifiedName qName = fromManyAssociationEntry.getKey();
+            ManyAssociationState fromManyAssoc = fromManyAssociationEntry.getValue();
+            ManyAssociationState toManyAssoc = newEntityState.manyAssociationValueOf( qName );
+            for( EntityReference entityReference : fromManyAssoc )
+            {
+                toManyAssoc.add( 0, entityReference );
+            }
+        }
+        for( Map.Entry<QualifiedName, NamedAssociationState> fromNamedAssociationEntry : namedAssociations.entrySet() )
+        {
+            QualifiedName qName = fromNamedAssociationEntry.getKey();
+            NamedAssociationState fromNamedAssoc = fromNamedAssociationEntry.getValue();
+            NamedAssociationState toNamedAssoc = newEntityState.namedAssociationValueOf( qName );
+            for( String name : fromNamedAssoc )
+            {
+                toNamedAssoc.put( name, fromNamedAssoc.get( name ) );
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderManyAssociationState.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderManyAssociationState.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderManyAssociationState.java
new file mode 100644
index 0000000..3b482d7
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderManyAssociationState.java
@@ -0,0 +1,84 @@
+/*
+ *  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.runtime.unitofwork;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.spi.entity.ManyAssociationState;
+
+/**
+ * Default implementation of ManyAssociationState that also
+ * keeps a list of changes that can be extracted at any time.
+ */
+public final class BuilderManyAssociationState
+    implements ManyAssociationState
+{
+    private List<EntityReference> references;
+
+    public BuilderManyAssociationState()
+    {
+        references = new ArrayList<EntityReference>();
+    }
+
+    @Override
+    public int count()
+    {
+        return references.size();
+    }
+
+    @Override
+    public boolean contains( EntityReference entityReference )
+    {
+        return references.contains( entityReference );
+    }
+
+    @Override
+    public boolean add( int i, EntityReference entityReference )
+    {
+        if( references.contains( entityReference ) )
+        {
+            return false;
+        }
+
+        references.add( i, entityReference );
+        return true;
+    }
+
+    @Override
+    public boolean remove( EntityReference entityReference )
+    {
+        return references.remove( entityReference );
+    }
+
+    @Override
+    public EntityReference get( int i )
+    {
+        return references.get( i );
+    }
+
+    @Override
+    public Iterator<EntityReference> iterator()
+    {
+        return references.iterator();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderNamedAssociationState.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderNamedAssociationState.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderNamedAssociationState.java
new file mode 100644
index 0000000..d50d79b
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/BuilderNamedAssociationState.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.runtime.unitofwork;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.spi.entity.NamedAssociationState;
+
+/**
+ * Default implementation of NamedAssociationState that also
+ * keeps a list of changes that can be extracted at any time.
+ */
+public final class BuilderNamedAssociationState
+    implements NamedAssociationState
+{
+    private final Map<String, EntityReference> references;
+
+    public BuilderNamedAssociationState()
+    {
+        references = new LinkedHashMap<>();
+    }
+
+    @Override
+    public int count()
+    {
+        return references.size();
+    }
+
+    @Override
+    public boolean containsName( String name )
+    {
+        return references.containsKey( name );
+    }
+
+    @Override
+    public boolean put( String name, EntityReference entityReference )
+    {
+        return references.put( name, entityReference ) != null;
+    }
+
+    @Override
+    public boolean remove( String name )
+    {
+        return references.remove( name ) != null;
+    }
+
+    @Override
+    public EntityReference get( String name )
+    {
+        return references.get( name );
+    }
+
+    @Override
+    public String nameOf( EntityReference entityReference )
+    {
+        for( Map.Entry<String, EntityReference> entry : references.entrySet() )
+        {
+            if( entry.getValue().equals( entityReference ) )
+            {
+                return entry.getKey();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Iterator<String> iterator()
+    {
+        return references.keySet().iterator();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityBuilderInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityBuilderInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityBuilderInstance.java
new file mode 100644
index 0000000..5044ff6
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityBuilderInstance.java
@@ -0,0 +1,139 @@
+/*
+ *  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.runtime.unitofwork;
+
+import org.apache.polygene.api.entity.EntityBuilder;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.entity.LifecycleException;
+import org.apache.polygene.api.identity.Identity;
+import org.apache.polygene.runtime.composite.FunctionStateResolver;
+import org.apache.polygene.runtime.entity.EntityInstance;
+import org.apache.polygene.runtime.entity.EntityModel;
+import org.apache.polygene.spi.entity.EntityState;
+import org.apache.polygene.spi.entitystore.EntityStoreUnitOfWork;
+import org.apache.polygene.spi.module.ModuleSpi;
+
+import static org.apache.polygene.api.identity.HasIdentity.IDENTITY_STATE_NAME;
+
+/**
+ * Implementation of EntityBuilder. Maintains an instance of the entity which
+ * will not have its state validated until it is created by calling newInstance().
+ */
+public final class EntityBuilderInstance<T>
+    implements EntityBuilder<T>
+{
+    private final EntityModel model;
+    private final ModuleUnitOfWork uow;
+    private final EntityStoreUnitOfWork store;
+    private Identity identity;
+
+    private final BuilderEntityState entityState;
+    private final EntityInstance prototypeInstance;
+
+    public EntityBuilderInstance(
+        EntityDescriptor model,
+        ModuleUnitOfWork uow,
+        EntityStoreUnitOfWork store,
+        Identity identity
+    )
+    {
+        this( model, uow, store, identity, null );
+    }
+
+    public EntityBuilderInstance(
+        EntityDescriptor model,
+        ModuleUnitOfWork uow,
+        EntityStoreUnitOfWork store,
+        Identity identity,
+        FunctionStateResolver stateResolver
+    )
+    {
+        this.model = (EntityModel) model;
+        this.uow = uow;
+        this.store = store;
+        this.identity = identity;
+        EntityReference reference = EntityReference.create( identity );
+        entityState = new BuilderEntityState( model, reference );
+        this.model.initState( model.module(), entityState );
+        if( stateResolver != null )
+        {
+            stateResolver.populateState( this.model, entityState );
+        }
+        entityState.setPropertyValue( IDENTITY_STATE_NAME, identity );
+        prototypeInstance = this.model.newInstance( uow, (ModuleSpi) model.module().instance(), entityState );
+    }
+
+    @SuppressWarnings( "unchecked" )
+    @Override
+    public T instance()
+    {
+        checkValid();
+        return prototypeInstance.<T>proxy();
+    }
+
+    @Override
+    public <K> K instanceFor( Class<K> mixinType )
+    {
+        checkValid();
+        return prototypeInstance.newProxy( mixinType );
+    }
+
+    @Override
+    @SuppressWarnings( "unchecked" )
+    public T newInstance()
+        throws LifecycleException
+    {
+        checkValid();
+
+        // Figure out whether to use given or generated reference
+        Identity identity = (Identity) entityState.propertyValueOf( IDENTITY_STATE_NAME );
+        EntityReference entityReference = EntityReference.create( identity );
+        EntityState newEntityState = model.newEntityState( store, entityReference );
+
+        prototypeInstance.invokeCreate();
+
+        // Check constraints
+        prototypeInstance.checkConstraints();
+
+        entityState.copyTo( newEntityState );
+
+        EntityInstance instance = model.newInstance( uow, (ModuleSpi) model.module().instance(), newEntityState );
+
+        Object proxy = instance.proxy();
+
+        // Add entity in UOW
+        uow.addEntity( instance );
+
+        // Invalidate builder
+        this.identity = null;
+
+        return (T) proxy;
+    }
+
+    private void checkValid()
+        throws IllegalStateException
+    {
+        if( identity == null )
+        {
+            throw new IllegalStateException( "EntityBuilder is not valid after call to newInstance()" );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityFunction.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityFunction.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityFunction.java
new file mode 100644
index 0000000..936f5aa
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityFunction.java
@@ -0,0 +1,46 @@
+/*
+ *  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.runtime.unitofwork;
+
+import java.lang.reflect.Type;
+import java.util.function.BiFunction;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.unitofwork.UnitOfWorkFactory;
+
+import static org.apache.polygene.api.util.Classes.RAW_CLASS;
+
+public class EntityFunction
+    implements BiFunction<EntityReference, Type, Object>
+{
+
+    private final UnitOfWorkFactory uowf;
+
+    public EntityFunction( UnitOfWorkFactory uowf )
+    {
+        this.uowf = uowf;
+    }
+
+    @Override
+    public Object apply( EntityReference entityReference, Type type )
+    {
+        return uowf.currentUnitOfWork().get( RAW_CLASS.apply( type ), entityReference.identity() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityStateStore.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityStateStore.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityStateStore.java
new file mode 100644
index 0000000..9f020f9
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/EntityStateStore.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.runtime.unitofwork;
+
+import org.apache.polygene.api.association.AssociationStateHolder;
+import org.apache.polygene.spi.entity.EntityState;
+
+/**
+ * JAVADOC
+ */
+final class EntityStateStore
+{
+    AssociationStateHolder stateHolder;
+    EntityState state;
+
+    @Override
+    public String toString()
+    {
+        return state.entityReference().toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java
new file mode 100644
index 0000000..bd18383
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java
@@ -0,0 +1,769 @@
+/*
+ *  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.runtime.unitofwork;
+
+import java.time.Instant;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+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.PolygeneAPI;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.association.AssociationStateHolder;
+import org.apache.polygene.api.association.ManyAssociation;
+import org.apache.polygene.api.association.NamedAssociation;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.entity.EntityBuilder;
+import org.apache.polygene.api.entity.EntityComposite;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.entity.LifecycleException;
+import org.apache.polygene.api.identity.HasIdentity;
+import org.apache.polygene.api.identity.Identity;
+import org.apache.polygene.api.identity.IdentityGenerator;
+import org.apache.polygene.api.identity.StringIdentity;
+import org.apache.polygene.api.injection.scope.Service;
+import org.apache.polygene.api.injection.scope.Structure;
+import org.apache.polygene.api.injection.scope.Uses;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.property.StateHolder;
+import org.apache.polygene.api.query.Query;
+import org.apache.polygene.api.query.QueryBuilder;
+import org.apache.polygene.api.query.QueryExecutionException;
+import org.apache.polygene.api.query.grammar.OrderBy;
+import org.apache.polygene.api.service.NoSuchServiceException;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.unitofwork.ConcurrentEntityModificationException;
+import org.apache.polygene.api.unitofwork.NoSuchEntityException;
+import org.apache.polygene.api.unitofwork.NoSuchEntityTypeException;
+import org.apache.polygene.api.unitofwork.UnitOfWork;
+import org.apache.polygene.api.unitofwork.UnitOfWorkCallback;
+import org.apache.polygene.api.unitofwork.UnitOfWorkCompletionException;
+import org.apache.polygene.api.unitofwork.UnitOfWorkFactory;
+import org.apache.polygene.api.usecase.Usecase;
+import org.apache.polygene.api.util.NullArgumentException;
+import org.apache.polygene.api.value.ValueBuilder;
+import org.apache.polygene.api.value.ValueComposite;
+import org.apache.polygene.runtime.association.AssociationInstance;
+import org.apache.polygene.runtime.composite.FunctionStateResolver;
+import org.apache.polygene.runtime.entity.EntityInstance;
+import org.apache.polygene.runtime.entity.EntityModel;
+import org.apache.polygene.runtime.property.PropertyModel;
+import org.apache.polygene.runtime.value.ValueInstance;
+import org.apache.polygene.spi.entity.EntityState;
+import org.apache.polygene.spi.entity.EntityStatus;
+import org.apache.polygene.spi.entitystore.EntityStore;
+import org.apache.polygene.spi.module.ModuleSpi;
+import org.apache.polygene.spi.query.EntityFinder;
+import org.apache.polygene.spi.query.EntityFinderException;
+import org.apache.polygene.spi.query.QueryBuilderSPI;
+import org.apache.polygene.spi.query.QuerySource;
+
+import static org.apache.polygene.api.identity.HasIdentity.IDENTITY_STATE_NAME;
+
+/**
+ * JAVADOC
+ */
+public class ModuleUnitOfWork
+    implements UnitOfWork
+{
+    @Uses
+    private UnitOfWorkInstance uow;
+
+    @Structure
+    private PolygeneAPI api;
+
+    @Structure
+    private ModuleDescriptor module;
+
+    @Service
+    private UnitOfWorkFactory unitOfWorkFactory;
+
+    public ModuleDescriptor module()
+    {
+        return module;
+    }
+
+    public UnitOfWorkInstance instance()
+    {
+        return uow;
+    }
+
+    @Override
+    public UnitOfWorkFactory unitOfWorkFactory()
+    {
+        return unitOfWorkFactory;
+    }
+
+    @Override
+    public Instant currentTime()
+    {
+        return uow.currentTime();
+    }
+
+    @Override
+    public Usecase usecase()
+    {
+        return uow.usecase();
+    }
+
+    @Override
+    public <T> T metaInfo( Class<T> infoType )
+    {
+        return uow.metaInfo().get( infoType );
+    }
+
+    @Override
+    public void setMetaInfo( Object metaInfo )
+    {
+        uow.metaInfo().set( metaInfo );
+    }
+
+    @Override
+    @SuppressWarnings( { "raw", "unchecked" } )
+    public <T> Query<T> newQuery( QueryBuilder<T> queryBuilder )
+    {
+        QueryBuilderSPI queryBuilderSPI = (QueryBuilderSPI) queryBuilder;
+
+        return queryBuilderSPI.newQuery( new UoWQuerySource( this ) );
+    }
+
+    @Override
+    public <T> T newEntity( Class<T> type )
+        throws NoSuchEntityTypeException, LifecycleException
+    {
+        return newEntity( type, null );
+    }
+
+    @Override
+    public <T> T newEntity( Class<T> type, Identity identity )
+        throws NoSuchEntityTypeException, LifecycleException
+    {
+        return newEntityBuilder( type, identity ).newInstance();
+    }
+
+    @Override
+    public <T> EntityBuilder<T> newEntityBuilder( Class<T> type )
+        throws NoSuchEntityTypeException
+    {
+        return newEntityBuilder( type, null );
+    }
+
+    @Override
+    public <T> EntityBuilder<T> newEntityBuilder( Class<T> type, Identity identity )
+        throws NoSuchEntityTypeException
+    {
+        EntityDescriptor model = module.typeLookup().lookupEntityModel( type );
+
+        if( model == null )
+        {
+            throw new NoSuchEntityTypeException( type.getName(), module.name(), module.typeLookup() );
+        }
+
+        ModuleDescriptor modelModule = model.module();
+        EntityStore entityStore = ( (ModuleSpi) modelModule.instance() ).entityStore();
+
+        // Generate id if necessary
+        if( identity == null )
+        {
+            IdentityGenerator idGen = ( (ModuleSpi) modelModule.instance() ).identityGenerator();
+            if( idGen == null )
+            {
+                throw new NoSuchServiceException( IdentityGenerator.class.getName(), modelModule
+                    .name(), modelModule.typeLookup() );
+            }
+            identity = idGen.generate( model.types().findFirst().orElse( null ) );
+        }
+        EntityBuilder<T> builder;
+
+        builder = new EntityBuilderInstance<>( model,
+                                               this,
+                                               uow.getEntityStoreUnitOfWork( entityStore ),
+                                               identity );
+        return builder;
+    }
+
+    @Override
+    public <T> EntityBuilder<T> newEntityBuilderWithState(
+        Class<T> type,
+        Function<PropertyDescriptor, Object> propertyFunction,
+        Function<AssociationDescriptor, EntityReference> associationFunction,
+        Function<AssociationDescriptor, Stream<EntityReference>> manyAssociationFunction,
+        Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociationFunction
+    )
+        throws NoSuchEntityTypeException
+    {
+        return newEntityBuilderWithState( type, null,
+                                          propertyFunction,
+                                          associationFunction,
+                                          manyAssociationFunction,
+                                          namedAssociationFunction );
+    }
+
+    @Override
+    public <T> EntityBuilder<T> newEntityBuilderWithState(
+        Class<T> type, Identity identity,
+        Function<PropertyDescriptor, Object> propertyFunction,
+        Function<AssociationDescriptor, EntityReference> associationFunction,
+        Function<AssociationDescriptor, Stream<EntityReference>> manyAssociationFunction,
+        Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociationFunction
+    )
+        throws NoSuchEntityTypeException
+    {
+        NullArgumentException.validateNotNull( "propertyFunction", propertyFunction );
+        NullArgumentException.validateNotNull( "associationFunction", associationFunction );
+        NullArgumentException.validateNotNull( "manyAssociationFunction", manyAssociationFunction );
+        NullArgumentException.validateNotNull( "namedAssociationFunction", namedAssociationFunction );
+
+        EntityDescriptor model = module.typeLookup().lookupEntityModel( type );
+
+        if( model == null )
+        {
+            throw new NoSuchEntityTypeException( type.getName(), module.name(), module.typeLookup() );
+        }
+
+        ModuleDescriptor modelModule = model.module();
+        ModuleSpi moduleSpi = (ModuleSpi) modelModule.instance();
+        EntityStore entityStore = moduleSpi.entityStore();
+
+        FunctionStateResolver stateResolver = new FunctionStateResolver(
+            propertyFunction, associationFunction, manyAssociationFunction, namedAssociationFunction
+        );
+
+        if( identity == null )
+        {
+            // Use reference from StateResolver if available
+            PropertyModel identityModel = (PropertyModel) model
+                .state()
+                .findPropertyModelByQualifiedName( IDENTITY_STATE_NAME );
+            String propertyState = (String) stateResolver.getPropertyState(identityModel);
+            if( propertyState == null )
+            {
+                // Generate reference
+                IdentityGenerator idGen = moduleSpi.identityGenerator();
+                if( idGen == null )
+                {
+                    String typeName = IdentityGenerator.class.getName();
+                    throw new NoSuchServiceException( typeName, modelModule.name(), modelModule.typeLookup() );
+                }
+                identity = idGen.generate( model.types().findFirst().orElse( null ) );
+            }
+            else
+            {
+                identity = new StringIdentity(propertyState);
+            }
+        }
+
+        return new EntityBuilderInstance<>( model,
+                                            this,
+                                            uow.getEntityStoreUnitOfWork( entityStore ),
+                                            identity,
+                                            stateResolver );
+    }
+
+    @Override
+    public <T> T get( Class<T> type, Identity identity )
+        throws NoSuchEntityTypeException, NoSuchEntityException
+    {
+        Iterable<EntityDescriptor> models = module.typeLookup().lookupEntityModels( type );
+
+        if( !models.iterator().hasNext() )
+        {
+            throw new NoSuchEntityTypeException( type.getName(), module.name(), module.typeLookup() );
+        }
+
+        return uow.get( EntityReference.create( identity ), this, models, type );
+    }
+
+    @Override
+    @SuppressWarnings( "unchecked" )
+    public <T> T get( T entity )
+        throws NoSuchEntityTypeException
+    {
+        EntityComposite entityComposite = (EntityComposite) entity;
+        EntityInstance compositeInstance = EntityInstance.entityInstanceOf( entityComposite );
+        EntityDescriptor model = compositeInstance.entityModel();
+        Class<T> type = (Class<T>) compositeInstance.types().findFirst().orElse( null );
+        return uow.get( compositeInstance.reference(), this, Collections.singletonList( model ), type );
+    }
+
+    @Override
+    public void remove( Object entity )
+        throws LifecycleException
+    {
+        uow.checkOpen();
+
+        EntityComposite entityComposite = (EntityComposite) entity;
+
+        EntityInstance compositeInstance = EntityInstance.entityInstanceOf( entityComposite );
+
+        if( compositeInstance.status() == EntityStatus.NEW )
+        {
+            compositeInstance.remove( this );
+            uow.remove( compositeInstance.reference() );
+        }
+        else if( compositeInstance.status() == EntityStatus.LOADED || compositeInstance.status() == EntityStatus.UPDATED )
+        {
+            compositeInstance.remove( this );
+        }
+        else
+        {
+            throw new NoSuchEntityException( compositeInstance.reference(), compositeInstance.types(), usecase() );
+        }
+    }
+
+    @SuppressWarnings( "DuplicateThrows" )
+    @Override
+    public void complete()
+        throws UnitOfWorkCompletionException, ConcurrentEntityModificationException
+    {
+        uow.complete();
+    }
+
+    @Override
+    public void discard()
+    {
+        uow.discard();
+    }
+
+    @Override
+    public void close()
+    {
+        discard();
+    }
+
+    @Override
+    public boolean isOpen()
+    {
+        return uow.isOpen();
+    }
+
+    @Override
+    public boolean isPaused()
+    {
+        return uow.isPaused();
+    }
+
+    @Override
+    public void pause()
+    {
+        uow.pause();
+    }
+
+    @Override
+    public void resume()
+    {
+        uow.resume();
+    }
+
+    @Override
+    public void addUnitOfWorkCallback( UnitOfWorkCallback callback )
+    {
+        uow.addUnitOfWorkCallback( callback );
+    }
+
+    @Override
+    public void removeUnitOfWorkCallback( UnitOfWorkCallback callback )
+    {
+        uow.removeUnitOfWorkCallback( callback );
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if( this == o )
+        {
+            return true;
+        }
+        if( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        ModuleUnitOfWork that = (ModuleUnitOfWork) o;
+
+        return uow.equals( that.uow );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return uow.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return uow.toString();
+    }
+
+    public void addEntity( EntityInstance instance )
+    {
+        uow.addEntity( instance );
+    }
+
+    @Override
+    public <T extends HasIdentity> T toValue(Class<T> primaryType, T entityComposite )
+    {
+        Function<PropertyDescriptor, Object> propertyFunction = new ToValuePropertyMappingFunction( entityComposite );
+        Function<AssociationDescriptor, EntityReference> assocationFunction = new ToValueAssociationMappingFunction<>( entityComposite );
+        Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = new ToValueManyAssociationMappingFunction<>( entityComposite );
+        Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = new ToValueNameAssociationMappingFunction<>( entityComposite );
+
+        @SuppressWarnings( "unchecked" )
+        ValueBuilder<T> builder = module().instance().newValueBuilderWithState(
+            primaryType, propertyFunction, assocationFunction, manyAssocFunction, namedAssocFunction );
+        return builder.newInstance();
+    }
+
+    @Override
+    public <T extends HasIdentity> Map<String, T> toValueMap(NamedAssociation<T> association )
+    {
+        @SuppressWarnings( "unchecked" )
+        Class<T> primaryType = (Class<T>) api.associationDescriptorFor( association ).type();
+
+        return association
+            .toMap()
+            .entrySet()
+            .stream()
+            .collect( Collectors.toMap( Map.Entry::getKey, entry -> toValue( primaryType, entry.getValue()) ) );
+    }
+
+    @Override
+    public <T extends HasIdentity> List<T> toValueList(ManyAssociation<T> association )
+    {
+        @SuppressWarnings( "unchecked" )
+        Class<T> primaryType = (Class<T>) api.associationDescriptorFor( association ).type();
+
+        return association
+            .toList()
+            .stream()
+            .map( entity -> toValue( primaryType, entity ) )
+            .collect( Collectors.toList() );
+    }
+
+    @Override
+    public <T extends HasIdentity> Set<T> toValueSet(ManyAssociation<T> association )
+    {
+        @SuppressWarnings( "unchecked" )
+        Class<T> primaryType = (Class<T>) api.associationDescriptorFor( association ).type();
+
+        return association
+            .toSet()
+            .stream()
+            .map( entity -> toValue( primaryType, entity ) )
+            .collect( Collectors.toSet() );
+    }
+
+    @Override
+    public <T extends HasIdentity> T toEntity(Class<T> primaryType, T valueComposite )
+    {
+        Function<PropertyDescriptor, Object> propertyFunction = new ToEntityPropertyMappingFunction<>( valueComposite );
+        Function<AssociationDescriptor, EntityReference> assocationFunction = new ToEntityAssociationMappingFunction<>( valueComposite );
+        Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = new ToEntityManyAssociationMappingFunction<>( valueComposite );
+        Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = new ToEntityNameAssociationMappingFunction<>( valueComposite );
+
+        try
+        {
+            T entity = get( primaryType, valueComposite.identity().get() );
+            // If successful, then this entity is to by modified.
+            EntityInstance instance = EntityInstance.entityInstanceOf( (EntityComposite) entity );
+            EntityState state = instance.entityState();
+            FunctionStateResolver stateResolver = new FunctionStateResolver( propertyFunction,
+                                                                             assocationFunction,
+                                                                             manyAssocFunction,
+                                                                             namedAssocFunction );
+            EntityModel model = (EntityModel) EntityInstance.entityInstanceOf( (EntityComposite) entity ).descriptor();
+            stateResolver.populateState( model, state );
+            return entity;
+        }
+        catch( NoSuchEntityException e )
+        {
+            EntityBuilder<T> entityBuilder = newEntityBuilderWithState( primaryType,
+                                                                        valueComposite.identity().get(),
+                                                                        propertyFunction,
+                                                                        assocationFunction,
+                                                                        manyAssocFunction,
+                                                                        namedAssocFunction );
+            return entityBuilder.newInstance();
+        }
+    }
+
+    private static class UoWQuerySource implements QuerySource
+    {
+        private final ModuleUnitOfWork moduleUnitOfWork;
+
+        private UoWQuerySource( ModuleUnitOfWork moduleUnitOfWork )
+        {
+            this.moduleUnitOfWork = moduleUnitOfWork;
+        }
+
+        @Override
+        public <T> T find( Class<T> resultType,
+                           Predicate<Composite> whereClause,
+                           List<OrderBy> orderBySegments,
+                           Integer firstResult,
+                           Integer maxResults,
+                           Map<String, Object> variables
+        )
+        {
+            final EntityFinder entityFinder = moduleUnitOfWork.module()
+                .instance()
+                .findService( EntityFinder.class )
+                .get();
+
+            try
+            {
+                EntityReference foundEntity = entityFinder.findEntity( resultType, whereClause, variables == null ? Collections.emptyMap() : variables );
+                if( foundEntity != null )
+                {
+                    try
+                    {
+                        return moduleUnitOfWork.get( resultType, foundEntity.identity() );
+                    }
+                    catch( NoSuchEntityException e )
+                    {
+                        return null; // Index is out of sync - entity has been removed
+                    }
+                }
+                // No entity was found
+                return null;
+            }
+            catch( EntityFinderException e )
+            {
+                throw new QueryExecutionException( "Finder caused exception", e );
+            }
+        }
+
+        @Override
+        public <T> long count( Class<T> resultType,
+                               Predicate<Composite> whereClause,
+                               List<OrderBy> orderBySegments,
+                               Integer firstResult,
+                               Integer maxResults,
+                               Map<String, Object> variables
+        )
+        {
+            EntityFinder entityFinder = moduleUnitOfWork.module().instance().findService( EntityFinder.class ).get();
+
+            try
+            {
+                return entityFinder.countEntities( resultType, whereClause, variables == null ? Collections.emptyMap() : variables );
+            }
+            catch( EntityFinderException e )
+            {
+                e.printStackTrace();
+                return 0;
+            }
+        }
+
+        @Override
+        public <T> Stream<T> stream( Class<T> resultType,
+                                     Predicate<Composite> whereClause,
+                                     List<OrderBy> orderBySegments,
+                                     Integer firstResult,
+                                     Integer maxResults,
+                                     Map<String, Object> variables )
+        {
+            EntityFinder entityFinder = moduleUnitOfWork.module().instance().findService( EntityFinder.class ).get();
+
+            try
+            {
+                return entityFinder.findEntities(
+                    resultType,
+                    whereClause,
+                    orderBySegments,
+                    firstResult,
+                    maxResults,
+                    variables == null ? Collections.emptyMap() : variables
+                ).map( ref ->
+                       {
+                           try
+                           {
+                               return moduleUnitOfWork.get( resultType, ref.identity() );
+                           }
+                           catch( NoSuchEntityException e )
+                           {
+                               // Index is out of sync - entity has been removed
+                               return null;
+                           }
+                       } );
+            }
+            catch( EntityFinderException e )
+            {
+                throw new QueryExecutionException( "Query '" + toString() + "' could not be executed", e );
+            }
+        }
+    }
+
+    private class ToValuePropertyMappingFunction
+        implements Function<PropertyDescriptor, Object>
+    {
+        private Object entity;
+
+        public ToValuePropertyMappingFunction( Object entity )
+        {
+            this.entity = entity;
+        }
+
+        @Override
+        public Object apply( PropertyDescriptor propertyDescriptor )
+        {
+            EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState();
+            return entityState.propertyValueOf( propertyDescriptor.qualifiedName() );
+        }
+    }
+
+    private class ToValueAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, EntityReference>
+    {
+        private final T entity;
+
+        public ToValueAssociationMappingFunction( T entity )
+        {
+            this.entity = entity;
+        }
+
+        @Override
+        public EntityReference apply( AssociationDescriptor associationDescriptor )
+        {
+            EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState();
+            return entityState.associationValueOf( associationDescriptor.qualifiedName() );
+        }
+    }
+
+    private class ToValueManyAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, Stream<EntityReference>>
+    {
+        private final T entity;
+
+        public ToValueManyAssociationMappingFunction( T entity )
+        {
+            this.entity = entity;
+        }
+
+        @Override
+        public Stream<EntityReference> apply( AssociationDescriptor associationDescriptor )
+        {
+            EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState();
+            return entityState.manyAssociationValueOf( associationDescriptor.qualifiedName() ).stream();
+        }
+    }
+
+    private class ToValueNameAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>>
+    {
+        private final T entity;
+
+        public ToValueNameAssociationMappingFunction( T entity )
+        {
+            this.entity = entity;
+        }
+
+        @Override
+        public Stream<Map.Entry<String, EntityReference>> apply( AssociationDescriptor associationDescriptor )
+        {
+            EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState();
+            return entityState.namedAssociationValueOf( associationDescriptor.qualifiedName() ).stream();
+        }
+    }
+
+    private class ToEntityPropertyMappingFunction<T>
+        implements Function<PropertyDescriptor, Object>
+    {
+        private final T value;
+
+        public ToEntityPropertyMappingFunction( T value )
+        {
+            this.value = value;
+        }
+
+        @Override
+        public Object apply( PropertyDescriptor propertyDescriptor )
+        {
+            StateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state();
+            Property<Object> property = state.propertyFor( propertyDescriptor.accessor() );
+            return property.get();
+        }
+    }
+
+    private class ToEntityAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, EntityReference>
+    {
+
+        private final T value;
+
+        public ToEntityAssociationMappingFunction( T value )
+        {
+            this.value = value;
+        }
+
+        @Override
+        public EntityReference apply( AssociationDescriptor associationDescriptor )
+        {
+            AssociationStateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state();
+            AssociationInstance<T> association = (AssociationInstance<T>) state.associationFor( associationDescriptor.accessor() );
+            return association.getAssociationState().get();
+        }
+    }
+
+    private class ToEntityManyAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, Stream<EntityReference>>
+    {
+
+        private final T value;
+
+        public ToEntityManyAssociationMappingFunction( T valueComposite )
+        {
+            this.value = valueComposite;
+        }
+
+        @Override
+        public Stream<EntityReference> apply( AssociationDescriptor associationDescriptor )
+        {
+            ValueInstance valueInstance = ValueInstance.valueInstanceOf( (ValueComposite) value );
+            return valueInstance.state().manyAssociationFor( associationDescriptor.accessor() ).references();
+        }
+    }
+
+    private class ToEntityNameAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>>
+    {
+        private final T value;
+
+        public ToEntityNameAssociationMappingFunction( T valueComposite )
+        {
+            this.value = valueComposite;
+        }
+
+        @Override
+        public Stream<Map.Entry<String, EntityReference>> apply( AssociationDescriptor associationDescriptor )
+        {
+            ValueInstance valueInstance = ValueInstance.valueInstanceOf( (ValueComposite) value );
+            return valueInstance.state().namedAssociationFor( associationDescriptor.accessor() ).references();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/UnitOfWorkFactoryMixin.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/UnitOfWorkFactoryMixin.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/UnitOfWorkFactoryMixin.java
new file mode 100644
index 0000000..d5a3609
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/UnitOfWorkFactoryMixin.java
@@ -0,0 +1,100 @@
+/*
+ *  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.runtime.unitofwork;
+
+import java.time.Instant;
+import java.util.Stack;
+import org.apache.polygene.api.composite.TransientBuilderFactory;
+import org.apache.polygene.api.entity.EntityComposite;
+import org.apache.polygene.api.injection.scope.Structure;
+import org.apache.polygene.api.metrics.MetricsProvider;
+import org.apache.polygene.api.time.SystemTime;
+import org.apache.polygene.api.unitofwork.UnitOfWork;
+import org.apache.polygene.api.unitofwork.UnitOfWorkFactory;
+import org.apache.polygene.api.usecase.Usecase;
+import org.apache.polygene.runtime.entity.EntityInstance;
+import org.apache.polygene.spi.module.ModuleSpi;
+
+public class UnitOfWorkFactoryMixin
+    implements UnitOfWorkFactory
+{
+    @Structure
+    private TransientBuilderFactory tbf;
+
+    @Structure
+    private ModuleSpi module;
+
+    // Implementation of UnitOfWorkFactory
+    @Override
+    public UnitOfWork newUnitOfWork()
+    {
+        return newUnitOfWork( Usecase.DEFAULT );
+    }
+
+    @Override
+    public UnitOfWork newUnitOfWork(Instant currentTime )
+    {
+        return newUnitOfWork( Usecase.DEFAULT, currentTime );
+    }
+
+    @Override
+    public UnitOfWork newUnitOfWork( Usecase usecase )
+    {
+        return newUnitOfWork( usecase == null ? Usecase.DEFAULT : usecase, SystemTime.now() );
+    }
+
+    @Override
+    public UnitOfWork newUnitOfWork( Usecase usecase, Instant currentTime )
+    {
+        UnitOfWorkInstance unitOfWorkInstance = new UnitOfWorkInstance( module, usecase, currentTime, metricsProvider() );
+        return tbf.newTransient( UnitOfWork.class, unitOfWorkInstance );
+    }
+
+    private MetricsProvider metricsProvider()
+    {
+        return module.metricsProvider();
+    }
+
+    @Override
+    public boolean isUnitOfWorkActive()
+    {
+        Stack<UnitOfWorkInstance> stack = UnitOfWorkInstance.getCurrent();
+        return !stack.isEmpty();
+    }
+
+    @Override
+    public UnitOfWork currentUnitOfWork()
+    {
+        Stack<UnitOfWorkInstance> stack = UnitOfWorkInstance.getCurrent();
+        if( stack.size() == 0 )
+        {
+            throw new IllegalStateException( "No current UnitOfWork active" );
+        }
+        return tbf.newTransient( UnitOfWork.class, stack.peek() );
+    }
+
+    @Override
+    public UnitOfWork getUnitOfWork( EntityComposite entity )
+    {
+        EntityInstance instance = EntityInstance.entityInstanceOf( entity );
+        return instance.unitOfWork();
+    }
+}


Mime
View raw message