use of org.qi4j.spi.entity.EntityState in project qi4j-sdk by Qi4j.
the class JSONMapEntityStoreMixin method entityStateOf.
@Override
public synchronized EntityState entityStateOf(EntityStoreUnitOfWork unitOfWork, EntityReference identity) {
EntityState state = fetchCachedState(identity, (DefaultEntityStoreUnitOfWork) unitOfWork);
if (state != null) {
return state;
}
// Get state
Reader in = mapEntityStore.get(identity);
JSONEntityState loadedState = readEntityState((DefaultEntityStoreUnitOfWork) unitOfWork, in);
if (doCacheOnRead((DefaultEntityStoreUnitOfWork) unitOfWork)) {
cache.put(identity.identity(), new CacheState(loadedState.state()));
}
return loadedState;
}
use of org.qi4j.spi.entity.EntityState in project qi4j-sdk by Qi4j.
the class DefaultEntityStoreUnitOfWork method entityStateOf.
@Override
public EntityState entityStateOf(EntityReference anIdentity) throws EntityNotFoundException {
EntityState entityState = states.get(anIdentity);
if (entityState != null) {
return entityState;
}
entityState = entityStoreSPI.entityStateOf(this, anIdentity);
states.put(anIdentity, entityState);
return entityState;
}
use of org.qi4j.spi.entity.EntityState in project qi4j-sdk by Qi4j.
the class SQLEntityStoreMixin method applyChanges.
@Override
public StateCommitter applyChanges(final EntityStoreUnitOfWork unitofwork, final Iterable<EntityState> states) {
return new StateCommitter() {
@Override
public void commit() {
Connection connection = null;
PreparedStatement insertPS = null;
PreparedStatement updatePS = null;
PreparedStatement removePS = null;
try {
connection = database.getConnection();
connection.setAutoCommit(false);
insertPS = database.prepareInsertEntityStatement(connection);
updatePS = database.prepareUpdateEntityStatement(connection);
removePS = database.prepareRemoveEntityStatement(connection);
for (EntityState state : states) {
EntityStatus status = state.status();
DefaultEntityState defState = ((SQLEntityState) state).getDefaultEntityState();
Long entityPK = ((SQLEntityState) state).getEntityPK();
if (EntityStatus.REMOVED.equals(status)) {
database.populateRemoveEntityStatement(removePS, entityPK, state.identity());
removePS.addBatch();
} else {
StringWriter writer = new StringWriter();
writeEntityState(defState, writer, unitofwork.identity());
writer.flush();
if (EntityStatus.UPDATED.equals(status)) {
Long entityOptimisticLock = ((SQLEntityState) state).getEntityOptimisticLock();
database.populateUpdateEntityStatement(updatePS, entityPK, entityOptimisticLock, defState.identity(), writer.toString(), unitofwork.currentTime());
updatePS.addBatch();
} else if (EntityStatus.NEW.equals(status)) {
database.populateInsertEntityStatement(insertPS, defState.identity(), writer.toString(), unitofwork.currentTime());
insertPS.addBatch();
}
}
}
removePS.executeBatch();
insertPS.executeBatch();
updatePS.executeBatch();
connection.commit();
} catch (SQLException sqle) {
SQLUtil.rollbackQuietly(connection);
if (LOGGER.isDebugEnabled()) {
StringWriter sb = new StringWriter();
sb.append("SQLException during commit, logging nested exceptions before throwing EntityStoreException:\n");
SQLException e = sqle;
while (e != null) {
e.printStackTrace(new PrintWriter(sb, true));
e = e.getNextException();
}
LOGGER.debug(sb.toString());
}
throw new EntityStoreException(sqle);
} catch (RuntimeException re) {
SQLUtil.rollbackQuietly(connection);
throw new EntityStoreException(re);
} finally {
SQLUtil.closeQuietly(insertPS);
SQLUtil.closeQuietly(updatePS);
SQLUtil.closeQuietly(removePS);
SQLUtil.closeQuietly(connection);
}
}
@Override
public void cancel() {
}
};
}
use of org.qi4j.spi.entity.EntityState in project qi4j-sdk by Qi4j.
the class AbstractSQLIndexing method indexEntities.
@Override
public void indexEntities(Iterable<EntityState> changedStates) throws SQLException {
final String schemaName = this._state.schemaName().get();
final SQLVendor vendor = this.descriptor.metaInfo(SQLVendor.class);
Connection connectionTest = AbstractSQLStartup.CONNECTION_FOR_REINDEXING.get();
boolean connectionFromStartupWasNull = connectionTest == null;
boolean wasAutoCommit = false;
boolean wasReadOnly = false;
if (connectionFromStartupWasNull) {
connectionTest = this._dataSource.getConnection();
} else {
wasAutoCommit = connectionTest.getAutoCommit();
wasReadOnly = connectionTest.isReadOnly();
}
final Connection connection = connectionTest;
PreparedStatement updateEntityTablePS = null;
PreparedStatement removeEntityPS = null;
PreparedStatement insertToPropertyQNamesPS = null;
PreparedStatement clearEntityDataPS = null;
Lazy<PreparedStatement, SQLException> queryEntityPKPS = new Lazy<>(new LazyInit<PreparedStatement, SQLException>() {
@Override
public PreparedStatement create() throws SQLException {
return connection.prepareStatement(vendor.toString(createQueryEntityPkByIdentityStatement(schemaName, vendor)));
}
});
Lazy<PreparedStatement, SQLException> insertToEntityTableAutoGenerated = new Lazy<>(new LazyInit<PreparedStatement, SQLException>() {
@Override
public PreparedStatement create() throws SQLException {
return connection.prepareStatement(createInsertStatementWithAutoGeneratedIDForEntitiesTable(schemaName, ENTITY_TABLE_NAME, vendor).toString());
}
});
Lazy<PreparedStatement, SQLException> insertToEntityTypeTablePS = new Lazy<>(new LazyInit<PreparedStatement, SQLException>() {
@Override
public PreparedStatement create() throws SQLException {
return connection.prepareStatement(createInsertEntityTypeStatement(schemaName, vendor).toString());
}
});
Map<QualifiedName, PreparedStatement> qNameInsertPSs = new HashMap<>();
try {
connection.setAutoCommit(false);
connection.setReadOnly(false);
// TODO cache all queries.
updateEntityTablePS = connection.prepareStatement(this.createUpdateEntityTableStatement(schemaName, vendor).toString());
removeEntityPS = connection.prepareStatement(this.createDeleteFromEntityTableStatement(schemaName, vendor).toString());
insertToPropertyQNamesPS = connection.prepareStatement(vendor.toString(this.createInsertStatement(schemaName, DBNames.ALL_QNAMES_TABLE_NAME, AMOUNT_OF_COLUMNS_IN_ALL_QNAMES_TABLE, vendor)));
clearEntityDataPS = connection.prepareStatement(this.createClearEntityDataStatement(schemaName, vendor).toString());
Map<Long, EntityState> statesByPK = new HashMap<>();
Map<Long, Integer> qNamePKs = new HashMap<>();
Iterable<EntityState> relatedStates = Iterables.filter(new Specification<EntityState>() {
@Override
public boolean satisfiedBy(EntityState item) {
return item.entityDescriptor().queryable();
}
}, Iterables.map(SQLCompatEntityStateWrapper.WRAP, changedStates));
for (EntityState eState : relatedStates) {
EntityStatus status = eState.status();
Long pk = null;
boolean needToInsert = status.equals(EntityStatus.NEW);
if (!needToInsert) {
if (status.equals(EntityStatus.UPDATED)) {
pk = this.findEntityPK(eState, queryEntityPKPS);
if (pk == null) {
// Happens when reindexing
needToInsert = true;
} else {
// TODO if multiple applications with different application model use
// indexing, need to sync type-table.
this.updateEntityInfoAndProperties(connection, qNameInsertPSs, insertToPropertyQNamesPS, clearEntityDataPS, updateEntityTablePS, eState, pk, qNamePKs);
}
} else if (status.equals(EntityStatus.REMOVED)) {
this.removeEntity(eState, removeEntityPS);
} else {
// TODO possibly handle LOADED state somehow
// throw new
// UnsupportedOperationException("Did not understand what to do with state [id = "
// +
// eState.identity().identity() + ", status = " + status + "].");
}
}
if (needToInsert) {
pk = this.getPKFromAutoGeneratedIDInsert(eState, insertToEntityTableAutoGenerated.getValue(), vendor, connection);
this.insertPropertyType(connection, insertToEntityTypeTablePS.getValue(), eState, pk);
this.insertProperties(connection, qNameInsertPSs, insertToPropertyQNamesPS, eState, pk, qNamePKs);
}
if (pk != null) {
statesByPK.put(pk, eState);
}
}
removeEntityPS.executeBatch();
updateEntityTablePS.executeBatch();
clearEntityDataPS.executeBatch();
if (insertToEntityTypeTablePS.hasValue()) {
insertToEntityTypeTablePS.getValue().executeBatch();
}
for (Map.Entry<Long, EntityState> entry : statesByPK.entrySet()) {
EntityState eState = entry.getValue();
Long pk = entry.getKey();
this.insertAssoAndManyAssoQNames(qNameInsertPSs, insertToPropertyQNamesPS, eState, qNamePKs.get(pk), pk);
}
insertToPropertyQNamesPS.executeBatch();
for (PreparedStatement ps : qNameInsertPSs.values()) {
ps.executeBatch();
}
connection.commit();
} catch (SQLException sqle) {
SQLUtil.rollbackQuietly(connection);
throw sqle;
} finally {
try {
if (queryEntityPKPS.hasValue()) {
SQLUtil.closeQuietly(queryEntityPKPS.getValue());
}
if (insertToEntityTableAutoGenerated.hasValue()) {
SQLUtil.closeQuietly(insertToEntityTableAutoGenerated.getValue());
}
SQLUtil.closeQuietly(updateEntityTablePS);
SQLUtil.closeQuietly(removeEntityPS);
SQLUtil.closeQuietly(insertToPropertyQNamesPS);
SQLUtil.closeQuietly(clearEntityDataPS);
for (PreparedStatement ps : qNameInsertPSs.values()) {
SQLUtil.closeQuietly(ps);
}
} finally {
if (connectionFromStartupWasNull) {
SQLUtil.closeQuietly(connection);
} else {
connection.setReadOnly(wasReadOnly);
connection.setAutoCommit(wasAutoCommit);
}
}
}
}
use of org.qi4j.spi.entity.EntityState in project qi4j-sdk by Qi4j.
the class EntityResource method post.
@Override
public Representation post(Representation entityRepresentation, Variant variant) throws ResourceException {
Usecase usecase = UsecaseBuilder.newUsecase("Update entity");
EntityStoreUnitOfWork unitOfWork = entityStore.newUnitOfWork(usecase, module, System.currentTimeMillis());
EntityState entity = getEntityState(unitOfWork);
Form form = new Form(entityRepresentation);
try {
final EntityDescriptor descriptor = entity.entityDescriptor();
// Parse JSON into properties
for (PropertyDescriptor persistentProperty : descriptor.state().properties()) {
if (!persistentProperty.isImmutable()) {
String formValue = form.getFirstValue(persistentProperty.qualifiedName().name(), null);
if (formValue == null) {
entity.setPropertyValue(persistentProperty.qualifiedName(), null);
} else {
entity.setPropertyValue(persistentProperty.qualifiedName(), valueSerialization.deserialize(persistentProperty.valueType(), formValue));
}
}
}
for (AssociationDescriptor associationType : descriptor.state().associations()) {
String newStringAssociation = form.getFirstValue(associationType.qualifiedName().name());
if (newStringAssociation == null || newStringAssociation.isEmpty()) {
entity.setAssociationValue(associationType.qualifiedName(), null);
} else {
entity.setAssociationValue(associationType.qualifiedName(), EntityReference.parseEntityReference(newStringAssociation));
}
}
for (AssociationDescriptor associationType : descriptor.state().manyAssociations()) {
String newStringAssociation = form.getFirstValue(associationType.qualifiedName().name());
ManyAssociationState manyAssociation = entity.manyAssociationValueOf(associationType.qualifiedName());
if (newStringAssociation == null) {
// Remove "left-overs"
for (EntityReference entityReference : manyAssociation) {
manyAssociation.remove(entityReference);
}
continue;
}
BufferedReader bufferedReader = new BufferedReader(new StringReader(newStringAssociation));
String identity;
try {
// Synchronize old and new association
int index = 0;
while ((identity = bufferedReader.readLine()) != null) {
EntityReference reference = new EntityReference(identity);
if (manyAssociation.count() < index && manyAssociation.get(index).equals(reference)) {
continue;
}
try {
unitOfWork.entityStateOf(reference);
manyAssociation.remove(reference);
manyAssociation.add(index++, reference);
} catch (EntityNotFoundException e) {
// Ignore this entity - doesn't exist
}
}
// Remove "left-overs"
while (manyAssociation.count() > index) {
manyAssociation.remove(manyAssociation.get(index));
}
} catch (IOException e) {
// Ignore
}
}
for (AssociationDescriptor associationType : descriptor.state().namedAssociations()) {
String newStringAssociation = form.getFirstValue(associationType.qualifiedName().name());
NamedAssociationState namedAssociation = entity.namedAssociationValueOf(associationType.qualifiedName());
if (newStringAssociation == null) {
// Remove "left-overs"
for (String name : namedAssociation) {
namedAssociation.remove(name);
}
continue;
}
Set<String> names = new HashSet<>();
BufferedReader bufferedReader = new BufferedReader(new StringReader(newStringAssociation));
String line;
try {
while ((line = bufferedReader.readLine()) != null) {
String name = line;
line = bufferedReader.readLine();
if (line == null) {
break;
}
String identity = line;
EntityReference reference = new EntityReference(identity);
try {
unitOfWork.entityStateOf(reference);
namedAssociation.remove(name);
namedAssociation.put(name, reference);
names.add(name);
} catch (EntityNotFoundException e) {
// Ignore this entity - doesn't exist
}
}
// Remove "left-overs"
for (String assocName : Iterables.toList(namedAssociation)) {
if (!names.contains(assocName)) {
namedAssociation.remove(assocName);
}
}
} catch (IOException e) {
// Ignore
}
}
} catch (ValueSerializationException | IllegalArgumentException e) {
throw new ResourceException(Status.SERVER_ERROR_INTERNAL, e);
}
try {
unitOfWork.applyChanges().commit();
} catch (ConcurrentEntityStateModificationException e) {
throw new ResourceException(Status.CLIENT_ERROR_CONFLICT);
} catch (EntityNotFoundException e) {
throw new ResourceException(Status.CLIENT_ERROR_GONE);
}
getResponse().setStatus(Status.SUCCESS_RESET_CONTENT);
return new EmptyRepresentation();
}
Aggregations