Skip to content

Commit

Permalink
Experimental implementation of event.isRelatedToItem(itemPath).
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Feb 27, 2015
1 parent c3e6314 commit 90b06dc
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 2 deletions.
Expand Up @@ -59,8 +59,16 @@ public ItemPath(QName... qnames) {
add(qname);
}
}

public ItemPath(ItemPath parentPath, QName subName) {

public ItemPath(String... names) {
this.segments = new ArrayList<ItemPathSegment>(names.length);
for (String name : names) {
add(new QName(name));
}
}


public ItemPath(ItemPath parentPath, QName subName) {
this.segments = new ArrayList<ItemPathSegment>(parentPath.segments.size()+1);
segments.addAll(parentPath.segments);
add(subName);
Expand Down
Expand Up @@ -16,17 +16,32 @@

package com.evolveum.midpoint.notifications.api.events;

import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.PrismReference;
import com.evolveum.midpoint.prism.PrismValue;
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.prism.path.IdItemPathSegment;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.NameItemPathSegment;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.LightweightIdentifier;
import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EventCategoryType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EventOperationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EventStatusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

import javax.xml.namespace.QName;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
Expand Down Expand Up @@ -159,4 +174,117 @@ public void createExpressionVariables(Map<QName, Object> variables, OperationRes
variables.put(SchemaConstants.C_REQUESTER, requester != null ? requester.resolveObjectType(result) : null);
variables.put(SchemaConstants.C_REQUESTEE, requestee != null ? requestee.resolveObjectType(result) : null);
}

// Finding items in deltas/objects
// this is similar to delta.hasItemDelta but much, much more relaxed (we completely ignore ID path segments and we take subpaths into account)
//
// Very experimental implementation. Needs a bit of time to clean up and test adequately.
public <O extends ObjectType> boolean containsItem(ObjectDelta<O> delta, ItemPath itemPath) {
if (delta.getChangeType() == ChangeType.ADD) {
return containsItem(delta.getObjectToAdd(), itemPath);
} else if (delta.getChangeType() == ChangeType.MODIFY) {
return containsItemInModifications(delta.getModifications(), itemPath);
} else {
return false;
}
}

private boolean containsItemInModifications(Collection<? extends ItemDelta> modifications, ItemPath itemPath) {
for (ItemDelta itemDelta : modifications) {
if (containsItem(itemDelta, itemPath)) {
return true;
}
}
return false;
}

private boolean containsItem(ItemDelta itemDelta, ItemPath itemPath) {
ItemPath namesOnlyPathTested = itemPath.namedSegmentsOnly();
ItemPath namesOnlyPathInDelta = itemDelta.getPath().namedSegmentsOnly();
if (namesOnlyPathTested.isSubPathOrEquivalent(namesOnlyPathInDelta)) {
return true;
}
// however, we can add/delete whole container (containing part of the path)
// e.g. we can test for activation/administrativeStatus, and the delta is:
// ADD activation VALUE (administrativeStatus=ENABLED)
if (!namesOnlyPathInDelta.isSubPath(namesOnlyPathTested)) {
return false;
}
// for ADD values we know
// for REPLACE values we know - for values being added, but NOT for values being left behind
// for DELETE we have a problem if we are deleting "by ID" - we just don't know if the value being deleted contains the path in question or not

ItemPath remainder = namesOnlyPathTested.remainder(namesOnlyPathInDelta);
return containsItemInValues(itemDelta.getValuesToAdd(), remainder) ||
containsItemInValues(itemDelta.getValuesToReplace(), remainder) ||
containsItemInValues(itemDelta.getValuesToDelete(), remainder);
}

// remainder contains only named segments and is not empty
private boolean containsItemInValues(Collection<PrismValue> values, ItemPath remainder) {
if (values == null) {
return false;
}
for (PrismValue value : values) {
if (value instanceof PrismContainerValue) { // we do not want to look inside references nor primitive values
if (containsItem((PrismContainerValue) value, remainder)) {
return true;
}
}
}
return false;
}

public boolean containsItem(List<ObjectDelta<FocusType>> deltas, ItemPath itemPath) {
for (ObjectDelta objectDelta : deltas) {
if (containsItem(objectDelta, itemPath)) {
return true;
}
}
return false;
}

// itemPath is empty or starts with named item path segment
private boolean containsItem(PrismContainer container, ItemPath itemPath) {
if (container.size() == 0) {
return false; // there is a container, but no values
}
if (itemPath.isEmpty()) {
return true;
}
for (Object o : container.getValues()) {
if (containsItem((PrismContainerValue) o, itemPath)) {
return true;
}
}
return false;
}

// path starts with named item path segment
private boolean containsItem(PrismContainerValue prismContainerValue, ItemPath itemPath) {
QName first = ((NameItemPathSegment) itemPath.first()).getName();
Item item = prismContainerValue.findItem(first);
if (item == null) {
return false;
}
ItemPath pathTail = pathTail(itemPath);
if (item instanceof PrismContainer) {
return containsItem((PrismContainer) item, pathTail);
} else if (item instanceof PrismReference) {
return pathTail.isEmpty(); // we do not want to look inside references
} else if (item instanceof PrismProperty) {
return pathTail.isEmpty(); // ...neither inside atomic values
} else {
return false; // should not occur anyway
}
}

private ItemPath pathTail(ItemPath itemPath) {
while (!itemPath.isEmpty() && itemPath.first() instanceof IdItemPathSegment) {
itemPath = itemPath.tail();
}
return itemPath;
}


}
Expand Up @@ -16,6 +16,7 @@

package com.evolveum.midpoint.notifications.api.events;

import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.LightweightIdentifier;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
Expand Down Expand Up @@ -78,4 +79,26 @@ public interface Event {
void setRequestee(SimpleObjectRef requestee);

void createExpressionVariables(Map<QName, Object> variables, OperationResult result);

/**
* Checks if the event is related to an item with a given path.
* The meaning of the result depends on a kind of event (focal, resource object, workflow)
* and on operation (add, modify, delete).
*
* Namely, this method is currently defined for ADD and MODIFY (not for DELETE) operations,
* for focal and resource objects events (not for workflow ones).
*
* For MODIFY it checks whether an item with a given path is touched.
* For ADD it checks whether there is a value for an item with a given path in the object created.
*
* For unsupported events the method returns false.
*
* Paths are compared without taking ID segments into account.
*
* EXPERIMENTAL; does not always work (mainly for values being deleted)
*
* @param itemPath
* @return
*/
boolean isRelatedToItem(ItemPath itemPath);
}
Expand Up @@ -23,6 +23,7 @@
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.delta.ChangeType;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.ObjectDeltaOperation;
import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator;
import com.evolveum.midpoint.util.exception.SchemaException;
Expand Down Expand Up @@ -180,4 +181,10 @@ public boolean hasFocusOfType(QName focusType) {
}
return hasFocusOfType(expectedClass);
}

@Override
public boolean isRelatedToItem(ItemPath itemPath) {
return containsItem(getFocusDeltas(), itemPath);
}

}
Expand Up @@ -19,6 +19,7 @@
import com.evolveum.midpoint.notifications.api.OperationStatus;
import com.evolveum.midpoint.prism.delta.ChangeType;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.provisioning.api.ResourceOperationDescription;
import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator;
import com.evolveum.midpoint.util.logging.Trace;
Expand Down Expand Up @@ -128,6 +129,11 @@ public boolean isStatusType(EventStatusType eventStatusType) {
return operationStatus.matchesEventStatusType(eventStatusType);
}

@Override
public boolean isRelatedToItem(ItemPath itemPath) {
return containsItem(getShadowDelta(), itemPath);
}

@Override
public String toString() {
return "ResourceObjectEvent{" +
Expand Down
Expand Up @@ -19,6 +19,7 @@
import com.evolveum.midpoint.notifications.api.OperationStatus;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ChangeType;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator;
import com.evolveum.midpoint.wf.util.ApprovalUtils;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EventOperationType;
Expand Down Expand Up @@ -114,6 +115,10 @@ private OperationStatus resultToStatus(ChangeType changeType, String decision) {
}
}

@Override
public boolean isRelatedToItem(ItemPath itemPath) {
return false;
}

@Override
public String toString() {
Expand Down

0 comments on commit 90b06dc

Please sign in to comment.