378 lines
17 KiB
Java
378 lines
17 KiB
Java
package eu.eudat.service.visibility;
|
|
|
|
import eu.eudat.commons.types.description.PropertyDefinitionEntity;
|
|
import eu.eudat.commons.types.descriptiontemplate.*;
|
|
import eu.eudat.model.persist.descriptionproperties.PropertyDefinitionPersist;
|
|
|
|
import javax.ws.rs.NotSupportedException;
|
|
import java.util.*;
|
|
|
|
public class VisibilityServiceImpl implements VisibilityService {
|
|
|
|
private final DefinitionEntity definition;
|
|
private final PropertyDefinition propertyDefinition;
|
|
|
|
private Map<String, List<RuleWithTarget>> rulesBySources;
|
|
private Map<FieldKey, Boolean> visibility;
|
|
|
|
public VisibilityServiceImpl(DefinitionEntity definition, PropertyDefinitionPersist propertyDefinition) {
|
|
this.definition = definition;
|
|
this.propertyDefinition = new PropertyDefinition(propertyDefinition);
|
|
}
|
|
|
|
public VisibilityServiceImpl(DefinitionEntity definition, PropertyDefinitionEntity propertyDefinition) {
|
|
this.definition = definition;
|
|
this.propertyDefinition = new PropertyDefinition(propertyDefinition);
|
|
}
|
|
|
|
private void initRules(){
|
|
if (this.rulesBySources != null) return;
|
|
rulesBySources = new HashMap<>();
|
|
for (FieldEntity fieldEntity : this.definition.getAllField()){
|
|
if (fieldEntity.getVisibilityRules() != null && !fieldEntity.getVisibilityRules().isEmpty()) {
|
|
for (RuleEntity rule : fieldEntity.getVisibilityRules()){
|
|
if (!rulesBySources.containsKey(fieldEntity.getId())) rulesBySources.put(fieldEntity.getId(), new ArrayList<>());
|
|
RuleWithTarget ruleWithTarget = new RuleWithTarget(fieldEntity.getId(), rule, fieldEntity);
|
|
rulesBySources.get(fieldEntity.getId()).add(ruleWithTarget);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isVisible(String id, Integer ordinal) {
|
|
this.calculateVisibility();
|
|
FieldKey fieldKey = new FieldKey(id, ordinal);
|
|
return this.visibility.getOrDefault(fieldKey, false);
|
|
}
|
|
|
|
@Override
|
|
public Map<FieldKey, Boolean> getVisibilityStates() {
|
|
this.calculateVisibility();
|
|
return visibility;
|
|
}
|
|
|
|
private void calculateVisibility(){
|
|
if (visibility != null) return;
|
|
|
|
this.initRules();
|
|
this.buildTargetVisibility();
|
|
this.expandVisibilityToChildren();
|
|
this.setDefaultVisibilityForNotCaclucted();
|
|
this.hideParentIfAllChildrenAreHidden();
|
|
}
|
|
|
|
private void buildTargetVisibility(){
|
|
visibility = new HashMap<>();
|
|
for (Map.Entry<String, List<RuleWithTarget>> ruleForSource : rulesBySources.entrySet()){
|
|
for (RuleWithTarget rule : ruleForSource.getValue()){
|
|
if (propertyDefinition.getFieldSets() != null && !propertyDefinition.getFieldSets().isEmpty()){
|
|
for (PropertyDefinitionFieldSet propertyDefinitionFieldSet: propertyDefinition.getFieldSets().values()) {
|
|
if (propertyDefinitionFieldSet.getItems() != null && !propertyDefinitionFieldSet.getItems().isEmpty()) {
|
|
for (PropertyDefinitionFieldSetItem definitionFieldSetItem : propertyDefinitionFieldSet.getItems()) {
|
|
if (definitionFieldSetItem.getFields() != null && !definitionFieldSetItem.getFields().isEmpty()) {
|
|
for (String key : definitionFieldSetItem.getFields().keySet()) {
|
|
if (rule.getSource().equals(key)){
|
|
Field field = definitionFieldSetItem.getFields().get(key);
|
|
|
|
if (definitionFieldSetItem.getFields().containsKey(rule.getTarget())){ //Rule applies only for current multiple item
|
|
FieldKey fieldKey = new FieldKey(rule.getTarget(), definitionFieldSetItem.getOrdinal());
|
|
boolean currentState = this.visibility.getOrDefault(fieldKey, false);
|
|
this.visibility.put(fieldKey, currentState || ruleIsTrue(rule, field));
|
|
} else if (!this.definition.getFieldById(rule.getTarget()).isEmpty() || !this.definition.getFieldSetById(rule.getTarget()).isEmpty()) { //Rule applies to different fieldset, so we apply for all multiple items
|
|
List<Integer> ordinals = this.getKeyOrdinals(rule.getTarget());
|
|
for (Integer ordinal : ordinals){
|
|
FieldKey fieldKey = new FieldKey(rule.getTarget(), ordinal);
|
|
boolean currentState = this.visibility.getOrDefault(fieldKey, false);
|
|
this.visibility.put(fieldKey, currentState || ruleIsTrue(rule, field));
|
|
}
|
|
} else {
|
|
FieldKey fieldKey = new FieldKey(rule.getTarget(), null); //Ordinal is null if target not on field
|
|
boolean currentState = this.visibility.getOrDefault(fieldKey, false);
|
|
this.visibility.put(fieldKey, currentState || ruleIsTrue(rule, field));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private List<Integer> getKeyOrdinals(String key){
|
|
if (propertyDefinition.getFieldSets() != null && !propertyDefinition.getFieldSets().isEmpty()){
|
|
for (Map.Entry<String, PropertyDefinitionFieldSet> propertyDefinitionFieldSet: propertyDefinition.getFieldSets().entrySet()) {
|
|
if (propertyDefinitionFieldSet.getKey().equals(key)) return propertyDefinitionFieldSet.getValue().getItems().stream().map(PropertyDefinitionFieldSetItem::getOrdinal).toList();
|
|
|
|
if (propertyDefinitionFieldSet.getValue() != null && propertyDefinitionFieldSet.getValue().getItems() != null && !propertyDefinitionFieldSet.getValue().getItems().isEmpty()) {
|
|
for (PropertyDefinitionFieldSetItem definitionFieldSetItem : propertyDefinitionFieldSet.getValue().getItems()) {
|
|
if (definitionFieldSetItem.getFields() != null && !definitionFieldSetItem.getFields().isEmpty()) {
|
|
for (String fieldKey : definitionFieldSetItem.getFields().keySet()) {
|
|
if (fieldKey.equals(key)) return propertyDefinitionFieldSet.getValue().getItems().stream().map(PropertyDefinitionFieldSetItem::getOrdinal).toList();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
private void expandVisibilityToChildren(){
|
|
if (this.definition.getPages() == null) return;
|
|
for (PageEntity pageEntity : this.definition.getPages()){
|
|
FieldKey fieldKey = new FieldKey(pageEntity.getId(), null);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
this.expandPageVisibility(pageEntity, currentValue);
|
|
}
|
|
}
|
|
|
|
private void expandPageVisibility(PageEntity pageEntity, Boolean parentVisibility){
|
|
if (pageEntity.getSections() == null) return;
|
|
for (SectionEntity sectionEntity : pageEntity.getSections()){
|
|
FieldKey fieldKey = new FieldKey(sectionEntity.getId(), null);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue != null){
|
|
if (parentVisibility != null && !parentVisibility) { //Parent is hidden so all childs should be hidden
|
|
this.visibility.put(fieldKey, false);
|
|
this.expandSectionVisibility(sectionEntity, currentValue);
|
|
} else {
|
|
this.expandSectionVisibility(sectionEntity, currentValue);
|
|
}
|
|
} else {
|
|
if (parentVisibility != null) this.visibility.put(fieldKey, parentVisibility);
|
|
this.expandSectionVisibility(sectionEntity, parentVisibility);
|
|
}
|
|
}
|
|
}
|
|
private void expandSectionVisibility(SectionEntity sectionEntity, Boolean parentVisibility){
|
|
if (sectionEntity.getSections() != null) {
|
|
for (SectionEntity subSectionEntity : sectionEntity.getSections()) {
|
|
FieldKey fieldKey = new FieldKey(subSectionEntity.getId(), null);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue != null){
|
|
if (parentVisibility != null && !parentVisibility) { //Parent is hidden so all childs should be hidden
|
|
this.visibility.put(fieldKey, false);
|
|
this.expandSectionVisibility(subSectionEntity, currentValue);
|
|
} else {
|
|
this.expandSectionVisibility(subSectionEntity, currentValue);
|
|
}
|
|
} else {
|
|
if (parentVisibility != null) this.visibility.put(fieldKey, parentVisibility);
|
|
this.expandSectionVisibility(subSectionEntity, parentVisibility);
|
|
}
|
|
}
|
|
}
|
|
if (sectionEntity.getFieldSets() != null) {
|
|
for (FieldSetEntity fieldSetEntity : sectionEntity.getFieldSets()) {
|
|
if (propertyDefinition.getFieldSets() != null && !propertyDefinition.getFieldSets().isEmpty()){
|
|
PropertyDefinitionFieldSet propertyDefinitionFieldSet = propertyDefinition.getFieldSets().getOrDefault(fieldSetEntity.getId(), null);
|
|
if (propertyDefinitionFieldSet != null && propertyDefinitionFieldSet.getItems() != null && !propertyDefinitionFieldSet.getItems().isEmpty()) {
|
|
for (PropertyDefinitionFieldSetItem definitionFieldSetItem : propertyDefinitionFieldSet.getItems()) {
|
|
FieldKey fieldKey = new FieldKey(fieldSetEntity.getId(), definitionFieldSetItem.getOrdinal());
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue != null){
|
|
if (parentVisibility != null && !parentVisibility) { //Parent is hidden so all childs should be hidden
|
|
this.visibility.put(fieldKey, false);
|
|
this.expandFieldSetVisibility(fieldSetEntity, currentValue, definitionFieldSetItem.getOrdinal());
|
|
} else {
|
|
this.expandFieldSetVisibility(fieldSetEntity, currentValue, definitionFieldSetItem.getOrdinal());
|
|
}
|
|
} else {
|
|
if (parentVisibility != null) this.visibility.put(fieldKey, parentVisibility);
|
|
this.expandFieldSetVisibility(fieldSetEntity, parentVisibility, definitionFieldSetItem.getOrdinal());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void expandFieldSetVisibility(FieldSetEntity fieldSetEntity, Boolean parentVisibility, Integer ordinal){
|
|
if (fieldSetEntity.getFields() != null) {
|
|
for (FieldEntity fieldEntity : fieldSetEntity.getFields()) {
|
|
FieldKey fieldKey = new FieldKey(fieldEntity.getId(), ordinal);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue != null){
|
|
if (parentVisibility != null && !parentVisibility) { //Parent is hidden so all childs should be hidden
|
|
this.visibility.put(fieldKey, false);
|
|
}
|
|
} else if (parentVisibility != null){
|
|
this.visibility.put(fieldKey, parentVisibility);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void setDefaultVisibilityForNotCaclucted(){
|
|
if (this.definition.getPages() == null) return;
|
|
for (PageEntity pageEntity : this.definition.getPages()){
|
|
FieldKey fieldKey = new FieldKey(pageEntity.getId(), null);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue == null) this.visibility.put(fieldKey, true);
|
|
this.setDefaultPageVisibility(pageEntity);
|
|
}
|
|
}
|
|
|
|
private void setDefaultPageVisibility(PageEntity pageEntity){
|
|
if (pageEntity.getSections() == null) return;
|
|
for (SectionEntity sectionEntity : pageEntity.getSections()){
|
|
FieldKey fieldKey = new FieldKey(sectionEntity.getId(), null);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue == null){
|
|
this.visibility.put(fieldKey, true);
|
|
this.setDefaultSectionVisibility(sectionEntity);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void setDefaultSectionVisibility(SectionEntity sectionEntity){
|
|
if (sectionEntity.getSections() != null) {
|
|
for (SectionEntity subSectionEntity : sectionEntity.getSections()) {
|
|
FieldKey fieldKey = new FieldKey(subSectionEntity.getId(), null);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue == null){
|
|
this.visibility.put(fieldKey, true);
|
|
this.setDefaultSectionVisibility(subSectionEntity);
|
|
}
|
|
}
|
|
}
|
|
if (sectionEntity.getFieldSets() != null) {
|
|
for (FieldSetEntity fieldSetEntity : sectionEntity.getFieldSets()) {
|
|
if (propertyDefinition.getFieldSets() != null && !propertyDefinition.getFieldSets().isEmpty()){
|
|
PropertyDefinitionFieldSet propertyDefinitionFieldSet = propertyDefinition.getFieldSets().getOrDefault(fieldSetEntity.getId(), null);
|
|
if (propertyDefinitionFieldSet != null && propertyDefinitionFieldSet.getItems() != null && !propertyDefinitionFieldSet.getItems().isEmpty()) {
|
|
for (PropertyDefinitionFieldSetItem definitionFieldSetItem : propertyDefinitionFieldSet.getItems()) {
|
|
FieldKey fieldKey = new FieldKey(fieldSetEntity.getId(), definitionFieldSetItem.getOrdinal());
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue == null){
|
|
this.visibility.put(fieldKey, true);
|
|
this.setDefaultFieldSetVisibility(fieldSetEntity, definitionFieldSetItem.getOrdinal());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void setDefaultFieldSetVisibility(FieldSetEntity fieldSetEntity, Integer ordinal){
|
|
if (fieldSetEntity.getFields() != null) {
|
|
for (FieldEntity fieldEntity : fieldSetEntity.getFields()) {
|
|
FieldKey fieldKey = new FieldKey(fieldEntity.getId(), ordinal);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, null);
|
|
if (currentValue == null){
|
|
this.visibility.put(fieldKey, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void hideParentIfAllChildrenAreHidden(){
|
|
if (this.definition.getPages() == null) return;
|
|
for (PageEntity pageEntity : this.definition.getPages()){
|
|
FieldKey fieldKey = new FieldKey(pageEntity.getId(), null);
|
|
boolean isCurrentHidden = this.isHiddenPageVisibilityIfAllChildrenIsHidden(pageEntity);
|
|
if (this.visibility.getOrDefault(fieldKey, true) && isCurrentHidden){
|
|
this.visibility.put(fieldKey, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean isHiddenPageVisibilityIfAllChildrenIsHidden(PageEntity pageEntity){
|
|
boolean isHidden = true;
|
|
if (pageEntity.getSections() == null) return isHidden;
|
|
|
|
for (SectionEntity sectionEntity : pageEntity.getSections()){
|
|
FieldKey fieldKey = new FieldKey(sectionEntity.getId(), null);
|
|
boolean isCurrentHidden = this.isHiddenSectionIfAllChildrenIsHidden(sectionEntity);
|
|
if (this.visibility.getOrDefault(fieldKey, true) && isCurrentHidden){
|
|
this.visibility.put(fieldKey, false);
|
|
}
|
|
isHidden = isHidden && isCurrentHidden;
|
|
}
|
|
return isHidden;
|
|
}
|
|
|
|
private boolean isHiddenSectionIfAllChildrenIsHidden(SectionEntity sectionEntity){
|
|
boolean isHidden = true;
|
|
if (sectionEntity.getSections() != null) {
|
|
for (SectionEntity subSectionEntity : sectionEntity.getSections()) {
|
|
FieldKey fieldKey = new FieldKey(subSectionEntity.getId(), null);
|
|
boolean isCurrentHidden = this.isHiddenSectionIfAllChildrenIsHidden(subSectionEntity);
|
|
if (this.visibility.getOrDefault(fieldKey, true) && isCurrentHidden){
|
|
this.visibility.put(fieldKey, false);
|
|
}
|
|
isHidden = isHidden && isCurrentHidden;
|
|
}
|
|
}
|
|
if (sectionEntity.getFieldSets() != null) {
|
|
for (FieldSetEntity fieldSetEntity : sectionEntity.getFieldSets()) {
|
|
if (propertyDefinition.getFieldSets() != null && !propertyDefinition.getFieldSets().isEmpty()){
|
|
PropertyDefinitionFieldSet propertyDefinitionFieldSet = propertyDefinition.getFieldSets().getOrDefault(fieldSetEntity.getId(), null);
|
|
if (propertyDefinitionFieldSet != null && propertyDefinitionFieldSet.getItems() != null && !propertyDefinitionFieldSet.getItems().isEmpty()) {
|
|
for (PropertyDefinitionFieldSetItem definitionFieldSetItem : propertyDefinitionFieldSet.getItems()) {
|
|
FieldKey fieldKey = new FieldKey(fieldSetEntity.getId(), definitionFieldSetItem.getOrdinal());
|
|
boolean isCurrentHidden = this.isHiddenFieldSetIfAllChildrenIsHidden(fieldSetEntity, definitionFieldSetItem.getOrdinal());
|
|
if (this.visibility.getOrDefault(fieldKey, true) && isCurrentHidden){
|
|
this.visibility.put(fieldKey, false);
|
|
}
|
|
isHidden = isHidden && isCurrentHidden;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return isHidden;
|
|
}
|
|
|
|
private boolean isHiddenFieldSetIfAllChildrenIsHidden(FieldSetEntity fieldSetEntity, Integer ordinal){
|
|
boolean isHidden = true;
|
|
if (fieldSetEntity.getFields() != null) {
|
|
for (FieldEntity fieldEntity : fieldSetEntity.getFields()) {
|
|
FieldKey fieldKey = new FieldKey(fieldEntity.getId(), ordinal);
|
|
Boolean currentValue = this.visibility.getOrDefault(fieldKey, true);
|
|
isHidden = isHidden && !currentValue;
|
|
}
|
|
return isHidden;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private boolean ruleIsTrue(RuleWithTarget rule, Field field){
|
|
if (field != null){
|
|
eu.eudat.commons.enums.FieldType fieldType = rule.getFieldEntity() != null && rule.getFieldEntity().getData() != null ? rule.getFieldEntity().getData().getFieldType() : eu.eudat.commons.enums.FieldType.FREE_TEXT;
|
|
if (eu.eudat.commons.enums.FieldType.isTextType(fieldType) && field.getTextValue() != null && !field.getTextValue().isBlank()) {
|
|
if (eu.eudat.commons.enums.FieldType.UPLOAD.equals(fieldType)){
|
|
throw new NotSupportedException("Upload file rule not supported");
|
|
} else {
|
|
return field.getTextValue().equals(rule.getTextValue());
|
|
}
|
|
}
|
|
else if (eu.eudat.commons.enums.FieldType.isTextListType(fieldType) && field.getTextListValue() != null && !field.getTextListValue().isEmpty()) {
|
|
return rule.getTextListValue() != null &&
|
|
new HashSet<>(field.getTextListValue()).containsAll(rule.getTextListValue());
|
|
}
|
|
else if (eu.eudat.commons.enums.FieldType.isReferenceType(fieldType)) {
|
|
return rule.getTextListValue() != null &&
|
|
new HashSet<>(field.getTextListValue()).containsAll(rule.getTextListValue());
|
|
}
|
|
else if (eu.eudat.commons.enums.FieldType.isDateType(fieldType) && field.getDateValue() != null) return field.getDateValue().equals(rule.getDateValue());
|
|
else if (eu.eudat.commons.enums.FieldType.isExternalIdentifierType(fieldType) && field.getExternalIdentifier() != null) {
|
|
throw new NotSupportedException("External identifier rule not supported");
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|