All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.edu.icm.unity.engine.attribute.AttributesHelper Maven / Gradle / Ivy

/*
 * Copyright (c) 2013 ICM Uniwersytet Warszawski All rights reserved.
 * See LICENCE.txt file for licensing information.
 */
package pl.edu.icm.unity.engine.attribute;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static pl.edu.icm.unity.types.basic.audit.AuditEventTag.AUTHN;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.collect.ImmutableMap;

import pl.edu.icm.unity.base.capacityLimit.CapacityLimitName;
import pl.edu.icm.unity.base.utils.Log;
import pl.edu.icm.unity.engine.api.attributes.AttributeClassHelper;
import pl.edu.icm.unity.engine.api.attributes.AttributeValueSyntax;
import pl.edu.icm.unity.engine.api.identity.EntityResolver;
import pl.edu.icm.unity.engine.api.mvel.CachingMVELGroupProvider;
import pl.edu.icm.unity.engine.audit.AuditEventTrigger;
import pl.edu.icm.unity.engine.audit.AuditEventTrigger.AuditEventTriggerBuilder;
import pl.edu.icm.unity.engine.audit.AuditPublisher;
import pl.edu.icm.unity.engine.capacityLimits.InternalCapacityLimitVerificator;
import pl.edu.icm.unity.engine.credential.CredentialAttributeTypeProvider;
import pl.edu.icm.unity.exceptions.CapacityLimitReachedException;
import pl.edu.icm.unity.exceptions.EngineException;
import pl.edu.icm.unity.exceptions.IllegalAttributeTypeException;
import pl.edu.icm.unity.exceptions.IllegalAttributeValueException;
import pl.edu.icm.unity.exceptions.IllegalGroupValueException;
import pl.edu.icm.unity.exceptions.IllegalIdentityValueException;
import pl.edu.icm.unity.exceptions.IllegalTypeException;
import pl.edu.icm.unity.exceptions.SchemaConsistencyException;
import pl.edu.icm.unity.stdext.attr.StringAttribute;
import pl.edu.icm.unity.store.api.AttributeDAO;
import pl.edu.icm.unity.store.api.AttributeTypeDAO;
import pl.edu.icm.unity.store.api.EntityDAO;
import pl.edu.icm.unity.store.api.IdentityDAO;
import pl.edu.icm.unity.store.api.MembershipDAO;
import pl.edu.icm.unity.store.api.generic.AttributeClassDB;
import pl.edu.icm.unity.store.types.StoredAttribute;
import pl.edu.icm.unity.types.basic.Attribute;
import pl.edu.icm.unity.types.basic.AttributeExt;
import pl.edu.icm.unity.types.basic.AttributeType;
import pl.edu.icm.unity.types.basic.AttributesClass;
import pl.edu.icm.unity.types.basic.EntityInformation;
import pl.edu.icm.unity.types.basic.EntityParam;
import pl.edu.icm.unity.types.basic.EntityState;
import pl.edu.icm.unity.types.basic.Group;
import pl.edu.icm.unity.types.basic.Identity;
import pl.edu.icm.unity.types.basic.VerifiableElementBase;
import pl.edu.icm.unity.types.basic.audit.AuditEventAction;
import pl.edu.icm.unity.types.basic.audit.AuditEventTag;
import pl.edu.icm.unity.types.basic.audit.AuditEventType;
import pl.edu.icm.unity.types.confirmation.ConfirmationInfo;
import pl.edu.icm.unity.types.confirmation.VerifiableElement;

/**
 * Attributes and ACs related operations, intended for reuse between other classes.
 * No operation in this interface performs any authorization.
 * @author K. Benedyczak
 */
@Component
public class AttributesHelper
{
	private static final Logger log = Log.getLogger(Log.U_SERVER_CORE,	AttributesHelper.class);

	
	private final AttributeClassDB acDB;
	private final AttributeClassUtil acUtil;
	private final IdentityDAO identityDAO;
	private final EntityDAO entityDAO;
	private final EntityResolver idResolver;
	private final AttributeTypeDAO attributeTypeDAO;
	private final AttributeDAO attributeDAO;
	private final MembershipDAO membershipDAO;
	private final AttributeStatementProcessor statementsHelper;
	private final AttributeTypeHelper atHelper;
	private final AuditPublisher audit;
	private final InternalCapacityLimitVerificator capacityLimitVerificator;
	private final PublicAttributeRegistry attrRegistry;
	private final AttributeTypeByMetaCache attributeTypeByMetaCache;
	
	@Autowired
	public AttributesHelper(
			AttributeClassDB acDB, IdentityDAO identityDAO,
			EntityDAO entityDAO, EntityResolver idResolver,
			AttributeTypeDAO attributeTypeDAO, AttributeDAO attributeDAO,
			MembershipDAO membershipDAO, AttributeStatementProcessor statementsHelper,
			AttributeTypeHelper atHelper, AttributeClassUtil acUtil,
			AuditPublisher audit,
			InternalCapacityLimitVerificator capacityLimitVerificator,
			AttributeTypeByMetaCache attributeTypeByMetaCache)
	{
		this.acDB = acDB;
		this.identityDAO = identityDAO;
		this.entityDAO = entityDAO;
		this.idResolver = idResolver;
		this.attributeTypeDAO = attributeTypeDAO;
		this.attributeDAO = attributeDAO;
		this.membershipDAO = membershipDAO;
		this.statementsHelper = statementsHelper;
		this.atHelper = atHelper;
		this.acUtil = acUtil;
		this.audit = audit;
		this.capacityLimitVerificator = capacityLimitVerificator;
		this.attrRegistry = new PublicAttributeRegistry(attributeDAO, atHelper);
		this.attributeTypeByMetaCache = attributeTypeByMetaCache;
	}

	public Map getAllAttributesAsMapOneGroup(long entityId, String groupPath) 
			throws EngineException
	{
		if (groupPath == null)
			throw new IllegalArgumentException("For this method group must be specified");
		return getEntityAttributesInGroupAsMap(entityId, groupPath, null);
	}
	
	/**
	 * @return single attribute of a given entity in a given group.
	 */
	public AttributeExt getAttributeOneGroup(long entityId, String groupPath, String attributeTypeName) throws EngineException
	{
		if (groupPath == null)
			throw new IllegalArgumentException("For this method group must be specified");
		if (attributeTypeName == null)
			throw new IllegalArgumentException("For this method attribute name must be specified");
		return getEntityAttributesInGroupAsMap(entityId, groupPath, attributeTypeName).get(attributeTypeName);
	}

	/**
	 * Returns {@link AttributeType} which has the given metadata set. The metadata used as parameter must be
	 * singleton, i.e. it is guaranteed that there is at maximum only one type with it.
	 */
	public AttributeType getAttributeTypeWithSingeltonMetadata(String metadataId)
			throws EngineException
	{
		return attributeTypeByMetaCache.getAttributeTypeWithSingeltonMetadata(metadataId);
	}
	
	public AttributeExt getAttributeByMetadata(EntityParam entity, String group,
			String metadataId) throws EngineException
	{
		AttributeType at = getAttributeTypeWithSingeltonMetadata(metadataId);
		if (at == null)
			return null;
		long entityId = idResolver.getEntityId(entity);
		return getAttributeOneGroup(entityId, group, at.getName());
	}

	public String getAttributeValueByMetadata(EntityParam entity, String group, String metadataId)
			throws EngineException
	{
		AttributeExt attribute = getAttributeByMetadata(entity, group, metadataId);
		if (attribute == null)
			return null;
		List values = attribute.getValues();
		if (values.isEmpty())
			return null;
		return values.get(0).toString();
	}

	
	/**
	 * Sets ACs of a given entity. Pure business logic - no authZ and transaction management.
	 */
	public void setAttributeClasses(long entityId, String group, Collection classes) 
			throws EngineException
	{
		AttributeClassHelper acHelper = acUtil.getACHelper(group, classes);
		
		List attributes = attributeDAO.getEntityAttributes(entityId, null, group);
		Collection attributeNames = attributes.stream().
				map(Attribute::getName).
				collect(toList());
		Map allTypes = attributeTypeDAO.getAllAsMap();
		acHelper.checkAttribtues(attributeNames, allTypes);

		Attribute classAttr = StringAttribute.of(AttributeClassTypeProvider.ATTRIBUTE_CLASSES_ATTRIBUTE, 
				group, new ArrayList<>(classes));
		createOrUpdateAttribute(classAttr, entityId);
	}
	
	
	public Collection getAttributesInternal(long entityId, 
			boolean effective, String groupPath, String attributeTypeName, 
			boolean allowDisabled) throws EngineException
	{
		List groupsPaths = groupPath != null ? singletonList(groupPath) : emptyList();
		return getAttributesInternal(entityId, effective, groupsPaths, attributeTypeName, allowDisabled);
	}

	public Collection getAttributesInternal(long entityId,
			boolean effective, List groupsPaths, String attributeTypeName,
			boolean allowDisabled) throws EngineException
	{
		if (!allowDisabled)
		{
			EntityInformation entityInformation = entityDAO.getByKey(entityId);
			if (entityInformation.getEntityState() == EntityState.disabled)
				throw new IllegalIdentityValueException("The entity is disabled");
		}
		if (groupsPaths != null)
		{
			Set allGroups = membershipDAO.getEntityMembershipSimple(entityId);
			if (!allGroups.containsAll(groupsPaths))
				throw new IllegalGroupValueException("The entity is not a member of the group "
					+ groupsPaths);
		}
		return getAllAttributes(entityId, groupsPaths, effective, attributeTypeName);
	}

	public AttributeExt getEffectiveAttributeOneGroup(long entityId, String groupPath, 
			String attributeTypeName) throws EngineException
	{
		return getAttributeOneGroup(entityId, groupPath, attributeTypeName);
	}

	public Collection getAllAttributes(long entityId, List groupsPaths, boolean effective,
	                                                 String attributeTypeName) throws EngineException
	{
		Map> asMap = getEntityAttributesAsMap(entityId, groupsPaths, effective,
			attributeTypeName);
		List ret = new ArrayList<>();
		for (Map entry: asMap.values())
			ret.addAll(entry.values());
		return ret;
	}

	/**
	 * As {@link #addAttribute(long, Attribute, AttributeType, boolean, boolean)} but the attribute type 
	 * is automatically resolved
	 */
	public void addAttribute(long entityId, Attribute attribute, boolean update, boolean honorInitialConfirmation) 
			throws EngineException
	{
		AttributeType at = attributeTypeDAO.get(attribute.getName());
		addAttribute(entityId, attribute, at, update, honorInitialConfirmation);
	}
	
	/**
	 * Adds an attribute. This method performs engine level checks: whether the attribute type is not immutable,
	 * and properly sets unverified state if attribute is added by ordinary user (not an admin).
	 * 
	 * @param honorInitialConfirmation if true then operation is run by privileged user, 
	 * otherwise it is modification of self possessed attribute and verification status must be set to unverified.
	 */
	public void addAttribute(long entityId, Attribute attribute, AttributeType at, boolean update,
			boolean honorInitialConfirmation) throws EngineException
	{
		if (attribute == null)
			throw new IllegalArgumentException("Trying to add null attribute for " + entityId);
		if (at == null)
			throw new IllegalArgumentException("Trying to add attribute " + attribute.getName() + " without type");
		if (at.isInstanceImmutable())
			throw new SchemaConsistencyException("The attribute with name " + at.getName() + 
					" can not be manually modified");
		addAttributeInternal(entityId, attribute, at, update, honorInitialConfirmation);
	}

	/**
	 * As {@link #addSystemAttribute(long, Attribute, AttributeType, boolean)} but the attribute type 
	 * is automatically resolved
	 */
	public void addSystemAttribute(long entityId, Attribute attribute, boolean update) 
			throws EngineException
	{
		AttributeType at = attributeTypeDAO.get(attribute.getName());
		addSystemAttribute(entityId, attribute, at, update);
	}
	
	/**
	 * Adds a system attribute. Use only internally.
	 */
	public void addSystemAttribute(long entityId, Attribute attribute, AttributeType at, boolean update) 
			throws EngineException
	{
		addAttributeInternal(entityId, attribute, at, update, true);
	}
	
	private void addAttributeInternal(long entityId, Attribute attribute, AttributeType at, boolean update,
			boolean honorInitialConfirmation) throws EngineException
	{
		if (attribute.getValueSyntax() == null)
			attribute.setValueSyntax(at.getValueSyntax());
		enforceCorrectConfirmationState(entityId, update, attribute, honorInitialConfirmation);
		validate(attribute, at);
		
		AttributeExt aExt = new AttributeExt(attribute, true);
		StoredAttribute param = new StoredAttribute(aExt, entityId);
		List existing = attributeDAO.getEntityAttributes(entityId, attribute.getName(), 
				attribute.getGroupPath());
			
		if (existing.isEmpty())
		{
			if (!membershipDAO.isMember(entityId, attribute.getGroupPath()))
				throw new IllegalGroupValueException("The entity is not a member "
						+ "of the group specified in the attribute");
			checkAttributeCapacityLimit(at, aExt);	
			long createdAttrId = attributeDAO.create(param);
			attrRegistry.registerAttributeInfo(attribute, createdAttrId);
			audit.log(getAttrAudit(entityId, attribute, AuditEventAction.ADD));
		} else
		{
			if (!update)
				throw new IllegalAttributeValueException("The attribute already exists");
			AttributeExt updated = existing.get(0);
			param.getAttribute().setCreationTs(updated.getCreationTs());
			checkAttributeCapacityLimit(at, aExt);
			attributeDAO.updateAttribute(param);
			audit.log(getAttrAudit(entityId, attribute, AuditEventAction.UPDATE));
		}
	}

	private void checkAttributeCapacityLimit(AttributeType at, Attribute attr) throws CapacityLimitReachedException
	{

		if (isSystemAttribute(at))
			return;

		capacityLimitVerificator.assertInSystemLimitForSingleAdd(CapacityLimitName.AttributesCount,
				() -> attributeDAO.getCountWithoutType(attributeTypeDAO.getAllAsMap().values().stream()
						.filter(t -> isSystemAttribute(t)).map(t -> t.getName())
						.collect(toList())));
		capacityLimitVerificator.assertInSystemLimit(CapacityLimitName.AttributeValuesCount,
				() -> Long.valueOf(attr.getValues().size()));
		capacityLimitVerificator.assertInSystemLimit(CapacityLimitName.AttributeCumulativeValuesSize,
				() -> Long.valueOf(attr.getValues().stream().filter(v -> v != null)
						.mapToInt(String::length).sum()));

		for (String v : attr.getValues())
		{
			if (v != null)
				capacityLimitVerificator.assertInSystemLimit(CapacityLimitName.AttributeValueSize,
						() -> Long.valueOf(v.length()));
		}

	}
	
	private boolean isSystemAttribute(AttributeType at)
	{
		return at.isInstanceImmutable() || at.isTypeImmutable();
	}
	
	private AuditEventTriggerBuilder getAttrAudit(long entityId, Attribute attribute, AuditEventAction action)
	{
		return AuditEventTrigger.builder()
				.type(AuditEventType.ATTRIBUTE)
				.action(action)
				.name(attribute.getName())
				.subject(entityId)
				.details(ImmutableMap.of("group", attribute.getGroupPath(),
						"value", getTrimmedFirstValue(attribute)))
				.tags(AuditEventTag.USERS);
	}
	
	private String getTrimmedFirstValue(Attribute attr)
	{
		if (attr.getValues().isEmpty())
			return "-NONE-";
		
		final int showLength = 30;
		String fValue = attr.getValues().get(0);
		AttributeValueSyntax syntax = atHelper.getUnconfiguredSyntax(attr.getValueSyntax());
		String deserialized = internalValueToExternal(syntax, fValue);
		return deserialized.length() > showLength ? deserialized.substring(0, showLength-3) + "..." : deserialized;
	}
	
	private  String internalValueToExternal(AttributeValueSyntax syntax, String internalValue)
	{
		T deserialized = syntax.convertFromString(internalValue);
		return syntax.serializeSimple(deserialized);
	}
	
	/**
	 * Makes sure that the initial confirmation state is correctly set. This works as follows:
	 * - if honorInitialConfirmation is true then we assume that admin is performing the modification
	 * and everything is left as originally requested.
	 * - otherwise it is assumed that ordinary user is the caller, and all values are set as unconfirmed,
	 * unless the operation is updating an existing attribute - then values which are equal to already existing
	 * preserve their confirmation state. 
	 * 

* What is more it is checked in case of attribute update, when there is no-admin mode if the attribute * being updated had at least one confirmed value. If yes, also at least one confirmed value must be preserved. */ @SuppressWarnings("unchecked") private void enforceCorrectConfirmationState(long entityId, boolean update, Attribute attribute, boolean honorInitialConfirmation) throws EngineException { @SuppressWarnings("rawtypes") AttributeValueSyntax syntax = atHelper.getUnconfiguredSyntax(attribute.getValueSyntax()); if (!syntax.isEmailVerifiable() || honorInitialConfirmation) return; if (!update) { setUnconfirmed(attribute, syntax); return; } Collection attrs = attributeDAO.getEntityAttributes(entityId, attribute.getName(), attribute.getGroupPath()); if (attrs.isEmpty()) { setUnconfirmed(attribute, syntax); return; } AttributeExt updated = attrs.iterator().next(); Set preservedStateIndices = new HashSet(); boolean oneConfirmedValuePreserved = false; //first we find matching values where confirmation state should be preserved for (int i=0; i void setUnconfirmed(Attribute attribute, AttributeValueSyntax syntax) { setConfirmationStatus(attribute, syntax, false); } public static void setConfirmed(Attribute attribute, AttributeValueSyntax syntax) { setConfirmationStatus(attribute, syntax, true); } private static void setConfirmationStatus(Attribute attribute, AttributeValueSyntax syntax, boolean confirmed) { List updated = new ArrayList<>(attribute.getValues().size()); for (String v : attribute.getValues()) { T val = syntax.convertFromString(v); val.setConfirmationInfo(new ConfirmationInfo(confirmed)); updated.add(syntax.convertToString(val)); } attribute.setValues(updated); } /** * Checks if the given set of attributes fulfills rules of ACs of a specified group */ public void checkGroupAttributeClassesConsistency(List attributes, String path) throws EngineException { AttributeClassHelper helper = acUtil.getACHelper(path, new ArrayList<>(0)); Set attributeNames = new HashSet<>(attributes.size()); for (Attribute a: attributes) attributeNames.add(a.getName()); helper.checkAttribtues(attributeNames, null); } /** * Same as {@link #addAttribute(SqlSession, long, boolean, AttributeType, boolean, Attribute)} * but for a whole list of attributes. It is assumed that attributes are always created. * Attribute type is automatically resolved. */ public void addAttributesList(List attributes, long entityId, boolean honorInitialConfirmation) throws EngineException { Map typesMap = attributeTypeDAO.getAllAsMap(); for (Attribute a: attributes) addAttribute(entityId, a, typesMap.get(a.getName()), true, honorInitialConfirmation); } /** * Creates or updates an attribute. No schema checking is performed. */ public void createOrUpdateAttribute(Attribute toCreate, long entityId) { StoredAttribute sAttr = toStoredAttribute(toCreate, entityId); List existing = attributeDAO.getEntityAttributes(entityId, toCreate.getName(), toCreate.getGroupPath()); if (existing.isEmpty()) { attributeDAO.create(sAttr); if (toCreate.getName().startsWith(CredentialAttributeTypeProvider.CREDENTIAL_PREFIX)) { audit.log(AuditEventTrigger.builder() .type(AuditEventType.CREDENTIALS) .action(AuditEventAction.ADD) .name(toCreate.getName()) .subject(entityId) .tags(AUTHN)); } } else { sAttr.getAttribute().setCreationTs(existing.get(0).getCreationTs()); attributeDAO.updateAttribute(sAttr); if (toCreate.getName().startsWith(CredentialAttributeTypeProvider.CREDENTIAL_PREFIX)) { audit.log(AuditEventTrigger.builder() .type(AuditEventType.CREDENTIALS) .action(AuditEventAction.UPDATE) .name(toCreate.getName()) .subject(entityId) .tags(AUTHN)); } } } /** * Creates or updates an attribute. No schema checking is performed. */ public void createAttribute(Attribute toCreate, long entityId) { StoredAttribute sAttr = toStoredAttribute(toCreate, entityId); attributeDAO.create(sAttr); } private StoredAttribute toStoredAttribute(Attribute toCreate, long entityId) { AttributeExt aExt = new AttributeExt(toCreate, true); return new StoredAttribute(aExt, entityId); } /** * Checks if the given {@link Attribute} is valid wrt the {@link AttributeType} constraints */ public void validate(Attribute attribute, AttributeType at) throws IllegalAttributeValueException, IllegalAttributeTypeException { List values = attribute.getValues(); if (at.getMinElements() > values.size()) throw new IllegalAttributeValueException("Attribute must have at least " + at.getMinElements() + " values"); if (at.getMaxElements() < values.size()) throw new IllegalAttributeValueException("Attribute must have at most " + at.getMaxElements() + " values"); if (!attribute.getName().equals(at.getName())) throw new IllegalAttributeTypeException( "Attribute being checked has type " + attribute.getName() + " while provided type is " + at.getName()); if (!attribute.getValueSyntax().equals(at.getValueSyntax())) throw new IllegalAttributeTypeException( "Attribute being checked has syntax " + attribute.getValueSyntax() + " while provided type uses " + at.getValueSyntax()); AttributeValueSyntax initializedValueSyntax = atHelper.getSyntax(at); for (String val: values) initializedValueSyntax.validateStringValue(val); if (at.isUniqueValues()) { for (int i=0; i getFirstVerifiableAttributeValueFilteredByMeta(String metadataId, Collection list) throws EngineException { Optional attrName = getAttributeName(metadataId); if (!attrName.isPresent()) return Optional.empty(); return convertToVerifiableAttributeValue(attrName.get(), getFirstValueOfAttributeFilteredByName(attrName.get(), list)); } private Optional getAttributeName(String metadata) throws EngineException { AttributeType attrType = getAttributeTypeWithSingeltonMetadata(metadata); if (attrType == null) return Optional.empty(); return Optional.of(attrType.getName()); } private Optional convertToVerifiableAttributeValue(String attributeName, Optional value) { if (!value.isPresent()) { return Optional.empty(); } AttributeValueSyntax attributeSyntax = getAttributeSyntaxNotThrowing(attributeName); if (attributeSyntax != null && attributeSyntax.isEmailVerifiable()) { return Optional.of((VerifiableElementBase) attributeSyntax.convertFromString(value.get())); }else { return Optional.of(new VerifiableElementBase(value.get())); } } private AttributeValueSyntax getAttributeSyntaxNotThrowing(String attributeName) { try { return atHelper.getUnconfiguredSyntaxForAttributeName(attributeName); } catch (Exception e) { // ok log.debug("Can not get attribute syntax for attribute " + attributeName); return null; } } public Optional getFirstValueOfAttributeFilteredByMeta(String metadataId, Collection list) throws EngineException { Optional attrName = getAttributeName(metadataId); if (!attrName.isPresent()) return Optional.empty(); return getFirstValueOfAttributeFilteredByName(attrName.get(), list); } private Optional getFirstValueOfAttributeFilteredByName(String attrName, Collection list) throws EngineException { for (Attribute attr : list) { if (attr.getName().equals(attrName) && attr.getValues() != null && !attr.getValues().isEmpty()) { return Optional.ofNullable(attr.getValues().get(0)); } } return Optional.empty(); } /** * See {@link #getAllAttributes(long, String, String, SqlSession)}, the only difference is that the result * is returned in a map indexed with groups (1st key) and attribute names (submap key). */ private Map> getEntityAttributesAsMap(long entityId, List groupsPaths, boolean effective, String attributeTypeName) throws EngineException { Map> directAttributesByGroup = getAllEntityAttributesMap(entityId); if (!effective) { groupsPaths.forEach(g -> filterMap(directAttributesByGroup, g, attributeTypeName)); return directAttributesByGroup; } Map allUserGroupsMap = membershipDAO.getEntityMembershipGroups(entityId).stream() .collect(Collectors.toMap(g -> g.getPathEncoded(), g -> g)); List groups = groupsPaths.isEmpty() ? new ArrayList<>(allUserGroupsMap.keySet()) : groupsPaths.stream().filter(allUserGroupsMap::containsKey).collect(Collectors.toList()); Map> ret = new HashMap<>(); Map allClasses = acDB.getAllAsMap(); List identities = identityDAO.getByEntity(entityId); Collection allUserGroups = allUserGroupsMap.values(); CachingMVELGroupProvider mvelGroupProvider = new CachingMVELGroupProvider(allUserGroupsMap); for (String group: groups) { if (!allUserGroupsMap.containsKey(group)) continue; Map inGroup = statementsHelper.getEffectiveAttributes(identities, group, attributeTypeName, allUserGroups, directAttributesByGroup, allClasses, allUserGroupsMap::get, attributeTypeDAO::get, mvelGroupProvider::get); ret.put(group, inGroup); } return ret; } /** * Returns map of attributes of a given entity in a given group, indexed by attribute names. */ private Map getEntityAttributesInGroupAsMap(long entityId, String groupPath, String attributeTypeName) throws EngineException { Map> directAttributesByGroup = getAllEntityAttributesMap(entityId); Map allUserGroups = membershipDAO.getEntityMembershipGroups(entityId).stream() .collect(Collectors.toMap(g -> g.getPathEncoded(), g -> g)); if (!allUserGroups.containsKey(groupPath)) return Collections.emptyMap(); Map allClasses = acDB.getAllAsMap(); List identities = identityDAO.getByEntity(entityId); CachingMVELGroupProvider mvelGroupProvider = new CachingMVELGroupProvider(allUserGroups); return statementsHelper.getEffectiveAttributes(identities, groupPath, attributeTypeName, allUserGroups.values(), directAttributesByGroup, allClasses, allUserGroups::get, attributeTypeDAO::get, mvelGroupProvider::get); } /** * @return map indexed with groups. Values are maps of all attributes in given group, indexed with attribute names. */ public Map> getAllEntityAttributesMap(long entityId) throws IllegalTypeException, IllegalGroupValueException { List attributes = attributeDAO.getAttributes(null, entityId, null); Map> ret = new HashMap<>(); for (StoredAttribute attribute: attributes) { Map attrsInGroup = ret.computeIfAbsent(attribute.getAttribute().getGroupPath(), k -> new HashMap<>()); attrsInGroup.put(attribute.getAttribute().getName(), attribute.getAttribute()); } return ret; } private void filterMap(Map> directAttributesByGroup, String groupPath, String attributeTypeName) { if (groupPath != null) { Map v = directAttributesByGroup.get(groupPath); directAttributesByGroup.clear(); if (v != null) directAttributesByGroup.put(groupPath, v); } if (attributeTypeName != null) { for (Map e: directAttributesByGroup.values()) { AttributeExt at = e.get(attributeTypeName); e.clear(); if (at != null) e.put(attributeTypeName, at); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy