You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2016/12/17 10:27:42 UTC
[06/81] [abbrv] [partial] zest-java git commit: ZEST-195 ;
Replace all "zest" with "polygene"
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/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();
+ }
+}