/* Copyright 2008 Edward Yakop.
*
* 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.qi4j.entitystore.qrm.internal;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.qi4j.api.common.QualifiedName;
import org.qi4j.api.common.TypeName;
import org.qi4j.entitystore.qrm.IdentifierConverter;
import org.qi4j.spi.entity.EntityStatus;
import org.qi4j.spi.entity.EntityType;
import org.qi4j.spi.entity.QualifiedIdentity;
import org.qi4j.spi.entity.association.AssociationDescriptor;
import org.qi4j.spi.entity.association.AssociationType;
import org.qi4j.spi.entitystore.EntityNotFoundException;
import org.qi4j.spi.property.PropertyDescriptor;
import org.qi4j.spi.property.PropertyType;
import static org.qi4j.api.util.NullArgumentException.*;
import static org.qi4j.spi.entity.EntityStatus.*;
/**
* {@code IBatisEntityState} represents {@code IBatis} version of {@link org.qi4j.spi.entity.EntityState}.
*/
public final class QrmEntityState
// implements EntityState, Serializable
{
private static final long serialVersionUID = 1L;
private final EntityType entityType;
private final QualifiedIdentity identity;
private final Map<QualifiedName, Object> propertyValues = new HashMap<QualifiedName, Object>();
private final Map<QualifiedName, QualifiedIdentity> associations = new HashMap<QualifiedName, QualifiedIdentity>();
private final Map<QualifiedName, Collection<QualifiedIdentity>> manyAssociations = new HashMap<QualifiedName, Collection<QualifiedIdentity>>();
private long version;
private long lastModified;
private EntityStatus status;
private IdentifierConverter identifierConverter = new CapitalizingIdentifierConverter();
/**
* Construct an instance of {@code IBatisEntityState}.
*
* @param entityType The entityType of this State. This argument must not be {@code null}.
* @param identity The identity. This argument must not be {@code null}.
* @param rawData The field values of this entity state. This argument must not be {@code null}.
* @param version The version of the state.
* @param status The current status of the state. This argument must not be {@code null}.
* @param lastModified The last modification date.
*
* @throws IllegalArgumentException if any of the following arguments are null; entityType, identity, rawData, status
*/
public QrmEntityState(
final EntityType entityType, final QualifiedIdentity identity,
final Map<QualifiedName, Object> rawData,
final long version, final long lastModified,
final EntityStatus status
)
throws IllegalArgumentException
{
validateNotNull( "aDescriptor", entityType );
validateNotNull( "anIdentity", identity );
validateNotNull( "propertyValuez", rawData );
validateNotNull( "aStatus", status );
// TODO validateNotNull( "aVersion", aVersion );
this.entityType = entityType;
this.identity = identity;
this.status = status;
mapData( entityType, rawData );
this.version = version;
this.lastModified = lastModified;
}
private void mapData( final EntityType entityType, final Map<QualifiedName, Object> rawData )
{
Map<String, Object> convertedData = identifierConverter.convertKeys( rawData );
System.err.println( rawData );
System.err.println( convertedData );
mapProperties( convertedData, entityType );
mapAssociations( convertedData, entityType );
}
private void mapAssociations( final Map<String, Object> rawData, final EntityType stateDescriptor )
{
for( final AssociationType associationDescriptor : stateDescriptor.associations() )
{
final QualifiedName qualifiedName = associationDescriptor.qualifiedName();
final String typeName = associationDescriptor.type().name();
final String associationId = (String) identifierConverter.getValueFromData( rawData, qualifiedName );
if( associationId != null )
{
setAssociation( qualifiedName, new QualifiedIdentity( associationId, typeName ) );
}
}
for( final AssociationType associationDescriptor : stateDescriptor.manyAssociations() )
{
final QualifiedName qualifiedName = associationDescriptor.qualifiedName();
final TypeName typeName = associationDescriptor.type();
Collection<String> identifiers = (Collection<String>) identifierConverter.getValueFromData( rawData, qualifiedName );
if( identifiers != null && !identifiers.isEmpty() )
{
setManyAssociation( qualifiedName, createQualifiedIdentities( identifiers, typeName, associationDescriptor ) );
}
}
}
private Collection<QualifiedIdentity> createQualifiedIdentities( final Collection<String> identifiers,
final TypeName typeName,
AssociationType associationType
)
{
final int size = identifiers.size();
final Collection<QualifiedIdentity> qualifiedIdentities = createManyAssociationCollection( size, associationType );
for( String identifier : identifiers )
{
qualifiedIdentities.add( new QualifiedIdentity( identifier, typeName ) );
}
return qualifiedIdentities;
}
private Collection<QualifiedIdentity> createManyAssociationCollection( int size,
AssociationType associationType
)
{
return new ArrayList<QualifiedIdentity>( size );
}
private void mapProperties( final Map<String, Object> rawData, final EntityType compositeModel )
{
for( final PropertyType propertyDescriptor : compositeModel.properties() )
{
final QualifiedName qualifiedName = propertyDescriptor.qualifiedName();
final Object value = identifierConverter.getValueFromData( rawData, qualifiedName );
setProperty( qualifiedName, convertValue( propertyDescriptor, value ) );
}
}
private Object convertValue( final PropertyType propertyDescriptor, final Object value )
{
return value; // TODO Implement value conversion
}
private Class getPropertyTypeClass( final PropertyDescriptor propertyModel )
{
if( propertyModel.type() instanceof Class )
{
return (Class) propertyModel.type();
}
return null;
}
private String getTypeName( final AssociationDescriptor associationModel )
{
final Type associationType = associationModel.type();
if( associationType instanceof Class )
{
final Class type = (Class) associationType;
return type.getName();
}
return associationType.toString();
}
/**
* Returns the identity of the entity that this EntityState represents.
*
* @return the identity of the entity that this EntityState represents.
*/
public QualifiedIdentity qualifiedIdentity()
{
return identity;
}
public long version()
{
return version;
}
public long lastModified()
{
return lastModified;
}
public void remove()
{
status = REMOVED;
}
/**
* Returns the status of entity represented by this entity state.
*
* @return The status of entity represented by this entity state.
*/
public final EntityStatus status()
{
return status;
}
public EntityType entityType()
{
return entityType;
}
/**
* Returns the property value given the property qualified name.
*
* @param qualifiedName The property qualified name. This argument must not be {@code null}.
*
* @return The property value given qualified name.
*/
public final Object getProperty( final QualifiedName qualifiedName )
{
return propertyValues.get( qualifiedName );
}
public void setProperty( final QualifiedName qualifiedName, final Object newValue )
{
propertyValues.put( qualifiedName, newValue );
}
public QualifiedIdentity getAssociation( final QualifiedName qualifiedName )
{
if( status == REMOVED )
{
return null;
}
if( !associations.containsKey( qualifiedName ) )
{
return null;
}
final QualifiedIdentity qualifiedIdentity = associations.get( qualifiedName );
return qualifiedIdentity == null ? QualifiedIdentity.NULL : qualifiedIdentity;
}
public void setAssociation( final QualifiedName qualifiedName, final QualifiedIdentity qualifiedIdentity )
{
if( status == REMOVED )
{
throw new EntityNotFoundException( null );
}
associations.put( qualifiedName, qualifiedIdentity != null ? qualifiedIdentity : QualifiedIdentity.NULL );
}
public Collection<QualifiedIdentity> getManyAssociation( final QualifiedName qualifiedName )
{
if( status == REMOVED )
{
return null;
}
return manyAssociations.get( qualifiedName );
}
public Collection<QualifiedIdentity> setManyAssociation(
final QualifiedName qualifiedName, final Collection<QualifiedIdentity> newManyAssociations
)
{
validateNotNull( "qualifiedName", qualifiedName );
if( status == REMOVED )
{
throw new EntityNotFoundException( null );
}
return manyAssociations.put( qualifiedName, newManyAssociations );
}
public String convertIdentifier( final QualifiedName qualifiedIdentifier )
{
return identifierConverter.convertIdentifier( qualifiedIdentifier );
}
public final Iterable<QualifiedName> propertyNames()
{
return Collections.unmodifiableSet( propertyValues.keySet() );
}
public final Iterable<QualifiedName> associationNames()
{
return Collections.unmodifiableSet( associations.keySet() );
}
public final Iterable<QualifiedName> manyAssociationNames()
{
return Collections.unmodifiableSet( manyAssociations.keySet() );
}
public Map<QualifiedName, Object> getPropertyValues()
{
return propertyValues;
}
public void hasBeenApplied()
{
status = EntityStatus.LOADED;
version++;
}
}