package org.qi4j.entitystore.neo4j; import java.io.File; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.neo4j.index.IndexService; import org.neo4j.index.lucene.LuceneIndexService; import org.neo4j.kernel.EmbeddedGraphDatabase; import org.qi4j.api.common.Optional; import org.qi4j.api.configuration.Configuration; import org.qi4j.api.entity.EntityDescriptor; import org.qi4j.api.entity.EntityReference; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.This; import org.qi4j.api.service.ServiceActivation; import org.qi4j.api.service.qualifier.Tagged; import org.qi4j.api.structure.Module; import org.qi4j.api.usecase.Usecase; import org.qi4j.api.value.ValueSerialization; import org.qi4j.io.Input; import org.qi4j.io.Output; import org.qi4j.io.Receiver; import org.qi4j.io.Sender; import org.qi4j.library.fileconfig.FileConfiguration; import org.qi4j.spi.entity.EntityState; import org.qi4j.spi.entity.EntityStatus; import org.qi4j.spi.entitystore.*; public class NeoEntityStoreMixin implements ServiceActivation, EntityStore, EntityStoreSPI { @Optional @Service FileConfiguration fileConfiguration; @Service @Tagged( ValueSerialization.Formats.JSON ) private ValueSerialization valueSerialization; @This private Configuration<NeoConfiguration> config; private EmbeddedGraphDatabase neo; private IndexService indexService; private AtomicInteger count = new AtomicInteger(0); private String uuid; @Override public void activateService() throws Exception { String path = config.get().path().get(); if (path == null) { if (fileConfiguration != null) path = new File(fileConfiguration.dataDirectory(), config.get().identity().get()).getAbsolutePath(); else path = "build/neodb"; } neo = new EmbeddedGraphDatabase(path); indexService = new LuceneIndexService(neo); uuid = UUID.randomUUID().toString() + "-"; } @Override public void passivateService() throws Exception { indexService.shutdown(); neo.shutdown(); } @Override public EntityStoreUnitOfWork newUnitOfWork( Usecase usecase, Module module, long currentTime ) { return new NeoEntityStoreUnitOfWork(neo, indexService, valueSerialization, newUnitOfWorkId(), module, currentTime); } @Override public Input<EntityState, EntityStoreException> entityStates(final Module module) { return new Input<EntityState, EntityStoreException>() { @Override public <ReceiverThrowableType extends Throwable> void transferTo(Output<? super EntityState, ReceiverThrowableType> output) throws EntityStoreException, ReceiverThrowableType { output.receiveFrom(new Sender<EntityState, EntityStoreException>() { @Override public <ReceiverThrowableType extends Throwable> void sendTo(Receiver<? super EntityState, ReceiverThrowableType> receiver) throws ReceiverThrowableType, EntityStoreException { NeoEntityStoreUnitOfWork uow = new NeoEntityStoreUnitOfWork(neo, indexService, valueSerialization, newUnitOfWorkId(), module, System.currentTimeMillis()); try { Iterable<Relationship> relationships = neo.getReferenceNode().getRelationships(RelTypes.ENTITY_TYPE_REF, Direction.OUTGOING); for (Relationship entityTypeRel : relationships) { Node entityType = entityTypeRel.getEndNode(); for (Relationship entityRel : entityType.getRelationships(RelTypes.IS_OF_TYPE, Direction.INCOMING)) { Node entityNode = entityRel.getStartNode(); NeoEntityState entityState = new NeoEntityState( valueSerialization, uow, entityNode, EntityStatus.LOADED); receiver.receive(entityState); } } } finally { uow.discard(); } } }); } }; } @Override public StateCommitter applyChanges( EntityStoreUnitOfWork unitofwork, Iterable<EntityState> state ) { for (EntityState firstState : state) { if (firstState instanceof NeoEntityState) { return ((NeoEntityState) firstState).unitOfWork().applyChanges(); } } return null; } @Override public EntityState entityStateOf( EntityStoreUnitOfWork unitOfWork, EntityReference identity ) { return unitOfWork.entityStateOf( identity ); } @Override public EntityState newEntityState( EntityStoreUnitOfWork uow, EntityReference ref, EntityDescriptor descriptor ) { return uow.newEntityState(ref, descriptor); } private String newUnitOfWorkId() { return uuid + Integer.toHexString(count.incrementAndGet()); } }