package org.dcache.services.info.stateInfo;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.dcache.services.info.base.StateExhibitor;
import org.dcache.services.info.base.StatePath;
/**
* The SetMapVisitor builds a Map between a list of items and some list
* within that item (at a fixed relative path). For example, if the
* dCache state has entries like:
* <pre>
* aa.bb.item1.cc.dd.i1E1
* aa.bb.item1.cc.dd.i1E2
* aa.bb.item1.cc.dd.i1E3
* aa.bb.item2.cc.dd.i2E1
* aa.bb.item2.cc.dd.i2E2
* aa.bb.item2.cc.dd.i2E3
* aa.bb.item3.cc.dd.i3E1
* </pre>
* then the output would be the mapping:
* <pre>
* item1 -> {i1E1, i1E2, i1E3}
* item2 -> {i2E1, i2E2, i2E3}
* item3 -> {i3E1}
* </pre>
*
* @author Paul Millar <paul.millar@desy.de>
*/
public class SetMapVisitor extends SkeletonListVisitor
{
/**
* Obtain a Map between list items and their corresponding Set of the children of some
* fixed relative path for dCache's current state. For example, if dCache currently
* contains:
* <pre>
* aa.bb.item1.cc.dd.i1E1
* aa.bb.item1.cc.dd.i1E2
* aa.bb.item1.cc.dd.i1E3
* aa.bb.item2.cc.dd.i2E1
* aa.bb.item2.cc.dd.i2E2
* aa.bb.item2.cc.dd.i2E3
* aa.bb.item3.cc.dd.i3E1
* </pre>
* then, with pathToMainList of aa.bb and pathToSecondList of cc.dd, the output
* would be the mapping:
* <pre>
* "item1" -> {"i1E1", "i1E2", "i1E3"}
* "item2" -> {"i2E1", "i2E2", "i2E3"}
* "item3" -> {"i3E1"}
* </pre>
*
* @param pathToMainList the StatePath for the common parent for the primary list
* @param pathToSecondList the StatePath, relative to the list item for parent of the item list.
* @return a mapping between an item and the set of items at a fixed relative path.
*/
public static Map<String,Set<String>> getDetails(StateExhibitor exhibitor,
StatePath pathToMainList,
StatePath pathToSecondList) {
SetMapVisitor visitor = new SetMapVisitor(pathToMainList, pathToSecondList);
exhibitor.visitState(visitor);
return visitor.getMap();
}
/** Record the relative path to the parent object of the secondard list items */
private final StatePath _relativePathToList;
/** The mapping to return */
private final Map<String,Set<String>> _map = new HashMap<>();
/** The (absolute) StatePath to the current list-item's parent */
private StatePath _pathToSet;
/** The set of secondary list-items for the current (primary) list item */
private Set<String> _thisListItemSet;
/**
* Create a new visitor that extracts a mapping from dCache state.
* @param pathToPrimaryList path of the common parent of the primary list
* @param relativePathToSecondList path, relative to the primary list item, of
* the common parent of the secondary list.
*/
public SetMapVisitor(StatePath pathToPrimaryList, StatePath relativePathToSecondList)
{
super(pathToPrimaryList);
_relativePathToList = relativePathToSecondList;
}
@Override
protected void newListItem(String listItemName)
{
super.newListItem(listItemName);
_pathToSet = getPathToList().newChild(listItemName).newChild(_relativePathToList);
_thisListItemSet = new HashSet<>();
_map.put(listItemName, _thisListItemSet);
}
@Override
protected void exitingListItem(String listItemName)
{
super.exitingListItem(listItemName);
_pathToSet = null;
_thisListItemSet = null;
}
@Override
public void visitCompositePreDescend(StatePath path, Map<String, String> metadata)
{
super.visitCompositePreDescend(path, metadata);
if (isInListItem()) {
if (_pathToSet.isParentOf(path)) {
_thisListItemSet.add(path.getLastElement());
}
}
}
/**
* Obtain the results of running the visitor over dCache's state.
* @return a map between the primary and secondary lists.
*/
public Map<String,Set<String>> getMap()
{
return _map;
}
}