package org.dcache.services.info.base; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * Information about all changes a particular StateComposite should undertake * as the result of transition. * * @author Paul Millar <paul.millar@desy.de> */ public class StateChangeSet { final Map<String, StateComponent> _newChildren = new HashMap<>(); final Map<String, StateComponent> _updatedChildren = new HashMap<>(); final Set<String> _removedChildren = new HashSet<>(); final Set<String> _itrChildren = new HashSet<>(); Date _whenIShouldExpire; boolean _hasImmortalChildren; /** * Record that a new child is to be added to this StateComposite. * * @param childName * the name of the child * @param value * the StateComponent */ protected void recordNewChild(String childName, StateComponent value) { purgeChildEntries(childName); _newChildren.put(childName, value); } /** * Record that a child is to be updated. * * @param path * the StatePath of the StateComposite that contains this * child. * @param childName * the name of the child. * @param value * the new value of this child. */ protected void recordUpdatedChild(String childName, StateComponent value) { purgeChildEntries(childName); _updatedChildren.put(childName, value); } /** * Record that a child is to be removed. * * @param path * the StatePath of the StateComposite that contains this * child. * @param childName * the name of the child. */ protected void recordRemovedChild(String childName) { purgeChildEntries(childName); _removedChildren.add(childName); } /** * Record that this StateTransition adds a child to this (presumably) * StateComposite that is Immortal. * * @param path */ protected void recordChildIsImmortal() { _hasImmortalChildren = true; } /** * Record that the _whenIShouldExpire Date should be changed. If a new * value is already set for this transition, it is only updated if the * new value will occur sooner than the currently record value. * * @param childExpiryDate * the new Date to be used. */ protected void recordNewWhenIShouldExpireDate(Date childExpiryDate) { if (childExpiryDate == null) { return; } if (_whenIShouldExpire == null || childExpiryDate.after(_whenIShouldExpire)) { _whenIShouldExpire = childExpiryDate; } } /** * Discover the new whenIShouldExpire Date, if one is present. * * @param path * the StatePath of the StateComposite * @return the new Data, if one exists, or null. */ protected Date getWhenIShouldExpireDate() { return _whenIShouldExpire; } /** * Record that the named child StateComponent has had some activity * during a StateTransition. * * @param path * the StateComposite that is iterating into a child. * @param childName * the name of the child. */ protected void recordChildItr(String childName) { _itrChildren.add(childName); } /** * Return the Set of child names for children of path that have been * iterated into when building the StateTransition. * * @param path * the StatePath of the StateComposite * @return a Set of child names, or null if this StateComposite was not * updated. */ protected Set<String> getItrChildren() { return _itrChildren; } /** * Check whether a child has altered. * * @param path * the StateComposite that is the parent of the child. * @param childName * the name of the child under question. * @return true if this child is to be added, updated or removed. */ protected boolean hasChildChanged(String childName) { return _itrChildren.contains(childName) || _newChildren.containsKey(childName) || _updatedChildren.containsKey(childName) || _removedChildren.contains(childName); } /** * Return whether this Transition introduces an Immortal child that is a * child of this StatePath * * @param path * @return */ protected boolean haveImmortalChild() { return _hasImmortalChildren; } /** * Returns whether a particular named child is to be removed. * * @param path * The StatePath of the StateComposite * @param name * the child's name * @return true if the child is to be remove, false otherwise. */ protected boolean childIsRemoved(String name) { return _removedChildren.contains(name); } /** * Returns whether a particular named child is to be updated. * * @param path * The StatePath of the StateComposite * @param name * the child's name * @return true if this child is to be removed, false otherwise. */ protected boolean childIsUpdated(String name) { return _updatedChildren.containsKey(name); } /** * Remove the named child from the list of those to be removed. If the * named child isn't to be removed then this method has no effect. * * @param childName */ protected void ensureChildNotRemoved(String childName) { _removedChildren.remove(childName); } /** * Returns whether a particular named child is to be added. * * @param path * The StatePath of the StateComposite * @param name * the child's name * @return true if this child is to be removed, false otherwise. */ protected boolean childIsNew(String name) { return _newChildren.containsKey(name); } /** * Return the fresh value for a child; that is, the value of this child * after the transition, provided it has been altered. * <p> * If the child is new or is to be updated then the new value is return. * If the child is to be deleted or is unmodified, then null is returned. * * @param path * the StatePath of the containing StateComposite * @param childName * the name of the child. * @return the updated or new value for this child, or null. */ protected StateComponent getFreshChildValue(String childName) { StateComponent newValue; newValue = _newChildren.get(childName); return newValue != null ? newValue : _updatedChildren.get(childName); } /** * Obtain a collection of all new Children of the StateComposite pointed * to by path. * * @param path * the path of the StateComposite * @return a collection of new children. */ protected Set<String> getNewChildren() { return _newChildren.keySet(); } /** * Obtain a collection of all children to be removed. * * @param path * the StatePath of the StateComposite * @return a collection of children's names. */ protected Set<String> getRemovedChildren() { return _removedChildren; } /** * Obtain a collection of all children that are to be update. * * @param path * the StatePath of the StateComposite * @return a collection of children's names. */ protected Collection<String> getUpdatedChildren() { return _updatedChildren.keySet(); } /** * Obtain the updated value for a child of some StateComposite. This * method only returns a value if the child is to be updated. If this * child is: * <ul> * <li>not updated, * <li>a new Component, * <li>to be removed * </ul> * then null is returned. * * @param path * @param childName * @return */ protected StateComponent getUpdatedChildValue(String childName) { return _updatedChildren.get(childName); } /** * Obtain the new value for a child of some StateComposite. This is a * value registered as a new child value. If this metric is not new, null * is returned. * * @param path * @param childName * @return */ protected StateComponent getNewChildValue(String childName) { return _newChildren.get(childName); } /** * Dump our contents to a (quite verbose) String. * * @return */ protected String dumpContents() { StringBuilder sb = new StringBuilder(); sb.append(" new:\n"); for (Map.Entry<String, StateComponent> newEntry : _newChildren.entrySet()) { sb.append(" "); sb.append(newEntry.getKey()); sb.append(" --> "); sb.append(newEntry.getValue().toString()); sb.append("\n"); } sb.append(" update:\n"); for (Map.Entry<String, StateComponent> updateEntry : _updatedChildren.entrySet()) { sb.append(" "); sb.append(updateEntry.getKey()); sb.append(" --> "); sb.append(updateEntry.getValue().toString()); sb.append("\n"); } sb.append(" remove:\n"); for (String childName : _removedChildren) { sb.append(" "); sb.append(childName); sb.append("\n"); } return sb.toString(); } /** * Remove any reference to the named child in the new, updated or removed * children. The list of those child entries to iterate down into is not * affected. * <p> * It is intended this is done before adding a child entry. * * @param childName */ private void purgeChildEntries(String childName) { _newChildren.remove(childName); _updatedChildren.remove(childName); _removedChildren.remove(childName); } }