blob: be48cd3cc38ae6f52ad7bc056f7f2c95550d6f6b [file] [log] [blame]
/*
* Copyright (c) 2008-2011, Rickard Öberg. All Rights Reserved.
*
* Licensed 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.zest.library.rdf.entity;
import org.openrdf.model.BNode;
import org.openrdf.model.Graph;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.impl.GraphImpl;
import org.apache.zest.api.Qi4j;
import org.apache.zest.api.association.AssociationDescriptor;
import org.apache.zest.api.composite.Composite;
import org.apache.zest.api.entity.EntityDescriptor;
import org.apache.zest.api.entity.EntityReference;
import org.apache.zest.api.injection.scope.Service;
import org.apache.zest.api.property.PropertyDescriptor;
import org.apache.zest.api.service.qualifier.Tagged;
import org.apache.zest.api.type.ValueCompositeType;
import org.apache.zest.api.type.ValueType;
import org.apache.zest.api.util.Classes;
import org.apache.zest.api.value.ValueComposite;
import org.apache.zest.api.value.ValueSerialization;
import org.apache.zest.api.value.ValueSerializer;
import org.apache.zest.api.value.ValueSerializer.Options;
import org.apache.zest.library.rdf.Rdfs;
import org.apache.zest.spi.entity.EntityState;
import org.apache.zest.spi.entity.ManyAssociationState;
import static org.apache.zest.functional.Iterables.first;
/**
* JAVADOC
*/
public class EntityStateSerializer
{
@Service
@Tagged( ValueSerialization.Formats.JSON )
private ValueSerializer valueSerializer;
public URI createEntityURI( ValueFactory valueFactory, EntityReference identity )
{
return valueFactory.createURI( identity.toURI() );
}
public Iterable<Statement> serialize( final EntityState entityState )
{
return serialize( entityState, true );
}
public Iterable<Statement> serialize( final EntityState entityState,
final boolean includeNonQueryable )
{
Graph graph = new GraphImpl();
serialize( entityState, includeNonQueryable, graph );
return graph;
}
public void serialize( final EntityState entityState,
final boolean includeNonQueryable,
final Graph graph )
{
ValueFactory values = graph.getValueFactory();
EntityReference identity = entityState.identity();
URI entityUri = createEntityURI( values, identity );
graph.add( entityUri,
Rdfs.TYPE,
values.createURI( Classes.toURI( first( entityState.entityDescriptor().types() ) ) ) );
serializeProperties( entityState,
graph,
entityUri,
entityState.entityDescriptor(),
includeNonQueryable );
serializeAssociations( entityState,
graph,
entityUri,
entityState.entityDescriptor().state().associations(),
includeNonQueryable );
serializeManyAssociations( entityState,
graph,
entityUri,
entityState.entityDescriptor().state().manyAssociations(),
includeNonQueryable );
}
private void serializeProperties( final EntityState entityState,
final Graph graph,
final Resource subject,
final EntityDescriptor entityType,
final boolean includeNonQueryable )
{
// Properties
for( PropertyDescriptor persistentProperty : entityType.state().properties() )
{
Object property = entityState.propertyValueOf( persistentProperty.qualifiedName() );
if( property != null )
{
serializeProperty( persistentProperty, property, subject, graph, includeNonQueryable );
}
}
}
private void serializeProperty( PropertyDescriptor persistentProperty,
Object property,
Resource subject,
Graph graph,
boolean includeNonQueryable )
{
if( !( includeNonQueryable || persistentProperty.queryable() ) )
{
return; // Skip non-queryable
}
ValueType valueType = persistentProperty.valueType();
final ValueFactory valueFactory = graph.getValueFactory();
String propertyURI = persistentProperty.qualifiedName().toURI();
URI predicate = valueFactory.createURI( propertyURI );
String baseURI = propertyURI.substring( 0, propertyURI.indexOf( '#' ) ) + "/";
if( valueType instanceof ValueCompositeType )
{
serializeValueComposite( subject, predicate, (ValueComposite) property, valueType,
graph, baseURI, includeNonQueryable );
}
else
{
String stringProperty = valueSerializer.serialize( new Options().withoutTypeInfo(), property );
final Literal object = valueFactory.createLiteral( stringProperty );
graph.add( subject, predicate, object );
}
}
private void serializeValueComposite( Resource subject, URI predicate,
ValueComposite value,
ValueType valueType,
Graph graph,
String baseUri,
boolean includeNonQueryable )
{
final ValueFactory valueFactory = graph.getValueFactory();
BNode collection = valueFactory.createBNode();
graph.add( subject, predicate, collection );
for( PropertyDescriptor persistentProperty : ( (ValueCompositeType) valueType ).properties() )
{
Object propertyValue = Qi4j.FUNCTION_COMPOSITE_INSTANCE_OF
.map( (Composite) value )
.state()
.propertyFor( persistentProperty.accessor() )
.get();
if( propertyValue == null )
{
continue; // Skip null values
}
ValueType type = persistentProperty.valueType();
if( type instanceof ValueCompositeType )
{
URI pred = valueFactory.createURI( baseUri, persistentProperty.qualifiedName().name() );
serializeValueComposite( collection, pred, (ValueComposite) propertyValue, type, graph,
baseUri + persistentProperty.qualifiedName().name() + "/",
includeNonQueryable );
}
else
{
serializeProperty( persistentProperty, propertyValue, collection, graph, includeNonQueryable );
}
}
}
private void serializeAssociations( final EntityState entityState,
final Graph graph, URI entityUri,
final Iterable<? extends AssociationDescriptor> associations,
final boolean includeNonQueryable )
{
ValueFactory values = graph.getValueFactory();
// Associations
for( AssociationDescriptor associationType : associations )
{
if( !( includeNonQueryable || associationType.queryable() ) )
{
continue; // Skip non-queryable
}
EntityReference associatedId = entityState.associationValueOf( associationType.qualifiedName() );
if( associatedId != null )
{
URI assocURI = values.createURI( associationType.qualifiedName().toURI() );
URI assocEntityURI = values.createURI( associatedId.toURI() );
graph.add( entityUri, assocURI, assocEntityURI );
}
}
}
private void serializeManyAssociations( final EntityState entityState,
final Graph graph,
final URI entityUri,
final Iterable<? extends AssociationDescriptor> associations,
final boolean includeNonQueryable )
{
ValueFactory values = graph.getValueFactory();
// Many-Associations
for( AssociationDescriptor associationType : associations )
{
if( !( includeNonQueryable || associationType.queryable() ) )
{
continue; // Skip non-queryable
}
BNode collection = values.createBNode();
graph.add( entityUri, values.createURI( associationType.qualifiedName().toURI() ), collection );
graph.add( collection, Rdfs.TYPE, Rdfs.SEQ );
ManyAssociationState associatedIds = entityState.manyAssociationValueOf( associationType.qualifiedName() );
for( EntityReference associatedId : associatedIds )
{
URI assocEntityURI = values.createURI( associatedId.toURI() );
graph.add( collection, Rdfs.LIST_ITEM, assocEntityURI );
}
}
}
}