/* * 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.processor; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.xml.namespace.QName; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAttributesType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import org.jetbrains.annotations.NotNull; /** * Resource Object Definition (Object Class). * * Object Class refers to a type of object on the Resource. Unix account, Active * Directory group, inetOrgPerson LDAP objectclass or a schema of USERS database * table are all Object Classes from the midPoint point of view. Object class * defines a set of attribute names, types for each attributes and few * additional properties. * * This class represents schema definition for resource object (object class). * See {@link Definition} for more details. * * Resource Object Definition is immutable. TODO: This will probably need to be * changed to a mutable object. * * @author Radovan Semancik * */ public class ResourceAttributeContainerDefinitionImpl extends PrismContainerDefinitionImpl<ShadowAttributesType> implements ResourceAttributeContainerDefinition { private static final long serialVersionUID = 3943909626639924429L; public ResourceAttributeContainerDefinitionImpl(QName name, ObjectClassComplexTypeDefinition complexTypeDefinition, PrismContext prismContext) { super(name, complexTypeDefinition, prismContext); super.setCompileTimeClass(ShadowAttributesType.class); } @Override public ObjectClassComplexTypeDefinition getComplexTypeDefinition() { return (ObjectClassComplexTypeDefinition)super.getComplexTypeDefinition(); } /** * Returns the definition of primary identifier attributes of a resource object. * * May return empty set if there are no identifier attributes. Must not * return null. * * The exception should be never thrown unless there is some bug in the * code. The validation of model consistency should be done at the time of * schema parsing. * * @return definition of identifier attributes * @throws IllegalStateException * if there is no definition for the referenced attributed */ // TODO: rename to getPrimaryIdentifiers @Override public Collection<? extends ResourceAttributeDefinition> getPrimaryIdentifiers() { return getComplexTypeDefinition().getPrimaryIdentifiers(); } /** * Returns the definition of secondary identifier attributes of a resource * object. * * May return empty set if there are no secondary identifier attributes. * Must not return null. * * The exception should be never thrown unless there is some bug in the * code. The validation of model consistency should be done at the time of * schema parsing. * * @return definition of secondary identifier attributes * @throws IllegalStateException * if there is no definition for the referenced attributed */ @Override public Collection<? extends ResourceAttributeDefinition> getSecondaryIdentifiers() { return getComplexTypeDefinition().getSecondaryIdentifiers(); } @Override public Collection<? extends ResourceAttributeDefinition> getAllIdentifiers() { return getComplexTypeDefinition().getAllIdentifiers(); } /** * Returns the definition of description attribute of a resource object. * * Returns null if there is no description attribute. * * The exception should be never thrown unless there is some bug in the * code. The validation of model consistency should be done at the time of * schema parsing. * * @return definition of secondary identifier attributes * @throws IllegalStateException * if there is more than one description attribute. But this * should never happen. * @throws IllegalStateException * if there is no definition for the referenced attributed */ @Override public ResourceAttributeDefinition getDescriptionAttribute() { return getComplexTypeDefinition().getDescriptionAttribute(); } public void setDescriptionAttribute(ResourceAttributeDefinition descriptionAttribute) { // We can afford to delegate a set here as we know that there is one-to-one correspondence between // object class definition and attribute container ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setDescriptionAttribute(descriptionAttribute); } /** * Specifies which resource attribute should be used as a "technical" name * for the account. This name will appear in log files and other troubleshooting * tools. The name should be a form of unique identifier that can be used to * locate the resource object for diagnostics. It should not contain white chars and * special chars if that can be avoided and it should be reasonable short. * It is different from a display name attribute. Display name is intended for a * common user or non-technical administrator (such as role administrator). The * naming attribute is intended for technical IDM administrators and developers. * * @return resource attribute definition that should be used as a "technical" name * for the account. */ @Override public ResourceAttributeDefinition getNamingAttribute() { return getComplexTypeDefinition().getNamingAttribute(); } public void setNamingAttribute(ResourceAttributeDefinition namingAttribute) { // We can afford to delegate a set here as we know that there is one-to-one correspondence between // object class definition and attribute container ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setNamingAttribute(namingAttribute); } public void setNamingAttribute(QName namingAttribute) { ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setNamingAttribute(namingAttribute); } /** * Returns the native object class string for the resource object. * * Native object class is the name of the Resource Object Definition (Object * Class) as it is seen by the resource itself. The name of the Resource * Object Definition may be constrained by XSD or other syntax and therefore * may be "mangled" to conform to such syntax. The <i>native object * class</i> value will contain unmangled name (if available). * * Returns null if there is no native object class. * * The exception should be never thrown unless there is some bug in the * code. The validation of model consistency should be done at the time of * schema parsing. * * @return native object class * @throws IllegalStateException * if there is more than one description attribute. */ @Override public String getNativeObjectClass() { return getComplexTypeDefinition().getNativeObjectClass(); } public void setNativeObjectClass(String nativeObjectClass) { // We can afford to delegate a set here as we know that there is one-to-one correspondence between // object class definition and attribute container ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setNativeObjectClass(nativeObjectClass); } /** * Indicates whether definition is should be used as default account type. * * If true value is returned then the definition should be used as a default * account type definition. This is a way how a resource connector may * suggest applicable object classes (resource object definitions) for * accounts. * * If no information about account type is present, false should be * returned. This method must return true only if isAccountType() returns * true. * * The exception should be never thrown unless there is some bug in the * code. The validation of at-most-one value should be done at the time of * schema parsing. The exception may not even be thrown at all if the * implementation is not able to determine duplicity. * * @return true if the definition should be used as account type. * @throws IllegalStateException * if more than one default account is suggested in the schema. */ @Override public boolean isDefaultInAKind() { return getComplexTypeDefinition().isDefaultInAKind(); } public void setDefaultInAKind(boolean defaultAccountType) { ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setDefaultInAKind(defaultAccountType); } @Override public String getIntent() { return getComplexTypeDefinition().getIntent(); } public void setIntent(String accountTypeName) { ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setIntent(accountTypeName); } @Override public ShadowKindType getKind() { return getComplexTypeDefinition().getKind(); } public void setKind(ShadowKindType kind) { ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setKind(kind); } /** * Returns the definition of display name attribute. * * Display name attribute specifies which resource attribute should be used * as title when displaying objects of a specific resource object class. It * must point to an attribute of String type. If not present, primary * identifier should be used instead (but this method does not handle this * default behavior). * * Returns null if there is no display name attribute. * * The exception should be never thrown unless there is some bug in the * code. The validation of model consistency should be done at the time of * schema parsing. * * @return native object class * @throws IllegalStateException * if there is more than one display name attribute or the * definition of the referenced attribute does not exist. */ @Override public ResourceAttributeDefinition getDisplayNameAttribute() { return getComplexTypeDefinition().getDisplayNameAttribute(); } public void setDisplayNameAttribute(ResourceAttributeDefinition displayName) { ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setDisplayNameAttribute(displayName); } /** * TODO * * Convenience method. It will internally look up the correct definition. * * @param displayName */ public void setDisplayNameAttribute(QName displayName) { ((ObjectClassComplexTypeDefinitionImpl) getComplexTypeDefinition()).setDisplayNameAttribute(displayName); } @NotNull @Override public ResourceAttributeContainer instantiate() { return instantiate(getName()); } @NotNull @Override public ResourceAttributeContainer instantiate(QName name) { name = addNamespaceIfApplicable(name); return new ResourceAttributeContainer(name, this, prismContext); } @NotNull @Override public ResourceAttributeContainerDefinitionImpl clone() { ResourceAttributeContainerDefinitionImpl clone = new ResourceAttributeContainerDefinitionImpl(name, (ObjectClassComplexTypeDefinition)complexTypeDefinition.clone(), prismContext); copyDefinitionData(clone); return clone; } protected void copyDefinitionData(ResourceAttributeContainerDefinitionImpl clone) { super.copyDefinitionData(clone); } @Override public ResourceAttributeDefinition findAttributeDefinition(QName elementQName) { return findAttributeDefinition(elementQName, false); } @Override public ResourceAttributeDefinition findAttributeDefinition(QName elementQName, boolean caseInsensitive) { return findItemDefinition(elementQName, ResourceAttributeDefinition.class, caseInsensitive); } @Override public ResourceAttributeDefinition findAttributeDefinition(ItemPath elementPath) { return findItemDefinition(elementPath, ResourceAttributeDefinition.class); } @Override public ResourceAttributeDefinition findAttributeDefinition(String elementLocalname) { QName elementQName = new QName(getName().getNamespaceURI(),elementLocalname); return findAttributeDefinition(elementQName); } @Override public List<? extends ResourceAttributeDefinition> getAttributeDefinitions() { List<ResourceAttributeDefinition> attrs = new ArrayList<>(); for (ItemDefinition def: complexTypeDefinition.getDefinitions()) { if (def instanceof ResourceAttributeDefinition) { attrs.add((ResourceAttributeDefinition)def); } else { throw new IllegalStateException("Found "+def+" in resource attribute container, only attribute definitions are expected here"); } } return attrs; } // Only attribute definitions should be here. @Override public List<? extends ResourceAttributeDefinition> getDefinitions() { return getAttributeDefinitions(); } @Override public <T extends ShadowType> PrismObjectDefinition<T> toShadowDefinition() { PrismObjectDefinition<T> origShadowDef = (PrismObjectDefinition<T>) prismContext.getSchemaRegistry(). findObjectDefinitionByCompileTimeClass(ShadowType.class); PrismObjectDefinition<T> shadowDefinition = origShadowDef.cloneWithReplacedDefinition(ShadowType.F_ATTRIBUTES, this); return shadowDefinition; } @Override public String debugDump(int indent) { StringBuilder sb = new StringBuilder(); for (int i=0; i<indent; i++) { sb.append(DebugDumpable.INDENT_STRING); } sb.append(toString()); for (Definition def : getDefinitions()) { sb.append("\n"); if (def instanceof ResourceAttributeDefinition) { ResourceAttributeDefinition attrDef = (ResourceAttributeDefinition)def; sb.append(attrDef.debugDump(indent+1)); if (attrDef.isIdentifier(this)) { sb.deleteCharAt(sb.length()-1); sb.append(" id"); } } else { sb.append(def.debugDump(indent+1)); } } return sb.toString(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()).append(":").append(getName()).append(" (").append(getTypeName()).append(")"); if (isDefaultInAKind()) { sb.append(" def"); } if (getKind() != null) { sb.append(" ").append(getKind()); } if (getNativeObjectClass()!=null) { sb.append(" native="); sb.append(getNativeObjectClass()); } return sb.toString(); } }