package org.dcache.services.info.base; import java.util.HashMap; import java.util.Map; /** * StatePersistentMetadataContainer is a hierarchical storage for information * that should persist independently from whether the corresponding StateComponent * object(s)exist, yet StateComponents may have a corresponding * StatePersistentMetadata. * <p> * The stored metadata is a simple keyword-value pairs, with both Strings. * * @author Paul Millar <paul.millar@desy.de> */ public class StatePersistentMetadata { private final Map<String,StatePersistentMetadata> _children = new HashMap<>(); private final Map<String,String> _payload = new HashMap<>(); private StatePersistentMetadata _wildcard; protected StatePersistentMetadata() { // Reduce visibility of our constructor } /** * Look up a child reference given by the String. If one doesn't exist, a new child * object is created and this is returned. The special wildcard value "*" is treated * differently. * @param reference the label for this child object * @return a child StatePersistentMetadataContainer object */ private StatePersistentMetadata getOrCreateChild(String reference) { // Deal with the wildcard special case. if (reference.equals("*")) { if (_wildcard == null) { _wildcard = new StatePersistentMetadata(); } return _wildcard; } /** * More generally, look up in our hash-table. */ StatePersistentMetadata child = _children.get(reference); if (child == null) { child = new StatePersistentMetadata(); _children.put(reference, child); } return child; } /** * Look for the best-match child StatePersistentMetadata object for the named * child. Will return null if not suitable reference is available. * @param name the child object in the State hierarchy * @return child persistent metadata object, if one is available, or null. */ protected StatePersistentMetadata getChild(String name) { StatePersistentMetadata child = _children.get(name); if (child == null) { child = _wildcard; } return child; } /** * Add some metadata at a particular point in the hierarchy. Extra nodes are * created as necessary. * @param path the path to the node that should be updated. * @param update the set of updates to administer. */ void add(StatePath path, Map<String,String> update) { /** Catch bad input */ if (update == null) { return; } /** If we still have more path to traverse, do so */ if (path != null) { String pathElement = path.getFirstElement(); getOrCreateChild(pathElement).add(path.childPath(), update); return; } /** Update our metadata */ _payload.putAll(update); } /** * Return this node's payload: a Map of metadata information. * @return */ Map<String,String> getMetadata() { return _payload; } /** * Add a default (hard-coded) set of persistent metadata. */ protected void addDefault() { this.add(StatePath.parsePath("domains.*"), branchMetadata("domain", "name")); this.add(StatePath.parsePath("domains.*.cells.*"), branchMetadata("cell", "name")); this.add(StatePath.parsePath("domains.*.routing.local.*"), branchMetadata("cellref", "name")); this.add(StatePath.parsePath("domains.*.routing.named-cells.*"), branchMetadata("cell", "name")); this.add(StatePath.parsePath("domains.*.routing.named-cells.*.*"), branchMetadata("domainref", "name")); this.add(StatePath.parsePath("domains.*.routing.remote.*"), branchMetadata("domain", "name")); this.add(StatePath.parsePath("domains.*.routing.remote.*.*"), branchMetadata("cellref", "name")); this.add(StatePath.parsePath("pools.*"), branchMetadata("pool", "name")); this.add(StatePath.parsePath("pools.*.links.*"), branchMetadata("linkref", "name")); this.add(StatePath.parsePath("pools.*.poolgroups.*"), branchMetadata("poolgroupref", "name")); this.add(StatePath.parsePath("pools.*.queues.*"), branchMetadata("queue", "type")); this.add(StatePath.parsePath("pools.*.queues.named-queues.*"), branchMetadata("queue", "name")); this.add(StatePath.parsePath("poolgroups.*"), branchMetadata("poolgroup", "name")); this.add(StatePath.parsePath("poolgroups.*.links.*"), branchMetadata("linkref", "name")); this.add(StatePath.parsePath("poolgroups.*.pools.*"), branchMetadata("poolref", "name")); this.add(StatePath.parsePath("links.*"), branchMetadata("link", "name")); this.add(StatePath.parsePath("links.*.poolgroups.*"), branchMetadata("poolgroupref", "name")); this.add(StatePath.parsePath("links.*.pools.*"), branchMetadata("poolref", "name")); this.add(StatePath.parsePath("links.*.unitgroups.*"), branchMetadata("unitgroupref", "name")); this.add(StatePath.parsePath("links.*.units.protocol.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("links.*.units.net.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("links.*.units.store.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("links.*.units.dcache.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("linkgroups.*"), branchMetadata("linkgroup", "lgid")); this.add(StatePath.parsePath("linkgroups.*.authorisation.*"), branchMetadata("authorised", "name")); this.add(StatePath.parsePath("linkgroups.*.reservations.*"), branchMetadata("reservationref", "reservation-id")); this.add(StatePath.parsePath("reservations.*"), branchMetadata("reservation", "reservation-id")); this.add(StatePath.parsePath("summary.linkgroup.blanket-auth.by-VO.*"), branchMetadata("VO", "name")); this.add(StatePath.parsePath("summary.linkgroup.blanket-auth.by-VO.*.linkgroups.*"), branchMetadata("linkgroupref", "lgid")); this.add(StatePath.parsePath("summary.linkgroup.blanket-auth.all.linkgroups.*"), branchMetadata("linkgroupref", "lgid")); this.add(StatePath.parsePath("summary.reservations.by-VO.*"), branchMetadata("VO", "name")); this.add(StatePath.parsePath("summary.reservations.by-VO.*.by-description.*"), branchMetadata("reservation-group", "description")); this.add(StatePath.parsePath("summary.reservations.by-VO.*.by-description.*.reservations.*"), branchMetadata("reservation", "id")); this.add(StatePath.parsePath("units.*"), branchMetadata("unit", "name")); this.add(StatePath.parsePath("units.*.unitgroups.*"), branchMetadata("unitgroupref", "ref")); this.add(StatePath.parsePath("unitgroups.*"), branchMetadata("unitgroup", "name")); this.add(StatePath.parsePath("unitgroups.*.units.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("unitgroups.*.links.*"), branchMetadata("linkref", "name")); this.add(StatePath.parsePath("doors.*"), branchMetadata("door", "name")); this.add(StatePath.parsePath("doors.*.interfaces.*"), branchMetadata("interface", "id")); this.add(StatePath.parsePath("doors.*.tags.*"), branchMetadata("tag", "id")); this.add(StatePath.parsePath("nas.*"), branchMetadata("nas", "id")); this.add(StatePath.parsePath("nas.*.links.*"), branchMetadata("linkref", "name")); this.add(StatePath.parsePath("nas.*.pools.*"), branchMetadata("poolref", "name")); this.add(StatePath.parsePath("nas.*.units.store.read.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.store.write.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.store.stage.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.dcache.read.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.dcache.write.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.dcache.stage.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.protocol.read.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.protocol.write.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.protocol.stage.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.net.read.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.net.write.*"), branchMetadata("unitref", "name")); this.add(StatePath.parsePath("nas.*.units.net.stage.*"), branchMetadata("unitref", "name")); } /** * Prepare a Map that updates the persistent metadata hierarchy to include * a Class and IdName values, these values are indexed by * <tt>METADATA_BRANCH_CLASS_KEY</tt> and <tt>METADATA_BRANCH_IDNAME_KEY</tt> * respectively. * @param branchClass the name of this list's classification. * @param branchIdName how to refer to the general class of individual item's unique id. * @return a new Map entry, ready to be passed to StatePersistentMetadata.add(). */ private Map<String,String> branchMetadata(String branchClass, String branchIdName) { Map<String,String> metadataUpdate = new HashMap<>(); metadataUpdate.put(State.METADATA_BRANCH_CLASS_KEY, branchClass); metadataUpdate.put(State.METADATA_BRANCH_IDNAME_KEY, branchIdName); return metadataUpdate; } }