Search in sources :

Example 1 with EntityChangedEvent

use of com.haulmont.cuba.core.app.events.EntityChangedEvent in project cuba by cuba-platform.

the class RdbmsStore method commit.

@Override
@SuppressWarnings("unchecked")
public Set<Entity> commit(CommitContext context) {
    if (log.isDebugEnabled())
        log.debug("commit: commitInstances=" + context.getCommitInstances() + ", removeInstances=" + context.getRemoveInstances());
    Set<Entity> saved = new HashSet<>();
    List<Entity> persisted = new ArrayList<>();
    List<BaseGenericIdEntity> identityEntitiesToStoreDynamicAttributes = new ArrayList<>();
    List<CategoryAttributeValue> attributeValuesToRemove = new ArrayList<>();
    EntityManager em = null;
    boolean softDeletionBefore;
    SavedEntitiesHolder savedEntitiesHolder;
    try (Transaction tx = getSaveTransaction(storeName, context.isJoinTransaction())) {
        em = persistence.getEntityManager(storeName);
        checkPermissions(context);
        softDeletionBefore = em.isSoftDeletion();
        em.setSoftDeletion(context.isSoftDeletion());
        List<BaseGenericIdEntity> entitiesToStoreDynamicAttributes = new ArrayList<>();
        // persist new
        for (Entity entity : context.getCommitInstances()) {
            if (entityStates.isNew(entity)) {
                if (isAuthorizationRequired(context)) {
                    attributeSecurity.beforePersist(entity);
                }
                em.persist(entity);
                saved.add(entity);
                persisted.add(entity);
                if (isAuthorizationRequired(context))
                    checkOperationPermitted(entity, EntityOp.CREATE);
                if (!context.isDiscardCommitted()) {
                    View view = getViewFromContextOrNull(context, entity);
                    entityFetcher.fetch(entity, view, true);
                    attributeSecurity.afterPersist(entity, view);
                }
                if (entityHasDynamicAttributes(entity)) {
                    if (entity instanceof BaseDbGeneratedIdEntity) {
                        identityEntitiesToStoreDynamicAttributes.add((BaseGenericIdEntity) entity);
                    } else {
                        entitiesToStoreDynamicAttributes.add((BaseGenericIdEntity) entity);
                    }
                }
            }
        }
        // merge the rest - instances can be detached or not
        for (Entity entity : context.getCommitInstances()) {
            if (!entityStates.isNew(entity)) {
                if (isAuthorizationRequired(context)) {
                    security.assertToken(entity);
                }
                security.restoreSecurityStateAndFilteredData(entity);
                if (isAuthorizationRequired(context)) {
                    attributeSecurity.beforeMerge(entity);
                }
                Entity merged = em.merge(entity);
                saved.add(merged);
                entityFetcher.fetch(merged, getViewFromContext(context, entity));
                attributeSecurity.afterMerge(merged);
                if (isAuthorizationRequired(context))
                    checkOperationPermitted(merged, EntityOp.UPDATE);
                if (entityHasDynamicAttributes(entity)) {
                    BaseGenericIdEntity originalBaseGenericIdEntity = (BaseGenericIdEntity) entity;
                    BaseGenericIdEntity mergedBaseGenericIdEntity = (BaseGenericIdEntity) merged;
                    mergeDynamicAttributes(originalBaseGenericIdEntity, mergedBaseGenericIdEntity);
                    entitiesToStoreDynamicAttributes.add(mergedBaseGenericIdEntity);
                }
            }
        }
        for (BaseGenericIdEntity entity : entitiesToStoreDynamicAttributes) {
            dynamicAttributesManagerAPI.storeDynamicAttributes(entity);
        }
        // remove
        for (Entity entity : context.getRemoveInstances()) {
            if (isAuthorizationRequired(context)) {
                security.assertToken(entity);
            }
            security.restoreSecurityStateAndFilteredData(entity);
            Entity e;
            if (entity instanceof SoftDelete) {
                attributeSecurity.beforeMerge(entity);
                e = em.merge(entity);
                entityFetcher.fetch(e, getViewFromContext(context, entity));
                attributeSecurity.afterMerge(e);
            } else {
                e = em.merge(entity);
            }
            if (isAuthorizationRequired(context))
                checkOperationPermitted(e, EntityOp.DELETE);
            em.remove(e);
            saved.add(e);
            if (entityHasDynamicAttributes(entity)) {
                Map<String, CategoryAttributeValue> dynamicAttributes = ((BaseGenericIdEntity) entity).getDynamicAttributes();
                // old values of dynamic attributes on deleted entity are used in EntityChangedEvent
                ((BaseGenericIdEntity) e).setDynamicAttributes(dynamicAttributes);
                // noinspection ConstantConditions
                for (CategoryAttributeValue categoryAttributeValue : dynamicAttributes.values()) {
                    if (!entityStates.isNew(categoryAttributeValue)) {
                        if (Stores.isMain(storeName)) {
                            em.remove(categoryAttributeValue);
                        } else {
                            attributeValuesToRemove.add(categoryAttributeValue);
                        }
                        saved.add(categoryAttributeValue);
                    }
                }
            }
        }
        if (!context.isDiscardCommitted() && isAuthorizationRequired(context) && userSessionSource.getUserSession().getConstraints().exists()) {
            security.calculateFilteredData(saved);
        }
        savedEntitiesHolder = SavedEntitiesHolder.setEntities(saved);
        if (context.isJoinTransaction()) {
            List<EntityChangedEventInfo> eventsInfo = entityChangedEventManager.collect(saved);
            persistenceSupport.processFlush(em, false);
            em.getDelegate().flush();
            List<EntityChangedEvent> events = new ArrayList<>(eventsInfo.size());
            for (EntityChangedEventInfo info : eventsInfo) {
                events.add(new EntityChangedEvent(info.getSource(), Id.of(info.getEntity()), info.getType(), info.getChanges()));
            }
            for (Entity entity : saved) {
                detachEntity(em, entity, getViewFromContext(context, entity));
            }
            entityChangedEventManager.publish(events);
        }
        tx.commit();
        if (em != null) {
            em.setSoftDeletion(softDeletionBefore);
        }
    }
    if (!attributeValuesToRemove.isEmpty()) {
        try (Transaction tx = getSaveTransaction(Stores.MAIN, context.isJoinTransaction())) {
            EntityManager entityManager = persistence.getEntityManager();
            for (CategoryAttributeValue entity : attributeValuesToRemove) {
                entityManager.remove(entity);
            }
            tx.commit();
        }
    }
    if (!identityEntitiesToStoreDynamicAttributes.isEmpty()) {
        try (Transaction tx = getSaveTransaction(storeName, context.isJoinTransaction())) {
            for (BaseGenericIdEntity entity : identityEntitiesToStoreDynamicAttributes) {
                dynamicAttributesManagerAPI.storeDynamicAttributes(entity);
            }
            tx.commit();
        }
    }
    Set<Entity> resultEntities = savedEntitiesHolder.getEntities(saved);
    reloadIfUnfetched(resultEntities, context);
    if (!context.isDiscardCommitted() && isAuthorizationRequired(context) && userSessionSource.getUserSession().getConstraints().exists()) {
        security.applyConstraints(resultEntities);
    }
    if (!context.isDiscardCommitted()) {
        if (isAuthorizationRequired(context)) {
            for (Entity entity : resultEntities) {
                if (!persisted.contains(entity)) {
                    attributeSecurity.afterCommit(entity);
                }
            }
        }
        // Update references from newly persisted entities to merged detached entities. Otherwise a new entity can
        // contain a stale instance of a merged one.
        entityReferencesNormalizer.updateReferences(persisted, resultEntities);
    }
    return context.isDiscardCommitted() ? Collections.emptySet() : resultEntities;
}
Also used : EntityChangedEventInfo(com.haulmont.cuba.core.sys.persistence.EntityChangedEventInfo) EntityChangedEvent(com.haulmont.cuba.core.app.events.EntityChangedEvent)

Example 2 with EntityChangedEvent

use of com.haulmont.cuba.core.app.events.EntityChangedEvent in project cuba by cuba-platform.

the class EntityChangedEventManager method internalCollect.

public List<EntityChangedEventInfo> internalCollect(Collection<Entity> entities) {
    List<EntityChangedEventInfo> list = new ArrayList<>();
    for (Entity entity : entities) {
        PublishingInfo info = infoCache.computeIfAbsent(entity.getClass(), aClass -> {
            MetaClass metaClass = metadata.getClassNN(entity.getClass());
            Map attrMap = (Map) metaClass.getAnnotations().get(PublishEntityChangedEvents.class.getName());
            if (attrMap != null) {
                if (!(entity instanceof BaseGenericIdEntity)) {
                    log.warn("Cannot publish EntityChangedEvent for {} because it is not a BaseGenericIdEntity", entity);
                } else {
                    return new PublishingInfo(Boolean.TRUE.equals(attrMap.get("created")), Boolean.TRUE.equals(attrMap.get("updated")), Boolean.TRUE.equals(attrMap.get("deleted")));
                }
            }
            return new PublishingInfo();
        });
        if (info.publish) {
            EntityChangedEvent.Type type = null;
            AttributeChanges attributeChanges = null;
            if (info.onCreated && BaseEntityInternalAccess.isNew((BaseGenericIdEntity) entity)) {
                type = EntityChangedEvent.Type.CREATED;
                attributeChanges = getEntityAttributeChanges(entity, false);
            } else {
                if (info.onUpdated || info.onDeleted) {
                    AttributeChangeListener changeListener = (AttributeChangeListener) ((ChangeTracker) entity)._persistence_getPropertyChangeListener();
                    if (changeListener == null) {
                        log.trace("Cannot publish EntityChangedEvent for {} because its AttributeChangeListener is null", entity);
                        continue;
                    }
                    if (info.onDeleted && PersistenceImplSupport.isDeleted((BaseGenericIdEntity) entity, changeListener)) {
                        type = EntityChangedEvent.Type.DELETED;
                        attributeChanges = getEntityAttributeChanges(entity, true);
                    } else if (info.onUpdated && changeListener.hasChanges()) {
                        type = EntityChangedEvent.Type.UPDATED;
                        attributeChanges = getEntityAttributeChanges(entity, changeListener.getObjectChangeSet());
                    }
                }
            }
            if (type != null) {
                @SuppressWarnings("unchecked") EntityChangedEventInfo eventData = new EntityChangedEventInfo(this, entity, type, attributeChanges);
                list.add(eventData);
            }
        }
    }
    log.trace("collected {}", list);
    return list;
}
Also used : AttributeChanges(com.haulmont.cuba.core.app.events.AttributeChanges) EntityChangedEvent(com.haulmont.cuba.core.app.events.EntityChangedEvent) MetaClass(com.haulmont.chile.core.model.MetaClass) AttributeChangeListener(org.eclipse.persistence.internal.descriptors.changetracking.AttributeChangeListener) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 3 with EntityChangedEvent

use of com.haulmont.cuba.core.app.events.EntityChangedEvent in project documentation by cuba-platform.

the class OrderLineChangedListener method beforeCommit.

@EventListener
public void beforeCommit(EntityChangedEvent<OrderLine, UUID> event) {
    Order order;
    if (event.getType() != EntityChangedEvent.Type.DELETED) {
        // <1>
        order = // <2>
        txDm.load(event.getEntityId()).view(// <3>
        "orderLine-with-order").one().getOrder();
    } else {
        // <5>
        Id<Order, UUID> orderId = event.getChanges().getOldReferenceId("order");
        order = txDm.load(orderId).one();
    }
    long count = // <6>
    txDm.load(OrderLine.class).query("select o from sales_OrderLine o where o.order = :order").parameter("order", order).view("orderLine-with-product").list().stream().filter(orderLine -> Boolean.TRUE.equals(orderLine.getProduct().getSpecial())).count();
    order.setNumberOfSpecialProducts((int) count);
    // <7>
    txDm.save(order);
}
Also used : Order(com.company.sales.entity.Order) Inject(javax.inject.Inject) Component(org.springframework.stereotype.Component) EntityChangedEvent(com.haulmont.cuba.core.app.events.EntityChangedEvent) TransactionalDataManager(com.haulmont.cuba.core.TransactionalDataManager) EventListener(org.springframework.context.event.EventListener) UUID(java.util.UUID) OrderLine(com.company.sales.entity.OrderLine) Order(com.company.sales.entity.Order) Id(com.haulmont.cuba.core.entity.contracts.Id) OrderLine(com.company.sales.entity.OrderLine) UUID(java.util.UUID) EventListener(org.springframework.context.event.EventListener)

Example 4 with EntityChangedEvent

use of com.haulmont.cuba.core.app.events.EntityChangedEvent in project jmix by jmix-framework.

the class CubaEntityChangedEventManager method handleEvent.

@EventListener
public void handleEvent(io.jmix.core.event.EntityChangedEvent<? extends Entity> event) {
    PublishingInfo info = infoCache.computeIfAbsent(event.getEntityId().getEntityClass(), aClass -> {
        MetaClass metaClass = metadata.getClass(event.getEntityId().getEntityClass());
        MetaClass originalMetaClass = extendedEntities.getOriginalOrThisMetaClass(metaClass);
        Map attrMap = (Map) metaClass.getAnnotations().get(PublishEntityChangedEvents.class.getName());
        if (attrMap != null) {
            return new PublishingInfo(Boolean.TRUE.equals(attrMap.get("created")), Boolean.TRUE.equals(attrMap.get("updated")), Boolean.TRUE.equals(attrMap.get("deleted")), originalMetaClass);
        }
        return new PublishingInfo();
    });
    EntityChangedEvent.Type type = resolveType(event.getType());
    if (!info.publish || (!info.onCreated && type == EntityChangedEvent.Type.CREATED) || (!info.onUpdated && type == EntityChangedEvent.Type.UPDATED) || (!info.onDeleted && type == EntityChangedEvent.Type.DELETED)) {
        return;
    }
    io.jmix.core.Id<? extends Entity> entityId = event.getEntityId();
    eventPublisher.publish(new EntityChangedEvent<>(event.getSource(), Id.of(entityId.getValue(), entityId.getEntityClass()), type, new AttributeChanges(event.getChanges())));
}
Also used : AttributeChanges(com.haulmont.cuba.core.app.events.AttributeChanges) MetaClass(io.jmix.core.metamodel.model.MetaClass) EntityChangedEvent(com.haulmont.cuba.core.app.events.EntityChangedEvent) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Map(java.util.Map) EventListener(org.springframework.context.event.EventListener)

Example 5 with EntityChangedEvent

use of com.haulmont.cuba.core.app.events.EntityChangedEvent in project documentation by cuba-platform.

the class CustomerChangedListener method beforeCommit.

// <1>
@EventListener
public void beforeCommit(EntityChangedEvent<Customer, UUID> event) {
    // <2>
    Id<Customer, UUID> entityId = event.getEntityId();
    // <3>
    EntityChangedEvent.Type changeType = event.getType();
    AttributeChanges changes = event.getChanges();
    if (changes.isChanged("name")) {
        // <4>
        // <5>
        String oldName = changes.getOldValue("name");
    // ...
    }
}
Also used : AttributeChanges(com.haulmont.cuba.core.app.events.AttributeChanges) Customer(com.company.demo.entity.Customer) EntityChangedEvent(com.haulmont.cuba.core.app.events.EntityChangedEvent) UUID(java.util.UUID) TransactionalEventListener(org.springframework.transaction.event.TransactionalEventListener) EventListener(org.springframework.context.event.EventListener)

Aggregations

EntityChangedEvent (com.haulmont.cuba.core.app.events.EntityChangedEvent)5 AttributeChanges (com.haulmont.cuba.core.app.events.AttributeChanges)3 EventListener (org.springframework.context.event.EventListener)3 UUID (java.util.UUID)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 Customer (com.company.demo.entity.Customer)1 Order (com.company.sales.entity.Order)1 OrderLine (com.company.sales.entity.OrderLine)1 MetaClass (com.haulmont.chile.core.model.MetaClass)1 TransactionalDataManager (com.haulmont.cuba.core.TransactionalDataManager)1 Id (com.haulmont.cuba.core.entity.contracts.Id)1 EntityChangedEventInfo (com.haulmont.cuba.core.sys.persistence.EntityChangedEventInfo)1 MetaClass (io.jmix.core.metamodel.model.MetaClass)1 Map (java.util.Map)1 Inject (javax.inject.Inject)1 AttributeChangeListener (org.eclipse.persistence.internal.descriptors.changetracking.AttributeChangeListener)1 Component (org.springframework.stereotype.Component)1 TransactionalEventListener (org.springframework.transaction.event.TransactionalEventListener)1