package org.javers.core.snapshot;
import org.javers.common.collections.Defaults;
import org.javers.common.collections.EnumerableFunction;
import org.javers.common.exception.JaversException;
import org.javers.core.commit.CommitMetadata;
import org.javers.core.metamodel.object.*;
import org.javers.core.metamodel.property.Property;
import org.javers.core.metamodel.type.*;
import java.util.Objects;
import static org.javers.common.exception.JaversExceptionCode.NOT_IMPLEMENTED;
import static org.javers.core.metamodel.object.CdoSnapshotBuilder.cdoSnapshot;
import static org.javers.core.metamodel.object.SnapshotType.*;
/**
* @author bartosz walacik
*/
public class SnapshotFactory {
private final TypeMapper typeMapper;
private final GlobalIdFactory globalIdFactory;
public SnapshotFactory(TypeMapper typeMapper, GlobalIdFactory globalIdFactory) {
this.typeMapper = typeMapper;
this.globalIdFactory = globalIdFactory;
}
public CdoSnapshot createTerminal(GlobalId globalId, CdoSnapshot previous, CommitMetadata commitMetadata) {
ManagedType managedType = typeMapper.getJaversManagedType(globalId);
return cdoSnapshot()
.withGlobalId(globalId)
.withManagedType(managedType)
.withCommitMetadata(commitMetadata)
.withType(TERMINAL)
.withVersion(previous.getVersion()+1)
.build();
}
public CdoSnapshot createInitial(CdoWrapper cdoWrapper, CommitMetadata commitMetadata) {
return initSnapshotBuilder(cdoWrapper, commitMetadata)
.withState(createSnapshotState(cdoWrapper))
.withType(INITIAL)
.markAllAsChanged()
.withVersion(1L)
.build();
}
public CdoSnapshot createUpdate(CdoWrapper cdoWrapper, CdoSnapshot previous, CommitMetadata commitMetadata) {
return initSnapshotBuilder(cdoWrapper, commitMetadata)
.withState(createSnapshotState(cdoWrapper))
.withType(UPDATE)
.markChanged(previous)
.withVersion(previous.getVersion()+1)
.build();
}
public CdoSnapshotState createSnapshotState(CdoWrapper cdoWrapper){
CdoSnapshotStateBuilder stateBuilder = CdoSnapshotStateBuilder.cdoSnapshotState();
for (JaversProperty property : cdoWrapper.getManagedType().getProperties()) {
Object propertyVal = cdoWrapper.getPropertyValue(property.getName());
if (Objects.equals(propertyVal, Defaults.defaultValue(property.getGenericType()))) {
continue;
}
stateBuilder.withPropertyValue(property, dehydrateProperty(property, propertyVal, cdoWrapper.getGlobalId()));
}
return stateBuilder.build();
}
private Object extractAndDehydrateEnumerable(Object propertyVal, EnumerableType propertyType, OwnerContext owner) {
EnumerableFunction dehydratorMapFunction;
if (propertyType instanceof ContainerType) {
JaversType itemType = typeMapper.getJaversType( ((ContainerType)propertyType).getItemClass() );
dehydratorMapFunction = new DehydrateContainerFunction(itemType, globalIdFactory);
}
else if (propertyType instanceof KeyValueType) {
MapContentType mapContentType = typeMapper.getMapContentType((KeyValueType) propertyType);
dehydratorMapFunction = new DehydrateMapFunction(globalIdFactory, mapContentType);
}
else {
throw new JaversException(NOT_IMPLEMENTED);
}
return propertyType.map(propertyVal, dehydratorMapFunction, owner);
}
private CdoSnapshotBuilder initSnapshotBuilder(CdoWrapper cdoWrapper, CommitMetadata commitMetadata) {
return cdoSnapshot()
.withGlobalId(cdoWrapper.getGlobalId())
.withCommitMetadata(commitMetadata)
.withManagedType(cdoWrapper.getManagedType());
}
private Object dehydrateProperty(JaversProperty property, Object propertyVal, GlobalId id){
OwnerContext owner = new PropertyOwnerContext(id, property.getName());
if (property.getType() instanceof EnumerableType) {
return extractAndDehydrateEnumerable(propertyVal, (EnumerableType) property.getType(), owner);
} else {
return globalIdFactory.dehydrate(propertyVal, property.getType(), owner);
}
}
}