/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the LICENSE file that accompanied
* this code.
*
* --
*/
package com.sun.sgs.service;
import com.sun.sgs.app.TransactionException;
import com.sun.sgs.auth.Identity;
import java.util.Iterator;
/**
*
* The Node Mapping Service has the following responsibilities:
* <ul>
* <li> maintain mapping of active identities to nodes, and vice versa
* <li> decide when the mapping should change (e.g. when a new
* client joins the system, a client account is canceled, an AI object
* is created, node failure, load balancing, an identity is quiescent)
* <li> notify interested services of changes in the mapping
* </ul>
*
* While decisions about changes to the map will be made outside a
* transaction, the actual mapping change will occur inside a transaction.
* Services can assume the mapping has not changed during one of their own
* transactions.
* <p>
* On initial client login, the {@link ClientSessionService} will get a
* node assignment via {@link #assignNode assignNode}. If the assigned node
* is the current node (as determined by the nodeId), the client will proceed
* with the login protocol.
* Otherwise, the client will get a login response indicating a redirection,
* and the client code should attempt to log in at the redirected node.
* <p>
* Mappings will be removed when the system believes an identity has become
* quiescent, for example when a client logs out and there are no more durable
* tasks to be run for that client's identity. In order to determine whether an
* identity is quiescent, services which manage resources being used on an
* identity's behalf inform this mapping service when the identity is active
* or inactive on a node by calling {@link #setStatus setStatus}. The node
* mapping service will use this information for a simple reference counting
* garbage collection scheme within the map. Status is tracked per node, so
* services should consider only their local node state when calling setStatus.
*
* <p>
* <b> TODO We might want a transactional method that returns true if
* an identity is both assigned to the local node and the local node
* is alive, as a convenience to other services. </b>
* <p>
* <b> TODO A variation of "assignNode" which adds hints for identities the
* input might want to colocate with will probably be added later. </b>
*/
public interface NodeMappingService extends Service {
/**
* Assigns the identity to a node and adds the assignment to the map.
* If the identity has no node assignment, or the current assignment
* is not to a live node, a node is selected for it; otherwise, no action
* is performed.
* <p>
* Additionally (and atomically), notes that the service considers the
* identity to be active, as though
* {@link #setStatus setStatus(service, identity, true)} had
* been called on the assigned node.
* <p>
* This method should not be called while in a transaction, as this
* method call could entail remote communication.
* <p>
* The returned node ID might not match the ID of the node returned from an
* immediate call to {@link #getNode getNode} in a transaction because an
* identity's node assignment may change at any time.
*
* @param service the class of the caller
* @param identity the identity to assign to a node
*
* @return the ID of the node that the identity was assigned to,
* or -1 if the assignment failed
* @throws IllegalStateException if this method is called while in a
* transaction
*
*/
long assignNode(Class service, Identity identity);
/**
* Inform the {@code NodeMappingService} that a service instance has
* observed a change in status of an identity on this node. When all
* services which have previously noted an identity as active set the
* status to false, the identity can be removed from the map. If a node
* fails or the node mapping service initiates a mapping change (for
* load balancing), all status votes for the failing or old node are
* implicitly set to inactive.
* <p>
* This method should not be called while in a transaction, as this
* method call could entail remote communication.
* <p>
* @param service the class of the calling service
* @param identity the identity for which {@code service} has observed a
* state change
* @param active {@code true} if the identity is active,
* {@code false} if the identity is inactive
*
* @throws UnknownIdentityException if the identity is not in the map
* @throws IllegalStateException if this method is called while in a
* transaction
*/
void setStatus(Class service, Identity identity,
boolean active) throws UnknownIdentityException;
/**
* Returns the live node to which the identity is assigned.
* <p>
* This method must be called from within a transaction.
*
* @param identity the identity
* @return node information for the specified {@code identity}
*
* @throws UnknownIdentityException if the identity is not in the map
* @throws TransactionException if the operation failed because of
* a problem with the current transaction
*/
Node getNode(Identity identity) throws UnknownIdentityException;
/**
* Returns an {@code Iterator} for the set of identities assigned to a node.
* The set will be empty if no identities are assigned to the node.
* <p>
* The {@code remove} operation of the returned iterator is not supported
* and will throw {@code UnsupportedOperationException} if invoked.
* <p>
* This method should only be called within a transaction, and the
* returned iterator should only be used within that transaction.
*
* @param nodeId a node ID
* @return an iterator for all identities assigned to this node
*
* @throws UnknownNodeException if the nodeId is unknown
* @throws IllegalArgumentException if the specified {@code nodeId}
* is not within the range of valid IDs
* @throws TransactionException if the operation failed because of
* a problem with the current transaction
*/
Iterator<Identity> getIdentities(long nodeId) throws UnknownNodeException;
/**
* Adds a {@code listener} to be notified when an identity has been selected
* to be relocated off the local node. The listener will be invoked
* outside of a transaction.
* <p>
* If a {@code Service} needs to take actions before an identity is moved,
* it should register one (or more) {@code listener} objects when
* constructed. The order of callbacks to listener objects is not
* specified, and the callbacks will occur asynchronously.
* <p>
* The identity will be moved, and the mapping modified, when all
* {@code listener} objects have completed their work, or after a time
* delay in case a {@code listener} does not respond that it is finished.
*
* @param listener a listener to be notified prior to an identity moving
* from the local node
*/
void addIdentityRelocationListener(IdentityRelocationListener listener);
/**
* Adds a {@code listener} to be notified when the identity
* mapping for this node is modified. This method is not performed
* under a transaction; {@code listeners} are held locally on nodes.
* <p>
* If a {@code Service} needs to take actions when identities are added to
* or removed from a local node, it should register one (or more)
* {@code listener} objects when it is constructed. The order of callbacks
* to listener objects is not specified, and the callbacks will occur
* asynchronously.
*
* @param listener a listener to be notified of local changes to the map
*/
void addNodeMappingListener(NodeMappingListener listener);
}