You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by pa...@apache.org on 2017/03/13 10:35:23 UTC
[31/50] [abbrv] polygene-java git commit: New (de)serialization API
and SPI & new implementations
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c9dd7229/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java
new file mode 100644
index 0000000..5450ec9
--- /dev/null
+++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java
@@ -0,0 +1,216 @@
+/*
+ * 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.serialization.javaxjson;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.UncheckedIOException;
+import java.util.Base64;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import org.apache.polygene.api.PolygeneAPI;
+import org.apache.polygene.api.association.AssociationStateHolder;
+import org.apache.polygene.api.composite.CompositeInstance;
+import org.apache.polygene.api.injection.scope.This;
+import org.apache.polygene.api.injection.scope.Uses;
+import org.apache.polygene.api.service.ServiceDescriptor;
+import org.apache.polygene.api.type.EnumType;
+import org.apache.polygene.api.type.MapType;
+import org.apache.polygene.api.type.ValueCompositeType;
+import org.apache.polygene.api.type.ValueType;
+import org.apache.polygene.api.value.ValueComposite;
+import org.apache.polygene.api.value.ValueDescriptor;
+import org.apache.polygene.spi.serialization.AbstractTextSerializer;
+import org.apache.polygene.spi.serialization.JsonSerializer;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toList;
+import static org.apache.polygene.api.util.Collectors.toMap;
+
+public class JavaxJsonSerializer extends AbstractTextSerializer implements JsonSerializer
+{
+ @This
+ private JavaxJsonAdapters adapters;
+
+ @Uses
+ private ServiceDescriptor descriptor;
+
+ @Override
+ public <T> Function<T, JsonValue> toJsonFunction( Options options )
+ {
+ return object -> doSerialize( options, object, true );
+ }
+
+ private JsonValue doSerialize( Options options, Object object, boolean root )
+ {
+ if( object == null )
+ {
+ return JsonValue.NULL;
+ }
+ Class<?> objectClass = object.getClass();
+ JavaxJsonAdapter<?> adapter = adapters.adapterFor( objectClass );
+ if( adapter != null )
+ {
+ return adapter.serialize( object, obj -> doSerialize( options, obj, false ) );
+ }
+ if( EnumType.isEnum( objectClass ) )
+ {
+ return JavaxJson.toJsonString( object.toString() );
+ }
+ if( ValueCompositeType.isValueComposite( objectClass ) )
+ {
+ return serializeValueComposite( options, object, root );
+ }
+ if( MapType.isMap( objectClass ) )
+ {
+ return serializeMap( options, (Map<?, ?>) object );
+ }
+ if( Iterable.class.isAssignableFrom( objectClass ) )
+ {
+ return serializeIterable( options, (Iterable<?>) object );
+ }
+ if( Stream.class.isAssignableFrom( objectClass ) )
+ {
+ return serializeStream( options, (Stream<?>) object );
+ }
+ // Fallback to Java Serialization in Base 64
+ // Include all arrays!
+ return serializeBase64( object );
+ }
+
+ private JsonObject serializeValueComposite( Options options, Object composite, boolean root )
+ {
+ CompositeInstance instance = PolygeneAPI.FUNCTION_COMPOSITE_INSTANCE_OF.apply( (ValueComposite) composite );
+ ValueDescriptor descriptor = (ValueDescriptor) instance.descriptor();
+ AssociationStateHolder state = (AssociationStateHolder) instance.state();
+ ValueCompositeType valueType = descriptor.valueType();
+
+ JsonObjectBuilder builder = Json.createObjectBuilder();
+ valueType.properties().forEach(
+ property -> builder.add(
+ property.qualifiedName().name(),
+ doSerialize( options, state.propertyFor( property.accessor() ).get(), false ) ) );
+ valueType.associations().forEach(
+ association -> builder.add(
+ association.qualifiedName().name(),
+ doSerialize( options, state.associationFor( association.accessor() ).reference(), false ) ) );
+ valueType.manyAssociations().forEach(
+ association -> builder.add(
+ association.qualifiedName().name(),
+ doSerialize( options, state.manyAssociationFor( association.accessor() ).references()
+ .collect( toList() ),
+ false ) ) );
+ valueType.namedAssociations().forEach(
+ association -> builder.add(
+ association.qualifiedName().name(),
+ doSerialize( options,
+ state.namedAssociationFor( association.accessor() ).references()
+ .collect( toMap() ),
+ false ) ) );
+ if( !root && options.includeTypeInfo() )
+ {
+ withTypeInfo( builder, valueType );
+ }
+ return builder.build();
+ }
+
+ private JsonObjectBuilder withTypeInfo( JsonObjectBuilder builder, ValueType valueType )
+ {
+ return builder.add( getTypeInfoPropertyName(), valueType.primaryType().getName() );
+ }
+
+ /**
+ * Map serialization.
+ *
+ * {@literal Map<String, ?>} are serialized to a {@literal JsonObject}.
+ * {@literal Map<?, ?>} are serialized to a {@literal JsonArray} or key/value {@literal JsonObject}s.
+ * Empty maps are serialized to an empty {@literal JsonObject}.
+ */
+ private JsonValue serializeMap( Options options, Map<?, ?> map )
+ {
+ if( map.isEmpty() )
+ {
+ // Defaults to {}
+ return Json.createObjectBuilder().build();
+ }
+ Predicate<Object> characterKeyPredicate = key ->
+ key != null && ( key instanceof CharSequence || key instanceof Character );
+ if( map.keySet().stream().allMatch( characterKeyPredicate ) )
+ {
+ JsonObjectBuilder builder = Json.createObjectBuilder();
+ map.entrySet().forEach( entry -> builder.add( entry.getKey().toString(),
+ doSerialize( options, entry.getValue(), false ) ) );
+ return builder.build();
+ }
+ else
+ {
+ JsonArrayBuilder builder = Json.createArrayBuilder();
+ map.entrySet().forEach(
+ entry -> builder.add(
+ Json.createObjectBuilder()
+ .add( "key", doSerialize( options, entry.getKey(), false ) )
+ .add( "value", doSerialize( options, entry.getValue(), false ) )
+ .build() ) );
+ return builder.build();
+ }
+ }
+
+ private JsonArray serializeIterable( Options options, Iterable<?> iterable )
+ {
+ return serializeStream( options, StreamSupport.stream( iterable.spliterator(), false ) );
+ }
+
+ private <T> JsonArray serializeStream( Options options, Stream<?> stream )
+ {
+ JsonArrayBuilder builder = Json.createArrayBuilder();
+ stream.forEach( element -> builder.add( doSerialize( options, element, false ) ) );
+ return builder.build();
+ }
+
+ private JsonString serializeBase64( Object object )
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ try( ObjectOutputStream out = new ObjectOutputStream( bout ) )
+ {
+ out.writeUnshared( object );
+ byte[] bytes = Base64.getEncoder().encode( bout.toByteArray() );
+ return JavaxJson.toJsonString( new String( bytes, UTF_8 ) );
+ }
+ catch( IOException ex )
+ {
+ throw new UncheckedIOException( ex );
+ }
+ }
+
+ private String getTypeInfoPropertyName()
+ {
+ return JavaxJsonSettings.orDefault( descriptor.metaInfo( JavaxJsonSettings.class ) )
+ .getTypeInfoPropertyName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c9dd7229/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java
new file mode 100644
index 0000000..266bd99
--- /dev/null
+++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.polygene.serialization.javaxjson;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.apache.polygene.api.type.ValueType;
+
+public class JavaxJsonSettings
+{
+ public static final JavaxJsonSettings DEFAULT = new JavaxJsonSettings();
+
+ public static JavaxJsonSettings orDefault( JavaxJsonSettings settings )
+ {
+ return settings != null ? settings : DEFAULT;
+ }
+
+ private String typeInfoPropertyName;
+ private Map<ValueType, JavaxJsonAdapter<?>> adapters;
+
+ public JavaxJsonSettings()
+ {
+ typeInfoPropertyName = "_type";
+ adapters = new LinkedHashMap<>();
+ }
+
+ public String getTypeInfoPropertyName()
+ {
+ return typeInfoPropertyName;
+ }
+
+ public void setTypeInfoPropertyName( String typeInfoPropertyName )
+ {
+ this.typeInfoPropertyName = typeInfoPropertyName;
+ }
+
+ public Map<ValueType, JavaxJsonAdapter<?>> getAdapters()
+ {
+ return adapters;
+ }
+
+ public JavaxJsonSettings withTypeInfoPropertyName( String typeInfoPropertyName )
+ {
+ setTypeInfoPropertyName( typeInfoPropertyName );
+ return this;
+ }
+
+ public JavaxJsonSettings withJsonAdapter( ValueType valueType, JavaxJsonAdapter<?> adapter )
+ {
+ getAdapters().put( valueType, adapter );
+ return this;
+ }
+
+ public JavaxJsonSettings withJsonAdapter( JavaxJsonAdapter<?> adapter )
+ {
+ return withJsonAdapter( ValueType.of( adapter.type() ), adapter );
+ }
+}
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c9dd7229/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/package.html
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/package.html b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/package.html
new file mode 100644
index 0000000..43db1d9
--- /dev/null
+++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/package.html
@@ -0,0 +1,24 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ ~
+ -->
+<html>
+ <body>
+ <h2>javax.json Serialization.</h2>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c9dd7229/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONEntityState.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONEntityState.java b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONEntityState.java
index 6bbef04..e4b5c05 100644
--- a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONEntityState.java
+++ b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONEntityState.java
@@ -14,28 +14,32 @@
* 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.spi.entitystore.helpers;
import java.time.Instant;
+import java.util.Map;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
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.property.PropertyDescriptor;
+import org.apache.polygene.api.serialization.SerializationException;
import org.apache.polygene.api.structure.ModuleDescriptor;
import org.apache.polygene.api.type.ValueType;
-import org.apache.polygene.api.value.ValueSerialization;
-import org.apache.polygene.api.value.ValueSerializationException;
+import org.apache.polygene.api.value.ValueDescriptor;
+import org.apache.polygene.serialization.javaxjson.JavaxJson;
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;
import org.apache.polygene.spi.entitystore.EntityStoreException;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import org.apache.polygene.spi.serialization.JsonSerialization;
/**
* Standard JSON implementation of EntityState.
@@ -43,7 +47,6 @@ import org.json.JSONObject;
public final class JSONEntityState
implements EntityState
{
- private static final String[] EMPTY_NAMES = new String[ 0 ];
private static final String[] CLONE_NAMES =
{
JSONKeys.IDENTITY,
@@ -54,27 +57,27 @@ public final class JSONEntityState
};
private final ModuleDescriptor module;
- private final ValueSerialization valueSerialization;
private final String version;
private final EntityReference reference;
private final EntityDescriptor entityDescriptor;
+ private final JsonSerialization serialization;
private EntityStatus status;
private Instant lastModified;
- private JSONObject state;
+ private JsonObject state;
/* package */ JSONEntityState( ModuleDescriptor module,
- ValueSerialization valueSerialization,
+ JsonSerialization serialization,
String version,
Instant lastModified,
EntityReference reference,
EntityStatus status,
EntityDescriptor entityDescriptor,
- JSONObject state
+ JsonObject state
)
{
this.module = module;
- this.valueSerialization = valueSerialization;
+ this.serialization = serialization;
this.version = version;
this.lastModified = lastModified;
this.reference = reference;
@@ -107,22 +110,45 @@ public final class JSONEntityState
{
try
{
- Object json = state.getJSONObject( JSONKeys.PROPERTIES ).opt( stateName.name() );
- if( JSONObject.NULL.equals( json ) )
+ JsonValue json = state.getJsonObject( JSONKeys.PROPERTIES ).get( stateName.name() );
+ if( json == null || JsonValue.NULL.equals( json ) )
{
return null;
}
else
{
- PropertyDescriptor descriptor = entityDescriptor.state().findPropertyModelByQualifiedName( stateName );
- if( descriptor == null )
+ // TODO This rely on _type explicitely :(
+ // Needed because of this mess that is JsonEntityState
+ ValueType propertyValueType = null;
+ if( json.getValueType() == JsonValue.ValueType.OBJECT )
+ {
+ String typeInfo = ( (JsonObject) json ).getString( "_type", null );
+ if( typeInfo != null )
+ {
+ ValueDescriptor valueDescriptor = module.valueDescriptor( typeInfo );
+ if( valueDescriptor != null )
+ {
+ propertyValueType = valueDescriptor.valueType();
+ }
+ }
+ }
+ if( propertyValueType == null )
+ {
+ PropertyDescriptor descriptor = entityDescriptor.state()
+ .findPropertyModelByQualifiedName( stateName );
+ if( descriptor != null )
+ {
+ propertyValueType = descriptor.valueType();
+ }
+ }
+ if( propertyValueType == null )
{
return null;
}
- return valueSerialization.deserialize( module, descriptor.valueType(), json.toString() );
+ return serialization.fromJson( module, propertyValueType, json );
}
}
- catch( ValueSerializationException | JSONException e )
+ catch( SerializationException e )
{
throw new EntityStoreException( e );
}
@@ -133,129 +159,44 @@ public final class JSONEntityState
{
try
{
- Object jsonValue;
- if( newValue == null || ValueType.isPrimitiveValue( newValue ) )
- {
- jsonValue = newValue;
- }
- else if( ValueType.isIdentity( newValue ) )
- {
- jsonValue = newValue.toString();
- }
- else
- {
- String serialized = valueSerialization.serialize( newValue );
- if( serialized.startsWith( "{" ) )
- {
- jsonValue = new JSONObject( serialized );
- }
- else if( serialized.startsWith( "[" ) )
- {
- jsonValue = new JSONArray( serialized );
- }
- else
- {
- jsonValue = serialized;
- }
- }
- cloneStateIfGlobalStateLoaded();
- state.getJSONObject( JSONKeys.PROPERTIES ).put( stateName.name(), jsonValue );
+ JsonValue jsonValue = serialization.toJson( newValue );
+ stateCloneWithProperty( stateName.name(), jsonValue );
markUpdated();
}
- catch( ValueSerializationException | JSONException e )
+ catch( SerializationException e )
{
throw new EntityStoreException( "Unable to set property " + stateName + " value " + newValue, e );
}
}
- private JSONObject cloneJSON( JSONObject jsonObject )
- throws JSONException
- {
- String[] names = JSONObject.getNames( jsonObject );
- if( names == null )
- {
- names = EMPTY_NAMES;
- }
- return new JSONObject( jsonObject, names );
- }
-
@Override
public EntityReference associationValueOf( QualifiedName stateName )
{
- try
- {
- Object jsonValue = state.getJSONObject( JSONKeys.ASSOCIATIONS ).opt( stateName.name() );
- if( jsonValue == null )
- {
- return null;
- }
-
- EntityReference value = jsonValue == JSONObject.NULL
- ? null
- : EntityReference.parseEntityReference( (String) jsonValue );
- return value;
- }
- catch( JSONException e )
+ String jsonValue = state.getJsonObject( JSONKeys.ASSOCIATIONS ).getString( stateName.name(), null );
+ if( jsonValue == null )
{
- throw new EntityStoreException( e );
+ return null;
}
+ return EntityReference.parseEntityReference( jsonValue );
}
@Override
public void setAssociationValue( QualifiedName stateName, EntityReference newEntity )
{
- try
- {
- cloneStateIfGlobalStateLoaded();
- state.getJSONObject( JSONKeys.ASSOCIATIONS ).put( stateName.name(), newEntity == null
- ? null
- : newEntity.identity().toString() );
- markUpdated();
- }
- catch( JSONException e )
- {
- throw new EntityStoreException( e );
- }
+ stateCloneWithAssociation( stateName.name(), newEntity );
+ markUpdated();
}
@Override
public ManyAssociationState manyAssociationValueOf( QualifiedName stateName )
{
- try
- {
- JSONObject manyAssociations = state.getJSONObject( JSONKeys.MANY_ASSOCIATIONS );
- JSONArray jsonValues = manyAssociations.optJSONArray( stateName.name() );
- if( jsonValues == null )
- {
- jsonValues = new JSONArray();
- manyAssociations.put( stateName.name(), jsonValues );
- }
- return new JSONManyAssociationState( this, jsonValues );
- }
- catch( JSONException e )
- {
- throw new EntityStoreException( e );
- }
+ return new JSONManyAssociationState( this, stateName.name() );
}
@Override
public NamedAssociationState namedAssociationValueOf( QualifiedName stateName )
{
- try
- {
- JSONObject namedAssociations = state.getJSONObject( JSONKeys.NAMED_ASSOCIATIONS );
- JSONObject jsonValues = namedAssociations.optJSONObject( stateName.name() );
- if( jsonValues == null )
- {
- jsonValues = new JSONObject();
- namedAssociations.put( stateName.name(), jsonValues );
- }
- return new JSONNamedAssociationState( this, jsonValues );
- }
- catch( JSONException e )
- {
- throw new EntityStoreException( e );
- }
+ return new JSONNamedAssociationState( this, stateName.name() );
}
@Override
@@ -282,7 +223,7 @@ public final class JSONEntityState
return entityDescriptor;
}
- public JSONObject state()
+ public JsonObject state()
{
return state;
}
@@ -293,7 +234,7 @@ public final class JSONEntityState
return reference + "(" + state + ")";
}
- public void markUpdated()
+ void markUpdated()
{
if( status == EntityStatus.LOADED )
{
@@ -301,29 +242,217 @@ public final class JSONEntityState
}
}
- void cloneStateIfGlobalStateLoaded()
+ void stateCloneWithVersionAndModified( String version, Instant lastModified )
+ {
+ JsonObjectBuilder builder = JavaxJson.toBuilder( state );
+ builder.add( JSONKeys.VERSION, version );
+ builder.add( JSONKeys.MODIFIED, lastModified.toEpochMilli() );
+ state = builder.build();
+ }
+
+ void stateCloneWithProperty( String stateName, JsonValue value )
{
- if( status != EntityStatus.LOADED )
+ JsonObjectBuilder builder = stateShallowClone();
+ JsonObjectBuilder propertiesBuilder = JavaxJson.toBuilder( state.getJsonObject( JSONKeys.PROPERTIES ) );
+ if( value == null )
+ {
+ propertiesBuilder.add( stateName, JsonValue.NULL );
+ }
+ else
{
- return;
+ propertiesBuilder.add( stateName, value );
}
+ builder.add( JSONKeys.PROPERTIES, propertiesBuilder.build() );
+ builder.add( JSONKeys.ASSOCIATIONS, state.get( JSONKeys.ASSOCIATIONS ) );
+ builder.add( JSONKeys.MANY_ASSOCIATIONS, state.get( JSONKeys.MANY_ASSOCIATIONS ) );
+ builder.add( JSONKeys.NAMED_ASSOCIATIONS, state.get( JSONKeys.NAMED_ASSOCIATIONS ) );
+ state = builder.build();
+ }
- try
+ void stateCloneWithAssociation( String stateName, EntityReference ref )
+ {
+ JsonObjectBuilder builder = stateShallowClone();
+ JsonObjectBuilder assocBuilder = JavaxJson.toBuilder( state.getJsonObject( JSONKeys.ASSOCIATIONS ) );
+ if( ref == null )
{
- JSONObject newProperties = cloneJSON( state.getJSONObject( JSONKeys.PROPERTIES ) );
- JSONObject newAssoc = cloneJSON( state.getJSONObject( JSONKeys.ASSOCIATIONS ) );
- JSONObject newManyAssoc = cloneJSON( state.getJSONObject( JSONKeys.MANY_ASSOCIATIONS ) );
- JSONObject newNamedAssoc = cloneJSON( state.getJSONObject( JSONKeys.NAMED_ASSOCIATIONS ) );
- JSONObject stateClone = new JSONObject( state, CLONE_NAMES );
- stateClone.put( JSONKeys.PROPERTIES, newProperties );
- stateClone.put( JSONKeys.ASSOCIATIONS, newAssoc );
- stateClone.put( JSONKeys.MANY_ASSOCIATIONS, newManyAssoc );
- stateClone.put( JSONKeys.NAMED_ASSOCIATIONS, newNamedAssoc );
- state = stateClone;
+ assocBuilder.add( stateName, JsonValue.NULL );
}
- catch( JSONException e )
+ else
{
- throw new EntityStoreException( e );
+ assocBuilder.add( stateName, ref.identity().toString() );
+ }
+ builder.add( JSONKeys.PROPERTIES, state.get( JSONKeys.PROPERTIES ) );
+ builder.add( JSONKeys.ASSOCIATIONS, assocBuilder.build() );
+ builder.add( JSONKeys.MANY_ASSOCIATIONS, state.get( JSONKeys.MANY_ASSOCIATIONS ) );
+ builder.add( JSONKeys.NAMED_ASSOCIATIONS, state.get( JSONKeys.NAMED_ASSOCIATIONS ) );
+ state = builder.build();
+ }
+
+ void stateCloneAddManyAssociation( int idx, String stateName, EntityReference ref )
+ {
+ JsonObjectBuilder builder = stateShallowClone();
+ JsonObjectBuilder manyAssociations = Json.createObjectBuilder();
+ JsonObject previousManyAssociations = state.getJsonObject( JSONKeys.MANY_ASSOCIATIONS );
+ for( Map.Entry<String, JsonValue> previousManyAssociation : previousManyAssociations.entrySet() )
+ {
+ String key = previousManyAssociation.getKey();
+ if( !key.equals( stateName ) )
+ {
+ manyAssociations.add( key, previousManyAssociation.getValue() );
+ }
+ }
+ JsonValue previousReferences = previousManyAssociations.get( stateName );
+ JsonArrayBuilder references = Json.createArrayBuilder();
+ String newRef = ref.identity().toString();
+ if( previousReferences == null || previousReferences.getValueType() != JsonValue.ValueType.ARRAY )
+ {
+ references.add( newRef );
+ }
+ else
+ {
+ JsonArray previousReferencesArray = (JsonArray) previousReferences;
+ boolean insert = !previousReferencesArray.contains( newRef );
+ for( int i = 0; i < previousReferencesArray.size(); i++ )
+ {
+ if( insert && i == idx )
+ {
+ references.add( newRef );
+ }
+ references.add( previousReferencesArray.getString( i ) );
+ }
+ if( insert && idx >= previousReferencesArray.size() )
+ {
+ references.add( newRef );
+ }
+ }
+ manyAssociations.add( stateName, references.build() );
+ builder.add( JSONKeys.PROPERTIES, state.get( JSONKeys.PROPERTIES ) );
+ builder.add( JSONKeys.ASSOCIATIONS, state.get( JSONKeys.ASSOCIATIONS ) );
+ builder.add( JSONKeys.MANY_ASSOCIATIONS, manyAssociations.build() );
+ builder.add( JSONKeys.NAMED_ASSOCIATIONS, state.get( JSONKeys.NAMED_ASSOCIATIONS ) );
+ state = builder.build();
+ }
+
+ void stateCloneRemoveManyAssociation( String stateName, EntityReference ref )
+ {
+ String stringRef = ref.identity().toString();
+ JsonObjectBuilder builder = stateShallowClone();
+ JsonObjectBuilder manyAssociations = Json.createObjectBuilder();
+ JsonObject previousManyAssociations = state.getJsonObject( JSONKeys.MANY_ASSOCIATIONS );
+ for( Map.Entry<String, JsonValue> previousManyAssociation : previousManyAssociations.entrySet() )
+ {
+ String key = previousManyAssociation.getKey();
+ if( !key.equals( stateName ) )
+ {
+ manyAssociations.add( key, previousManyAssociation.getValue() );
+ }
+ }
+ JsonValue previousReferences = previousManyAssociations.get( stateName );
+ JsonArrayBuilder references = Json.createArrayBuilder();
+ if( previousReferences != null && previousReferences.getValueType() == JsonValue.ValueType.ARRAY )
+ {
+ JsonArray previousReferencesArray = (JsonArray) previousReferences;
+ for( int idx = 0; idx < previousReferencesArray.size(); idx++ )
+ {
+ String previousRef = previousReferencesArray.getString( idx );
+ if( !stringRef.equals( previousRef ) )
+ {
+ references.add( previousRef );
+ }
+ }
+ }
+ manyAssociations.add( stateName, references.build() );
+ builder.add( JSONKeys.PROPERTIES, state.get( JSONKeys.PROPERTIES ) );
+ builder.add( JSONKeys.ASSOCIATIONS, state.get( JSONKeys.ASSOCIATIONS ) );
+ builder.add( JSONKeys.MANY_ASSOCIATIONS, manyAssociations.build() );
+ builder.add( JSONKeys.NAMED_ASSOCIATIONS, state.get( JSONKeys.NAMED_ASSOCIATIONS ) );
+ state = builder.build();
+ }
+
+ void stateCloneAddNamedAssociation( String stateName, String name, EntityReference ref )
+ {
+ JsonObjectBuilder builder = stateShallowClone();
+ JsonObject previousNamedAssociations = state.getJsonObject( JSONKeys.NAMED_ASSOCIATIONS );
+ JsonObjectBuilder namedAssociations = Json.createObjectBuilder();
+ for( Map.Entry<String, JsonValue> previousNamedAssociation : previousNamedAssociations.entrySet() )
+ {
+ String key = previousNamedAssociation.getKey();
+ if( !key.equals( stateName ) )
+ {
+ namedAssociations.add( key, previousNamedAssociation.getValue() );
+ }
+ }
+ JsonValue previousReferences = previousNamedAssociations.get( stateName );
+ JsonObjectBuilder references = Json.createObjectBuilder();
+ String newRef = ref.identity().toString();
+ if( previousReferences == null || !( previousReferences instanceof JsonObject ) )
+ {
+ references.add( name, newRef );
+ }
+ else
+ {
+ JsonObject previousReferencesObject = (JsonObject) previousReferences;
+ for( Map.Entry<String, JsonValue> previousNamedReference : previousReferencesObject.entrySet() )
+ {
+ String key = previousNamedReference.getKey();
+ if( !key.equals( name ) )
+ {
+ references.add( key, previousNamedReference.getValue() );
+ }
+ }
+ references.add( name, ref.identity().toString() );
+ }
+ namedAssociations.add( stateName, references.build() );
+ builder.add( JSONKeys.PROPERTIES, state.get( JSONKeys.PROPERTIES ) );
+ builder.add( JSONKeys.ASSOCIATIONS, state.get( JSONKeys.ASSOCIATIONS ) );
+ builder.add( JSONKeys.MANY_ASSOCIATIONS, state.get( JSONKeys.MANY_ASSOCIATIONS ) );
+ builder.add( JSONKeys.NAMED_ASSOCIATIONS, namedAssociations.build() );
+ state = builder.build();
+ }
+
+ void stateCloneRemoveNamedAssociation( String stateName, String name )
+ {
+ JsonObjectBuilder builder = stateShallowClone();
+ JsonObjectBuilder namedAssociations = Json.createObjectBuilder();
+ JsonObject previousNamedAssociations = state.getJsonObject( JSONKeys.NAMED_ASSOCIATIONS );
+ for( Map.Entry<String, JsonValue> previousNamedAssociation : previousNamedAssociations.entrySet() )
+ {
+ String key = previousNamedAssociation.getKey();
+ if( !key.equals( stateName ) )
+ {
+ namedAssociations.add( key, previousNamedAssociation.getValue() );
+ }
+ }
+ JsonValue previousReferences = previousNamedAssociations.get( stateName );
+ JsonObjectBuilder references = Json.createObjectBuilder();
+ if( previousReferences != null && previousReferences.getValueType() == JsonValue.ValueType.OBJECT )
+ {
+ JsonObject previousReferencesObject = (JsonObject) previousReferences;
+ for( Map.Entry<String, JsonValue> previousNamedRef : previousReferencesObject.entrySet() )
+ {
+ String previousName = previousNamedRef.getKey();
+ if( !name.equals( previousName ) )
+ {
+ references.add( previousName, previousNamedRef.getValue() );
+ }
+ }
+ }
+ namedAssociations.add( stateName, references.build() );
+ builder.add( JSONKeys.PROPERTIES, state.get( JSONKeys.PROPERTIES ) );
+ builder.add( JSONKeys.ASSOCIATIONS, state.get( JSONKeys.ASSOCIATIONS ) );
+ builder.add( JSONKeys.MANY_ASSOCIATIONS, state.get( JSONKeys.MANY_ASSOCIATIONS ) );
+ builder.add( JSONKeys.NAMED_ASSOCIATIONS, namedAssociations.build() );
+ state = builder.build();
+ }
+
+ private JsonObjectBuilder stateShallowClone()
+ {
+ JsonObjectBuilder builder = Json.createObjectBuilder();
+ for( String cloneName : CLONE_NAMES )
+ {
+ JsonValue cloneValue = state.get( cloneName );
+ builder.add( cloneName, cloneValue == null ? JsonValue.NULL : cloneValue );
}
+ return builder;
}
}
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c9dd7229/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONManyAssociationState.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONManyAssociationState.java b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONManyAssociationState.java
index b1efbc1..e9b99c4 100644
--- a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONManyAssociationState.java
+++ b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONManyAssociationState.java
@@ -21,39 +21,52 @@ package org.apache.polygene.spi.entitystore.helpers;
import java.util.Iterator;
import java.util.NoSuchElementException;
-import org.json.JSONArray;
-import org.json.JSONException;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
import org.apache.polygene.api.entity.EntityReference;
import org.apache.polygene.spi.entity.ManyAssociationState;
import org.apache.polygene.spi.entitystore.EntityStoreException;
/**
* JSON implementation of ManyAssociationState.
- * <p>Backed by a JSONArray.</p>
+ * <p>Backed by a JsonArray.</p>
*/
public final class JSONManyAssociationState
implements ManyAssociationState
{
-
private final JSONEntityState entityState;
- private final JSONArray references;
+ private final String stateName;
- public JSONManyAssociationState( JSONEntityState entityState, JSONArray references )
+ /* package */ JSONManyAssociationState( JSONEntityState entityState, String stateName )
{
this.entityState = entityState;
- this.references = references;
+ this.stateName = stateName;
+ }
+
+ private JsonArray getReferences()
+ {
+ JsonObject manyAssociations = entityState.state().getJsonObject( JSONKeys.MANY_ASSOCIATIONS );
+ JsonValue references = manyAssociations.get( stateName );
+ if( references != null && references.getValueType() == JsonValue.ValueType.ARRAY )
+ {
+ return (JsonArray) references;
+ }
+ return Json.createArrayBuilder().build();
}
@Override
public int count()
{
- return references.length();
+ return getReferences().size();
}
@Override
public boolean contains( EntityReference entityReference )
{
- return indexOfReference( entityReference.toString() ) != -1;
+ return indexOfReference( entityReference.identity().toString() ) != -1;
}
@Override
@@ -65,12 +78,11 @@ public final class JSONManyAssociationState
{
return false;
}
- entityState.cloneStateIfGlobalStateLoaded();
- insertReference( idx, entityReference.identity().toString() );
+ entityState.stateCloneAddManyAssociation( idx, stateName, entityReference );
entityState.markUpdated();
return true;
}
- catch( JSONException e )
+ catch( JsonException e )
{
throw new EntityStoreException( e );
}
@@ -82,8 +94,7 @@ public final class JSONManyAssociationState
int refIndex = indexOfReference( entityReference.identity().toString() );
if( refIndex != -1 )
{
- entityState.cloneStateIfGlobalStateLoaded();
- references.remove( refIndex );
+ entityState.stateCloneRemoveManyAssociation( stateName, entityReference );
entityState.markUpdated();
return true;
}
@@ -93,14 +104,7 @@ public final class JSONManyAssociationState
@Override
public EntityReference get( int i )
{
- try
- {
- return EntityReference.parseEntityReference( references.getString( i ) );
- }
- catch( JSONException e )
- {
- throw new EntityStoreException( e );
- }
+ return EntityReference.parseEntityReference( getReferences().getString( i ) );
}
@Override
@@ -113,7 +117,7 @@ public final class JSONManyAssociationState
@Override
public boolean hasNext()
{
- return idx < references.length();
+ return idx < getReferences().size();
}
@Override
@@ -121,11 +125,11 @@ public final class JSONManyAssociationState
{
try
{
- EntityReference ref = EntityReference.parseEntityReference( references.getString( idx ) );
+ EntityReference ref = EntityReference.parseEntityReference( getReferences().getString( idx ) );
idx++;
return ref;
}
- catch( JSONException e )
+ catch( JsonException e )
{
throw new NoSuchElementException();
}
@@ -142,49 +146,19 @@ public final class JSONManyAssociationState
@Override
public String toString()
{
- return references.toString();
+ return getReferences().toString();
}
- private int indexOfReference( String enityIdentityAsString )
+ private int indexOfReference( String entityIdentityAsString )
{
- for( int idx = 0; idx < references.length(); idx++ )
+ JsonArray references = getReferences();
+ for( int idx = 0; idx < references.size(); idx++ )
{
- if( enityIdentityAsString.equals( references.opt( idx ) ) )
+ if( entityIdentityAsString.equals( references.getString( idx, null ) ) )
{
return idx;
}
}
return -1;
}
-
- private void insertReference( int insert, Object item )
- throws JSONException
- {
- if( insert < 0 || insert > references.length() )
- {
- throw new JSONException( "JSONArray[" + insert + "] is out of bounds." );
- }
- if( insert == references.length() )
- {
- // append
- references.put( item );
- }
- else
- {
- // insert (copy/insert/apply)
- JSONArray output = new JSONArray();
- for( int idx = 0; idx < references.length(); idx++ )
- {
- if( idx == insert )
- {
- output.put( item );
- }
- output.put( references.opt( idx ) );
- }
- for( int idx = 0; idx < output.length(); idx++ )
- {
- references.put( idx, output.opt( idx ) );
- }
- }
- }
}
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c9dd7229/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONMapEntityStoreMixin.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONMapEntityStoreMixin.java b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONMapEntityStoreMixin.java
index 82d4c05..a7f7690 100644
--- a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONMapEntityStoreMixin.java
+++ b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONMapEntityStoreMixin.java
@@ -14,8 +14,6 @@
* 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.spi.entitystore.helpers;
@@ -24,12 +22,18 @@ import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Reader;
+import java.io.StringReader;
import java.io.Writer;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import java.util.function.Function;
import java.util.stream.Stream;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonReader;
import org.apache.polygene.api.cache.CacheOptions;
import org.apache.polygene.api.common.Optional;
import org.apache.polygene.api.entity.EntityDescriptor;
@@ -42,13 +46,11 @@ import org.apache.polygene.api.injection.scope.Structure;
import org.apache.polygene.api.injection.scope.This;
import org.apache.polygene.api.injection.scope.Uses;
import org.apache.polygene.api.service.ServiceDescriptor;
-import org.apache.polygene.api.service.qualifier.Tagged;
import org.apache.polygene.api.structure.Application;
import org.apache.polygene.api.structure.ModuleDescriptor;
import org.apache.polygene.api.unitofwork.NoSuchEntityTypeException;
import org.apache.polygene.api.usecase.Usecase;
-import org.apache.polygene.api.value.ValueSerialization;
-import org.apache.polygene.spi.PolygeneSPI;
+import org.apache.polygene.serialization.javaxjson.JavaxJson;
import org.apache.polygene.spi.cache.Cache;
import org.apache.polygene.spi.cache.CachePool;
import org.apache.polygene.spi.cache.NullCache;
@@ -60,9 +62,7 @@ import org.apache.polygene.spi.entitystore.EntityStoreException;
import org.apache.polygene.spi.entitystore.EntityStoreSPI;
import org.apache.polygene.spi.entitystore.EntityStoreUnitOfWork;
import org.apache.polygene.spi.entitystore.StateCommitter;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.json.JSONTokener;
+import org.apache.polygene.spi.serialization.JsonSerialization;
/**
* Implementation of EntityStore that works with an implementation of MapEntityStore.
@@ -82,14 +82,10 @@ public class JSONMapEntityStoreMixin
private EntityStoreSPI entityStoreSpi;
@Structure
- private PolygeneSPI spi;
-
- @Structure
private Application application;
@Service
- @Tagged( ValueSerialization.Formats.JSON )
- private ValueSerialization valueSerialization;
+ private JsonSerialization serialization;
@Service
IdentityGenerator identityGenerator;
@@ -107,7 +103,6 @@ public class JSONMapEntityStoreMixin
private Cache<CacheState> cache;
protected String uuid;
- private int count;
public JSONMapEntityStoreMixin()
{
@@ -142,102 +137,109 @@ public class JSONMapEntityStoreMixin
// EntityStore
@Override
- public EntityStoreUnitOfWork newUnitOfWork( ModuleDescriptor module, Usecase usecaseMetaInfo, Instant currentTime )
+ public EntityStoreUnitOfWork newUnitOfWork( ModuleDescriptor module, Usecase usecase, Instant currentTime )
{
- return new DefaultEntityStoreUnitOfWork( module, entityStoreSpi, newUnitOfWorkId(), usecaseMetaInfo, currentTime );
+ return new DefaultEntityStoreUnitOfWork( module, entityStoreSpi, newUnitOfWorkId(), usecase, currentTime );
}
// EntityStoreSPI
@Override
- public EntityState newEntityState( EntityStoreUnitOfWork unitOfWork,
+ public EntityState newEntityState( EntityStoreUnitOfWork uow,
EntityReference reference,
EntityDescriptor entityDescriptor
)
{
try
{
- JSONObject state = new JSONObject();
- state.put( JSONKeys.IDENTITY, reference.identity() );
- state.put( JSONKeys.APPLICATION_VERSION, application.version() );
- state.put( JSONKeys.TYPE, entityDescriptor.types().findFirst().get().getName() );
- state.put( JSONKeys.VERSION, unitOfWork.identity() );
- state.put( JSONKeys.MODIFIED, unitOfWork.currentTime().toEpochMilli() );
- state.put( JSONKeys.PROPERTIES, new JSONObject() );
- state.put( JSONKeys.ASSOCIATIONS, new JSONObject() );
- state.put( JSONKeys.MANY_ASSOCIATIONS, new JSONObject() );
- state.put( JSONKeys.NAMED_ASSOCIATIONS, new JSONObject() );
- return new JSONEntityState( entityDescriptor.module(),
- valueSerialization,
- "",
- unitOfWork.currentTime(),
+ JsonObjectBuilder builder = Json.createObjectBuilder();
+ builder.add( JSONKeys.IDENTITY, reference.identity().toString() );
+ builder.add( JSONKeys.APPLICATION_VERSION, application.version() );
+ builder.add( JSONKeys.TYPE, entityDescriptor.types().findFirst().get().getName() );
+ builder.add( JSONKeys.VERSION, uow.identity().toString() );
+ builder.add( JSONKeys.MODIFIED, uow.currentTime().toEpochMilli() );
+ builder.add( JSONKeys.PROPERTIES, Json.createObjectBuilder().build() );
+ builder.add( JSONKeys.ASSOCIATIONS, Json.createObjectBuilder().build() );
+ builder.add( JSONKeys.MANY_ASSOCIATIONS, Json.createObjectBuilder().build() );
+ builder.add( JSONKeys.NAMED_ASSOCIATIONS, Json.createObjectBuilder().build() );
+ JsonObject state = builder.build();
+ return new JSONEntityState( entityDescriptor.module(), serialization,
+ "", uow.currentTime(),
reference,
- EntityStatus.NEW,
- entityDescriptor,
+ EntityStatus.NEW, entityDescriptor,
state );
}
- catch( JSONException e )
+ catch( Exception e )
{
throw new EntityStoreException( e );
}
}
@Override
- public synchronized EntityState entityStateOf( EntityStoreUnitOfWork unitOfWork,
+ public synchronized EntityState entityStateOf( EntityStoreUnitOfWork uow,
ModuleDescriptor module,
- EntityReference reference
- )
+ EntityReference reference )
{
- EntityState state = fetchCachedState( reference, module, unitOfWork.currentTime() );
- if( state != null )
+ try
{
- return state;
+ EntityState state = fetchCachedState( reference, module, uow.currentTime() );
+ if( state != null )
+ {
+ return state;
+ }
+ // Get state
+ try( Reader in = mapEntityStore.get( reference ) )
+ {
+ JSONEntityState loadedState = readEntityState( module, in );
+ if( loadedState.status() == EntityStatus.UPDATED )
+ {
+ List<JSONEntityState> migrated = new ArrayList<>( 1 );
+ migrated.add( loadedState );
+ synchMigratedEntities( migrated );
+ }
+ if( doCacheOnRead( uow ) )
+ {
+ cache.put( reference.identity().toString(), new CacheState( loadedState.state() ) );
+ }
+ return loadedState;
+ }
}
- // Get state
- Reader in = mapEntityStore.get( reference );
- JSONEntityState loadedState = readEntityState( module, in );
- if( doCacheOnRead( unitOfWork ) )
+ catch( EntityStoreException ex )
{
- cache.put( reference.identity().toString(), new CacheState( loadedState.state() ) );
+ throw ex;
+ }
+ catch( Exception ex )
+ {
+ throw new EntityStoreException( ex );
}
- return loadedState;
}
@Override
- public synchronized String versionOf( EntityStoreUnitOfWork unitOfWork,
- EntityReference reference
- )
+ public synchronized String versionOf( EntityStoreUnitOfWork uow, EntityReference reference )
{
CacheState cacheState = cache.get( reference.identity().toString() );
if( cacheState != null )
{
- try
- {
- return cacheState.json.getString( JSONKeys.VERSION );
- }
- catch( JSONException e )
- {
- // Should not be able to happen, unless internal error in the cache system.
- throw new EntityStoreException( e );
- }
+ return cacheState.json.getString( JSONKeys.VERSION );
}
- // Get state
- Reader entityState = mapEntityStore.get( reference );
try
{
- JSONObject jsonObject = new JSONObject( new JSONTokener( entityState ) );
- return jsonObject.getString( JSONKeys.VERSION );
+ // Get state
+ Reader entityState = mapEntityStore.get( reference );
+ return Json.createReader( entityState ).readObject().getString( JSONKeys.VERSION );
}
- catch( JSONException e )
+ catch( EntityStoreException ex )
{
- throw new EntityStoreException( e );
+ throw ex;
+ }
+ catch( Exception ex )
+ {
+ throw new EntityStoreException( ex );
}
}
@Override
- public StateCommitter applyChanges( final EntityStoreUnitOfWork unitOfWork,
- final Iterable<EntityState> state
- )
+ public StateCommitter applyChanges( EntityStoreUnitOfWork uow, Iterable<EntityState> state )
throws EntityStoreException
{
return new StateCommitter()
@@ -250,10 +252,9 @@ public class JSONMapEntityStoreMixin
mapEntityStore.applyChanges( new MapEntityStore.MapChanges()
{
@Override
- public void visitMap( MapEntityStore.MapChanger changer )
- throws IOException
+ public void visitMap( MapEntityStore.MapChanger changer ) throws Exception
{
- CacheOptions options = unitOfWork.usecase().metaInfo( CacheOptions.class );
+ CacheOptions options = uow.usecase().metaInfo( CacheOptions.class );
if( options == null )
{
options = CacheOptions.ALWAYS;
@@ -262,26 +263,35 @@ public class JSONMapEntityStoreMixin
for( EntityState entityState : state )
{
JSONEntityState state = (JSONEntityState) entityState;
+ String newVersion = uow.identity().toString();
+ Instant lastModified = uow.currentTime();
if( state.status().equals( EntityStatus.NEW ) )
{
- try (Writer writer = changer.newEntity( state.entityReference(), state.entityDescriptor() ))
+ try( Writer writer = changer.newEntity( state.entityReference(),
+ state.entityDescriptor() ) )
{
- writeEntityState( state, writer, unitOfWork.identity().toString(), unitOfWork.currentTime() );
+ writeEntityState( state, writer, newVersion, lastModified );
}
if( options.cacheOnNew() )
{
- cache.put( state.entityReference().identity().toString(), new CacheState( state.state() ) );
+ cache.put( state.entityReference().identity().toString(),
+ new CacheState( state.state() ) );
}
}
else if( state.status().equals( EntityStatus.UPDATED ) )
{
- try (Writer writer = changer.updateEntity( state.entityReference(), state.entityDescriptor() ))
+ MapEntityStore.MapChange mapChange = new MapEntityStore.MapChange(
+ state.entityReference(), state.entityDescriptor(),
+ state.version(), newVersion, lastModified
+ );
+ try( Writer writer = changer.updateEntity( mapChange ) )
{
- writeEntityState( state, writer, unitOfWork.identity().toString(), unitOfWork.currentTime() );
+ writeEntityState( state, writer, newVersion, lastModified );
}
if( options.cacheOnWrite() )
{
- cache.put( state.entityReference().identity().toString(), new CacheState( state.state() ) );
+ cache.put( state.entityReference().identity().toString(),
+ new CacheState( state.state() ) );
}
}
else if( state.status().equals( EntityStatus.REMOVED ) )
@@ -293,7 +303,7 @@ public class JSONMapEntityStoreMixin
}
} );
}
- catch( IOException e )
+ catch( Exception e )
{
throw new EntityStoreException( e );
}
@@ -309,11 +319,13 @@ public class JSONMapEntityStoreMixin
@Override
public Stream<EntityState> entityStates( ModuleDescriptor module )
{
- List<EntityState> migrated = new ArrayList<>();
- return mapEntityStore.entityStates().map(
- reader ->
+ try
+ {
+ Stream<Reader> stateStream = mapEntityStore.entityStates();
+ List<JSONEntityState> migrated = new ArrayList<>();
+ Function<Reader, EntityState> function = reader ->
{
- EntityState entity = readEntityState( module, reader );
+ JSONEntityState entity = readEntityState( module, reader );
if( entity.status() == EntityStatus.UPDATED )
{
migrated.add( entity );
@@ -324,42 +336,55 @@ public class JSONMapEntityStoreMixin
}
}
return entity;
- }
- ).onClose(
- () ->
+ };
+ Runnable closer = () ->
{
// Synch any remaining migrated entities
if( !migrated.isEmpty() )
{
synchMigratedEntities( migrated );
}
- }
- );
+ };
+ return stateStream.map( function ).onClose( closer );
+ }
+ catch( EntityStoreException ex )
+ {
+ throw ex;
+ }
+ catch( Exception ex )
+ {
+ throw new EntityStoreException( ex );
+ }
}
- private void synchMigratedEntities( final List<EntityState> migratedEntities )
+ private void synchMigratedEntities( List<JSONEntityState> migratedEntities )
{
try
{
- mapEntityStore.applyChanges( new MapEntityStore.MapChanges()
- {
- @Override
- public void visitMap( MapEntityStore.MapChanger changer )
- throws IOException
+ mapEntityStore.applyChanges(
+ changer ->
{
- for( EntityState migratedEntity : migratedEntities )
+ for( JSONEntityState state : migratedEntities )
{
- JSONEntityState state = (JSONEntityState) migratedEntity;
- try( Writer writer = changer.updateEntity( state.entityReference(), state.entityDescriptor() ) )
+ Instant lastModified = state.lastModified();
+ String version = state.version();
+ MapEntityStore.MapChange changeInfo = new MapEntityStore.MapChange(
+ state.entityReference(), state.entityDescriptor(),
+ version, version, lastModified
+ );
+ try( Writer writer = changer.updateEntity( changeInfo ) )
{
- writeEntityState( state, writer, state.version(), state.lastModified() );
+ writeEntityState( state, writer, version, lastModified );
}
}
- }
- } );
+ } );
migratedEntities.clear();
}
- catch( IOException ex )
+ catch( EntityStoreException ex )
+ {
+ throw ex;
+ }
+ catch( Exception ex )
{
throw new EntityStoreException( "Synchronization of Migrated Entities failed.", ex );
}
@@ -367,20 +392,18 @@ public class JSONMapEntityStoreMixin
protected Identity newUnitOfWorkId()
{
- return identityGenerator.generate(EntityStore.class);
+ return identityGenerator.generate( EntityStore.class );
}
- protected void writeEntityState(JSONEntityState state, Writer writer, String version, Instant lastModified )
+ protected void writeEntityState( JSONEntityState state, Writer writer, String version, Instant lastModified )
throws EntityStoreException
{
try
{
- JSONObject jsonState = state.state();
- jsonState.put( JSONKeys.VERSION, version );
- jsonState.put( JSONKeys.MODIFIED, lastModified.toEpochMilli() );
- writer.append( jsonState.toString() );
+ state.stateCloneWithVersionAndModified( version, lastModified );
+ writer.append( state.state().toString() );
}
- catch( JSONException | IOException e )
+ catch( IOException e )
{
throw new EntityStoreException( "Could not store EntityState", e );
}
@@ -391,37 +414,38 @@ public class JSONMapEntityStoreMixin
{
try
{
- JSONObject jsonObject = new JSONObject( new JSONTokener( entityState ) );
+ JsonObject parsedState = Json.createReader( entityState ).readObject();
+ JsonObjectBuilder jsonStateBuilder = JavaxJson.toBuilder( parsedState );
EntityStatus status = EntityStatus.LOADED;
- String version = jsonObject.getString( JSONKeys.VERSION );
- Instant modified = Instant.ofEpochMilli(jsonObject.getLong( JSONKeys.MODIFIED ));
- Identity identity = new StringIdentity(jsonObject.getString( JSONKeys.IDENTITY ));
+ String version = parsedState.getString( JSONKeys.VERSION );
+ Instant modified = Instant.ofEpochMilli( parsedState.getJsonNumber( JSONKeys.MODIFIED ).longValueExact() );
+ Identity identity = new StringIdentity( parsedState.getString( JSONKeys.IDENTITY ) );
- // Check if NamedAssociation is supported
- if( !jsonObject.has( JSONKeys.NAMED_ASSOCIATIONS ) )
+ // Check if version is correct
+ JsonObject state;
+ String currentAppVersion = parsedState.getString( JSONKeys.APPLICATION_VERSION, "0.0" );
+ if( currentAppVersion.equals( application.version() ) )
{
- jsonObject.put( JSONKeys.NAMED_ASSOCIATIONS, new JSONObject() );
+ state = jsonStateBuilder.build();
}
-
- // Check if version is correct
- String currentAppVersion = jsonObject.optString( JSONKeys.APPLICATION_VERSION, "0.0" );
- if( !currentAppVersion.equals( application.version() ) )
+ else
{
if( migration != null )
{
- migration.migrate( jsonObject, application.version(), this );
+ state = migration.migrate( jsonStateBuilder.build(), application.version(), this );
}
else
{
// Do nothing - set version to be correct
- jsonObject.put( JSONKeys.APPLICATION_VERSION, application.version() );
+ jsonStateBuilder.add( JSONKeys.APPLICATION_VERSION, application.version() );
+ state = jsonStateBuilder.build();
}
// State changed
status = EntityStatus.UPDATED;
}
- String type = jsonObject.getString( JSONKeys.TYPE );
+ String type = state.getString( JSONKeys.TYPE );
EntityDescriptor entityDescriptor = module.entityDescriptor( type );
if( entityDescriptor == null )
@@ -429,33 +453,40 @@ public class JSONMapEntityStoreMixin
throw new NoSuchEntityTypeException( type, module.name(), module.typeLookup() );
}
- return new JSONEntityState( module,
- valueSerialization,
- version,
- modified,
+ return new JSONEntityState( module, serialization,
+ version, modified,
EntityReference.create( identity ),
- status,
- entityDescriptor,
- jsonObject
+ status, entityDescriptor,
+ state
);
}
- catch( JSONException e )
+ catch( EntityStoreException ex )
{
- throw new EntityStoreException( e );
+ throw ex;
+ }
+ catch( Exception ex )
+ {
+ throw new EntityStoreException( ex );
}
}
@Override
- public JSONObject jsonStateOf( String id )
- throws IOException
+ public JsonObject jsonStateOf( String id )
{
- try (Reader reader = mapEntityStore.get( EntityReference.parseEntityReference( id ) ))
+ try( Reader reader = mapEntityStore.get( EntityReference.parseEntityReference( id ) ) )
+ {
+ try( JsonReader jsonReader = Json.createReader( reader ) )
+ {
+ return jsonReader.readObject();
+ }
+ }
+ catch( EntityStoreException ex )
{
- return new JSONObject( new JSONTokener( reader ) );
+ throw ex;
}
- catch( JSONException e )
+ catch( Exception ex )
{
- throw new IOException( e );
+ throw new EntityStoreException( ex );
}
}
@@ -464,15 +495,20 @@ public class JSONMapEntityStoreMixin
CacheState cacheState = cache.get( reference.identity().toString() );
if( cacheState != null )
{
- JSONObject data = cacheState.json;
+ JsonObject data = cacheState.json;
try
{
String type = data.getString( JSONKeys.TYPE );
EntityDescriptor entityDescriptor = module.entityDescriptor( type );
- Instant lastModified = Instant.ofEpochMilli(data.getLong(JSONKeys.MODIFIED));
- return new JSONEntityState( module, valueSerialization, data.getString( JSONKeys.VERSION ), lastModified, reference, EntityStatus.LOADED, entityDescriptor, data );
+ String version = data.getString( JSONKeys.VERSION );
+ Instant lastModified = Instant.ofEpochMilli( data.getJsonNumber( JSONKeys.MODIFIED ).longValueExact() );
+ return new JSONEntityState( module, serialization,
+ version, lastModified,
+ reference,
+ EntityStatus.LOADED, entityDescriptor,
+ data );
}
- catch( JSONException e )
+ catch( Exception e )
{
// Should not be able to happen, unless internal error in the cache system.
throw new EntityStoreException( e );
@@ -490,13 +526,13 @@ public class JSONMapEntityStoreMixin
public static class CacheState
implements Externalizable
{
- public JSONObject json;
+ public JsonObject json;
public CacheState()
{
}
- private CacheState( JSONObject state )
+ private CacheState( JsonObject state )
{
json = state;
}
@@ -512,14 +548,7 @@ public class JSONMapEntityStoreMixin
public void readExternal( ObjectInput in )
throws IOException, ClassNotFoundException
{
- try
- {
- json = new JSONObject( in.readUTF() );
- }
- catch( JSONException e )
- {
- throw new IOException( e );
- }
+ json = Json.createReader( new StringReader( in.readUTF() ) ).readObject();
}
}
}
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c9dd7229/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONNamedAssociationState.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONNamedAssociationState.java b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONNamedAssociationState.java
index d37bb9c..74ea667 100644
--- a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONNamedAssociationState.java
+++ b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/JSONNamedAssociationState.java
@@ -19,42 +19,56 @@
*/
package org.apache.polygene.spi.entitystore.helpers;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
import java.util.NoSuchElementException;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import javax.json.Json;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
import org.apache.polygene.api.entity.EntityReference;
import org.apache.polygene.spi.entity.NamedAssociationState;
import org.apache.polygene.spi.entitystore.EntityStoreException;
/**
* JSON implementation of NamedAssociationState.
- * <p>Backed by a JSONObject.</p>
+ * <p>Backed by a JsonObject.</p>
*/
public final class JSONNamedAssociationState
implements NamedAssociationState
{
private final JSONEntityState entityState;
- private final JSONObject references;
+ private final String stateName;
- public JSONNamedAssociationState( JSONEntityState entityState, JSONObject references )
+ /* package */ JSONNamedAssociationState( JSONEntityState entityState, String stateName )
{
this.entityState = entityState;
- this.references = references;
+ this.stateName = stateName;
+ }
+
+ private JsonObject getReferences()
+ {
+ JsonObject namedAssociations = entityState.state().getJsonObject( JSONKeys.NAMED_ASSOCIATIONS );
+ JsonValue references = namedAssociations.get( stateName );
+ if( references != null && references.getValueType() == JsonValue.ValueType.OBJECT )
+ {
+ return (JsonObject) references;
+ }
+ return Json.createObjectBuilder().build();
}
@Override
public int count()
{
- return references.length();
+ return getReferences().size();
}
@Override
public boolean containsName( String name )
{
- return references.has( name );
+ return getReferences().containsKey( name );
}
@Override
@@ -62,16 +76,16 @@ public final class JSONNamedAssociationState
{
try
{
- if( references.has( name ) && entityReference.identity().toString().equals( references.getString( name ) ) )
+ if( containsName( name )
+ && entityReference.identity().toString().equals( getReferences().getString( name ) ) )
{
return false;
}
- entityState.cloneStateIfGlobalStateLoaded();
- references.put( name, entityReference.identity().toString() );
+ entityState.stateCloneAddNamedAssociation( stateName, name, entityReference );
entityState.markUpdated();
return true;
}
- catch( JSONException ex )
+ catch( JsonException ex )
{
throw new EntityStoreException( ex );
}
@@ -80,12 +94,11 @@ public final class JSONNamedAssociationState
@Override
public boolean remove( String name )
{
- if( !references.has( name ) )
+ if( !containsName( name ) )
{
return false;
}
- entityState.cloneStateIfGlobalStateLoaded();
- references.remove( name );
+ entityState.stateCloneRemoveNamedAssociation( stateName, name );
entityState.markUpdated();
return true;
}
@@ -93,29 +106,18 @@ public final class JSONNamedAssociationState
@Override
public EntityReference get( String name )
{
- try
- {
- return EntityReference.parseEntityReference( references.getString( name ) );
- }
- catch( JSONException ex )
- {
- return null;
- }
+ String stringRef = getReferences().getString( name, null );
+ return stringRef == null ? null : EntityReference.parseEntityReference( stringRef );
}
@Override
public String nameOf( EntityReference entityReference )
{
- JSONArray names = references.names();
- if( names == null )
- {
- return null;
- }
try
{
- for( int idx = 0; idx < names.length(); idx++ )
+ JsonObject references = getReferences();
+ for( String name : references.keySet() )
{
- String name = names.getString( idx );
if( entityReference.identity().toString().equals( references.getString( name ) ) )
{
return name;
@@ -123,7 +125,7 @@ public final class JSONNamedAssociationState
}
return null;
}
- catch( JSONException ex )
+ catch( JsonException ex )
{
throw new EntityStoreException( ex );
}
@@ -132,7 +134,7 @@ public final class JSONNamedAssociationState
@Override
public Iterator<String> iterator()
{
- final JSONArray names = references.names() == null ? new JSONArray() : references.names();
+ List<String> names = new ArrayList<>( getReferences().keySet() );
return new Iterator<String>()
{
private int idx = 0;
@@ -140,7 +142,7 @@ public final class JSONNamedAssociationState
@Override
public boolean hasNext()
{
- return idx < names.length();
+ return idx < names.size();
}
@Override
@@ -148,11 +150,11 @@ public final class JSONNamedAssociationState
{
try
{
- String next = names.getString( idx );
+ String next = names.get( idx );
idx++;
return next;
}
- catch( JSONException ex )
+ catch( JsonException ex )
{
throw new NoSuchElementException();
}
@@ -169,7 +171,6 @@ public final class JSONNamedAssociationState
@Override
public String toString()
{
- return references.toString();
+ return getReferences().toString();
}
-
}
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/c9dd7229/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/MapEntityStore.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/MapEntityStore.java b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/MapEntityStore.java
index a8ff1c9..901c2c1 100644
--- a/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/MapEntityStore.java
+++ b/core/spi/src/main/java/org/apache/polygene/spi/entitystore/helpers/MapEntityStore.java
@@ -22,48 +22,41 @@ package org.apache.polygene.spi.entitystore.helpers;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
+import java.time.Instant;
import java.util.stream.Stream;
import org.apache.polygene.api.entity.EntityDescriptor;
import org.apache.polygene.api.entity.EntityReference;
-import org.apache.polygene.spi.entitystore.EntityNotFoundException;
-import org.apache.polygene.spi.entitystore.EntityStoreException;
/**
* MapEntityStore.
*/
public interface MapEntityStore
{
-
/**
* @param entityReference The reference to the entity that we want to get.
* @return Entity state Reader
*/
- Reader get( EntityReference entityReference )
- throws EntityStoreException;
+ Reader get( EntityReference entityReference ) throws Exception;
/**
* @return All entities state Readers, must be closed
*/
- Stream<Reader> entityStates();
+ Stream<Reader> entityStates() throws Exception;
- void applyChanges( MapChanges changes )
- throws IOException;
+ void applyChanges( MapChanges changes ) throws Exception;
/**
* Changes to be applied on a MapEntityStore.
*/
interface MapChanges
{
-
/**
* Visitable MapChanges.
*
* @param changer Map changer
* @throws IOException on error
*/
- void visitMap( MapChanger changer )
- throws IOException;
-
+ void visitMap( MapChanger changer ) throws Exception;
}
/**
@@ -71,16 +64,65 @@ public interface MapEntityStore
*/
interface MapChanger
{
-
Writer newEntity( EntityReference ref, EntityDescriptor entityDescriptor )
- throws IOException;
+ throws Exception;
- Writer updateEntity( EntityReference ref, EntityDescriptor entityDescriptor )
- throws IOException;
+ Writer updateEntity( MapChange mapChange ) throws Exception;
void removeEntity( EntityReference ref, EntityDescriptor entityDescriptor )
- throws EntityNotFoundException;
-
+ throws Exception;
}
+ /**
+ * MapEntityStore change meta info.
+ *
+ * Implementations backed by a shared store can make use of this for e.g. optimistic locking.
+ */
+ class MapChange
+ {
+ private final EntityReference reference;
+ private final EntityDescriptor descriptor;
+ private final String previousVersion;
+ private final String newVersion;
+ private final Instant lastModified;
+
+ public MapChange( EntityReference reference, EntityDescriptor descriptor,
+ String previousVersion, String newVersion,
+ Instant lastModified )
+ {
+ this.reference = reference;
+ this.descriptor = descriptor;
+ this.previousVersion = previousVersion;
+ this.newVersion = newVersion;
+ this.lastModified = lastModified;
+ }
+
+ public EntityReference reference()
+ {
+ return reference;
+ }
+
+ public EntityDescriptor descriptor()
+ {
+ return descriptor;
+ }
+
+ /**
+ * @return null if the change is an insertion
+ */
+ public String previousVersion()
+ {
+ return previousVersion;
+ }
+
+ public String newVersion()
+ {
+ return newVersion;
+ }
+
+ public Instant lastModified()
+ {
+ return lastModified;
+ }
+ }
}