Search in sources :

Example 11 with EntityState

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;
}
Also used : Reader(java.io.Reader) EntityState(org.qi4j.spi.entity.EntityState)

Example 12 with EntityState

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;
}
Also used : EntityState(org.qi4j.spi.entity.EntityState)

Example 13 with 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() {
        }
    };
}
Also used : SQLEntityState(org.qi4j.entitystore.sql.internal.SQLEntityState) DefaultSQLEntityState(org.qi4j.entitystore.sql.internal.SQLEntityState.DefaultSQLEntityState) DefaultEntityState(org.qi4j.spi.entitystore.helpers.DefaultEntityState) SQLException(java.sql.SQLException) Connection(java.sql.Connection) PreparedStatement(java.sql.PreparedStatement) SQLEntityState(org.qi4j.entitystore.sql.internal.SQLEntityState) EntityState(org.qi4j.spi.entity.EntityState) DefaultSQLEntityState(org.qi4j.entitystore.sql.internal.SQLEntityState.DefaultSQLEntityState) DefaultEntityState(org.qi4j.spi.entitystore.helpers.DefaultEntityState) StringWriter(java.io.StringWriter) EntityStatus(org.qi4j.spi.entity.EntityStatus) StateCommitter(org.qi4j.spi.entitystore.StateCommitter) EntityStoreException(org.qi4j.spi.entitystore.EntityStoreException) PrintWriter(java.io.PrintWriter)

Example 14 with EntityState

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);
            }
        }
    }
}
Also used : SQLException(java.sql.SQLException) HashMap(java.util.HashMap) QualifiedName(org.qi4j.api.common.QualifiedName) Connection(java.sql.Connection) PreparedStatement(java.sql.PreparedStatement) EntityState(org.qi4j.spi.entity.EntityState) Lazy(org.qi4j.index.sql.support.skeletons.SQLSkeletonUtil.Lazy) EntityStatus(org.qi4j.spi.entity.EntityStatus) SQLVendor(org.sql.generation.api.vendor.SQLVendor) Map(java.util.Map) HashMap(java.util.HashMap)

Example 15 with EntityState

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();
}
Also used : PropertyDescriptor(org.qi4j.api.property.PropertyDescriptor) EntityStoreUnitOfWork(org.qi4j.spi.entitystore.EntityStoreUnitOfWork) Form(org.restlet.data.Form) NamedAssociationState(org.qi4j.spi.entity.NamedAssociationState) ValueSerializationException(org.qi4j.api.value.ValueSerializationException) EntityState(org.qi4j.spi.entity.EntityState) JSONEntityState(org.qi4j.spi.entitystore.helpers.JSONEntityState) AssociationDescriptor(org.qi4j.api.association.AssociationDescriptor) EntityNotFoundException(org.qi4j.spi.entitystore.EntityNotFoundException) IOException(java.io.IOException) ManyAssociationState(org.qi4j.spi.entity.ManyAssociationState) EntityDescriptor(org.qi4j.api.entity.EntityDescriptor) ConcurrentEntityStateModificationException(org.qi4j.spi.entitystore.ConcurrentEntityStateModificationException) EmptyRepresentation(org.restlet.representation.EmptyRepresentation) EntityReference(org.qi4j.api.entity.EntityReference) BufferedReader(java.io.BufferedReader) StringReader(java.io.StringReader) ResourceException(org.restlet.resource.ResourceException) Usecase(org.qi4j.api.usecase.Usecase) HashSet(java.util.HashSet)

Aggregations

EntityState (org.qi4j.spi.entity.EntityState)17 ResourceException (org.restlet.resource.ResourceException)4 Date (java.util.Date)3 EntityReference (org.qi4j.api.entity.EntityReference)3 EntityNotFoundException (org.qi4j.spi.entitystore.EntityNotFoundException)3 EntityStoreException (org.qi4j.spi.entitystore.EntityStoreException)3 EntityStoreUnitOfWork (org.qi4j.spi.entitystore.EntityStoreUnitOfWork)3 JSONEntityState (org.qi4j.spi.entitystore.helpers.JSONEntityState)3 PrintWriter (java.io.PrintWriter)2 Connection (java.sql.Connection)2 PreparedStatement (java.sql.PreparedStatement)2 SQLException (java.sql.SQLException)2 Test (org.junit.Test)2 PropertyDescriptor (org.qi4j.api.property.PropertyDescriptor)2 EntityInstance (org.qi4j.runtime.entity.EntityInstance)2 EntityStatus (org.qi4j.spi.entity.EntityStatus)2 EntityStore (org.qi4j.spi.entitystore.EntityStore)2 StateCommitter (org.qi4j.spi.entitystore.StateCommitter)2 DefaultEntityState (org.qi4j.spi.entitystore.helpers.DefaultEntityState)2 AbstractQi4jTest (org.qi4j.test.AbstractQi4jTest)2