-
Notifications
You must be signed in to change notification settings - Fork 188
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'refs/remotes/origin/master'
- Loading branch information
Showing
9 changed files
with
470 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
187 changes: 187 additions & 0 deletions
187
...chema/src/main/java/com/evolveum/midpoint/schema/util/cleanup/CleanupActionProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
/* | ||
* Copyright (C) 2010-2023 Evolveum and contributors | ||
* | ||
* This work is dual-licensed under the Apache License 2.0 | ||
* and European Union Public License. See LICENSE file for details. | ||
*/ | ||
|
||
package com.evolveum.midpoint.schema.util.cleanup; | ||
|
||
import com.evolveum.midpoint.prism.*; | ||
import com.evolveum.midpoint.prism.path.ItemPath; | ||
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; | ||
|
||
import javax.xml.namespace.QName; | ||
import java.util.*; | ||
|
||
/** | ||
* Utility class that can be used to process objects and remove unwanted items. | ||
* By default, it removes all operational items and all items marked with optionalCleanup. | ||
* | ||
* This behaviour can be configured via {@link CleanupActionProcessor#removeAskActionItemsByDefault} | ||
* and {@link CleanupActionProcessor#setPaths(List)}. | ||
*/ | ||
public class CleanupActionProcessor { | ||
|
||
private CleanupEventListener listener; | ||
|
||
private boolean removeAskActionItemsByDefault = true; | ||
|
||
private final Map<QName, Map<ItemPath, CleanupPathAction>> paths = new HashMap<>(); | ||
|
||
public void setListener(CleanupEventListener listener) { | ||
this.listener = listener; | ||
} | ||
|
||
public void setPaths(List<CleanupPath> paths) { | ||
if (paths == null) { | ||
paths = new ArrayList<>(); | ||
} | ||
|
||
this.paths.clear(); | ||
for (CleanupPath path : paths) { | ||
Map<ItemPath, CleanupPathAction> actions = this.paths.computeIfAbsent(path.getType(), k -> new HashMap<>()); | ||
actions.put(path.getPath(), path.getAction()); | ||
} | ||
} | ||
|
||
public void setRemoveAskActionItemsByDefault(boolean removeAskActionItemsByDefault) { | ||
this.removeAskActionItemsByDefault = removeAskActionItemsByDefault; | ||
} | ||
|
||
public <O extends ObjectType> void process(PrismObject<O> object) { | ||
processItemRecursively(object, ItemPath.EMPTY_PATH, new HashMap<>()); | ||
} | ||
|
||
private boolean processItemRecursively(Item<?, ?> item, ItemPath currentPath, Map<Item<?, ?>, CleanupPathAction> customItemActions) { | ||
boolean remove = processItem(item, currentPath, customItemActions); | ||
if (remove) { | ||
return true; | ||
} | ||
|
||
if (item instanceof PrismContainer<?>) { | ||
boolean emptyBefore = item.isEmpty(); | ||
|
||
final List<Item<?, ?>> toBeRemoved = new ArrayList<>(); | ||
|
||
for (PrismContainerValue<?> value : (List<PrismContainerValue<?>>) item.getValues()) { | ||
Collection<Item<?, ?>> items = value.getItems(); | ||
for (Item<?, ?> i : items) { | ||
if (processItemRecursively(i, currentPath.append(i.getElementName()), customItemActions)) { | ||
toBeRemoved.add(i); | ||
} | ||
} | ||
|
||
items.removeAll(toBeRemoved); | ||
} | ||
|
||
return !emptyBefore && item.isEmpty(); | ||
} | ||
|
||
return false; | ||
|
||
// probably nothing to do for PrismProperty, PrismReference | ||
// todo maybe connectorRef, passwords... | ||
} | ||
|
||
/** | ||
* @param item | ||
* @param currentPath | ||
* @param customItemActions | ||
* @return true if item should be removed, false otherwise | ||
*/ | ||
private boolean processItem(Item<?, ?> item, ItemPath currentPath, Map<Item<?, ?>, CleanupPathAction> customItemActions) { | ||
final ItemDefinition<?> def = item.getDefinition(); | ||
if (def != null) { | ||
updateCustomItemActions(item, customItemActions, def.getTypeName()); | ||
} | ||
|
||
CleanupPathAction customAction = customItemActions.get(item); | ||
if (customAction != null) { | ||
return switch (customAction) { | ||
case REMOVE -> true; | ||
case ASK -> fireOnCleanupItemEvent(item, currentPath); | ||
default -> false; | ||
}; | ||
} | ||
|
||
if (def == null) { | ||
return false; | ||
} | ||
|
||
if (def.isOperational()) { | ||
return true; | ||
} | ||
|
||
if (def.isOptionalCleanup()) { | ||
return fireOnCleanupItemEvent(item, currentPath); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
private void updateCustomItemActions(Item<?, ?> item, Map<Item<?, ?>, CleanupPathAction> customItemActions, QName type) { | ||
Map<ItemPath, CleanupPathAction> actions = paths.getOrDefault(type, Map.of()); | ||
if (actions.isEmpty()) { | ||
return; | ||
} | ||
|
||
actions.forEach((path, action) -> { | ||
if (path.isEmpty()) { | ||
customItemActions.put(item, action); | ||
return; | ||
} | ||
|
||
List<Item<?, ?>> foundItems = findItems(item, path); | ||
foundItems.forEach(i -> customItemActions.put(i, action)); | ||
}); | ||
} | ||
|
||
private List<Item<?, ?>> findItems(Item<?, ?> parent, ItemPath named) { | ||
List<Item<?, ?>> foundItems = new ArrayList<>(); | ||
|
||
if (!(parent instanceof PrismContainer<?>)) { | ||
return foundItems; | ||
} | ||
|
||
for (PrismContainerValue<?> value : (List<PrismContainerValue<?>>) parent.getValues()) { | ||
findItems(value, named, foundItems); | ||
} | ||
|
||
return foundItems; | ||
} | ||
|
||
private void findItems(PrismContainerValue<?> parent, ItemPath named, List<Item<?, ?>> foundItems) { | ||
if (named.isEmpty()) { | ||
return; | ||
} | ||
|
||
ItemPath first = named.firstToName(); | ||
ItemPath rest = named.rest(); | ||
|
||
Item<?, ?> found = parent.findItem(first); | ||
if (rest.isEmpty()) { | ||
if (found != null) { | ||
foundItems.add(found); | ||
} | ||
|
||
return; | ||
} | ||
|
||
if (!(found instanceof PrismContainer<?>)) { | ||
return; | ||
} | ||
|
||
for (PrismContainerValue<?> value : (List<PrismContainerValue<?>>) found.getValues()) { | ||
findItems(value, rest, foundItems); | ||
} | ||
} | ||
|
||
private boolean fireOnCleanupItemEvent(Item<?, ?> item, ItemPath path) { | ||
if (listener == null) { | ||
return removeAskActionItemsByDefault; | ||
} | ||
|
||
return listener.onCleanupItem(new CleanupEvent(item, path)); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
infra/schema/src/main/java/com/evolveum/midpoint/schema/util/cleanup/CleanupEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Copyright (C) 2010-2023 Evolveum and contributors | ||
* | ||
* This work is dual-licensed under the Apache License 2.0 | ||
* and European Union Public License. See LICENSE file for details. | ||
*/ | ||
|
||
package com.evolveum.midpoint.schema.util.cleanup; | ||
|
||
import com.evolveum.midpoint.prism.Item; | ||
import com.evolveum.midpoint.prism.path.ItemPath; | ||
|
||
public class CleanupEvent { | ||
|
||
private final Item<?, ?> item; | ||
|
||
private final ItemPath path; | ||
|
||
public CleanupEvent(Item<?, ?> item, ItemPath path) { | ||
this.item = item; | ||
this.path = path; | ||
} | ||
|
||
public Item<?, ?> getItem() { | ||
return item; | ||
} | ||
|
||
public ItemPath getPath() { | ||
return path; | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
.../schema/src/main/java/com/evolveum/midpoint/schema/util/cleanup/CleanupEventListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* Copyright (C) 2010-2023 Evolveum and contributors | ||
* | ||
* This work is dual-licensed under the Apache License 2.0 | ||
* and European Union Public License. See LICENSE file for details. | ||
*/ | ||
|
||
package com.evolveum.midpoint.schema.util.cleanup; | ||
|
||
/** | ||
* Listener that can be used to react on cleanup events created for items that are marked | ||
* with action {@link CleanupPathAction#ASK}. | ||
*/ | ||
@FunctionalInterface | ||
public interface CleanupEventListener { | ||
|
||
/** | ||
* Method that allows consumers to react on cleanup event marked with action {@link CleanupPathAction#ASK}. | ||
* | ||
* @return true if the item should be removed, false otherwise | ||
*/ | ||
boolean onCleanupItem(CleanupEvent event); | ||
} |
90 changes: 90 additions & 0 deletions
90
infra/schema/src/main/java/com/evolveum/midpoint/schema/util/cleanup/CleanupPath.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package com.evolveum.midpoint.schema.util.cleanup; | ||
|
||
import java.io.Serializable; | ||
import java.util.Comparator; | ||
import java.util.Objects; | ||
import javax.xml.namespace.QName; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
|
||
import com.evolveum.midpoint.prism.path.ItemPath; | ||
import com.evolveum.midpoint.util.QNameUtil; | ||
|
||
/** | ||
* Class that defines schema type (using {@link QName}). item path and action that should be used during cleanup operation | ||
*/ | ||
public class CleanupPath implements Serializable, Comparable<CleanupPath> { | ||
|
||
private QName type; | ||
|
||
private ItemPath path; | ||
|
||
private CleanupPathAction action; | ||
|
||
@SuppressWarnings("unused") | ||
public CleanupPath() { | ||
} | ||
|
||
public CleanupPath(QName type, ItemPath path, CleanupPathAction action) { | ||
this.type = type; | ||
this.path = path; | ||
this.action = action; | ||
} | ||
|
||
public QName getType() { | ||
return type; | ||
} | ||
|
||
public void setType(QName type) { | ||
this.type = type; | ||
} | ||
|
||
public ItemPath getPath() { | ||
return path; | ||
} | ||
|
||
public void setPath(ItemPath path) { | ||
this.path = path; | ||
} | ||
|
||
public CleanupPathAction getAction() { | ||
return action; | ||
} | ||
|
||
public void setAction(CleanupPathAction action) { | ||
this.action = action; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) {return true;} | ||
if (o == null || getClass() != o.getClass()) {return false;} | ||
CleanupPath that = (CleanupPath) o; | ||
return type == that.type && Objects.equals(path, that.path) && action == that.action; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(type, path, action); | ||
} | ||
|
||
private String getTypeAsString() { | ||
return type != null ? QNameUtil.qNameToUri(type) : null; | ||
} | ||
|
||
private String getPathAsString() { | ||
return path != null ? path.toString() : null; | ||
} | ||
|
||
@Override | ||
public int compareTo(@NotNull CleanupPath o) { | ||
return Comparator.nullsLast(Comparator.comparing(CleanupPath::getTypeAsString)) | ||
.thenComparing(Comparator.nullsLast(Comparator.comparing(CleanupPath::getPathAsString))) | ||
.thenComparing(Comparator.nullsLast(Comparator.comparing(CleanupPath::getAction))) | ||
.compare(this, o); | ||
} | ||
|
||
public CleanupPath copy() { | ||
return new CleanupPath(type, path, action); | ||
} | ||
} |
Oops, something went wrong.