/* * Copyright (c) 2010-2017 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.common.refinery; import com.evolveum.midpoint.common.ResourceObjectPattern; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinitionImpl; import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer; import com.evolveum.midpoint.schema.util.SchemaDebugUtil; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PagedSearchCapabilityType; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import org.jetbrains.annotations.NotNull; import javax.xml.namespace.QName; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; /** * Used to represent combined definition of structural and auxiliary object classes. * * @author semancik * */ public class CompositeRefinedObjectClassDefinitionImpl implements CompositeRefinedObjectClassDefinition { @NotNull private final RefinedObjectClassDefinition structuralObjectClassDefinition; @NotNull private final Collection<RefinedObjectClassDefinition> auxiliaryObjectClassDefinitions; private PrismObjectDefinition<ShadowType> objectDefinition; public CompositeRefinedObjectClassDefinitionImpl(@NotNull RefinedObjectClassDefinition structuralObjectClassDefinition, Collection<RefinedObjectClassDefinition> auxiliaryObjectClassDefinitions) { this.structuralObjectClassDefinition = structuralObjectClassDefinition; if (auxiliaryObjectClassDefinitions != null) { this.auxiliaryObjectClassDefinitions = auxiliaryObjectClassDefinitions; } else { this.auxiliaryObjectClassDefinitions = new ArrayList<>(); } } public RefinedObjectClassDefinition getStructuralObjectClassDefinition() { return structuralObjectClassDefinition; } @NotNull @Override public Collection<RefinedObjectClassDefinition> getAuxiliaryObjectClassDefinitions() { return auxiliaryObjectClassDefinitions; } @Override public PrismObjectDefinition<ShadowType> getObjectDefinition() { if (objectDefinition == null) { objectDefinition = RefinedObjectClassDefinitionImpl.constructObjectDefinition(this); } return objectDefinition; } @Override public Class<?> getCompileTimeClass() { return structuralObjectClassDefinition.getCompileTimeClass(); } @Override public boolean isContainerMarker() { return structuralObjectClassDefinition.isContainerMarker(); } @Override public boolean isPrimaryIdentifier(QName attrName) { return structuralObjectClassDefinition.isPrimaryIdentifier(attrName); } @Override public boolean isObjectMarker() { return structuralObjectClassDefinition.isObjectMarker(); } @Override public boolean isIgnored() { return structuralObjectClassDefinition.isIgnored(); } @Override public boolean isEmphasized() { return structuralObjectClassDefinition.isEmphasized(); } @Override public boolean isAbstract() { return structuralObjectClassDefinition.isAbstract(); } @Override public QName getSuperType() { return structuralObjectClassDefinition.getSuperType(); } @Override public boolean isSecondaryIdentifier(QName attrName) { return structuralObjectClassDefinition.isSecondaryIdentifier(attrName); } @Override public boolean isDeprecated() { return structuralObjectClassDefinition.isDeprecated(); } @Override public Integer getDisplayOrder() { return structuralObjectClassDefinition.getDisplayOrder(); } @Override public <X> RefinedAttributeDefinition<X> getDescriptionAttribute() { return structuralObjectClassDefinition.getDescriptionAttribute(); } @Override public <X> RefinedAttributeDefinition<X> getNamingAttribute() { return structuralObjectClassDefinition.getNamingAttribute(); } @Override public String getHelp() { return structuralObjectClassDefinition.getHelp(); } @NotNull @Override public QName getTypeName() { return structuralObjectClassDefinition.getTypeName(); } @Override public String getNativeObjectClass() { return structuralObjectClassDefinition.getNativeObjectClass(); } @Override public String getDocumentation() { return structuralObjectClassDefinition.getDocumentation(); } @Override public boolean isDefaultInAKind() { return structuralObjectClassDefinition.isDefaultInAKind(); } @Override public String getDocumentationPreview() { return structuralObjectClassDefinition.getDocumentationPreview(); } @Override public String getIntent() { return structuralObjectClassDefinition.getIntent(); } @Override public ShadowKindType getKind() { return structuralObjectClassDefinition.getKind(); } @Override public boolean isRuntimeSchema() { return structuralObjectClassDefinition.isRuntimeSchema(); } @Override public <X> RefinedAttributeDefinition<X> getDisplayNameAttribute() { return structuralObjectClassDefinition.getDisplayNameAttribute(); } @NotNull @Override public Collection<? extends RefinedAttributeDefinition<?>> getPrimaryIdentifiers() { return structuralObjectClassDefinition.getPrimaryIdentifiers(); } @NotNull @Override public Collection<? extends RefinedAttributeDefinition<?>> getSecondaryIdentifiers() { return structuralObjectClassDefinition.getSecondaryIdentifiers(); } @Override public Collection<? extends RefinedAttributeDefinition<?>> getAllIdentifiers() { return structuralObjectClassDefinition.getAllIdentifiers(); } @Override public boolean isAuxiliary() { return structuralObjectClassDefinition.isAuxiliary(); } // TODO - ok??? @NotNull @Override public Collection<RefinedAssociationDefinition> getAssociationDefinitions() { return structuralObjectClassDefinition.getAssociationDefinitions(); } @Override public Collection<RefinedAssociationDefinition> getAssociationDefinitions(ShadowKindType kind) { return structuralObjectClassDefinition.getAssociationDefinitions(kind); } @Override public Collection<QName> getNamesOfAssociations() { return structuralObjectClassDefinition.getNamesOfAssociations(); } @Override public boolean isEmpty() { return structuralObjectClassDefinition.isEmpty() && !auxiliaryObjectClassDefinitions.stream() .filter(def -> def.isEmpty()) .findAny().isPresent(); } @Override public Collection<ResourceObjectPattern> getProtectedObjectPatterns() { return structuralObjectClassDefinition.getProtectedObjectPatterns(); } @Override public String getDisplayName() { return structuralObjectClassDefinition.getDisplayName(); } @Override public String getDescription() { return structuralObjectClassDefinition.getDescription(); } @Override public boolean isDefault() { return structuralObjectClassDefinition.isDefault(); } @Override public ResourceType getResourceType() { return structuralObjectClassDefinition.getResourceType(); } @Override public ObjectClassComplexTypeDefinition getObjectClassDefinition() { return structuralObjectClassDefinition.getObjectClassDefinition(); } @Override public ResourceObjectReferenceType getBaseContext() { return structuralObjectClassDefinition.getBaseContext(); } @Override public ResourceObjectVolatilityType getVolatility() { return structuralObjectClassDefinition.getVolatility(); } @Override public List<MappingType> getPasswordInbound() { return structuralObjectClassDefinition.getPasswordInbound(); } @Override public List<MappingType> getPasswordOutbound() { return structuralObjectClassDefinition.getPasswordOutbound(); } @Override public AttributeFetchStrategyType getPasswordFetchStrategy() { return structuralObjectClassDefinition.getPasswordFetchStrategy(); } @Override public ObjectReferenceType getPasswordPolicy() { return structuralObjectClassDefinition.getPasswordPolicy(); } @Override public ResourceActivationDefinitionType getActivationSchemaHandling() { return structuralObjectClassDefinition.getActivationSchemaHandling(); } @Override public ResourceBidirectionalMappingType getActivationBidirectionalMappingType(QName propertyName) { return structuralObjectClassDefinition.getActivationBidirectionalMappingType(propertyName); } @Override public AttributeFetchStrategyType getActivationFetchStrategy(QName propertyName) { return structuralObjectClassDefinition.getActivationFetchStrategy(propertyName); } @Override public boolean matches(ShadowType shadowType) { return structuralObjectClassDefinition.matches(shadowType); } public <T extends CapabilityType> T getEffectiveCapability(Class<T> capabilityClass) { return structuralObjectClassDefinition.getEffectiveCapability(capabilityClass); } @Override public PagedSearchCapabilityType getPagedSearches() { return structuralObjectClassDefinition.getPagedSearches(); } @Override public boolean isPagedSearchEnabled() { return structuralObjectClassDefinition.isPagedSearchEnabled(); } @Override public boolean isObjectCountingEnabled() { return structuralObjectClassDefinition.isObjectCountingEnabled(); } @Override public <T extends ItemDefinition> T findItemDefinition(@NotNull QName name, @NotNull Class<T> clazz, boolean caseInsensitive) { T itemDef = structuralObjectClassDefinition.findItemDefinition(name, clazz, caseInsensitive); if (itemDef == null) { for (RefinedObjectClassDefinition auxiliaryObjectClassDefinition: auxiliaryObjectClassDefinitions) { itemDef = auxiliaryObjectClassDefinition.findItemDefinition(name, clazz, caseInsensitive); if (itemDef != null) { break; } } } return itemDef; } @Override public <ID extends ItemDefinition> ID findNamedItemDefinition(@NotNull QName firstName, @NotNull ItemPath rest, @NotNull Class<ID> clazz) { throw new UnsupportedOperationException(); // implement if needed } @NotNull @Override public Collection<? extends RefinedAttributeDefinition<?>> getAttributeDefinitions() { if (auxiliaryObjectClassDefinitions.isEmpty()) { return structuralObjectClassDefinition.getAttributeDefinitions(); } Collection<? extends RefinedAttributeDefinition<?>> defs = new ArrayList<>(); defs.addAll((Collection)structuralObjectClassDefinition.getAttributeDefinitions()); for(RefinedObjectClassDefinition auxiliaryObjectClassDefinition: auxiliaryObjectClassDefinitions) { for (RefinedAttributeDefinition<?> auxRAttrDef: auxiliaryObjectClassDefinition.getAttributeDefinitions()) { boolean add = true; for (RefinedAttributeDefinition def: defs) { if (def.getName().equals(auxRAttrDef.getName())) { add = false; break; } } if (add) { ((Collection)defs).add(auxRAttrDef); } } } return defs; } @Override public PrismContext getPrismContext() { return structuralObjectClassDefinition.getPrismContext(); } @Override public void revive(PrismContext prismContext) { structuralObjectClassDefinition.revive(prismContext); for (RefinedObjectClassDefinition auxiliaryObjectClassDefinition : auxiliaryObjectClassDefinitions) { auxiliaryObjectClassDefinition.revive(prismContext); } } @NotNull @Override public List<? extends ItemDefinition> getDefinitions() { return (List) getAttributeDefinitions(); } @Override public QName getExtensionForType() { return structuralObjectClassDefinition.getExtensionForType(); } @Override public boolean isXsdAnyMarker() { return structuralObjectClassDefinition.isXsdAnyMarker(); } @Override public String getDefaultNamespace() { return structuralObjectClassDefinition.getDefaultNamespace(); } @NotNull @Override public List<String> getIgnoredNamespaces() { return structuralObjectClassDefinition.getIgnoredNamespaces(); } @Override public LayerRefinedObjectClassDefinition forLayer(@NotNull LayerType layerType) { return LayerRefinedObjectClassDefinitionImpl.wrap(this, layerType); } @SuppressWarnings("unchecked") @Override public <X> RefinedAttributeDefinition<X> findAttributeDefinition(QName elementQName, boolean caseInsensitive) { return findItemDefinition(elementQName, RefinedAttributeDefinition.class, caseInsensitive); } @Override public <X> RefinedAttributeDefinition<X> findAttributeDefinition(@NotNull QName name) { return findAttributeDefinition(name, false); } public RefinedAssociationDefinition findAssociationDefinition(QName name) { for (RefinedAssociationDefinition assocType: getAssociationDefinitions()) { if (QNameUtil.match(assocType.getName(), name)) { return assocType; } } return null; } public Collection<RefinedAssociationDefinition> getEntitlementAssociationDefinitions() { return getAssociationDefinitions(ShadowKindType.ENTITLEMENT); } public RefinedAssociationDefinition findEntitlementAssociationDefinition(QName name) { for (RefinedAssociationDefinition assocType: getEntitlementAssociationDefinitions()) { if (QNameUtil.match(assocType.getName(), name)) { return assocType; } } return null; } @Override public Collection<? extends QName> getNamesOfAssociationsWithOutboundExpressions() { return getAssociationDefinitions().stream() .filter(assocDef -> assocDef.getOutboundMappingType() != null) .map(a -> a.getName()) .collect(Collectors.toCollection(HashSet::new)); } @Override public boolean hasAuxiliaryObjectClass(QName expectedObjectClassName) { if (structuralObjectClassDefinition.hasAuxiliaryObjectClass(expectedObjectClassName)) { return true; } return auxiliaryObjectClassDefinitions.stream().anyMatch( def -> QNameUtil.match(expectedObjectClassName, def.getTypeName())); } @Override public ResourceAttributeContainer instantiate(QName elementName) { return ObjectClassComplexTypeDefinitionImpl.instantiate(elementName, this); } @Override public <ID extends ItemDefinition> ID findItemDefinition(@NotNull ItemPath path, @NotNull Class<ID> clazz) { throw new UnsupportedOperationException("TODO implement if needed"); } @Override public void merge(ComplexTypeDefinition otherComplexTypeDef) { throw new UnsupportedOperationException("TODO implement if needed"); } @Override public String getResourceNamespace() { return structuralObjectClassDefinition.getResourceNamespace(); } // TODO @Override public Class getTypeClassIfKnown() { return null; } // TODO @Override public Class getTypeClass() { return null; } @Override public boolean containsAttributeDefinition(ItemPathType pathType) { return getRefinedObjectClassDefinitionsStream() .filter(def -> containsAttributeDefinition(pathType)) .findAny() .isPresent(); } private Stream<RefinedObjectClassDefinition> getRefinedObjectClassDefinitionsStream() { return Stream.concat(Stream.of(structuralObjectClassDefinition), auxiliaryObjectClassDefinitions.stream()); } @Override public boolean containsAttributeDefinition(QName attributeName) { return getRefinedObjectClassDefinitionsStream() .filter(def -> containsAttributeDefinition(attributeName)) .findAny() .isPresent(); } @Override public ObjectQuery createShadowSearchQuery(String resourceOid) throws SchemaException { return structuralObjectClassDefinition.createShadowSearchQuery(resourceOid); } @Override public PrismObject<ShadowType> createBlankShadow(RefinedObjectClassDefinition definition) { return structuralObjectClassDefinition.createBlankShadow(definition); } @Override public ResourceShadowDiscriminator getShadowDiscriminator() { return structuralObjectClassDefinition.getShadowDiscriminator(); } @Override public Collection<? extends QName> getNamesOfAttributesWithOutboundExpressions() { Set<QName> names = new HashSet<>(); getRefinedObjectClassDefinitionsStream().forEach( def -> names.addAll(def.getNamesOfAttributesWithOutboundExpressions()) ); return names; } @Override public Collection<? extends QName> getNamesOfAttributesWithInboundExpressions() { Set<QName> names = new HashSet<>(); getRefinedObjectClassDefinitionsStream().forEach( def -> names.addAll(def.getNamesOfAttributesWithInboundExpressions()) ); return names; } @Override public ResourcePasswordDefinitionType getPasswordDefinition() { // TODO what if there is a conflict? return getRefinedObjectClassDefinitionsStream() .map(def -> def.getPasswordDefinition()) .findFirst().orElse(null); } @NotNull @Override public CompositeRefinedObjectClassDefinitionImpl clone() { RefinedObjectClassDefinition structuralObjectClassDefinitionClone = structuralObjectClassDefinition.clone(); Collection<RefinedObjectClassDefinition> auxiliaryObjectClassDefinitionsClone = null; auxiliaryObjectClassDefinitionsClone = new ArrayList<>(this.auxiliaryObjectClassDefinitions.size()); for(RefinedObjectClassDefinition auxiliaryObjectClassDefinition: this.auxiliaryObjectClassDefinitions) { auxiliaryObjectClassDefinitionsClone.add(auxiliaryObjectClassDefinition.clone()); } return new CompositeRefinedObjectClassDefinitionImpl(structuralObjectClassDefinitionClone, auxiliaryObjectClassDefinitionsClone); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((auxiliaryObjectClassDefinitions == null) ? 0 : auxiliaryObjectClassDefinitions.hashCode()); result = prime * result + ((structuralObjectClassDefinition == null) ? 0 : structuralObjectClassDefinition.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } // if (!super.equals(obj)) { // return false; // } if (getClass() != obj.getClass()) { return false; } CompositeRefinedObjectClassDefinitionImpl other = (CompositeRefinedObjectClassDefinitionImpl) obj; if (!auxiliaryObjectClassDefinitions.equals(other.auxiliaryObjectClassDefinitions)) { return false; } if (!structuralObjectClassDefinition.equals(other.structuralObjectClassDefinition)) { return false; } return true; } @Override public String debugDump() { return debugDump(0); } @Override public String debugDump(int indent) { return debugDump(indent, null); } protected String debugDump(int indent, LayerType layer) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < indent; i++) { sb.append(INDENT_STRING); } sb.append(getDebugDumpClassName()).append(": "); sb.append(SchemaDebugUtil.prettyPrint(getTypeName())); sb.append("\n"); DebugUtil.debugDumpWithLabel(sb, "structural", structuralObjectClassDefinition, indent + 1); sb.append("\n"); DebugUtil.debugDumpWithLabel(sb, "auxiliary", auxiliaryObjectClassDefinitions, indent + 1); return sb.toString(); } /** * Return a human readable name of this class suitable for logs. */ // @Override public String getDebugDumpClassName() { return "crOCD"; } public String getHumanReadableName() { if (getDisplayName() != null) { return getDisplayName(); } else { return getKind()+":"+getIntent(); } } @Override public String toString() { if (auxiliaryObjectClassDefinitions.isEmpty()) { return getDebugDumpClassName() + " ("+getTypeName()+")"; } else { StringBuilder sb = new StringBuilder(); sb.append(getDebugDumpClassName()).append("(").append(getTypeName()); for (RefinedObjectClassDefinition auxiliaryObjectClassDefinition: auxiliaryObjectClassDefinitions) { sb.append("+").append(auxiliaryObjectClassDefinition.getTypeName()); } sb.append(")"); return sb.toString(); } } @NotNull @Override public CompositeRefinedObjectClassDefinitionImpl deepClone(Map<QName, ComplexTypeDefinition> ctdMap) { RefinedObjectClassDefinition structuralClone = structuralObjectClassDefinition.deepClone(ctdMap); List<RefinedObjectClassDefinition> auxiliaryClones = auxiliaryObjectClassDefinitions.stream() .map(def -> def.deepClone(ctdMap)) .collect(Collectors.toCollection(ArrayList::new)); return new CompositeRefinedObjectClassDefinitionImpl(structuralClone, auxiliaryClones); } @Override public boolean isListMarker() { return structuralObjectClassDefinition.isListMarker(); } }