One more post and I promise to leave it at that ()
my deliberate usage of the vague term “some kind of expression” should perhaps be replaced by … code … allow us to use the language we know best.
I will post my current setup here, perhaps other people will find it useful.
The first class is an example role.
For entity access I only use the packagename.
For entity attribute access I added a method that also allows to pass in a predicate over fields.
In this completely useless example this role gets modify access on all non-enum simple types. It also gets view access on all fields that have the NotNull annotation.
Pretty useless example, but it does show that with a bit of code you can now express powerful things. You could introduce eg. annotations and couple a role to it. This would allow to remove runtime reference to properties names.
The main point I guess that it gives us developers the tools to integrate our specific behavior into generic Cuba mechanisms.
@AlexBudarov @jon.craig i would like you guys opinion on this.
package mypackage;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.cuba.security.app.role.AnnotatedRoleDefinition;
import com.haulmont.cuba.security.app.role.annotation.Role;
import com.haulmont.cuba.security.entity.EntityAttrAccess;
import com.haulmont.cuba.security.entity.EntityOp;
import com.haulmont.cuba.security.role.EntityAttributePermissionsContainer;
import com.haulmont.cuba.security.role.EntityPermissionsContainer;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
@Role(name = "Business Entities Crud")
public class BusinessEntitiesCrudRole extends AnnotatedRoleDefinition {
@Inject
private EntityPermissionContainerBuilderFactory entityPermissionContainerBuilderFactory;
@Override
public EntityPermissionsContainer entityPermissions() {
return entityPermissionContainerBuilderFactory
.entityPermissionsContainer()
.add(m -> m.getJavaClass().getPackage().getName().startsWith("mypackage.entity"), EntityOp.values())
.build();
}
@Override
public EntityAttributePermissionsContainer entityAttributePermissions() {
return entityPermissionContainerBuilderFactory.entityAttributePermissionsContainerBuilder()
.add(m -> m.getJavaClass().getPackage().getName().startsWith("mypackage.entity"),
mp -> mp.getType() == MetaProperty.Type.DATATYPE, EntityAttrAccess.MODIFY)
.add(m -> m.getJavaClass().getPackage().getName().startsWith("mypackage.entity"),
mp -> mp.getAnnotatedElement().isAnnotationPresent(NotNull.class), EntityAttrAccess.VIEW)
.build();
}
}
package mypackage;
import com.haulmont.cuba.core.global.Metadata;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
@Component
public class EntityPermissionContainerBuilderFactory {
@Inject
private Metadata metadata;
public EntityPermissionsContainerBuilder entityPermissionsContainer() {
return new EntityPermissionsContainerBuilder(metadata);
}
public EntityAttributePermissionsContainerBuilder entityAttributePermissionsContainerBuilder() {
return new EntityAttributePermissionsContainerBuilder(metadata);
}
}
package mypackage;
import com.google.common.base.Strings;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.security.entity.Access;
import com.haulmont.cuba.security.entity.EntityOp;
import com.haulmont.cuba.security.role.EntityPermissionsContainer;
import com.haulmont.cuba.security.role.PermissionsUtils;
import lombok.AllArgsConstructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class EntityPermissionsContainerBuilder {
private Metadata metadata;
private List<EntityPermissionEntry> permissionEntries = new ArrayList<>();
EntityPermissionsContainerBuilder(Metadata metadata) {
this.metadata = metadata;
}
public EntityPermissionsContainerBuilder add(MetaClass metaClass, EntityOp... permissions) {
Arrays.stream(permissions).map(p -> new EntityPermissionEntry(metaClass, p)).forEach(permissionEntries::add);
return this;
}
public EntityPermissionsContainerBuilder add(Predicate<MetaClass> predicate, EntityOp...entityOp) {
metadata.getClasses().stream()
.filter(predicate)
.flatMap(m -> Arrays.stream(entityOp).map(op -> new EntityPermissionEntry(m, op)))
.forEach(permissionEntries::add);
return this;
}
public EntityPermissionsContainer build() {
EntityPermissionsContainer container = new EntityPermissionsContainer();
permissionEntries.stream().forEach(p -> addToPermissionToContainer(container, p.metaClass, p.entityOp));
return container;
}
private void addToPermissionToContainer(EntityPermissionsContainer permissions, MetaClass metaclass, EntityOp entityOp) {
String target = PermissionsUtils.getEntityOperationTarget(metaclass.getName(), entityOp);
Integer permissionValue = Access.ALLOW.getId();
permissions.getExplicitPermissions().put(target, permissionValue);
String extendedTarget = PermissionsUtils.evaluateExtendedEntityTarget(target);
if (!Strings.isNullOrEmpty(extendedTarget)) {
permissions.getExplicitPermissions().put(extendedTarget, permissionValue);
}
}
@AllArgsConstructor
private static class EntityPermissionEntry {
MetaClass metaClass;
EntityOp entityOp;
}
}
package mypackage;
import com.google.common.base.Strings;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.security.entity.EntityAttrAccess;
import com.haulmont.cuba.security.role.EntityAttributePermissionsContainer;
import com.haulmont.cuba.security.role.PermissionsContainer;
import com.haulmont.cuba.security.role.PermissionsUtils;
import lombok.AllArgsConstructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class EntityAttributePermissionsContainerBuilder {
private Metadata metadata;
private List<EntityAttributePermissionEntry> permissions = new ArrayList<>();
EntityAttributePermissionsContainerBuilder(Metadata metadata) {
this.metadata = metadata;
}
public EntityAttributePermissionsContainerBuilder add(MetaClass metaClass, EntityAttrAccess attrAccess, String... properties) {
Arrays.stream(properties)
.map(p -> new EntityAttributePermissionEntry(metaClass, p, attrAccess))
.forEach(permissions::add);
return this;
}
public EntityAttributePermissionsContainerBuilder add(Predicate<MetaClass> predicate, EntityAttrAccess attrAccess, String ... properties) {
metadata.getClasses().stream()
.filter(predicate)
.flatMap(m -> Arrays.stream(properties).map(p -> new EntityAttributePermissionEntry(m, p, attrAccess)));
return this;
}
public EntityAttributePermissionsContainerBuilder add(Predicate<MetaClass> predicate, Predicate<MetaProperty> fieldPredicate, EntityAttrAccess entityAttrAccess) {
metadata.getClasses().stream()
.filter(predicate)
.flatMap(m -> m.getProperties().stream()
.filter(fieldPredicate)
.map(p -> new EntityAttributePermissionEntry(m, p.getName(), entityAttrAccess))
).forEach(permissions::add);
return this;
}
public EntityAttributePermissionsContainer build() {
EntityAttributePermissionsContainer container = new EntityAttributePermissionsContainer();
permissions.forEach(p -> addEntityAttributeTarget(container, p.metaClass.getName(), p.property, p.access));
return container;
}
private void addEntityAttributeTarget(PermissionsContainer permissions, String entityName, String property,
EntityAttrAccess access) {
String target = PermissionsUtils.getEntityAttributeTarget(entityName, property);
Integer permissionValue = access.getId();
permissions.getExplicitPermissions().put(target, permissionValue);
String extendedTarget = PermissionsUtils.evaluateExtendedEntityTarget(target);
if (!Strings.isNullOrEmpty(extendedTarget)) {
permissions.getExplicitPermissions().put(extendedTarget, permissionValue);
}
}
@AllArgsConstructor
private static class EntityAttributePermissionEntry {
MetaClass metaClass;
String property;
EntityAttrAccess access;
}
}