/* * Copyright (c) 2010-2015 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.Collection; import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.StringUtils; /** * @author semancik * */ public class LensFocusContext<O extends ObjectType> extends LensElementContext<O> { private static final Trace LOGGER = TraceManager.getTrace(LensFocusContext.class); private ObjectDeltaWaves<O> secondaryDeltas = new ObjectDeltaWaves<>(); transient private SecurityPolicyType securityPolicy; transient private ObjectPolicyConfigurationType objectPolicyConfigurationType; private int getProjectionWave() { return getLensContext().getProjectionWave(); } private int getExecutionWave() { return getLensContext().getProjectionWave(); } public SecurityPolicyType getSecurityPolicy() { return securityPolicy; } public void setSecurityPolicy(SecurityPolicyType securityPolicy) { this.securityPolicy = securityPolicy; } public ObjectPolicyConfigurationType getObjectPolicyConfigurationType() { return objectPolicyConfigurationType; } public void setObjectPolicyConfigurationType(ObjectPolicyConfigurationType objectPolicyConfigurationType) { this.objectPolicyConfigurationType = objectPolicyConfigurationType; } public LensFocusContext(Class<O> objectTypeClass, LensContext<O> lensContext) { super(objectTypeClass, lensContext); } @Override public void setOid(String oid) { super.setOid(oid); secondaryDeltas.setOid(oid); } public ObjectDelta<O> getProjectionWavePrimaryDelta() throws SchemaException { if (getProjectionWave() == 0) { return getFixedPrimaryDelta(); } else { return secondaryDeltas.getMergedDeltas(getFixedPrimaryDelta(), getProjectionWave()); } } public boolean isDelete() { return getPrimaryDelta() != null && getPrimaryDelta().isDelete(); } public boolean isAdd() { return getPrimaryDelta() != null && getPrimaryDelta().isAdd(); } @Override public ObjectDelta<O> getSecondaryDelta() { try { return secondaryDeltas.getMergedDeltas(); } catch (SchemaException e) { // This should not happen throw new SystemException("Unexpected delta merging problem: "+e.getMessage(), e); } } public ObjectDelta<O> getSecondaryDelta(int wave) { return secondaryDeltas.get(wave); } public ObjectDeltaWaves<O> getSecondaryDeltas() { return secondaryDeltas; } public ObjectDelta<O> getProjectionWaveSecondaryDelta() throws SchemaException { return getWaveSecondaryDelta(getProjectionWave()); } public ObjectDelta<O> getWaveSecondaryDelta(int wave) throws SchemaException { return secondaryDeltas.get(wave); } @Override public ObjectDeltaObject<O> getObjectDeltaObject() throws SchemaException { return new ObjectDeltaObject<>(getObjectOld(), getDelta(), getObjectNew()); } @Override public void setSecondaryDelta(ObjectDelta<O> secondaryDelta) { throw new UnsupportedOperationException("Cannot set secondary delta to focus without a wave number"); } public void setSecondaryDelta(ObjectDelta<O> secondaryDelta, int wave) { this.secondaryDeltas.set(wave, secondaryDelta); } public void setProjectionWaveSecondaryDelta(ObjectDelta<O> secondaryDelta) { this.secondaryDeltas.set(getProjectionWave(), secondaryDelta); } public void swallowToProjectionWaveSecondaryDelta(ItemDelta<?,?> propDelta) throws SchemaException { ObjectDelta<O> secondaryDelta = getProjectionWaveSecondaryDelta(); if (secondaryDelta == null) { secondaryDelta = new ObjectDelta<O>(getObjectTypeClass(), ChangeType.MODIFY, getPrismContext()); secondaryDelta.setOid(getOid()); setProjectionWaveSecondaryDelta(secondaryDelta); } else if (secondaryDelta.containsModification(propDelta, true, true)) { return; } secondaryDelta.swallow(propDelta); } public void swallowToSecondaryDelta(ItemDelta<?,?> propDelta) throws SchemaException { ObjectDelta<O> secondaryDelta = getSecondaryDelta(0); if (secondaryDelta == null) { secondaryDelta = new ObjectDelta<O>(getObjectTypeClass(), ChangeType.MODIFY, getPrismContext()); secondaryDelta.setOid(getOid()); setSecondaryDelta(secondaryDelta, 0); } else if (secondaryDelta.containsModification(propDelta, true, true)) { return; } secondaryDelta.swallow(propDelta); } public boolean alreadyHasDelta(ItemDelta<?,?> itemDelta) { ObjectDelta<O> primaryDelta = getPrimaryDelta(); if (primaryDelta != null && primaryDelta.containsModification(itemDelta, true, true)) { return true; } if (secondaryDeltas != null) { for (ObjectDelta<O> waveSecondaryDelta: secondaryDeltas) { if (waveSecondaryDelta != null && waveSecondaryDelta.containsModification(itemDelta, true, true)) { return true; } } } return false; } public boolean hasAnyDelta() { if (getPrimaryDelta() != null && !getPrimaryDelta().isEmpty()) { return true; } if (secondaryDeltas != null) { for (ObjectDelta<O> waveSecondaryDelta: secondaryDeltas) { if (waveSecondaryDelta != null && !waveSecondaryDelta.isEmpty()) { return true; } } } return false; } /** * Returns user delta, both primary and secondary (merged together) for a current wave. * The returned object is (kind of) immutable. Changing it may do strange things (but most likely the changes will be lost). */ public ObjectDelta<O> getProjectionWaveDelta() throws SchemaException { return getWaveDelta(getProjectionWave()); } public ObjectDelta<O> getWaveDelta(int wave) throws SchemaException { if (wave == 0) { // Primary delta is executed only in the first wave (wave 0) return ObjectDelta.union(getFixedPrimaryDelta(), getWaveSecondaryDelta(wave)); } else { return getWaveSecondaryDelta(wave); } } // HIGHLY EXPERIMENTAL public ObjectDelta<O> getAggregatedWaveDelta(int wave) throws SchemaException { ObjectDelta<O> result = null; for (int w = 0; w <= wave; w++) { ObjectDelta<O> delta = getWaveDelta(w); if (delta == null) { continue; } if (result == null) { result = delta.clone(); } else { result.merge(delta); } } LOGGER.trace("Aggregated wave delta for wave {} = {}", wave, result != null ? result.debugDump() : "(null)"); return result; } public ObjectDelta<O> getWaveExecutableDelta(int wave) throws SchemaException { if (wave == 0) { if (getFixedPrimaryDelta() != null && getFixedPrimaryDelta().isAdd()) { ObjectDelta delta = getFixedPrimaryDelta(); for (ObjectDelta<O> secondary : getSecondaryDeltas()) { if (secondary != null) { secondary.applyTo(delta.getObjectToAdd()); } } return delta; } } return getWaveDelta(wave); } @Override public void cleanup() { // Clean up only delta in current wave. The deltas in previous waves are already done. // FIXME: this somehow breaks things. don't know why. but don't really care. the waves will be gone soon anyway // if (secondaryDeltas.get(getWave()) != null) { // secondaryDeltas.remove(getWave()); // } } @Override public void normalize() { super.normalize(); if (secondaryDeltas != null) { secondaryDeltas.normalize(); } } // @Override // public void reset() { // super.reset(); // secondaryDeltas = new ObjectDeltaWaves<O>(); // } @Override public void adopt(PrismContext prismContext) throws SchemaException { super.adopt(prismContext); if (secondaryDeltas != null) { secondaryDeltas.adopt(prismContext); } } public void clearIntermediateResults() { // Nothing to do } public void applyProjectionWaveSecondaryDeltas(Collection<ItemDelta<?,?>> itemDeltas) throws SchemaException { ObjectDelta<O> wavePrimaryDelta = getProjectionWavePrimaryDelta(); ObjectDelta<O> waveSecondaryDelta = getProjectionWaveSecondaryDelta(); for (ItemDelta<?,?> itemDelta: itemDeltas) { if (itemDelta != null && !itemDelta.isEmpty()) { if (wavePrimaryDelta == null || !wavePrimaryDelta.containsModification(itemDelta)) { if (waveSecondaryDelta == null) { waveSecondaryDelta = new ObjectDelta<O>(getObjectTypeClass(), ChangeType.MODIFY, getPrismContext()); if (getObjectNew() != null && getObjectNew().getOid() != null){ waveSecondaryDelta.setOid(getObjectNew().getOid()); } setProjectionWaveSecondaryDelta(waveSecondaryDelta); } waveSecondaryDelta.mergeModification(itemDelta); } } } } @Override public LensFocusContext<O> clone(LensContext lensContext) { LensFocusContext<O> clone = new LensFocusContext<O>(getObjectTypeClass(), lensContext); copyValues(clone, lensContext); return clone; } protected void copyValues(LensFocusContext<O> clone, LensContext lensContext) { super.copyValues(clone, lensContext); if (this.secondaryDeltas != null) { clone.secondaryDeltas = this.secondaryDeltas.clone(); } } @Override public String debugDump() { return debugDump(0); } public String dump(boolean showTriples) { return debugDump(0, showTriples); } @Override public String debugDump(int indent) { return debugDump(indent, true); } public String debugDump(int indent, boolean showTriples) { StringBuilder sb = new StringBuilder(); DebugUtil.indentDebugDump(sb, indent); sb.append(getDebugDumpTitle()); if (!isFresh()) { sb.append(", NOT FRESH"); } sb.append(", oid="); sb.append(getOid()); if (getIteration() != 0) { sb.append(", iteration=").append(getIteration()).append(" (").append(getIterationToken()).append(")"); } sb.append(", syncIntent=").append(getSynchronizationIntent()); 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.indentDebugDump(sb, indent + 1); sb.append(getDebugDumpTitle("secondary delta")).append(":"); if (secondaryDeltas.isEmpty()) { sb.append(" empty"); } else { sb.append("\n"); sb.append(secondaryDeltas.debugDump(indent + 2)); } sb.append("\n"); DebugUtil.debugDumpWithLabel(sb, getDebugDumpTitle("executed deltas"), getExecutedDeltas(), indent+1); return sb.toString(); } @Override protected String getElementDefaultDesc() { return "focus"; } @Override public String toString() { return "LensFocusContext(" + getObjectTypeClass().getSimpleName() + ":" + getOid() + ")"; } public String getHumanReadableName() { StringBuilder sb = new StringBuilder(); sb.append("focus("); PrismObject<O> object = getObjectNew(); if (object == null) { object = getObjectOld(); } if (object == null) { sb.append(getOid()); } else { sb.append(object.toString()); } sb.append(")"); return sb.toString(); } public void addToPrismContainer(PrismContainer<LensFocusContextType> lensFocusContextTypeContainer) throws SchemaException { LensFocusContextType lensFocusContextType = lensFocusContextTypeContainer.createNewValue().asContainerable(); super.storeIntoLensElementContextType(lensFocusContextType); lensFocusContextType.setSecondaryDeltas(secondaryDeltas.toObjectDeltaWavesType()); } public static LensFocusContext fromLensFocusContextType(LensFocusContextType focusContextType, LensContext lensContext, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException { String objectTypeClassString = focusContextType.getObjectTypeClass(); if (StringUtils.isEmpty(objectTypeClassString)) { throw new SystemException("Object type class is undefined in LensFocusContextType"); } LensFocusContext lensFocusContext; try { lensFocusContext = new LensFocusContext(Class.forName(objectTypeClassString), lensContext); } catch (ClassNotFoundException e) { throw new SystemException("Couldn't instantiate LensFocusContext because object type class couldn't be found", e); } lensFocusContext.retrieveFromLensElementContextType(focusContextType, result); lensFocusContext.secondaryDeltas = ObjectDeltaWaves.fromObjectDeltaWavesType(focusContextType.getSecondaryDeltas(), lensContext.getPrismContext()); // fixing provisioning type in delta (however, this is not usually needed, unless primary object is shadow or resource Objectable object; if (lensFocusContext.getObjectNew() != null) { object = lensFocusContext.getObjectNew().asObjectable(); } else if (lensFocusContext.getObjectOld() != null) { object = lensFocusContext.getObjectOld().asObjectable(); } else { object = null; } for (Object o : lensFocusContext.secondaryDeltas) { ObjectDelta<? extends ObjectType> delta = (ObjectDelta<? extends ObjectType>) o; if (delta != null) { lensFocusContext.fixProvisioningTypeInDelta(delta, object, result); } } return lensFocusContext; } @Override public void checkEncrypted() { super.checkEncrypted(); secondaryDeltas.checkEncrypted("secondary delta"); } @Override public void checkConsistence(String desc) { super.checkConsistence(desc); // all executed deltas should have the same oid (if any) String oid = null; for (LensObjectDeltaOperation operation : getExecutedDeltas()) { String oid1 = operation.getObjectDelta().getOid(); if (oid == null) { if (oid1 != null) { oid = oid1; } } else { if (oid1 != null && !oid.equals(oid1)) { String m = "Different OIDs in focus executed deltas: " + oid + ", " + oid1; LOGGER.error("{}: context = \n{}", m, this.debugDump()); throw new IllegalStateException(m); } } } } }