/* * Copyright (c) 2010-2016 Evolveum * * 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 com.evolveum.midpoint.schema.util; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.ItemPathSegment; import com.evolveum.midpoint.prism.path.NameItemPathSegment; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.processor.*; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; import javax.xml.namespace.QName; import org.apache.commons.lang.StringUtils; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * Methods that would belong to the ResourceObjectShadowType class but cannot go there * because of JAXB. * * @author Radovan Semancik */ public class ShadowUtil { public static Collection<ResourceAttribute<?>> getPrimaryIdentifiers(ShadowType shadowType) { return getPrimaryIdentifiers(shadowType.asPrismObject()); } // TODO: rename to getPrimaryIdentifiers public static Collection<ResourceAttribute<?>> getPrimaryIdentifiers(PrismObject<? extends ShadowType> shadow) { ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); if (attributesContainer == null) { return null; } return attributesContainer.getPrimaryIdentifiers(); } public static Collection<ResourceAttribute<?>> getSecondaryIdentifiers(ShadowType shadowType) { return getSecondaryIdentifiers(shadowType.asPrismObject()); } public static Collection<ResourceAttribute<?>> getSecondaryIdentifiers(PrismObject<? extends ShadowType> shadow) { ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); if (attributesContainer == null) { return null; } return attributesContainer.getSecondaryIdentifiers(); } public static ResourceAttribute<String> getSecondaryIdentifier(PrismObject<? extends ShadowType> shadow) throws SchemaException { Collection<ResourceAttribute<?>> secondaryIdentifiers = getSecondaryIdentifiers(shadow); if (secondaryIdentifiers == null || secondaryIdentifiers.isEmpty()) { return null; } if (secondaryIdentifiers.size() > 1) { throw new SchemaException("Too many secondary identifiers in "+shadow+": "+secondaryIdentifiers); } return (ResourceAttribute<String>) secondaryIdentifiers.iterator().next(); } public static Collection<ResourceAttribute<?>> getSecondaryIdentifiers(Collection<? extends ResourceAttribute<?>> identifiers, ObjectClassComplexTypeDefinition objectClassDefinition) throws SchemaException { if (identifiers == null) { return null; } Collection<ResourceAttribute<?>> secondaryIdentifiers = new ArrayList<>(); for (ResourceAttribute<?> identifier: identifiers) { if (objectClassDefinition.isSecondaryIdentifier(identifier.getElementName())) { secondaryIdentifiers.add(identifier); } } return secondaryIdentifiers; } public static String getSecondaryIdentifierRealValue(PrismObject<? extends ShadowType> shadow) throws SchemaException { ResourceAttribute<String> secondaryIdentifier = getSecondaryIdentifier(shadow); if (secondaryIdentifier == null) { return null; } return secondaryIdentifier.getRealValue(); } public static ResourceAttribute<?> getSecondaryIdentifier(ObjectClassComplexTypeDefinition objectClassDefinition, Collection<? extends ResourceAttribute<?>> identifiers) throws SchemaException { if (identifiers == null) { return null; } ResourceAttribute<?> secondaryIdentifier = null; for (ResourceAttribute<?> identifier: identifiers) { if (identifier.getDefinition().isSecondaryIdentifier(objectClassDefinition)) { if (secondaryIdentifier != null) { throw new SchemaException("More than one secondary identifier in "+objectClassDefinition); } secondaryIdentifier = identifier; } } return secondaryIdentifier; } public static Collection<ResourceAttribute<?>> getAllIdentifiers(PrismObject<? extends ShadowType> shadow) { ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); if (attributesContainer == null) { return null; } return attributesContainer.getAllIdentifiers(); } public static Collection<ResourceAttribute<?>> getAllIdentifiers(ShadowType shadow) { return getAllIdentifiers(shadow.asPrismObject()); } public static ResourceAttribute<String> getNamingAttribute(ShadowType shadow){ return getNamingAttribute(shadow.asPrismObject()); } public static ResourceAttribute<String> getNamingAttribute(PrismObject<? extends ShadowType> shadow) { ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); if (attributesContainer == null) { return null; } return attributesContainer.getNamingAttribute(); } public static Collection<ResourceAttribute<?>> getAttributes(ShadowType shadowType) { return getAttributes(shadowType.asPrismObject()); } public static Collection<ResourceAttribute<?>> getAttributes(PrismObject<? extends ShadowType> shadow) { return getAttributesContainer(shadow).getAttributes(); } public static <T> ResourceAttribute<T> getAttribute(PrismObject<? extends ShadowType> shadow, QName attrName) { return getAttributesContainer(shadow).findAttribute(attrName); } public static ResourceAttributeContainer getAttributesContainer(ShadowType shadowType) { return getAttributesContainer(shadowType.asPrismObject()); } public static ResourceAttributeContainer getAttributesContainer(PrismObject<? extends ShadowType> shadow) { return getAttributesContainer(shadow, ShadowType.F_ATTRIBUTES); } public static ResourceAttributeContainer getAttributesContainer(PrismObject<? extends ShadowType> shadow, QName containerName) { return getAttributesContainer(shadow.getValue(), containerName); } public static ResourceAttributeContainer getAttributesContainer(PrismContainerValue<?> cval, QName containerName) { PrismContainer attributesContainer = cval.findContainer(containerName); if (attributesContainer == null) { return null; } if (attributesContainer instanceof ResourceAttributeContainer) { return (ResourceAttributeContainer)attributesContainer; } else { throw new SystemException("Expected that <"+containerName.getLocalPart()+"> will be ResourceAttributeContainer but it is "+attributesContainer.getClass()); } } public static ResourceAttributeContainer getOrCreateAttributesContainer(PrismObject<? extends ShadowType> shadow, ObjectClassComplexTypeDefinition objectClassDefinition) { ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); if (attributesContainer != null) { return attributesContainer; } ResourceAttributeContainer emptyContainer = ResourceAttributeContainer.createEmptyContainer(ShadowType.F_ATTRIBUTES, objectClassDefinition); try { shadow.add(emptyContainer); } catch (SchemaException e) { throw new SystemException("Unexpected schema error: "+e.getMessage(), e); } return emptyContainer; } public static ObjectClassComplexTypeDefinition getObjectClassDefinition(ShadowType shadow) { // TODO: maybe we can do something more intelligent here ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); return attributesContainer.getDefinition().getComplexTypeDefinition(); } public static ObjectClassComplexTypeDefinition getObjectClassDefinition(PrismObject<? extends ShadowType> shadow) { // TODO: maybe we can do something more intelligent here ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); return attributesContainer.getDefinition().getComplexTypeDefinition(); } public static String getResourceOid(ShadowType shadowType) { return getResourceOid(shadowType.asPrismObject()); } public static String getResourceOid(PrismObject<ShadowType> shadow) { PrismReference resourceRef = shadow.findReference(ShadowType.F_RESOURCE_REF); if (resourceRef == null) { return null; } return resourceRef.getOid(); } public static PolyString getResourceName(ShadowType shadowType) { return getResourceName(shadowType.asPrismObject()); } public static PolyString getResourceName(PrismObject<ShadowType> shadow) { PrismReference resourceRef = shadow.findReference(ShadowType.F_RESOURCE_REF); if (resourceRef == null) { return null; } return resourceRef.getTargetName(); } public static String getSingleStringAttributeValue(ShadowType shadow, QName attrName) { return getSingleStringAttributeValue(shadow.asPrismObject(), attrName); } public static String getSingleStringAttributeValue(PrismObject<ShadowType> shadow, QName attrName) { PrismContainer<?> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer == null) { return null; } PrismProperty<String> attribute = attributesContainer.findProperty(attrName); if (attribute == null) { return null; } return attribute.getRealValue(); } public static String getMultiStringAttributeValueAsSingle(ShadowType shadow, QName attrName) { return getMultiStringAttributeValueAsSingle(shadow.asPrismObject(), attrName); } private static String getMultiStringAttributeValueAsSingle(PrismObject<ShadowType> shadow, QName attrName) { PrismContainer<?> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer == null) { return null; } PrismProperty<String> attribute = attributesContainer.findProperty(attrName); if (attribute == null) { return null; } Collection<String> realValues = attribute.getRealValues(); if (realValues == null || realValues.isEmpty()) { return null; } if (realValues.size() > 1) { throw new IllegalStateException("More than one value in attribute "+attrName); } return realValues.iterator().next(); } public static <T> List<T> getAttributeValues(ShadowType shadowType, QName attrName) { return getAttributeValues(shadowType.asPrismObject(), attrName); } public static <T> List<T> getAttributeValues(PrismObject<? extends ShadowType> shadow, QName attrName) { PrismContainer<?> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer == null || attributesContainer.isEmpty()) { return null; } PrismProperty<T> attr = attributesContainer.findProperty(attrName); if (attr == null) { return null; } List<T> values = new ArrayList<T>(); for (PrismPropertyValue<T> pval : attr.getValues()) { values.add(pval.getValue()); } if (values.isEmpty()) { return null; } return values; } public static <T> T getAttributeValue(ShadowType shadowType, QName attrName) throws SchemaException { return (T) getAttributeValue(shadowType.asPrismObject(), attrName); } public static <T> T getAttributeValue(PrismObject<? extends ShadowType> shadow, QName attrName) throws SchemaException { Collection<T> values = getAttributeValues(shadow, attrName); if (values == null || values.isEmpty()) { return null; } if (values.size() > 1) { throw new SchemaException("Attempt to get single value from multi-valued attribute "+attrName); } return values.iterator().next(); } public static void setPassword(ShadowType shadowType, ProtectedStringType password) { CredentialsType credentialsType = shadowType.getCredentials(); if (credentialsType == null) { credentialsType = new CredentialsType(); shadowType.setCredentials(credentialsType); } PasswordType passwordType = credentialsType.getPassword(); if (passwordType == null) { passwordType = new PasswordType(); credentialsType.setPassword(passwordType); } passwordType.setValue(password); } public static void setPasswordIncomplete(ShadowType shadowType) throws SchemaException { CredentialsType credentialsType = shadowType.getCredentials(); if (credentialsType == null) { credentialsType = new CredentialsType(); shadowType.setCredentials(credentialsType); } PasswordType passwordType = credentialsType.getPassword(); if (passwordType == null) { passwordType = new PasswordType(); credentialsType.setPassword(passwordType); } PrismContainerValue<PasswordType> passwordContainer = passwordType.asPrismContainerValue(); PrismProperty<ProtectedStringType> valueProperty = passwordContainer.findOrCreateProperty(PasswordType.F_VALUE); valueProperty.setIncomplete(true); } public static ActivationType getOrCreateActivation(ShadowType shadowType) { ActivationType activation = shadowType.getActivation(); if (activation == null) { activation = new ActivationType(); shadowType.setActivation(activation); } return activation; } /** * This is not supposed to be used in production code! It is just for the tests. */ public static void applyResourceSchema(PrismObject<? extends ShadowType> shadow, ResourceSchema resourceSchema) throws SchemaException { ShadowType shadowType = shadow.asObjectable(); QName objectClass = shadowType.getObjectClass(); ObjectClassComplexTypeDefinition objectClassDefinition = resourceSchema.findObjectClassDefinition(objectClass); applyObjectClass(shadow, objectClassDefinition); } private static void applyObjectClass(PrismObject<? extends ShadowType> shadow, ObjectClassComplexTypeDefinition objectClassDefinition) throws SchemaException { PrismContainer<?> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); ResourceAttributeContainerDefinition racDef = new ResourceAttributeContainerDefinitionImpl(ShadowType.F_ATTRIBUTES, objectClassDefinition, objectClassDefinition.getPrismContext()); attributesContainer.applyDefinition((PrismContainerDefinition) racDef, true); } public static PrismObjectDefinition<ShadowType> applyObjectClass(PrismObjectDefinition<ShadowType> shadowDefinition, ObjectClassComplexTypeDefinition objectClassDefinition) throws SchemaException { PrismObjectDefinition<ShadowType> shadowDefClone = shadowDefinition.cloneWithReplacedDefinition(ShadowType.F_ATTRIBUTES, objectClassDefinition.toResourceAttributeContainerDefinition()); return shadowDefClone; } /** * Returns intent from the shadow. Backwards compatible with older accountType. May also adjust for default * intent if necessary. */ public static String getIntent(ShadowType shadow) { if (shadow == null) { return null; } String intent = shadow.getIntent(); if (intent != null) { return intent; } return null; } public static ShadowKindType getKind(ShadowType shadow) { if (shadow == null) { return null; } ShadowKindType kind = shadow.getKind(); if (kind != null) { return kind; } return ShadowKindType.ACCOUNT; } public static <T> Collection<T> getAttributeValues(ShadowType shadow, QName attributeQname, Class<T> type) { ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); if (attributesContainer == null) { return null; } ResourceAttribute<T> attribute = attributesContainer.findAttribute(attributeQname); if (attribute == null) { return null; } return attribute.getRealValues(type); } public static QName getAttributeName(ItemPath attributePath, String message) throws SchemaException { if (attributePath == null || attributePath.isEmpty()) { return null; } ItemPathSegment firstPathSegment = attributePath.first(); if (!(firstPathSegment instanceof NameItemPathSegment)) { throw new SchemaException(message + ": first path segment is not a name segment"); } if (!QNameUtil.match(ShadowType.F_ATTRIBUTES, ((NameItemPathSegment) firstPathSegment).getName())) { throw new SchemaException(message + ": first path segment is not "+ShadowType.F_ATTRIBUTES); } if (attributePath.size() < 1) { throw new SchemaException(message + ": path too short ("+attributePath.size()+" segments)"); } if (attributePath.size() > 2) { throw new SchemaException(message + ": path too long ("+attributePath.size()+" segments)"); } ItemPathSegment secondPathSegment = attributePath.getSegments().get(1); if (!(secondPathSegment instanceof NameItemPathSegment)) { throw new SchemaException(message + ": second path segment is not a name segment"); } return ((NameItemPathSegment) secondPathSegment).getName(); } public static void checkConsistence(PrismObject<? extends ShadowType> shadow, String desc) { PrismReference resourceRef = shadow.findReference(ShadowType.F_RESOURCE_REF); if (resourceRef == null) { throw new IllegalStateException("No resourceRef in "+shadow+" in "+desc); } if (StringUtils.isBlank(resourceRef.getOid())) { throw new IllegalStateException("Null or empty OID in resourceRef in "+desc); } ShadowType shadowType = shadow.asObjectable(); if (shadowType.getObjectClass() == null) { throw new IllegalStateException("Null objectClass in "+desc); } PrismContainer<ShadowAttributesType> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer != null) { if (!(attributesContainer instanceof ResourceAttributeContainer)) { throw new IllegalStateException("The attributes element expected to be ResourceAttributeContainer but it is " +attributesContainer.getClass()+" instead in "+desc); } checkConsistency(attributesContainer.getDefinition(), " container definition in "+desc); } PrismContainerDefinition<ShadowAttributesType> attributesDefinition = shadow.getDefinition().findContainerDefinition(ShadowType.F_ATTRIBUTES); checkConsistency(attributesDefinition, " object definition in "+desc); } public static void checkConsistency(PrismContainerDefinition<ShadowAttributesType> attributesDefinition, String desc) { if (attributesDefinition == null) { throw new IllegalStateException("No definition for <attributes> in "+desc); } if (!(attributesDefinition instanceof ResourceAttributeContainerDefinition)) { throw new IllegalStateException("The attributes element definition expected to be ResourceAttributeContainerDefinition but it is " +attributesDefinition.getClass()+" instead in "+desc); } } // TODO is this correct? public static boolean isAccount(ShadowType shadowType) { if (shadowType.getKind() != null) { return shadowType.getKind() == ShadowKindType.ACCOUNT; } else { return true; // ??? } } public static boolean isProtected(PrismObject<? extends ShadowType> shadow) { if (shadow == null) { return false; } ShadowType shadowType = shadow.asObjectable(); Boolean protectedObject = shadowType.isProtectedObject(); return (protectedObject != null && protectedObject); } public static boolean isDead(ShadowType shadow){ return shadow.isDead() != null && shadow.isDead(); } public static boolean matches(ShadowType shadowType, String resourceOid, ShadowKindType kind, String intent) { if (shadowType == null) { return false; } if (!resourceOid.equals(shadowType.getResourceRef().getOid())) { return false; } if (!MiscUtil.equals(kind, shadowType.getKind())) { return false; } if (intent == null) { return true; } return MiscUtil.equals(intent, shadowType.getIntent()); } /** * Strict mathcing. E.g. null discriminator kind is intepreted as ACCOUNT and it must match the kind * in the shadow. */ public static boolean matches(PrismObject<ShadowType> shadow, ResourceShadowDiscriminator discr) { return matches(shadow.asObjectable(), discr); } /** * Strict mathcing. E.g. null discriminator kind is intepreted as ACCOUNT and it must match the kind * in the shadow. */ public static boolean matches(ShadowType shadowType, ResourceShadowDiscriminator discr) { if (shadowType == null) { return false; } if (!discr.getResourceOid().equals(shadowType.getResourceRef().getOid())) { return false; } if (!MiscUtil.equals(discr.getKind(), shadowType.getKind())) { return false; } return ResourceShadowDiscriminator.equalsIntent(shadowType.getIntent(), discr.getIntent()); } /** * Interprets ResourceShadowDiscriminator as a pattern. E.g. null discriminator kind is * interpreted to match any shadow kind. */ public static boolean matchesPattern(ShadowType shadowType, ShadowDiscriminatorType discr) { if (shadowType == null) { return false; } if (!discr.getResourceRef().getOid().equals(shadowType.getResourceRef().getOid())) { return false; } if (discr.getKind() != null && !MiscUtil.equals(discr.getKind(), shadowType.getKind())) { return false; } if (discr.getIntent() == null) { return true; } return ResourceShadowDiscriminator.equalsIntent(shadowType.getIntent(), discr.getIntent()); } public static boolean isConflicting(ShadowType shadow1, ShadowType shadow2) { if (!shadow1.getResourceRef().getOid().equals(shadow2.getResourceRef().getOid())) { return false; } if (!MiscUtil.equals(getKind(shadow1), getKind(shadow2))) { return false; } return ResourceShadowDiscriminator.equalsIntent(shadow1.getIntent(), shadow2.getIntent()); } public static String getHumanReadableName(PrismObject<? extends ShadowType> shadow) { if (shadow == null) { return "null"; } StringBuilder sb = new StringBuilder(); ShadowType shadowType = shadow.asObjectable(); ShadowKindType kind = shadowType.getKind(); if (kind != null) { sb.append(kind).append(" "); } sb.append("shadow "); boolean first = true; for(ResourceAttribute iattr: getPrimaryIdentifiers(shadow)) { if (first) { sb.append("["); first = false; } else { sb.append(","); } sb.append(iattr.getElementName().getLocalPart()); sb.append("="); sb.append(iattr.getRealValue()); } if (first) { sb.append("["); } sb.append("]"); return shadow.toString(); } public static String getHumanReadableName(ShadowType shadowType) { if (shadowType == null) { return "null"; } return getHumanReadableName(shadowType.asPrismObject()); } public static boolean isFullShadow(PrismObject<ShadowType> shadow) { ShadowType shadowType = shadow.asObjectable(); if (shadowType.getCachingMetadata() == null) { return false; } return shadowType.getCachingMetadata().getRetrievalTimestamp() != null; } public static <T extends ShadowType> PolyString determineShadowName(ShadowType shadow) throws SchemaException { return determineShadowName(shadow.asPrismObject()); } public static <T extends ShadowType> PolyString determineShadowName(PrismObject<T> shadow) throws SchemaException { String stringName = determineShadowStringName(shadow); if (stringName == null) { return null; } return new PolyString(stringName); } public static <T extends ShadowType> String determineShadowStringName(PrismObject<T> shadow) throws SchemaException { ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); if (attributesContainer == null) { return null; } ResourceAttribute<String> namingAttribute = attributesContainer.getNamingAttribute(); if (namingAttribute == null || namingAttribute.isEmpty()) { // No naming attribute defined. Try to fall back to identifiers. Collection<ResourceAttribute<?>> identifiers = attributesContainer.getPrimaryIdentifiers(); // We can use only single identifiers (not composite) if (identifiers.size() == 1) { PrismProperty<?> identifier = identifiers.iterator().next(); // Only single-valued identifiers Collection<PrismPropertyValue<?>> values = (Collection) identifier.getValues(); if (values.size() == 1) { PrismPropertyValue<?> value = values.iterator().next(); // and only strings if (value.getValue() instanceof String) { return (String) value.getValue(); } } } else { return attributesContainer.findAttribute(SchemaConstants.ICFS_NAME).getValue(String.class).getValue(); } // Identifier is not usable as name // TODO: better identification of a problem throw new SchemaException("No naming attribute defined (and identifier not usable)"); } // TODO: Error handling List<PrismPropertyValue<String>> possibleValues = namingAttribute.getValues(); if (possibleValues.size() > 1) { throw new SchemaException( "Cannot determine name of shadow. Found more than one value for naming attribute (attr: " + namingAttribute.getElementName() + ", values: {}" + possibleValues + ")"); } PrismPropertyValue<String> value = possibleValues.iterator().next(); if (value == null) { throw new SchemaException("Naming attribute has no value. Could not determine shadow name."); } return value.getValue(); // return // attributesContainer.getNamingAttribute().getValue().getValue(); } public static ResourceObjectIdentification getResourceObjectIdentification( PrismObject<ShadowType> shadow, ObjectClassComplexTypeDefinition objectClassDefinition) { return new ResourceObjectIdentification(objectClassDefinition, ShadowUtil.getPrimaryIdentifiers(shadow), ShadowUtil.getSecondaryIdentifiers(shadow)); } public static boolean matchesAttribute(ItemPath path, QName attributeName) { return (ShadowType.F_ATTRIBUTES.equals(ItemPath.getFirstName(path)) && QNameUtil.match(ItemPath.getFirstName(path.rest()), attributeName)); } public static boolean hasPrimaryIdentifier(Collection<? extends ResourceAttribute<?>> identifiers, ObjectClassComplexTypeDefinition objectClassDefinition) { for (ResourceAttribute identifier: identifiers) { if (objectClassDefinition.isPrimaryIdentifier(identifier.getElementName())) { return true; } } return false; } public static ResourceAttribute<?> fixAttributePath(ResourceAttribute<?> attribute) throws SchemaException { if (attribute == null) { return null; } if (ShadowType.F_ATTRIBUTES.equals(ItemPath.getFirstName(attribute.getPath()))) { return attribute; } ResourceAttribute<?> fixedAttribute = attribute.clone(); ResourceAttributeContainer container = new ResourceAttributeContainer(ShadowType.F_ATTRIBUTES, null, attribute.getPrismContext()); container.createNewValue().add(fixedAttribute); return fixedAttribute; } }