/*
* 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.model.impl.lens;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.namespace.QName;
import com.evolveum.midpoint.common.refinery.*;
import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.schema.DeltaConvertor;
import com.evolveum.midpoint.schema.ResourceShadowDiscriminator;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType;
import org.apache.commons.lang.StringUtils;
import org.jvnet.jaxb2_commons.lang.Validate;
import com.evolveum.midpoint.common.crypto.CryptoUtil;
import com.evolveum.midpoint.model.api.context.ModelProjectionContext;
import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision;
import com.evolveum.midpoint.prism.delta.ChangeType;
import com.evolveum.midpoint.prism.delta.DeltaSetTriple;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.prism.delta.ReferenceDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.processor.ResourceAttribute;
import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer;
import com.evolveum.midpoint.schema.processor.ResourceSchema;
import com.evolveum.midpoint.schema.util.MiscSchemaUtil;
import com.evolveum.midpoint.schema.util.ShadowUtil;
import com.evolveum.midpoint.schema.util.ResourceTypeUtil;
import com.evolveum.midpoint.schema.util.SchemaDebugUtil;
import com.evolveum.midpoint.util.Cloner;
import com.evolveum.midpoint.util.DebugUtil;
/**
* @author semancik
*
*/
public class LensProjectionContext extends LensElementContext<ShadowType> implements ModelProjectionContext {
private ObjectDelta<ShadowType> syncDelta;
private ObjectDelta<ShadowType> secondaryDelta;
/**
* If set to true: absolute state of this projection was detected by the synchronization.
* This is mostly for debugging and visibility. It is not used by projection logic.
*/
private boolean syncAbsoluteTrigger = false;
/**
* The wave in which this resource should be processed. Initial value of -1 means "undetermined".
*/
private int wave = -1;
/**
* Indicates that the wave computation is still in progress.
*/
private transient boolean waveIncomplete = false;
/**
* Definition of account type.
*/
private ResourceShadowDiscriminator resourceShadowDiscriminator;
private boolean fullShadow = false;
/**
* True if the account is assigned to the user by a valid assignment. It may be false for accounts that are either
* found to be illegal by live sync, were unassigned from user, etc.
* If set to null the situation is not yet known. Null is a typical value when the context is constructed.
*/
private boolean isAssigned;
private boolean isAssignedOld;
/**
* True if the account should be part of the synchronization. E.g. outbound expression should be applied to it.
*/
private boolean isActive;
/**
* True if there is a valid assignment for this projection and/or the policy allows such projection to exist.
*/
private Boolean isLegal = null;
private Boolean isLegalOld = null;
private boolean isExists;
/**
* Decision regarding the account. It indicated what the engine has DECIDED TO DO with the context.
* If set to null no decision was made yet. Null is also a typical value when the context is created.
*/
private SynchronizationPolicyDecision synchronizationPolicyDecision;
/**
* True if we want to reconcile account in this context.
*/
private boolean doReconciliation;
/**
* false if the context should be not taken into the account while synchronizing changes from other resource
*/
private boolean canProject = true;
/**
* Synchronization situation as it was originally detected by the synchronization code (SynchronizationService).
* This is mostly for debug purposes. Projector and clockwork do not need to care about this.
* The synchronization intent is used instead.
*/
private SynchronizationSituationType synchronizationSituationDetected = null;
/**
* Synchronization situation which was the result of synchronization reaction (projector and clockwork run).
* This is mostly for debug purposes. Projector and clockwork do not care about this (except for setting it).
* The synchronization decision is used instead.
*/
private SynchronizationSituationType synchronizationSituationResolved = null;
/**
* Delta set triple for accounts. Specifies which accounts should be added, removed or stay as they are.
* It tells almost nothing about attributes directly although the information about attributes are inside
* each account construction (in a form of ValueConstruction that contains attribute delta triples).
*
* Intermediary computation result. It is stored to allow re-computing of account constructions during
* iterative computations.
*
* Source: AssignmentProcessor
* Target: ConsolidationProcessor / ReconciliationProcessor (via squeezed structures)
*/
private transient PrismValueDeltaSetTriple<PrismPropertyValue<Construction>> constructionDeltaSetTriple;
/**
* Triples for outbound mappings; similar to the above.
* Source: OutboundProcessor
* Target: ConsolidationProcessor / ReconciliationProcessor (via squeezed structures)
*/
private transient Construction outboundConstruction;
/**
* Postprocessed triples from the above two properties.
* Source: ConsolidationProcessor
* Target: ReconciliationProcessor
*/
private transient Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>>> squeezedAttributes;
private transient Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismContainerValue<ShadowAssociationType>,PrismContainerDefinition<ShadowAssociationType>>>> squeezedAssociations;
private transient Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<QName>,PrismPropertyDefinition<QName>>>> squeezedAuxiliaryObjectClasses;
private transient Collection<ResourceObjectTypeDependencyType> dependencies = null;
// Cached copy, to avoid constructing it over and over again
private transient PrismObjectDefinition<ShadowType> shadowDefinition = null;
private transient RefinedObjectClassDefinition structuralObjectClassDefinition;
private transient Collection<RefinedObjectClassDefinition> auxiliaryObjectClassDefinitions;
private transient CompositeRefinedObjectClassDefinition compositeObjectClassDefinition;
private ValuePolicyType accountPasswordPolicy;
/**
* Resource that hosts this projection.
*/
transient private ResourceType resource;
/**
* EXPERIMENTAL. A flag that this projection context has to be put into 'history archive'.
* Necessary to evaluate old state of hasLinkedAccount.
*
* TODO implement as non-transient.
*/
transient private boolean toBeArchived;
transient private String humanReadableName;
LensProjectionContext(LensContext<? extends ObjectType> lensContext, ResourceShadowDiscriminator resourceAccountType) {
super(ShadowType.class, lensContext);
this.resourceShadowDiscriminator = resourceAccountType;
this.isAssigned = false;
this.isAssignedOld = false;
}
public ObjectDelta<ShadowType> getSyncDelta() {
return syncDelta;
}
public void setSyncDelta(ObjectDelta<ShadowType> syncDelta) {
this.syncDelta = syncDelta;
}
@Override
public ObjectDelta<ShadowType> getSecondaryDelta() {
return secondaryDelta;
}
@Override
public ObjectDeltaObject<ShadowType> getObjectDeltaObject() throws SchemaException {
return new ObjectDeltaObject<>(getObjectCurrent(), getDelta(), getObjectNew());
}
@Override
public void setSecondaryDelta(ObjectDelta<ShadowType> secondaryDelta) {
this.secondaryDelta = secondaryDelta;
}
public void addSecondaryDelta(ObjectDelta<ShadowType> delta) throws SchemaException {
if (secondaryDelta == null) {
secondaryDelta = delta;
} else {
secondaryDelta.merge(delta);
}
}
@Override
public void swallowToSecondaryDelta(ItemDelta<?,?> itemDelta) throws SchemaException {
if (secondaryDelta == null) {
secondaryDelta = new ObjectDelta<ShadowType>(getObjectTypeClass(), ChangeType.MODIFY, getPrismContext());
secondaryDelta.setOid(getOid());
}
secondaryDelta.swallow(itemDelta);
}
@Override
public void setOid(String oid) {
super.setOid(oid);
if (secondaryDelta != null) {
secondaryDelta.setOid(oid);
}
}
public boolean isSyncAbsoluteTrigger() {
return syncAbsoluteTrigger;
}
public void setSyncAbsoluteTrigger(boolean syncAbsoluteTrigger) {
this.syncAbsoluteTrigger = syncAbsoluteTrigger;
}
public int getWave() {
return wave;
}
public void setWave(int wave) {
this.wave = wave;
}
public boolean isWaveIncomplete() {
return waveIncomplete;
}
public void setWaveIncomplete(boolean waveIncomplete) {
this.waveIncomplete = waveIncomplete;
}
public boolean isDoReconciliation() {
return doReconciliation;
}
public void setDoReconciliation(boolean doReconciliation) {
this.doReconciliation = doReconciliation;
}
@Override
public ResourceShadowDiscriminator getResourceShadowDiscriminator() {
return resourceShadowDiscriminator;
}
public void setResourceShadowDiscriminator(ResourceShadowDiscriminator resourceShadowDiscriminator) {
this.resourceShadowDiscriminator = resourceShadowDiscriminator;
}
public boolean compareResourceShadowDiscriminator(ResourceShadowDiscriminator rsd, boolean compareOrder) {
Validate.notNull(rsd.getResourceOid());
if (resourceShadowDiscriminator == null) {
// This may be valid case e.g. in case of broken contexts or if a context is just loading
return false;
}
if (!rsd.getResourceOid().equals(resourceShadowDiscriminator.getResourceOid())) {
return false;
}
if (!rsd.getKind().equals(resourceShadowDiscriminator.getKind())) {
return false;
}
if (rsd.isThombstone() != resourceShadowDiscriminator.isThombstone()) {
return false;
}
if (rsd.getIntent() == null) {
try {
if (!getStructuralObjectClassDefinition().isDefaultInAKind()) {
return false;
}
} catch (SchemaException e) {
throw new SystemException("Internal error: "+e.getMessage(), e);
}
} else if (!rsd.getIntent().equals(resourceShadowDiscriminator.getIntent())) {
return false;
}
if (compareOrder && rsd.getOrder() != resourceShadowDiscriminator.getOrder()) {
return false;
}
return true;
}
public boolean isThombstone() {
if (resourceShadowDiscriminator == null) {
return false;
}
return resourceShadowDiscriminator.isThombstone();
}
public void addAccountSyncDelta(ObjectDelta<ShadowType> delta) throws SchemaException {
if (syncDelta == null) {
syncDelta = delta;
} else {
syncDelta.merge(delta);
}
}
public boolean isAdd() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.ADD) {
return true;
} else if (synchronizationPolicyDecision != null){
return false;
}
return super.isAdd();
}
public boolean isModify() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.KEEP) {
return true;
} else if (synchronizationPolicyDecision != null){
return false;
}
return super.isModify();
}
public boolean isDelete() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.DELETE) {
return true;
} else if (synchronizationPolicyDecision != null){
return false;
}
if (syncDelta != null && syncDelta.isDelete()) {
return true;
}
return super.isDelete();
}
public ResourceType getResource() {
return resource;
}
public void setResource(ResourceType resource) {
this.resource = resource;
}
@Override
public PrismObjectDefinition<ShadowType> getObjectDefinition() {
if (shadowDefinition == null) {
try {
shadowDefinition = ShadowUtil.applyObjectClass(super.getObjectDefinition(), getCompositeObjectClassDefinition());
} catch (SchemaException e) {
// This should not happen
throw new SystemException(e.getMessage(), e);
}
}
return shadowDefinition;
}
public boolean isAssigned() {
return isAssigned;
}
public void setAssigned(boolean isAssigned) {
this.isAssigned = isAssigned;
}
public boolean isAssignedOld() {
return isAssignedOld;
}
public void setAssignedOld(boolean isAssignedOld) {
this.isAssignedOld = isAssignedOld;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean isActive) {
this.isActive = isActive;
}
public Boolean isLegal() {
return isLegal;
}
public void setLegal(Boolean isLegal) {
this.isLegal = isLegal;
}
public Boolean isLegalOld() {
return isLegalOld;
}
public void setLegalOld(Boolean isLegalOld) {
this.isLegalOld = isLegalOld;
}
public boolean isExists() {
return isExists;
}
public void setExists(boolean exists) {
this.isExists = exists;
}
public SynchronizationPolicyDecision getSynchronizationPolicyDecision() {
return synchronizationPolicyDecision;
}
public void setSynchronizationPolicyDecision(SynchronizationPolicyDecision policyDecision) {
this.synchronizationPolicyDecision = policyDecision;
}
public SynchronizationSituationType getSynchronizationSituationDetected() {
return synchronizationSituationDetected;
}
public void setSynchronizationSituationDetected(
SynchronizationSituationType synchronizationSituationDetected) {
this.synchronizationSituationDetected = synchronizationSituationDetected;
}
public SynchronizationSituationType getSynchronizationSituationResolved() {
return synchronizationSituationResolved;
}
public void setSynchronizationSituationResolved(
SynchronizationSituationType synchronizationSituationResolved) {
this.synchronizationSituationResolved = synchronizationSituationResolved;
}
public boolean isFullShadow() {
return fullShadow;
}
/**
* Returns true if full shadow is available, either loaded or in a create delta.
*/
public boolean hasFullShadow() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.ADD) {
return true;
}
return isFullShadow();
}
public void setFullShadow(boolean fullShadow) {
this.fullShadow = fullShadow;
}
public ShadowKindType getKind() {
ResourceShadowDiscriminator discr = getResourceShadowDiscriminator();
if (discr != null) {
return discr.getKind();
}
if (getObjectOld()!=null) {
return getObjectOld().asObjectable().getKind();
}
if (getObjectCurrent()!=null) {
return getObjectCurrent().asObjectable().getKind();
}
if (getObjectNew()!=null) {
return getObjectNew().asObjectable().getKind();
}
return ShadowKindType.ACCOUNT;
}
public PrismValueDeltaSetTriple<PrismPropertyValue<Construction>> getConstructionDeltaSetTriple() {
return constructionDeltaSetTriple;
}
public void setConstructionDeltaSetTriple(
PrismValueDeltaSetTriple<PrismPropertyValue<Construction>> constructionDeltaSetTriple) {
this.constructionDeltaSetTriple = constructionDeltaSetTriple;
}
public Construction getOutboundConstruction() {
return outboundConstruction;
}
public void setOutboundConstruction(Construction outboundConstruction) {
this.outboundConstruction = outboundConstruction;
}
public Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>>> getSqueezedAttributes() {
return squeezedAttributes;
}
public void setSqueezedAttributes(Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>>> squeezedAttributes) {
this.squeezedAttributes = squeezedAttributes;
}
public Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismContainerValue<ShadowAssociationType>,PrismContainerDefinition<ShadowAssociationType>>>> getSqueezedAssociations() {
return squeezedAssociations;
}
public void setSqueezedAssociations(
Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismContainerValue<ShadowAssociationType>,PrismContainerDefinition<ShadowAssociationType>>>> squeezedAssociations) {
this.squeezedAssociations = squeezedAssociations;
}
public Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<QName>, PrismPropertyDefinition<QName>>>> getSqueezedAuxiliaryObjectClasses() {
return squeezedAuxiliaryObjectClasses;
}
public void setSqueezedAuxiliaryObjectClasses(
Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<QName>, PrismPropertyDefinition<QName>>>> squeezedAuxiliaryObjectClasses) {
this.squeezedAuxiliaryObjectClasses = squeezedAuxiliaryObjectClasses;
}
public ResourceObjectTypeDefinitionType getResourceObjectTypeDefinitionType() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.BROKEN) {
return null;
}
ResourceShadowDiscriminator discr = getResourceShadowDiscriminator();
if (discr == null) {
return null; // maybe when an account is deleted
}
if (resource == null) {
return null;
}
ResourceObjectTypeDefinitionType def = ResourceTypeUtil.getResourceObjectTypeDefinitionType(resource, discr.getKind(), discr.getIntent());
return def;
}
private ResourceSchema getResourceSchema() throws SchemaException {
return RefinedResourceSchemaImpl.getResourceSchema(resource, getNotNullPrismContext());
}
public RefinedResourceSchema getRefinedResourceSchema() throws SchemaException {
if (resource == null) {
return null;
}
return RefinedResourceSchemaImpl.getRefinedSchema(resource, LayerType.MODEL, getNotNullPrismContext());
}
public RefinedObjectClassDefinition getStructuralObjectClassDefinition() throws SchemaException {
if (structuralObjectClassDefinition == null) {
RefinedResourceSchema refinedSchema = getRefinedResourceSchema();
if (refinedSchema == null) {
return null;
}
structuralObjectClassDefinition = refinedSchema.getRefinedDefinition(getResourceShadowDiscriminator().getKind(), getResourceShadowDiscriminator().getIntent());
}
return structuralObjectClassDefinition;
}
public Collection<RefinedObjectClassDefinition> getAuxiliaryObjectClassDefinitions() throws SchemaException {
if (auxiliaryObjectClassDefinitions == null) {
refreshAuxiliaryObjectClassDefinitions();
}
return auxiliaryObjectClassDefinitions;
}
public void refreshAuxiliaryObjectClassDefinitions() throws SchemaException {
RefinedResourceSchema refinedSchema = getRefinedResourceSchema();
if (refinedSchema == null) {
return;
}
List<QName> auxiliaryObjectClassQNames = new ArrayList<>();
addAuxiliaryObjectClassNames(auxiliaryObjectClassQNames, getObjectOld());
addAuxiliaryObjectClassNames(auxiliaryObjectClassQNames, getObjectNew());
auxiliaryObjectClassDefinitions = new ArrayList<>(auxiliaryObjectClassQNames.size());
for (QName auxiliaryObjectClassQName: auxiliaryObjectClassQNames) {
RefinedObjectClassDefinition auxiliaryObjectClassDef = refinedSchema.getRefinedDefinition(auxiliaryObjectClassQName);
if (auxiliaryObjectClassDef == null) {
throw new SchemaException("Auxiliary object class "+auxiliaryObjectClassQName+" specified in "+this+" does not exist");
}
auxiliaryObjectClassDefinitions.add(auxiliaryObjectClassDef);
}
compositeObjectClassDefinition = null;
}
public CompositeRefinedObjectClassDefinition getCompositeObjectClassDefinition() throws SchemaException {
if (compositeObjectClassDefinition == null) {
RefinedObjectClassDefinition structuralObjectClassDefinition = getStructuralObjectClassDefinition();
if (structuralObjectClassDefinition != null) {
compositeObjectClassDefinition = new CompositeRefinedObjectClassDefinitionImpl(
structuralObjectClassDefinition, getAuxiliaryObjectClassDefinitions());
}
}
return compositeObjectClassDefinition;
}
private void addAuxiliaryObjectClassNames(List<QName> auxiliaryObjectClassQNames,
PrismObject<ShadowType> shadow) {
if (shadow == null) {
return;
}
for (QName aux: shadow.asObjectable().getAuxiliaryObjectClass()) {
if (!auxiliaryObjectClassQNames.contains(aux)) {
auxiliaryObjectClassQNames.add(aux);
}
}
}
public <T> RefinedAttributeDefinition<T> findAttributeDefinition(QName attrName) throws SchemaException {
RefinedAttributeDefinition<T> attrDef = getStructuralObjectClassDefinition().findAttributeDefinition(attrName);
if (attrDef != null) {
return attrDef;
}
for (RefinedObjectClassDefinition auxOcDef: getAuxiliaryObjectClassDefinitions()) {
attrDef = auxOcDef.findAttributeDefinition(attrName);
if (attrDef != null) {
return attrDef;
}
}
return null;
}
public Collection<ResourceObjectTypeDependencyType> getDependencies() {
if (dependencies == null) {
ResourceObjectTypeDefinitionType resourceAccountTypeDefinitionType = getResourceObjectTypeDefinitionType();
if (resourceAccountTypeDefinitionType == null) {
// No dependencies. But we cannot set null as that means "unknown". So let's set empty collection instead.
dependencies = new ArrayList<ResourceObjectTypeDependencyType>();
} else {
dependencies = resourceAccountTypeDefinitionType.getDependency();
}
}
return dependencies;
}
public ValuePolicyType getAccountPasswordPolicy() {
return accountPasswordPolicy;
}
public void setCanProject(boolean canProject) {
this.canProject = canProject;
}
public boolean isCanProject() {
return canProject;
}
public void setAccountPasswordPolicy(ValuePolicyType accountPasswordPolicy) {
this.accountPasswordPolicy = accountPasswordPolicy;
}
public AssignmentPolicyEnforcementType getAssignmentPolicyEnforcementType() {
// TODO: per-resource assignment enforcement
ResourceType resource = getResource();
ProjectionPolicyType globalAccountSynchronizationSettings = null;
if (resource != null){
globalAccountSynchronizationSettings = resource.getProjection();
}
if (globalAccountSynchronizationSettings == null) {
globalAccountSynchronizationSettings = getLensContext().getAccountSynchronizationSettings();
}
AssignmentPolicyEnforcementType globalAssignmentPolicyEnforcement = MiscSchemaUtil.getAssignmentPolicyEnforcementType(globalAccountSynchronizationSettings);
return globalAssignmentPolicyEnforcement;
}
public boolean isLegalize(){
ResourceType resource = getResource();
ProjectionPolicyType globalAccountSynchronizationSettings = null;
if (resource != null){
globalAccountSynchronizationSettings = resource.getProjection();
}
if (globalAccountSynchronizationSettings == null) {
globalAccountSynchronizationSettings = getLensContext().getAccountSynchronizationSettings();
}
if (globalAccountSynchronizationSettings == null){
return false;
}
if (globalAccountSynchronizationSettings.isLegalize() == null){
return false;
}
return globalAccountSynchronizationSettings.isLegalize();
}
/**
* Recomputes the new state of account (accountNew). It is computed by applying deltas to the old state (accountOld).
* Assuming that oldAccount is already set (or is null if it does not exist)
*/
public void recompute() throws SchemaException {
ObjectDelta<ShadowType> accDelta = getDelta();
PrismObject<ShadowType> base = getObjectCurrent();
if (base == null) {
base = getObjectOld();
}
ObjectDelta<ShadowType> syncDelta = getSyncDelta();
if (base == null && syncDelta != null
&& ChangeType.ADD.equals(syncDelta.getChangeType())) {
PrismObject<ShadowType> objectToAdd = syncDelta.getObjectToAdd();
if (objectToAdd != null) {
PrismObjectDefinition<ShadowType> objectDefinition = objectToAdd.getDefinition();
// TODO: remove constructor, use some factory method instead
base = new PrismObject<ShadowType>(objectToAdd.getElementName(), objectDefinition, getNotNullPrismContext());
base = syncDelta.computeChangedObject(base);
}
}
if (accDelta == null) {
// No change
setObjectNew(base);
return;
}
if (base == null && accDelta.isModify()) {
RefinedObjectClassDefinition rOCD = getCompositeObjectClassDefinition();
if (rOCD != null) {
base = rOCD.createBlankShadow();
}
}
setObjectNew(accDelta.computeChangedObject(base));
}
public void clearIntermediateResults() {
//constructionDeltaSetTriple = null;
outboundConstruction = null;
squeezedAttributes = null;
}
/**
* Distribute the resource that's in the context into all the prism objects (old, new) and deltas.
* The resourceRef will not just contain the OID but also full resource object. This may optimize handling
* of the objects in upper layers (e.g. GUI).
*/
public void distributeResource() {
ResourceType resourceType = getResource();
if (resourceType == null) {
return;
}
PrismObject<ResourceType> resource = resourceType.asPrismObject();
distributeResourceObject(getObjectOld(), resource);
distributeResourceObject(getObjectCurrent(), resource);
distributeResourceObject(getObjectNew(), resource);
distributeResourceDelta(getPrimaryDelta(), resource);
distributeResourceDelta(getSecondaryDelta(), resource);
}
private void distributeResourceObject(PrismObject<ShadowType> object, PrismObject<ResourceType> resource) {
if (object == null) {
return;
}
PrismReference resourceRef = object.findReference(ShadowType.F_RESOURCE_REF);
if (resourceRef != null) {
distributeResourceValues(resourceRef.getValues(), resource);
}
}
private void distributeResourceValue(PrismReferenceValue resourceRefVal, PrismObject<ResourceType> resource) {
if (resourceRefVal != null) {
resourceRefVal.setObject(resource);
}
}
private void distributeResourceDelta(ObjectDelta<ShadowType> delta, PrismObject<ResourceType> resource) {
if (delta == null) {
return;
}
if (delta.isAdd()) {
distributeResourceObject(delta.getObjectToAdd(), resource);
} else if (delta.isModify()) {
ReferenceDelta referenceDelta = delta.findReferenceModification(ShadowType.F_RESOURCE_REF);
if (referenceDelta != null) {
distributeResourceValues(referenceDelta.getValuesToAdd(), resource);
distributeResourceValues(referenceDelta.getValuesToDelete(), resource);
distributeResourceValues(referenceDelta.getValuesToReplace(), resource);
}
} // Nothing to do for DELETE delta
}
private void distributeResourceValues(Collection<PrismReferenceValue> values, PrismObject<ResourceType> resource) {
if (values == null) {
return;
}
for(PrismReferenceValue pval: values) {
distributeResourceValue(pval, resource);
}
}
/**
* Returns delta suitable for execution. The primary and secondary deltas may not make complete sense all by themselves.
* E.g. they may both be MODIFY deltas even in case that the account should be created. The deltas begin to make sense
* only if combined with sync decision. This method provides the deltas all combined and ready for execution.
*/
@Override
public ObjectDelta<ShadowType> getExecutableDelta() throws SchemaException {
SynchronizationPolicyDecision policyDecision = getSynchronizationPolicyDecision();
ObjectDelta<ShadowType> origDelta = getFixedDelta();
if (policyDecision == SynchronizationPolicyDecision.ADD) {
// let's try to retrieve original (non-fixed) delta. Maybe it's ADD delta so we spare fixing it.
origDelta = getDelta();
if (origDelta == null || origDelta.isModify()) {
// We need to convert modify delta to ADD
ObjectDelta<ShadowType> addDelta = new ObjectDelta<ShadowType>(getObjectTypeClass(),
ChangeType.ADD, getPrismContext());
RefinedObjectClassDefinition rObjectClassDef = getCompositeObjectClassDefinition();
if (rObjectClassDef == null) {
throw new IllegalStateException("Definition for account type " + getResourceShadowDiscriminator()
+ " not found in the context, but it should be there");
}
PrismObject<ShadowType> newAccount = (PrismObject<ShadowType>) rObjectClassDef.createBlankShadow();
addDelta.setObjectToAdd(newAccount);
if (origDelta != null) {
addDelta.merge(origDelta);
}
return addDelta;
}
} else if (policyDecision == SynchronizationPolicyDecision.KEEP) {
// Any delta is OK
} else if (policyDecision == SynchronizationPolicyDecision.DELETE) {
ObjectDelta<ShadowType> deleteDelta = new ObjectDelta<ShadowType>(getObjectTypeClass(),
ChangeType.DELETE, getPrismContext());
String oid = getOid();
if (oid == null) {
throw new IllegalStateException(
"Internal error: account context OID is null during attempt to create delete secondary delta; context="
+this);
}
deleteDelta.setOid(oid);
return deleteDelta;
} else {
// This is either UNLINK or null, both are in fact the same as KEEP
// Any delta is OK
}
return origDelta;
}
public void checkConsistence() {
checkConsistence(null, true, false);
}
@Override
public void checkConsistence(String contextDesc) {
super.checkConsistence(contextDesc);
if (secondaryDelta != null) {
boolean requireOid = isRequireSecondardyDeltaOid();
// Secondary delta may not have OID yet (as it may relate to ADD primary delta that doesn't have OID yet)
checkConsistence(secondaryDelta, requireOid, getElementDesc() + " secondary delta in " + this + (contextDesc == null ? "" : " in " + contextDesc));
}
}
public void checkConsistence(String contextDesc, boolean fresh, boolean force) {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.IGNORE) {
// No not check these. they may be quite wild.
return;
}
super.checkConsistence(contextDesc);
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.BROKEN) {
return;
}
if (fresh && !force && resourceShadowDiscriminator != null && !resourceShadowDiscriminator.isThombstone()) {
if (resource == null) {
throw new IllegalStateException("Null resource in "+this + (contextDesc == null ? "" : " in " +contextDesc));
}
if (resourceShadowDiscriminator == null) {
throw new IllegalStateException("Null resource account type in "+this + (contextDesc == null ? "" : " in " +contextDesc));
}
}
if (syncDelta != null) {
try {
syncDelta.checkConsistence(true, true, true, ConsistencyCheckScope.THOROUGH);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage()+"; in "+getElementDesc()+" sync delta in "+this + (contextDesc == null ? "" : " in " +contextDesc), e);
} catch (IllegalStateException e) {
throw new IllegalStateException(e.getMessage()+"; in "+getElementDesc()+" sync delta in "+this + (contextDesc == null ? "" : " in " +contextDesc), e);
}
}
}
@Override
protected void checkConsistence(PrismObject<ShadowType> object, String elementDesc, String contextDesc) {
super.checkConsistence(object, elementDesc, contextDesc);
ResourceAttributeContainer attributesContainer = ShadowUtil.getAttributesContainer(object);
if (attributesContainer != null) {
ResourceType resource = getResource();
if (resource != null) {
String resourceNamespace = ResourceTypeUtil.getResourceNamespace(resource);
for(ResourceAttribute<?> attribute: attributesContainer.getAttributes()) {
QName attrName = attribute.getElementName();
if (SchemaConstants.NS_ICF_SCHEMA.equals(attrName.getNamespaceURI())) {
continue;
}
if (resourceNamespace.equals(attrName.getNamespaceURI())) {
continue;
}
String desc = elementDesc+" in "+this + (contextDesc == null ? "" : " in " +contextDesc);
throw new IllegalStateException("Invalid namespace for attribute "+attrName+" in "+desc);
}
}
}
}
protected boolean isRequireSecondardyDeltaOid() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.ADD ||
synchronizationPolicyDecision == SynchronizationPolicyDecision.BROKEN ||
synchronizationPolicyDecision == SynchronizationPolicyDecision.IGNORE) {
return false;
}
if (getResourceShadowDiscriminator() != null && getResourceShadowDiscriminator().getOrder() > 0) {
// These may not have the OID yet
return false;
}
return super.isRequireSecondardyDeltaOid();
}
@Override
public void cleanup() {
secondaryDelta = null;
resetSynchronizationPolicyDecision();
// isLegal = null;
// isLegalOld = null;
isAssigned = false;
isAssignedOld = false; // ??? [med]
isActive = false;
}
@Override
public void normalize() {
super.normalize();
if (secondaryDelta != null) {
secondaryDelta.normalize();
}
if (syncDelta != null) {
syncDelta.normalize();
}
}
// @Override
// public void reset() {
// super.reset();
// wave = -1;
// fullShadow = false;
// isAssigned = false;
// isAssignedOld = false;
// isActive = false;
// resetSynchronizationPolicyDecision();
// constructionDeltaSetTriple = null;
// outboundConstruction = null;
// dependencies = null;
// squeezedAttributes = null;
// accountPasswordPolicy = null;
// }
protected void resetSynchronizationPolicyDecision() {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.DELETE || synchronizationPolicyDecision == SynchronizationPolicyDecision.UNLINK) {
toBeArchived = true;
} else if (synchronizationPolicyDecision != null) {
toBeArchived = false;
}
synchronizationPolicyDecision = null;
}
@Override
public void adopt(PrismContext prismContext) throws SchemaException {
super.adopt(prismContext);
if (syncDelta != null) {
prismContext.adopt(syncDelta);
}
if (secondaryDelta != null) {
prismContext.adopt(secondaryDelta);
}
}
@Override
public LensProjectionContext clone(LensContext<? extends ObjectType> lensContext) {
LensProjectionContext clone = new LensProjectionContext(lensContext, resourceShadowDiscriminator);
copyValues(clone, lensContext);
return clone;
}
protected void copyValues(LensProjectionContext clone, LensContext<? extends ObjectType> lensContext) {
super.copyValues(clone, lensContext);
// do NOT clone transient values such as accountConstructionDeltaSetTriple
// these are not meant to be cloned and they are also not directly clonnable
clone.dependencies = this.dependencies;
clone.doReconciliation = this.doReconciliation;
clone.fullShadow = this.fullShadow;
clone.isAssigned = this.isAssigned;
clone.isAssignedOld = this.isAssignedOld;
clone.outboundConstruction = this.outboundConstruction;
clone.synchronizationPolicyDecision = this.synchronizationPolicyDecision;
clone.resource = this.resource;
clone.resourceShadowDiscriminator = this.resourceShadowDiscriminator;
clone.squeezedAttributes = cloneSqueezedAttributes();
if (this.syncDelta != null) {
clone.syncDelta = this.syncDelta.clone();
}
clone.secondaryDelta = cloneDelta(this.secondaryDelta);
clone.wave = this.wave;
}
private Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>>> cloneSqueezedAttributes() {
if (squeezedAttributes == null) {
return null;
}
Map<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>>> clonedMap
= new HashMap<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>>>();
Cloner<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>> cloner = new Cloner<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>>() {
@Override
public ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>> clone(ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>> original) {
return original.clone();
}
};
for (Entry<QName, DeltaSetTriple<ItemValueWithOrigin<PrismPropertyValue<?>,PrismPropertyDefinition<?>>>> entry: squeezedAttributes.entrySet()) {
clonedMap.put(entry.getKey(), entry.getValue().clone(cloner));
}
return clonedMap;
}
/**
* Returns true if the projection has any value for specified attribute.
*/
public boolean hasValueForAttribute(QName attributeName) throws SchemaException {
ItemPath attrPath = new ItemPath(ShadowType.F_ATTRIBUTES, attributeName);
if (getObjectNew() != null) {
PrismProperty<?> attrNew = getObjectNew().findProperty(attrPath);
if (attrNew != null && !attrNew.isEmpty()) {
return true;
}
}
return false;
}
private boolean hasValueForAttribute(QName attributeName, Collection<PrismPropertyValue<Construction>> acPpvSet) {
if (acPpvSet == null) {
return false;
}
for (PrismPropertyValue<Construction> acPpv: acPpvSet) {
Construction ac = acPpv.getValue();
if (ac.hasValueForAttribute(attributeName)) {
return true;
}
}
return false;
}
@Override
public void checkEncrypted() {
super.checkEncrypted();
if (syncDelta != null) {
CryptoUtil.checkEncrypted(syncDelta);
}
if (secondaryDelta != null) {
CryptoUtil.checkEncrypted(secondaryDelta);
}
}
public String getHumanReadableName() {
if (humanReadableName == null) {
StringBuilder sb = new StringBuilder();
sb.append("account(");
String humanReadableAccountIdentifier = getHumanReadableIdentifier();
if (StringUtils.isEmpty(humanReadableAccountIdentifier)) {
sb.append("no ID");
} else {
sb.append("ID ");
sb.append(humanReadableAccountIdentifier);
}
ResourceShadowDiscriminator discr = getResourceShadowDiscriminator();
if (discr != null) {
sb.append(", type '");
sb.append(discr.getIntent());
sb.append("', ");
if (discr.getOrder() != 0) {
sb.append("order ").append(discr.getOrder()).append(", ");
}
} else {
sb.append(" (no discriminator) ");
}
sb.append(getResource());
sb.append(")");
humanReadableName = sb.toString();
}
return humanReadableName;
}
private String getHumanReadableIdentifier() {
PrismObject<ShadowType> object = getObjectNew();
if (object == null) {
object = getObjectOld();
}
if (object == null) {
object = getObjectCurrent();
}
if (object == null) {
return null;
}
if (object.canRepresent(ShadowType.class)) {
PrismObject<ShadowType> shadow = (PrismObject<ShadowType>)object;
Collection<ResourceAttribute<?>> identifiers = ShadowUtil.getPrimaryIdentifiers(shadow);
if (identifiers == null) {
return null;
}
StringBuilder sb = new StringBuilder();
Iterator<ResourceAttribute<?>> iterator = identifiers.iterator();
while (iterator.hasNext()) {
ResourceAttribute<?> id = iterator.next();
sb.append(id.toHumanReadableString());
if (iterator.hasNext()) {
sb.append(",");
}
}
return sb.toString();
} else {
return object.toString();
}
}
@Override
public String debugDump() {
return debugDump(0);
}
@Override
public String debugDump(int indent) {
return debugDump(indent, true);
}
public String debugDump(int indent, boolean showTriples) {
StringBuilder sb = new StringBuilder();
SchemaDebugUtil.indentDebugDump(sb, indent);
sb.append("PROJECTION ");
sb.append(getObjectTypeClass() == null ? "null" : getObjectTypeClass().getSimpleName());
sb.append(" ");
sb.append(getResourceShadowDiscriminator());
if (resource != null) {
sb.append(" : ");
sb.append(resource.getName().getOrig());
}
sb.append("\n");
SchemaDebugUtil.indentDebugDump(sb, indent + 1);
sb.append("OID: ").append(getOid());
sb.append(", wave ").append(wave);
if (fullShadow) {
sb.append(", full");
} else {
sb.append(", shadow");
}
sb.append(", exists=").append(isExists);
sb.append(", assigned=").append(isAssignedOld).append("->").append(isAssigned);
sb.append(", active=").append(isActive);
sb.append(", legal=").append(isLegalOld).append("->").append(isLegal);
sb.append(", recon=").append(doReconciliation);
sb.append(", syncIntent=").append(getSynchronizationIntent());
sb.append(", decision=").append(synchronizationPolicyDecision);
if (!isFresh()) {
sb.append(", NOT FRESH");
}
if (resourceShadowDiscriminator != null && resourceShadowDiscriminator.isThombstone()) {
sb.append(", THOMBSTONE");
}
if (syncAbsoluteTrigger) {
sb.append(", SYNC TRIGGER");
}
if (getIteration() != 0) {
sb.append(", iteration=").append(getIteration()).append(" (").append(getIterationToken()).append(")");
}
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("old"), getObjectOld(), indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("current"), getObjectCurrent(), indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("new"), getObjectNew(), indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("primary delta"), getPrimaryDelta(), indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("secondary delta"), getSecondaryDelta(), indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("sync delta"), getSyncDelta(), indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("executed deltas"), getExecutedDeltas(), indent+1);
if (showTriples) {
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("constructionDeltaSetTriple"), constructionDeltaSetTriple, indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("outbound account construction"), outboundConstruction, indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("squeezed attributes"), squeezedAttributes, indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("squeezed associations"), squeezedAssociations, indent + 1);
sb.append("\n");
DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("squeezed auxiliary object classes"), squeezedAuxiliaryObjectClasses, indent + 1);
// This is just a debug thing
// sb.append("\n");
// DebugUtil.indentDebugDump(sb, indent);
// sb.append("ACCOUNT dependencies\n");
// sb.append(DebugUtil.debugDump(dependencies, indent + 1));
}
return sb.toString();
}
@Override
protected String getElementDefaultDesc() {
return "projection";
}
@Override
public String toString() {
return "LensProjectionContext(" + (getObjectTypeClass() == null ? "null" : getObjectTypeClass().getSimpleName()) + ":" + getOid() +
( resource == null ? "" : " on " + resource ) + ")";
}
/**
* Return a human readable name of the projection object suitable for logs.
*/
public String toHumanReadableString() {
if (resourceShadowDiscriminator == null) {
return "(null" + resource + ")";
}
if (resource != null) {
return "("+getKindValue(resourceShadowDiscriminator.getKind()) + " ("+resourceShadowDiscriminator.getIntent()+") on " + resource + ")";
} else {
return "("+getKindValue(resourceShadowDiscriminator.getKind()) + " ("+resourceShadowDiscriminator.getIntent()+") on " + resourceShadowDiscriminator.getResourceOid() + ")";
}
}
public String getHumanReadableKind() {
if (resourceShadowDiscriminator == null) {
return "resource object";
}
return getKindValue(resourceShadowDiscriminator.getKind());
}
private String getKindValue(ShadowKindType kind) {
if (kind == null) {
return "null";
}
return kind.value();
}
@Override
protected String getElementDesc() {
if (resourceShadowDiscriminator == null) {
return "shadow";
}
return getKindValue(resourceShadowDiscriminator.getKind());
}
public void addToPrismContainer(PrismContainer<LensProjectionContextType> lensProjectionContextTypeContainer) throws SchemaException {
LensProjectionContextType lensProjectionContextType = lensProjectionContextTypeContainer.createNewValue().asContainerable();
super.storeIntoLensElementContextType(lensProjectionContextType);
lensProjectionContextType.setSyncDelta(syncDelta != null ? DeltaConvertor.toObjectDeltaType(syncDelta) : null);
lensProjectionContextType.setSecondaryDelta(secondaryDelta != null ? DeltaConvertor.toObjectDeltaType(secondaryDelta) : null);
lensProjectionContextType.setWave(wave);
lensProjectionContextType.setResourceShadowDiscriminator(resourceShadowDiscriminator != null ?
resourceShadowDiscriminator.toResourceShadowDiscriminatorType() : null);
lensProjectionContextType.setFullShadow(fullShadow);
lensProjectionContextType.setIsAssigned(isAssigned);
lensProjectionContextType.setIsAssignedOld(isAssignedOld);
lensProjectionContextType.setIsActive(isActive);
lensProjectionContextType.setIsLegal(isLegal);
lensProjectionContextType.setIsLegalOld(isLegalOld);
lensProjectionContextType.setIsExists(isExists);
lensProjectionContextType.setSynchronizationPolicyDecision(synchronizationPolicyDecision != null ? synchronizationPolicyDecision.toSynchronizationPolicyDecisionType() : null);
lensProjectionContextType.setDoReconciliation(doReconciliation);
lensProjectionContextType.setSynchronizationSituationDetected(synchronizationSituationDetected);
lensProjectionContextType.setSynchronizationSituationResolved(synchronizationSituationResolved);
lensProjectionContextType.setAccountPasswordPolicy(accountPasswordPolicy);
lensProjectionContextType.setSyncAbsoluteTrigger(syncAbsoluteTrigger);
}
public static LensProjectionContext fromLensProjectionContextType(LensProjectionContextType projectionContextType, LensContext lensContext, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException {
String objectTypeClassString = projectionContextType.getObjectTypeClass();
if (StringUtils.isEmpty(objectTypeClassString)) {
throw new SystemException("Object type class is undefined in LensProjectionContextType");
}
ResourceShadowDiscriminator resourceShadowDiscriminator = ResourceShadowDiscriminator.fromResourceShadowDiscriminatorType(projectionContextType.getResourceShadowDiscriminator());
LensProjectionContext projectionContext = new LensProjectionContext(lensContext, resourceShadowDiscriminator);
projectionContext.retrieveFromLensElementContextType(projectionContextType, result);
if (projectionContextType.getSyncDelta() != null) {
projectionContext.syncDelta = DeltaConvertor.createObjectDelta(projectionContextType.getSyncDelta(), lensContext.getPrismContext());
} else {
projectionContext.syncDelta = null;
}
ObjectDeltaType secondaryDeltaType = projectionContextType.getSecondaryDelta();
projectionContext.secondaryDelta = secondaryDeltaType != null ? (ObjectDelta) DeltaConvertor.createObjectDelta(secondaryDeltaType, lensContext.getPrismContext()) : null;
ObjectType object = projectionContextType.getObjectNew() != null ? projectionContextType.getObjectNew() : projectionContextType.getObjectOld();
projectionContext.fixProvisioningTypeInDelta(projectionContext.secondaryDelta, object, result);
projectionContext.wave = projectionContextType.getWave() != null ? projectionContextType.getWave() : 0;
projectionContext.fullShadow = projectionContextType.isFullShadow() != null ? projectionContextType.isFullShadow() : false;
projectionContext.isAssigned = projectionContextType.isIsAssigned() != null ? projectionContextType.isIsAssigned() : false;
projectionContext.isAssignedOld = projectionContextType.isIsAssignedOld() != null ? projectionContextType.isIsAssignedOld() : false;
projectionContext.isActive = projectionContextType.isIsActive() != null ? projectionContextType.isIsActive() : false;
projectionContext.isLegal = projectionContextType.isIsLegal();
projectionContext.isLegalOld = projectionContextType.isIsLegalOld();
projectionContext.isExists = projectionContextType.isIsExists() != null ? projectionContextType.isIsExists() : false;
projectionContext.synchronizationPolicyDecision = SynchronizationPolicyDecision.fromSynchronizationPolicyDecisionType(projectionContextType.getSynchronizationPolicyDecision());
projectionContext.doReconciliation = projectionContextType.isDoReconciliation() != null ? projectionContextType.isDoReconciliation() : false;
projectionContext.synchronizationSituationDetected = projectionContextType.getSynchronizationSituationDetected();
projectionContext.synchronizationSituationResolved = projectionContextType.getSynchronizationSituationResolved();
projectionContext.accountPasswordPolicy = projectionContextType.getAccountPasswordPolicy();
projectionContext.syncAbsoluteTrigger = projectionContextType.isSyncAbsoluteTrigger();
return projectionContext;
}
// determines whether full shadow is present, based on operation result got from provisioning
public void determineFullShadowFlag(OperationResultType fetchResult) {
if (fetchResult != null
&& (fetchResult.getStatus() == OperationResultStatusType.PARTIAL_ERROR
|| fetchResult.getStatus() == OperationResultStatusType.FATAL_ERROR)
&& (getObjectAny().asObjectable().getFailedOperationType() == null || getObjectAny().asObjectable().getFailedOperationType() != FailedOperationTypeType.ADD)) { // todo what about other kinds of status? [e.g. in-progress]
setFullShadow(false);
} else {
setFullShadow(true);
}
}
public boolean isToBeArchived() {
return toBeArchived;
}
public void setToBeArchived(boolean toBeArchived) {
this.toBeArchived = toBeArchived;
}
public String getResourceOid() {
if (resource != null) {
return resource.getOid();
} else if (resourceShadowDiscriminator != null) {
return resourceShadowDiscriminator.getResourceOid();
} else {
return null;
}
}
public ResourceObjectVolatilityType getVolatility() throws SchemaException {
RefinedObjectClassDefinition structuralObjectClassDefinition = getStructuralObjectClassDefinition();
if (structuralObjectClassDefinition == null) {
return null;
}
return structuralObjectClassDefinition.getVolatility();
}
public boolean hasPendingOperations() {
PrismObject<ShadowType> current = getObjectCurrent();
if (current == null) {
return false;
}
return !current.asObjectable().getPendingOperation().isEmpty();
}
}