PL-10102 EntityLog doesn't show changes for dynamic attributes

This commit is contained in:
Andrey Subbotin 2017-12-07 15:27:00 +04:00
parent aba7b72a3d
commit fea4a162f6
3 changed files with 439 additions and 66 deletions

View File

@ -16,16 +16,16 @@
*/
package com.haulmont.cuba.security.app;
import com.haulmont.bali.util.Preconditions;
import com.haulmont.chile.core.datatypes.Datatypes;
import com.haulmont.chile.core.model.Instance;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.chile.core.model.Range;
import com.haulmont.cuba.core.EntityManager;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.TypedQuery;
import com.haulmont.cuba.core.*;
import com.haulmont.cuba.core.app.ServerConfig;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributes;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
import com.haulmont.cuba.core.entity.*;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.core.sys.AppContext;
@ -64,6 +64,10 @@ public class EntityLog implements EntityLogAPI {
@Inject
protected ReferenceToEntitySupport referenceToEntitySupport;
@Inject
protected DynamicAttributes dynamicAttributes;
@Inject
protected DataManager dataManager;
@Inject
protected ServerConfig serverConfig;
protected volatile boolean loaded;
@ -145,6 +149,12 @@ public class EntityLog implements EntityLogAPI {
}
}
if (itemToSave.getType() == EntityLogItem.Type.MODIFY) {
sameEntityList.stream()
.filter(entityLogItem -> entityLogItem.getType() == EntityLogItem.Type.CREATE)
.findFirst()
.ifPresent(entityLogItem -> itemToSave.setType(EntityLogItem.Type.CREATE));
}
itemToSave.setChanges(getChanges(properties));
}
@ -167,6 +177,7 @@ public class EntityLog implements EntityLogAPI {
.orElse(null);
if (attr == null) {
attr = metadata.create(EntityLogAttr.class);
attr.setName(entityLogAttr.getName());
itemToSave.getAttributes().add(attr);
}
return attr;
@ -279,9 +290,15 @@ public class EntityLog implements EntityLogAPI {
}
protected String getEntityName(Entity entity) {
MetaClass metaClass = metadata.getSession().getClassNN(entity.getClass());
MetaClass originalMetaClass = metadata.getExtendedEntities().getOriginalMetaClass(metaClass);
return originalMetaClass != null ? originalMetaClass.getName() : metaClass.getName();
MetaClass metaClass;
if (entity instanceof CategoryAttributeValue) {
CategoryAttribute categoryAttribute = ((CategoryAttributeValue) entity).getCategoryAttribute();
Preconditions.checkNotNullArgument(categoryAttribute,"Category attribute is null");
metaClass = metadata.getClassNN(categoryAttribute.getCategoryEntityType());
} else {
metaClass = metadata.getSession().getClassNN(entity.getClass());
}
return metadata.getExtendedEntities().getOriginalOrThisMetaClass(metaClass).getName();
}
protected boolean doNotRegister(Entity entity) {
@ -309,9 +326,10 @@ public class EntityLog implements EntityLogAPI {
try {
if (doNotRegister(entity))
return;
String masterEntityName = getEntityName(entity);
boolean isCategoryAttributeValue = entity instanceof CategoryAttributeValue;
String entityName = getEntityName(entity);
Set<String> attributes = getLoggedAttributes(entityName, auto);
Set<String> attributes = getLoggedAttributes(masterEntityName, auto);
if (attributes != null && attributes.contains("*")) {
attributes = getAllAttributes(entity);
}
@ -319,17 +337,21 @@ public class EntityLog implements EntityLogAPI {
return;
}
MetaClass metaClass = metadata.getClassNN(entityName);
MetaClass metaClass = metadata.getClassNN(masterEntityName);
attributes = filterRemovedAttributes(metaClass, attributes);
String storeName = metadata.getTools().getStoreName(metaClass);
if (Stores.isMain(storeName)) {
internalRegisterCreate(entity, entityName, attributes);
if (isCategoryAttributeValue) {
internalRegisterModifyAttributeValue((CategoryAttributeValue) entity, null, attributes);
} else {
// Create a new transaction in main DB if we are saving an entity from additional data store
try (Transaction tx = persistence.createTransaction()) {
internalRegisterCreate(entity, entityName, attributes);
tx.commit();
String storeName = metadata.getTools().getStoreName(metaClass);
if (Stores.isMain(storeName)) {
internalRegisterCreate(entity, masterEntityName, attributes);
} else {
// Create a new transaction in main DB if we are saving an entity from additional data store
try (Transaction tx = persistence.createTransaction()) {
internalRegisterCreate(entity, masterEntityName, attributes);
tx.commit();
}
}
}
} catch (Exception e) {
@ -340,7 +362,13 @@ public class EntityLog implements EntityLogAPI {
protected Set<String> filterRemovedAttributes(MetaClass metaClass, Set<String> attributes) {
// filter attributes that do not exists in entity anymore
return attributes.stream()
.filter(attributeName -> metaClass.getProperty(attributeName) != null)
.filter(attributeName -> {
if (DynamicAttributesUtils.isDynamicAttribute(attributeName)){
return DynamicAttributesUtils.getMetaPropertyPath(metaClass, attributeName) != null;
} else {
return metaClass.getProperty(attributeName) != null;
}
})
.collect(Collectors.toSet());
}
@ -354,11 +382,42 @@ public class EntityLog implements EntityLogAPI {
item.setType(EntityLogItem.Type.CREATE);
item.setEntity(entityName);
item.setObjectEntityId(referenceToEntitySupport.getReferenceId(entity));
item.setAttributes(createAttributes(entity, attributes, null));
item.setAttributes(createLogAttributes(entity, attributes, null));
enqueueItem(item);
}
protected void internalRegisterModifyAttributeValue(CategoryAttributeValue entity, @Nullable EntityAttributeChanges changes,
Set<String> attributes) {
String propertyName = DynamicAttributesUtils.encodeAttributeCode(entity.getCode());
if (!attributes.contains(propertyName)) {
return;
}
Date ts = timeSource.currentTimestamp();
EntityManager em = persistence.getEntityManager();
Set<String> dirty;
if (changes == null) {
dirty = persistence.getTools().getDirtyFields(entity);
} else {
dirty = changes.getAttributes();
}
boolean registerDeleteOp = dirty.contains("deleteTs") && entity.isDeleted();
boolean hasChanges = dirty.stream().anyMatch(s -> s.endsWith("Value"));
if (hasChanges) {
EntityLogItem item = metadata.create(EntityLogItem.class);
item.setEventTs(ts);
item.setUser(findUser(em));
item.setType(EntityLogItem.Type.MODIFY);
item.setEntity(getEntityName(entity));
item.setObjectEntityId(entity.getObjectEntityId());
item.setAttributes(createDynamicLogAttribute(entity, changes, registerDeleteOp));
enqueueItem(item);
}
}
protected User findUser(EntityManager em) {
if (AppContext.isStarted())
return em.getReference(User.class, userSessionSource.getUserSession().getUser().getId());
@ -400,8 +459,9 @@ public class EntityLog implements EntityLogAPI {
if (doNotRegister(entity))
return;
String entityName = getEntityName(entity);
Set<String> attributes = getLoggedAttributes(entityName, auto);
String masterEntityName = getEntityName(entity);
boolean isCategoryAttributeValue = entity instanceof CategoryAttributeValue;
Set<String> attributes = getLoggedAttributes(masterEntityName, auto);
if (attributes != null && attributes.contains("*")) {
attributes = getAllAttributes(entity);
}
@ -409,17 +469,21 @@ public class EntityLog implements EntityLogAPI {
return;
}
MetaClass metaClass = metadata.getClassNN(entityName);
MetaClass metaClass = metadata.getClassNN(masterEntityName);
attributes = filterRemovedAttributes(metaClass, attributes);
String storeName = metadataTools.getStoreName(metaClass);
if (Stores.isMain(storeName)) {
internalRegisterModify(entity, changes, metaClass, storeName, attributes);
if (isCategoryAttributeValue) {
internalRegisterModifyAttributeValue((CategoryAttributeValue) entity, changes, attributes);
} else {
// Create a new transaction in main DB if we are saving an entity from additional data store
try (Transaction tx = persistence.createTransaction()) {
String storeName = metadataTools.getStoreName(metaClass);
if (Stores.isMain(storeName)) {
internalRegisterModify(entity, changes, metaClass, storeName, attributes);
tx.commit();
} else {
// Create a new transaction in main DB if we are saving an entity from additional data store
try (Transaction tx = persistence.createTransaction()) {
internalRegisterModify(entity, changes, metaClass, storeName, attributes);
tx.commit();
}
}
}
} catch (Exception e) {
@ -443,7 +507,7 @@ public class EntityLog implements EntityLogAPI {
EntityLogItem.Type type;
if (entity instanceof SoftDelete && dirty.contains("deleteTs") && !((SoftDelete) entity).isDeleted()) {
type = EntityLogItem.Type.RESTORE;
entityLogAttrs = createAttributes(entity, attributes, changes);
entityLogAttrs = createLogAttributes(entity, attributes, changes);
} else {
type = EntityLogItem.Type.MODIFY;
Set<String> dirtyAttributes = new HashSet<>();
@ -457,7 +521,7 @@ public class EntityLog implements EntityLogAPI {
}
}
}
entityLogAttrs = createAttributes(entity, dirtyAttributes, changes);
entityLogAttrs = createLogAttributes(entity, dirtyAttributes, changes);
}
if (!entityLogAttrs.isEmpty() || type == EntityLogItem.Type.RESTORE) {
EntityLogItem item = metadata.create(EntityLogItem.class);
@ -472,10 +536,13 @@ public class EntityLog implements EntityLogAPI {
}
}
private Set<EntityLogAttr> createAttributes(Entity entity, Set<String> attributes,
@Nullable EntityAttributeChanges changes) {
protected Set<EntityLogAttr> createLogAttributes(Entity entity, Set<String> attributes,
@Nullable EntityAttributeChanges changes) {
Set<EntityLogAttr> result = new HashSet<>();
for (String name : attributes) {
if (DynamicAttributesUtils.isDynamicAttribute(name)) {
continue;
}
EntityLogAttr attr = metadata.create(EntityLogAttr.class);
attr.setName(name);
@ -505,6 +572,30 @@ public class EntityLog implements EntityLogAPI {
return result;
}
protected Set<EntityLogAttr> createDynamicLogAttribute(CategoryAttributeValue entity, @Nullable EntityAttributeChanges changes, boolean registerDeleteOp) {
Set<EntityLogAttr> result = new HashSet<>();
EntityLogAttr attr = metadata.create(EntityLogAttr.class);
attr.setName(DynamicAttributesUtils.encodeAttributeCode(entity.getCode()));
Object value = entity.getValue();
attr.setValue(stringify(value));
Object valueId = getValueId(value);
if (valueId != null)
attr.setValueId(valueId.toString());
if (changes != null || registerDeleteOp) {
Object oldValue = getOldCategoryAttributeValue(entity, changes);
attr.setOldValue(stringify(oldValue));
Object oldValueId = getValueId(oldValue);
if (oldValueId != null) {
attr.setOldValueId(oldValueId.toString());
}
}
result.add(attr);
return result;
}
protected String getChanges(Properties properties) {
try {
StringWriter writer = new StringWriter();
@ -529,8 +620,9 @@ public class EntityLog implements EntityLogAPI {
if (doNotRegister(entity))
return;
String entityName = getEntityName(entity);
Set<String> attributes = getLoggedAttributes(entityName, auto);
String masterEntityName = getEntityName(entity);
boolean isCategoryAttributeValue = entity instanceof CategoryAttributeValue;
Set<String> attributes = getLoggedAttributes(masterEntityName, auto);
if (attributes != null && attributes.contains("*")) {
attributes = getAllAttributes(entity);
}
@ -538,17 +630,20 @@ public class EntityLog implements EntityLogAPI {
return;
}
MetaClass metaClass = metadata.getClassNN(entityName);
MetaClass metaClass = metadata.getClassNN(masterEntityName);
attributes = filterRemovedAttributes(metaClass, attributes);
String storeName = metadata.getTools().getStoreName(metaClass);
if (Stores.isMain(storeName)) {
internalRegisterDelete(entity, entityName, attributes);
if (isCategoryAttributeValue) {
internalRegisterModifyAttributeValue((CategoryAttributeValue) entity, null, attributes);
} else {
// Create a new transaction in main DB if we are saving an entity from additional data store
try (Transaction tx = persistence.createTransaction()) {
internalRegisterDelete(entity, entityName, attributes);
tx.commit();
String storeName = metadata.getTools().getStoreName(metaClass);
if (Stores.isMain(storeName)) {
internalRegisterDelete(entity, masterEntityName, attributes);
} else {
// Create a new transaction in main DB if we are saving an entity from additional data store
try (Transaction tx = persistence.createTransaction()) {
internalRegisterDelete(entity, masterEntityName, attributes);
tx.commit();
}
}
}
} catch (Exception e) {
@ -566,7 +661,7 @@ public class EntityLog implements EntityLogAPI {
item.setType(EntityLogItem.Type.DELETE);
item.setEntity(entityName);
item.setObjectEntityId(referenceToEntitySupport.getReferenceId(entity));
item.setAttributes(createAttributes(entity, attributes, null));
item.setAttributes(createLogAttributes(entity, attributes, null));
enqueueItem(item);
}
@ -576,13 +671,23 @@ public class EntityLog implements EntityLogAPI {
return null;
}
Set<String> attributes = new HashSet<>();
for (MetaProperty metaProperty : metadata.getClassNN(entity.getClass()).getProperties()) {
MetaClass metaClass = metadata.getClassNN(entity.getClass());
for (MetaProperty metaProperty : metaClass.getProperties()) {
Range range = metaProperty.getRange();
if (range.isClass() && range.getCardinality().isMany()) {
continue;
}
attributes.add(metaProperty.getName());
}
Collection<CategoryAttribute> categoryAttributes = dynamicAttributes.getAttributesForMetaClass(metaClass);
if (categoryAttributes != null) {
for (CategoryAttribute categoryAttribute : categoryAttributes) {
if (BooleanUtils.isNotTrue(categoryAttribute.getIsCollection())) {
attributes.add(
DynamicAttributesUtils.getMetaPropertyPath(metaClass, categoryAttribute).getMetaProperty().getName());
}
}
}
return attributes;
}
@ -618,6 +723,35 @@ public class EntityLog implements EntityLogAPI {
}
}
protected Object getOldCategoryAttributeValue(CategoryAttributeValue attributeValue, EntityAttributeChanges changes) {
CategoryAttribute categoryAttribute = attributeValue.getCategoryAttribute();
PersistenceTools persistenceTools = persistence.getTools();
String fieldName = null;
switch (categoryAttribute.getDataType()) {
case DATE:
fieldName = "dateValue";
break;
case ENUMERATION:
case STRING:
fieldName = "stringValue";
break;
case INTEGER:
fieldName = "intValue";
break;
case DOUBLE:
fieldName = "doubleValue";
break;
case BOOLEAN:
fieldName = "booleanValue";
break;
}
if (fieldName != null) {
return changes != null ? changes.getOldValue(fieldName) :
persistenceTools.getOldValue(attributeValue, fieldName);
}
return null;
}
protected void logError(Entity entity, Exception e) {
log.warn("Unable to log entity {}, id={}", entity, entity.getId(), e);
}

View File

@ -0,0 +1,206 @@
/*
* Copyright (c) 2008-2017 Haulmont.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package spec.cuba.core.entity_log
import com.haulmont.bali.db.QueryRunner
import com.haulmont.cuba.core.EntityManager
import com.haulmont.cuba.core.Query
import com.haulmont.cuba.core.Transaction
import com.haulmont.cuba.core.TypedQuery
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesManagerAPI
import com.haulmont.cuba.core.app.dynamicattributes.PropertyType
import com.haulmont.cuba.core.entity.Category
import com.haulmont.cuba.core.entity.CategoryAttribute
import com.haulmont.cuba.core.entity.ReferenceToEntity
import com.haulmont.cuba.core.global.AppBeans
import com.haulmont.cuba.core.global.DataManager
import com.haulmont.cuba.core.global.LoadContext
import com.haulmont.cuba.core.global.View
import com.haulmont.cuba.security.app.EntityLogAPI
import com.haulmont.cuba.security.entity.*
import com.haulmont.cuba.testsupport.TestContainer
import com.haulmont.cuba.testsupport.TestSupport
import org.junit.ClassRule
import spock.lang.Shared
import spock.lang.Specification
import java.sql.SQLException
class EntityLogDynamicAttributesTest extends Specification {
@Shared @ClassRule
public TestContainer cont = TestContainer.Common.INSTANCE
private UUID user1Id, categoryId, categoryAttributeId
private def entityLog
private DataManager dataManager
private def dynamicAttributesManagerAPI
void setup() {
_cleanup()
cont.persistence().runInTransaction { em ->
Query q
q = em.createNativeQuery("delete from SEC_ENTITY_LOG")
q.executeUpdate()
q = em.createNativeQuery("delete from SYS_ATTR_VALUE")
q.executeUpdate()
LoggedEntity le = new LoggedEntity()
le.setName('sec$User')
le.setAuto(true)
em.persist(le)
LoggedAttribute la = new LoggedAttribute()
la.setEntity(le)
la.setName('name')
em.persist(la)
la = new LoggedAttribute()
la.setEntity(le)
la.setName('+userAttribute')
em.persist(la)
Category category = new Category()
category.setName("user")
category.setEntityType("sec\$User")
categoryId = category.getId()
em.persist(category)
CategoryAttribute categoryAttribute = new CategoryAttribute()
categoryAttribute.setName("userAttribute")
categoryAttribute.setCode("userAttribute")
categoryAttribute.setCategory(category)
categoryAttribute.setCategoryEntityType("sec\$User")
categoryAttribute.setDataType(PropertyType.STRING)
categoryAttribute.setDefaultEntity(new ReferenceToEntity())
categoryAttributeId = categoryAttribute.getId()
em.persist(categoryAttribute)
}
entityLog = AppBeans.get(EntityLogAPI.class)
entityLog.invalidateCache()
dynamicAttributesManagerAPI = AppBeans.get(DynamicAttributesManagerAPI.class)
dynamicAttributesManagerAPI.loadCache()
dataManager = AppBeans.get(DataManager.class)
}
void cleanup() {
_cleanup()
if (user1Id != null)
cont.deleteRecord("SEC_USER", user1Id)
cont.deleteRecord("SYS_CATEGORY_ATTR", categoryAttributeId)
cont.deleteRecord("SYS_CATEGORY", categoryId)
}
private void _cleanup() throws SQLException {
QueryRunner runner = new QueryRunner(cont.persistence().getDataSource())
runner.update("delete from SEC_LOGGED_ATTR")
runner.update("delete from SEC_LOGGED_ENTITY")
runner.update("delete from SYS_ATTR_VALUE")
}
private List<EntityLogItem> getEntityLogItems(def userId) {
Transaction tx
List<EntityLogItem> items
tx = cont.persistence().createTransaction()
try {
EntityManager em = cont.persistence().getEntityManager()
TypedQuery<EntityLogItem> query = em.createQuery(
'select i from sec$EntityLog i where i.entity = ?1 and i.entityRef.entityId = ?2 order by i.eventTs desc', EntityLogItem.class)
query.setParameter(1, 'sec$User')
query.setParameter(2, userId)
items = query.getResultList()
tx.commit()
} finally {
tx.end()
}
return items
}
def "Entity Log: create/update/delete entity with dynamic attribute"() {
Group group = cont.persistence().callInTransaction({ em ->
em.find(Group.class, TestSupport.COMPANY_GROUP_ID)
})
when:
User user1 = cont.metadata().create(User)
user1Id = user1.getId()
user1.setGroup(group)
user1.setLogin("test")
user1.setName("test-name")
user1.getValue("+userAttribute")
user1.setValue("+userAttribute", "userName")
dataManager.commit(user1)
then:
def items = getEntityLogItems(user1Id)
items.size() == 1
def item = items[0]
item.type == EntityLogItem.Type.CREATE
item.attributes.find({ it.name == 'name' }).value == 'test-name'
item.attributes.find({ it.name == '+userAttribute' }).value == 'userName'
when:
LoadContext<User> loadContext = new LoadContext(User.class)
.setId(user1).setView(View.LOCAL).setLoadDynamicAttributes(true)
user1 = dataManager.load(loadContext)
user1Id = user1.getId()
user1.setValue("+userAttribute", "userName1")
dataManager.commit(user1)
then:
def items1 = getEntityLogItems(user1Id)
items1.size() == 2
def item1 = items1[0]
item1.type == EntityLogItem.Type.MODIFY
item1.attributes.find({ it.name == '+userAttribute' }).oldValue == 'userName'
item1.attributes.find({ it.name == '+userAttribute' }).value == 'userName1'
when:
loadContext = new LoadContext(User.class)
.setId(user1).setView(View.LOCAL).setLoadDynamicAttributes(true)
user1 = (User) dataManager.load(loadContext)
user1Id = user1.getId()
user1.setValue("+userAttribute", null)
dataManager.commit(user1)
then:
def items2 = getEntityLogItems(user1Id)
items2.size() == 3
def item2 = items2[0]
item2.type == EntityLogItem.Type.MODIFY
item2.attributes.find({ it.name == '+userAttribute' }).value == ""
item2.attributes.find({ it.name == '+userAttribute' }).oldValue == 'userName1'
}
}

View File

@ -20,8 +20,12 @@ package com.haulmont.cuba.gui.app.core.entitylog;
import com.haulmont.bali.util.ParamsMap;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.chile.core.model.Range;
import com.haulmont.cuba.core.app.EntityLogService;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributes;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
import com.haulmont.cuba.core.entity.CategoryAttribute;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.entity.HasUuid;
import com.haulmont.cuba.core.global.AppBeans;
@ -37,6 +41,7 @@ import com.haulmont.cuba.gui.data.CollectionDatasource;
import com.haulmont.cuba.gui.theme.ThemeConstants;
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
import com.haulmont.cuba.security.entity.*;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.time.DateUtils;
import javax.inject.Inject;
@ -62,6 +67,9 @@ public class EntityLogBrowser extends AbstractWindow {
@Inject
protected ReferenceToEntitySupport referenceToEntitySupport;
@Inject
protected DynamicAttributes dynamicAttributes;
@Inject
protected CollectionDatasource<EntityLogItem, UUID> entityLogDs;
@ -306,43 +314,49 @@ public class EntityLogBrowser extends AbstractWindow {
actionsPaneLayout.setVisible(false);
}
protected void fillAttributes(String metaClassName, LoggedEntity item, boolean setEditableCheckboxes) {
protected void fillAttributes(String metaClassName, LoggedEntity item, boolean editable) {
clearAttributes();
setSelectAllCheckBox(false);
if (metaClassName != null) {
MetaClass metaClass = metadata.getExtendedEntities().getEffectiveMetaClass(
metadata.getClassNN(metaClassName));
Collection<MetaProperty> metaProperties = metaClass.getProperties();
selectAllCheckBox.setEditable(setEditableCheckboxes);
List<MetaProperty> metaProperties = new ArrayList<>(metaClass.getProperties());
selectAllCheckBox.setEditable(editable);
Set<LoggedAttribute> enabledAttr = null;
if (item != null)
enabledAttr = item.getAttributes();
for (MetaProperty property : metaProperties) {
if (!systemAttrsList.contains(property.getName())) {
Range range = property.getRange();
if (range.isClass() && metadata.getTools().hasCompositePrimaryKey(range.asClass()) &&
!HasUuid.class.isAssignableFrom(range.asClass().getJavaClass())) {
continue;
if (allowLogProperty(property, null)) {
addAttribute(enabledAttr, property, editable);
}
}
Collection<CategoryAttribute> attributes = dynamicAttributes.getAttributesForMetaClass(metaClass);
if (attributes != null) {
for (CategoryAttribute categoryAttribute : attributes) {
MetaPropertyPath propertyPath = DynamicAttributesUtils.getMetaPropertyPath(metaClass, categoryAttribute);
MetaProperty property = propertyPath.getMetaProperty();
if (allowLogProperty(property, categoryAttribute)) {
addAttribute(enabledAttr, property, editable);
}
if (range.isClass() && range.getCardinality().isMany()) {
continue;
}
CheckBox checkBox = factory.createComponent(CheckBox.class);
if (enabledAttr != null && isEntityHaveAttribute(property.getName(), enabledAttr)) {
checkBox.setValue(true);
}
checkBox.setId(property.getName());
checkBox.setCaption(property.getName());
checkBox.setEditable(setEditableCheckboxes);
checkBox.addValueChangeListener(e -> checkAllCheckboxes());
attributesBoxScroll.add(checkBox);
}
}
}
}
protected void addAttribute(Set<LoggedAttribute> enabledAttributes, MetaProperty property, boolean editable) {
CheckBox checkBox = factory.createComponent(CheckBox.class);
if (enabledAttributes != null && isEntityHaveAttribute(property.getName(), enabledAttributes)) {
checkBox.setValue(true);
}
checkBox.setId(property.getName());
checkBox.setCaption(property.getName());
checkBox.setEditable(editable);
checkBox.addValueChangeListener(e -> checkAllCheckboxes());
attributesBoxScroll.add(checkBox);
}
protected void enableAllCheckBoxes(boolean b) {
if (canSelectAllCheckboxGenerateEvents) {
for (Component box : attributesBoxScroll.getComponents())
@ -474,6 +488,25 @@ public class EntityLogBrowser extends AbstractWindow {
cancelBtn.requestFocus();
}
protected boolean allowLogProperty(MetaProperty metaProperty, CategoryAttribute categoryAttribute) {
if (systemAttrsList.contains(metaProperty.getName())) {
return false;
}
Range range = metaProperty.getRange();
if (range.isClass() && metadata.getTools().hasCompositePrimaryKey(range.asClass()) &&
!HasUuid.class.isAssignableFrom(range.asClass().getJavaClass())) {
return false;
}
if (range.isClass() && range.getCardinality().isMany()) {
return false;
}
if (categoryAttribute != null &&
BooleanUtils.isTrue(categoryAttribute.getIsCollection())) {
return false;
}
return true;
}
protected class SaveAction extends AbstractAction {
public SaveAction() {