/* * Galaxy * Copyright (c) 2012-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.galaxy.cluster; import java.util.List; /** * Provides access to a distributed, observable filesystem-like node tree for configuration data. * <p> * Nodes in the tree are organized in a directory structure: each tree-node (not to be confused with <i>cluster nodes</i>, or machines) may have sub-nodes (children) as well as byte data associated * with it (the node's <i>contents</i>). The nodes are named in the following manner: the root of the tree is called "/", and generations are separated by the '/' (forward-slash) character. A node may * have the <i>simple name</i> "mynode" and its <i>full path</i> may be "/grandparent/parent/mynode". All full paths must begin with a "/".<br> * * The tree is available to all nodes (machines) in the cluster, and any change is immediately visible to all of them. The tree provides an important <i>ordering guarantee</i>: All children (of a * certain node) appear (throughout the cluster) <b>in the order in which they've been created</b>. * <p> * The tree also provides <i>ephemeral</i> nodes: those are automatically deleted when the creating cluster-node (machine) goes offline, i.e. disconnected from the cluster for whatever reason - * intentional or due to some fault. */ public interface DistributedTree { /** * Creates a new node in the tree. All nonexistent parent nodes are also created (i.e. all nonexistent nodes along the path). * <p> * The node can be <i>ephemeral</i> in which case, it and all its descendents will be deleted automatically when the creating cluster-node (this machine) goes offline, i.e. disconnected from the * cluster for whatever reason - intentional or due to some fault. Non-ephemeral (<i>permanent</i>) nodes persist in the tree until the entire cluster is taken down.<br> * * If the node is marked as ephemeral, all <b>nonexistent</b> ancestors that will be created in the process will be ephemeral as well. * * @param node The full path of the node to create. * @param ephemeral {@code true} if the node is to be <i>ephemeral</i>; {@code false} if it's to be <i>permanent</i>. */ void create(String node, boolean ephemeral); /** * Creates an ephemeral node that, when returned by {@link #getChildren(java.lang.String) getChildren()}, will be placed in the list in relation to other ordered ephemeral nodes by the relative order of its creation. * The node's ancestors are not created. * * @param node The full path of the node to create. */ void createEphemeralOrdered(String node); /** * Returns all child-nodes (direct descendents) of a given node, with ephemeral ordered nodes returned <b>in the order they were created</b>. * @param node The full path of the node. * @return A list of the simple names (without the full path) of all of the given node's children. */ List<String> getChildren(String node); /** * Returns {@code true} if the given node exists in the tree. * @param node The full path of the node to test. * @return {@code true} if the given node exists in the tree; {@code false} otherwise. */ boolean exists(String node); /** * Associates data with (sets the contents of) a given node. * @param node The full path name of the node. * @param data The data to be associated with the node. * @see #get(java.lang.String) */ void set(String node, byte[] data); /** * Returns the contents of a given node. * @param node The full path of the node. * @return The given node's data contents. * @see #set(java.lang.String, byte[]) */ byte[] get(String node); /** * Deletes a node and all its descendents from the tree. * @param node The full path of the node to be removed. */ void delete(String node); /** * Ensures that all updates to the tree done by this cluster node will have been seen by all nodes in the cluster when this method returns. */ void flush(); /** * Adds a {@link Listener listener} listening for modifications on the given node. * As soon as the listener is added, {@link Listener#nodeAdded(String) nodeAdded} is called for each child of {@code node}. * @param node The full path of the node to observe. * @param listener The listener. */ void addListener(String node, Listener listener); /** * Removes a listener. * @param node The full path of the node the listener is currently observing. * @param listener The listener to remove. */ void removeListener(String node, Listener listener); /** * Prints the tree's structure, starting at a given node, to the given stream. * @param node The node that will serve as the root of the dump. * @param out The output stream to which the tree structure is to be sent. */ void print(String node, java.io.PrintStream out); /** * Method is called when Galaxy Cluster is going offline and requests all services to shutdown. */ void shutdown(); /** * A listener for DistributedTree node events. */ public static interface Listener { /** * Invoked when a new node has been added to the tree. * @param node The new node's full path. */ void nodeAdded(String node); /** * Invoked when a node's contents has been modified. * @param node The updated node's full path. */ void nodeUpdated(String node); /** * Invoked when a node has been deleted from the tree. * @param node The deleted node's full path. */ void nodeDeleted(String node); /** * Invoked when a new child node of the listener's target node has been created. * {@link #nodeAdded(java.lang.String) nodeAdded} will be called on a listener listening on the child node, if one exists. * @param node The full path of the parent node. * @param child The simple name (without the full path) of the newly added child node. */ void nodeChildAdded(String node, String child); /** * Invoked when a child node's contents of the listener's target node has been modified. * {@link #nodeUpdated(java.lang.String) nodeUpdated} will be called on a listener listening on the child node, if one exists. * @param node The full path of the parent node. * @param child The simple name (without the full path) of the updated node. */ void nodeChildUpdated(String node, String child); /** * Invoked when a child node of the listener's target node has been deleted. * {@link #nodeDeleted(java.lang.String) nodeDeleted} will be called on a listener listening on the child node, if one exists. * @param node The full path of the parent node. * @param child The simple name (without the full path) of the deleted child node. */ void nodeChildDeleted(String node, String child); } /** * An abstract adapter class for receiving DistributedTree events. The methods in this class are empty. This class exists as convenience for creating listener objects. */ public static abstract class ListenerAdapter implements Listener { @Override public void nodeAdded(String node) { } @Override public void nodeUpdated(String node) { } @Override public void nodeDeleted(String node) { } @Override public void nodeChildAdded(String node, String childName) { } @Override public void nodeChildUpdated(String node, String childName) { } @Override public void nodeChildDeleted(String node, String childName) { } } }