Package jade.core

Source Code of jade.core.PlatformManagerImpl

/*****************************************************************
JADE - Java Agent DEvelopment Framework is a framework to develop
multi-agent systems in compliance with the FIPA specifications.
Copyright (C) 2000 CSELT S.p.A.

GNU Lesser General Public License

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation,
version 2.1 of the License.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA  02111-1307, USA.
*****************************************************************/

package jade.core;

//#APIDOC_EXCLUDE_FILE
//#MIDP_EXCLUDE_FILE

import jade.core.behaviours.Behaviour;

import jade.security.JADESecurityException;
import jade.mtp.TransportAddress;

import jade.util.leap.Map;
import jade.util.leap.HashMap;
import jade.util.leap.List;
import jade.util.leap.ArrayList;
import jade.util.leap.Iterator;
import jade.util.Logger;
import jade.util.TransportAddressWrapper;

import java.util.Vector;

/**
The <code>ServiceManagerImpl</code> class is the actual
implementation of JADE platform <i>Service Manager</i> and
<i>Service Finder</i> components. It holds a set of services and
manages them.

@author Giovanni Caire - TILAB
@author Giovanni Rimassa - FRAMeTech s.r.l.
*/
public class PlatformManagerImpl implements PlatformManager {

  private IMTPManager myIMTPManager;
  private CommandProcessor myCommandProcessor;

  // FIXME: The association between MainContainer and PlatformManagerImpl need be clarified...
  private MainContainerImpl myMain;
  private Map nodes;
  private Map services;
  private Map replicas;
  private Map monitors;
  private String localAddr;
  private String platformID;

  // These variables hold progressive numbers just used to name new nodes.
  // By convention, nodes hosting containers with a local copy of the Platform Manager are called
  // Main-Container-<N>, hosting containers whereas nodes without their own Platform Manager are
  // called Container-<M>.
  // Nodes not hosting containers are called Aux-Node-<K>
  private int containerNo = 1;
  private int mainContainerNo = 0;
  private int nodeNo = 1;

  private Logger myLogger = Logger.getMyLogger(getClass().getName());

  /**
     Inner class ServiceEntry (package scoped for debugging purpose)
   */
  class ServiceEntry {

    public ServiceEntry(Service s) {
      myService = s;
      slices = new HashMap();
    }

    public void addSlice(String name, Service.Slice s, Node n) {
      SliceEntry e = new SliceEntry(s, n);
      slices.put(name, e);
    }

    public Service.Slice removeSlice(String name) {
      SliceEntry e = (SliceEntry) slices.remove(name);
      if (e == null) {
        return null;
      } else {
        return e.getSlice();
      }
    }

    public Vector getSlices() {
      Iterator sliceEntries = slices.values().iterator();
      Vector result = new Vector();

      while (sliceEntries.hasNext()) {
        SliceEntry e = (SliceEntry) sliceEntries.next();
        result.addElement(e.getSlice());
      }

      return result;
    }

    public Service.Slice getSlice(String name) {
      SliceEntry e = (SliceEntry) slices.get(name);
      if (e == null) {
        return null;
      } else {
        return e.getSlice();
      }
    }

    public Node[] getNodes() {
      Object[] sliceEntries = slices.values().toArray();
      Node[] result = new Node[sliceEntries.length];

      for (int i = 0; i < result.length; i++) {
        SliceEntry e = (SliceEntry) sliceEntries[i];
        result[i] = e.getNode();
      }

      return result;
    }

    public Node getNode(String name) {
      SliceEntry e = (SliceEntry) slices.get(name);
      if (e == null) {
        return null;
      } else {
        return e.getNode();
      }
    }

    public void setService(Service svc) {
      myService = svc;
    }

    public Service getService() {
      return myService;
    }

    // For debugging purpose only
    Map getSlicesMap() {
      return slices;
    }
   
    private Service myService;
    private Map slices;

  } // End of inner class ServiceEntry class

  /**
     Inner class SliceEntry (package-scoped for debugging purpose)
   */
  class SliceEntry {

    public SliceEntry(Service.Slice s, Node n) {
      mySlice = s;
      myNode = n;
    }

    public Service.Slice getSlice() {
      return mySlice;
    }

    public Node getNode() {
      return myNode;
    }

    private Service.Slice mySlice;
    private Node myNode;

  } // End of inner class SliceEntry class

  /**
   Constructs a new Service Manager implementation complying with
   a given JADE profile. This constructor is package-scoped, so
   that only the JADE kernel is allowed to create a new Service
   Manager implementation.

   @param p The platform profile describing how the JADE platform
   is to be configured.
   */
  PlatformManagerImpl(Profile p) throws ProfileException {
    myCommandProcessor = p.getCommandProcessor();
    myIMTPManager = p.getIMTPManager();
    myMain = new MainContainerImpl(p, this);

    nodes = new HashMap();
    services = new HashMap();
    replicas = new HashMap();
    monitors = new HashMap();

    platformID = p.getParameter(Profile.PLATFORM_ID, null);
    if (platformID == null || platformID.equals("")) {
      try {
        // Build the PlatformID using the local host and port
        List l = myIMTPManager.getLocalAddresses();
        TransportAddress localAddr = (TransportAddress) l.get(0);
        platformID = localAddr.getHost() + ":" + localAddr.getPort() + "/JADE";
      } catch (Exception e) {
        throw new ProfileException("Can't set PlatformID", e);
      }
    }
  }

  MainContainerImpl getMain() {
    return myMain;
  }

  public void setPlatformName(String name) throws IMTPException {
    platformID = name;
  }

  // Implementation of the PlatformManager interface

  public String getPlatformName() throws IMTPException {
    return platformID;
  }

  public String getLocalAddress() {
    return localAddr;
  }

  public void setLocalAddress(String addr) {
    localAddr = addr;
  }

  /**
   @param dsc The Descriptor of the new Node
   @param services The services currently installed on the new Node
   @param propagated Flag indicating whether the new-node event
   was a propagated event within the replication mechanism
   */
  public String addNode(NodeDescriptor dsc, Vector nodeServices, boolean propagated) throws IMTPException, ServiceException, JADESecurityException {
    String newName = localAddNode(dsc, nodeServices, propagated);
    if (!propagated) {
      broadcastAddNode(dsc, nodeServices);
    }
    return newName;
  }

  // This may throw IMTPException since localAddSlice() throws IMTPException
  private String localAddNode(NodeDescriptor dsc, Vector nodeServices, boolean propagated) throws IMTPException, ServiceException, JADESecurityException {
    Node node = dsc.getNode();

    checkExistence(node);
   
    // If the node hosts a Container, adjust node name
    adjustName(dsc, node);

    // Issue a NEW_NODE vertical command
    if (!propagated) {
      // In this case we issue the command before adding the node
      // for authorization purposes
      issueNewNodeCommand(dsc);
    }

    // Add the new node
    if (isLocalNode(node)) {
      // If this is the local node it surely host a container (the main). Remove it
      myMain.addLocalContainer(dsc.getContainer());
    }
    else {
      if (myLogger.isLoggable(Logger.INFO)) {
        myLogger.log(Logger.INFO, "Adding node <" + dsc.getName() + "> to the platform");
      }

      // If the node hosts a container add it as a remote container
      if (dsc.getContainer() != null) {
        myMain.addRemoteContainer(dsc.getContainer());
      }
    }

   
    // Add the node to the global node list
    nodes.put(dsc.getName(), dsc);

    // Add all service slices
    // Do not broadcast since this information is already conveied when broadcasting the add-node event
    if (nodeServices != null) {
      for (int i = 0; i < nodeServices.size(); ++i) {
        ServiceDescriptor service = (ServiceDescriptor) nodeServices.elementAt(i);
        localAddSlice(service, dsc, propagated);
      }
    }

    // Start monitoring the new node if necessary
    if (!isLocalNode(node) && !propagated) {
      // Start monitoring
      monitor(dsc);
    }
   
    // Return the name given to the new node
    return node.getName();
  }

  private void broadcastAddNode(NodeDescriptor dsc, Vector nodeServices) throws ServiceException {
    // Avoid concurrent modification exception
    Object[] rr = replicas.values().toArray();
    for (int i = 0; i < rr.length; ++i) {
      PlatformManager replica = (PlatformManager) rr[i];
      try {
        replica.addNode(dsc, nodeServices, true);
      } catch (IMTPException imtpe) {
        // Zombie replica. Will be removed soon. Just ignore it
      } catch (JADESecurityException ae) {
        // Should never happen since this is a propagated info
        ae.printStackTrace();
      }
    }
  }

  public void removeNode(NodeDescriptor dsc, boolean propagated) throws IMTPException, ServiceException {
    localRemoveNode(dsc, propagated);
    // If this is the local node the node termination will cause the deregistration from replicas...
    if (!propagated && !isLocalNode(dsc.getNode())) {
      broadcastRemoveNode(dsc);
    }
  }

  private void localRemoveNode(NodeDescriptor dsc, boolean propagated) throws ServiceException {
    dsc = adjustDescriptor(dsc);
    Node node = dsc.getNode();

    // Remove all the slices corresponding to the removed node
    // Avoid concurrent modification exception
    Object[] allServiceKeys = services.keySet().toArray();
    for (int i = 0; i < allServiceKeys.length; i++) {
      String serviceKey = (String) allServiceKeys[i];
      localRemoveSlice(serviceKey, dsc.getName(), propagated);
    }

    // Remove the node
    if (isLocalNode(node)) {
      // If it is the local node it surely hosts a container (the main). Remove it
      myMain.removeLocalContainer(dsc.getContainer());
    } else {
      if (myLogger.isLoggable(Logger.INFO)) {
        myLogger.log(Logger.INFO, "Removing node <" + dsc.getName() + "> from the platform");
      }

      // If the node hosted a container remove it as a remote container
      if (dsc.getContainer() != null) {
        myMain.removeRemoteContainer(dsc.getContainer());
      }
    }

    // Remove the node from the global node list
    nodes.remove(dsc.getName());

    // Stop monitoring (this has no effect if we were not monitoring the dead node)
    Node parent = dsc.getParentNode();
    if (parent != null) {
      // If the dead node had a parent, notify the failure-monitor monitoring the parent
      NodeFailureMonitor failureMonitor = (NodeFailureMonitor) monitors.get(parent.getName());
      if (failureMonitor != null) {
        failureMonitor.removeChild(node);
      }
    }
    monitors.remove(node.getName());

    // Issue a DEAD_NODE vertical command
    if (!propagated) {
      GenericCommand gCmd = new GenericCommand(Service.DEAD_NODE, null, null);
      gCmd.addParam(dsc);
      Object result = myCommandProcessor.processIncoming(gCmd);
      if (result instanceof Throwable) {
        myLogger.log(Logger.WARNING, "Unexpected error processing DEAD_NODE command. Node is " + dsc.getName(), (Throwable) result);
      }
    }
  }

  private void broadcastRemoveNode(NodeDescriptor dsc) throws ServiceException {
    // Avoid concurrent modification exception
    Object[] rr = replicas.values().toArray();
    for (int i = 0; i < rr.length; ++i) {
      PlatformManager replica = (PlatformManager) rr[i];
      try {
        replica.removeNode(dsc, true);
      } catch (IMTPException imtpe) {
        // Zombie replica. Will be removed soon. Just ignore it
      }
    }
  }

  public void addSlice(ServiceDescriptor service, NodeDescriptor dsc, boolean propagated) throws IMTPException, ServiceException {
    localAddSlice(service, dsc, propagated);
    if (!propagated) {
      broadcastAddSlice(service, dsc);
    }
  }

  // This may throw IMTPException since IMTPManager.createSliceProxy throws IMTPException
  private void localAddSlice(ServiceDescriptor serviceDsc, NodeDescriptor dsc, boolean propagated) throws IMTPException, ServiceException {
    Service service = serviceDsc.getService();

    String serviceKey = service.getName();
    ServiceEntry e = (ServiceEntry) services.get(serviceKey);

    if (e == null) {
      if (myLogger.isLoggable(Logger.CONFIG)) {
        myLogger.log(Logger.CONFIG, "Adding entry for service <" + serviceKey + ">");
      }

      e = new ServiceEntry(service);
      services.put(serviceKey, e);
    }
    if (myLogger.isLoggable(Logger.CONFIG)) {
      myLogger.log(Logger.CONFIG, "Adding slice for service <" + serviceKey + "> on node <" + dsc.getName() + ">");
    }

    Node node = dsc.getNode();
    Service.Slice slice = null;
    if (service.getHorizontalInterface() != null) {
      // Create a real SliceProxy
      slice = myIMTPManager.createSliceProxy(serviceKey, service.getHorizontalInterface(), node);
    } else {
      // Create a dummy SliceProxy (it will never be used)
      slice = new SliceProxy(service, node);
    }

    String sliceKey = node.getName();
    e.addSlice(sliceKey, slice, node);

    if (isLocalNode(node)) {
      // The service is just started on this main container
      // Register the service-specific behaviour (if any) within the AMS
      Behaviour b = service.getAMSBehaviour();
      if (b != null) {
        myMain.installAMSBehaviour(b);
      }
    }

    if (!propagated) {
      issueNewSliceCommand(serviceKey, sliceKey);
    }
  }

  private void broadcastAddSlice(ServiceDescriptor service, NodeDescriptor dsc) throws ServiceException {
    // Avoid concurrent modification exception
    Object[] rr = replicas.values().toArray();
    for (int i = 0; i < rr.length; ++i) {
      PlatformManager replica = (PlatformManager) rr[i];
      try {
        replica.addSlice(service, dsc, true);
      } catch (IMTPException imtpe) {
        // Zombie replica. Will be removed soon. Just ignore it
      }
    }
  }

  public void removeSlice(String serviceKey, String sliceKey, boolean propagated) throws IMTPException, ServiceException {
    localRemoveSlice(serviceKey, sliceKey, propagated);
    if (!propagated) {
      broadcastRemoveSlice(serviceKey, sliceKey);
    }
  }

  private void localRemoveSlice(String serviceKey, String sliceKey, boolean propagated) throws ServiceException {
    ServiceEntry e = (ServiceEntry) services.get(serviceKey);

    if (e != null) {
      if (e.removeSlice(sliceKey) != null) {
        if (myLogger.isLoggable(Logger.CONFIG)) {
          myLogger.log(Logger.CONFIG, "Removing slice for service <" + serviceKey + "> on node <" + sliceKey + ">");
        }
      }
      // Clear the cache
      Service svc = e.getService();
      if (svc instanceof BaseService) {
        ((BaseService) svc).clearCachedSlice(sliceKey);
      }

      NodeDescriptor dsc = getDescriptor(sliceKey);
      if (dsc != null && isLocalNode(dsc.getNode())) {
        // The service slice was removed on this node
        // Deregister the service-specific behaviour (if any) within the AMS
        Behaviour b = e.getService().getAMSBehaviour();
        if (b != null) {
          myMain.uninstallAMSBehaviour(b);
        }
      }

      if (!propagated) {
        GenericCommand gCmd = new GenericCommand(Service.DEAD_SLICE, serviceKey, null);
        gCmd.addParam(sliceKey);
        Object result = myCommandProcessor.processIncoming(gCmd);
        if (result instanceof Throwable) {
          myLogger.log(Logger.WARNING, "Unexpected error processing DEAD_SLICE command. Service is " + serviceKey + " node is " + sliceKey, (Throwable) result);
        }
      }
    }
  }

  private void broadcastRemoveSlice(String serviceKey, String sliceKey) throws ServiceException {
    // Avoid concurrent modification exception
    Object[] rr = replicas.values().toArray();
    for (int i = 0; i < rr.length; ++i) {
      PlatformManager replica = (PlatformManager) rr[i];
      try {
        replica.removeSlice(serviceKey, sliceKey, true);
      } catch (IMTPException imtpe) {
        // Zombie replica. Will be removed soon. Just ignore it
      }
    }
  }

  public void addReplica(String newAddr, boolean propagated) throws IMTPException, ServiceException {
    PlatformManager newReplica = myIMTPManager.getPlatformManagerProxy(newAddr);
    localAddReplica(newReplica, propagated);
    if (!propagated) {
      broadcastAddReplica(newAddr);
    }
    // Actually add the new replica only after broadcasting
    replicas.put(TransportAddressWrapper.getWrapper(newReplica.getLocalAddress(), myIMTPManager), newReplica);
  }
 
 

  // This may throw IMTPException since the new replica must be informed about the platform status
  private void localAddReplica(PlatformManager newReplica, boolean propagated) throws IMTPException, ServiceException {
    if (myLogger.isLoggable(Logger.INFO)) {
      myLogger.log(Logger.INFO, "Adding replica <" + newReplica.getLocalAddress() + "> to the platform");
    }

    if (!propagated) {
      // Inform the new replica about existing nodes and their installed services...
      List infos = getAllNodesInfo();

      Iterator it = infos.iterator();
      while (it.hasNext()) {
        NodeInfo info = (NodeInfo) it.next();
        try {
          newReplica.addNode(info.getNodeDescriptor(), info.getServices(), true);
        } catch (JADESecurityException ae) {
          // Should never happen since this is a propagated info
          ae.printStackTrace();
        }
      }

      // Inform the new replica about other replicas
      // Avoid concurrent modification exception
      Object[] rr = replicas.values().toArray();
      for (int i = 0; i < rr.length; ++i) {
        PlatformManager replica = (PlatformManager) rr[i];
        newReplica.addReplica(replica.getLocalAddress(), true);
      }
    }
   
    // Issue a NEW_REPLICA command
    GenericCommand gCmd = new GenericCommand(Service.NEW_REPLICA, null, null);
    gCmd.addParam(newReplica.getLocalAddress());
    Object result = myCommandProcessor.processIncoming(gCmd);
    if (result instanceof Throwable) {
      myLogger.log(Logger.WARNING, "Unexpected error processing NEW_REPLICA command. Replica address is " + newReplica.getLocalAddress(), (Throwable) result);
    }
  }

  private void broadcastAddReplica(String newAddr) throws ServiceException {
    // Avoid concurrent modification exception
    Object[] rr = replicas.values().toArray();
    for (int i = 0; i < rr.length; ++i) {
      PlatformManager replica = (PlatformManager) rr[i];
      try {
        replica.addReplica(newAddr, true);
      } catch (IMTPException imtpe) {
        // Zombie replica. Will be removed soon. Just ignore it
      }
    }
  }

  public void removeReplica(String address, boolean propagated) throws IMTPException, ServiceException {
    localRemoveReplica(address, propagated);
    if (!propagated) {
      broadcastRemoveReplica(address);
    }
  }

  private void localRemoveReplica(String address, boolean propagated) throws ServiceException {
    if (myLogger.isLoggable(Logger.INFO)) {
      myLogger.log(Logger.INFO, "Removing replica <" + address + "> from the platform");
    }

    // Remove the old replica
    try {
      TransportAddressWrapper key = TransportAddressWrapper.getWrapper(address, myIMTPManager);
      if (replicas.remove(key) == null) {
        // The replica to remove is not among the known replicas --> Print a warning since this should never happen
        StringBuffer sb = new StringBuffer("Replica "+key.hashCode()+", "+key.getAddress()+"not found! Known replicas are: {");
        Iterator it = replicas.keySet().iterator();
        while (it.hasNext()) {
          TransportAddressWrapper taw = (TransportAddressWrapper) it.next();
          sb.append(""+taw.hashCode()+", "+taw.getAddress());
          if (it.hasNext()) {
            sb.append("; ");
          }
        }
        sb.append("}");
        myLogger.log(Logger.WARNING, sb.toString());
      }
    }
    catch (IMTPException imtpe) {
      // This should never happen as our IMTPManager must be able to deal with a replica address
      throw new ServiceException("Error parsing PlatformManager replica transport address");
    }

    if (!propagated) {
      // Notify first all non-child and non-main nodes.
      Object[] allNodes = nodes.values().toArray();
      for (int i = 0; i < allNodes.length; i++) {
        NodeDescriptor dsc = (NodeDescriptor) allNodes[i];
        if (dsc.getParentNode() == null) {
          Node n = dsc.getNode();
          if (!n.hasPlatformManager()) {
            try {
              n.platformManagerDead(address, getLocalAddress());
             
            } catch (IMTPException imtpe) {
              // The node died while no one was monitoring it
              removeTerminatedNode(n);
            }
          }
        }
      }
      // Then notify all child nodes.
      for (int i = 0; i < allNodes.length; i++) {
        NodeDescriptor dsc = (NodeDescriptor) allNodes[i];
        if (dsc.getParentNode() != null) {
          Node n = dsc.getNode();
          try {
            n.platformManagerDead(address, getLocalAddress());
          } catch (IMTPException imtpe) {
            // The node daid while no one was monitoring it
            removeTerminatedNode(n);
          }
        }
      }
    }
   
    // Issue a DEAD_REPLICA command
    GenericCommand gCmd = new GenericCommand(Service.DEAD_REPLICA, null, null);
    gCmd.addParam(address);
    Object result = myCommandProcessor.processIncoming(gCmd);
    if (result instanceof Throwable) {
      myLogger.log(Logger.WARNING, "Unexpected error processing DEAD_REPLICA command. Replica address is " + address, (Throwable) result);
    }
  }

  private void broadcastRemoveReplica(String address) throws ServiceException {
    // Avoid concurrent modification exception
    Object[] rr = replicas.values().toArray();
    for (int i = 0; i < rr.length; ++i) {
      PlatformManager replica = (PlatformManager) rr[i];
      try {
        replica.removeReplica(address, true);
      }
      catch (IMTPException imtpe) {
        // Zombie replica. Will be removed soon. Just ignore it
      }
    }
  }

  public void adopt(Node n, Node[] children) throws IMTPException {
    String name = n.getName();
    NodeDescriptor dsc = getDescriptor(name);
    if (dsc != null) {
      monitor(dsc);
      // Issue an ADOPTED_NODE Vertical command
      GenericCommand gCmd = new GenericCommand(Service.ADOPTED_NODE, null, null);
      gCmd.addParam(dsc);
      Object result = myCommandProcessor.processIncoming(gCmd);
      if (result instanceof Throwable) {
        myLogger.log(Logger.WARNING, "Unexpected error processing ADOPTED_NODE command. Node is " + dsc.getName(), (Throwable) result);
      }
      myLogger.log(Logger.INFO, "Node <" + n.getName() + "> adopted");
    } else {
      myLogger.log(Logger.WARNING, "NO descriptor found for node <" + n.getName() + "> requesting adoption. Ignore...");
    }
  }

  public void ping() throws IMTPException {
    // Just do nothing
  }

  /**
   * This method is invoked by the MainReplicationService when a new MainReplication slice is added
   * and has the effect of issuing a NEW_NODE VCommand and one NEW_SLICE VCommand for each service
   * installed in the node hosting the new MainReplication slice. This allows services to propagate
   * service specific information to their new slice
   */
  public void addMainContainerNode(NodeDescriptor dsc, Vector services) throws JADESecurityException {
    issueNewNodeCommand(dsc);
    for (int i = 0; i < services.size(); ++i) {
      ServiceDescriptor srvDsc = (ServiceDescriptor) services.get(i);
      issueNewSliceCommand(srvDsc.getService().getName(), dsc.getNode().getName());
    }
  }
  ////////////////////////////////
  // Service finding methods
  ////////////////////////////////
  public Service.Slice findSlice(String serviceKey, String sliceKey) throws IMTPException, ServiceException {
    ServiceEntry e = (ServiceEntry) services.get(serviceKey);

    if (e == null) {
      return null;
    } else {
      // If the special MAIN_SLICE name is used, return the local slice
      if (CaseInsensitiveString.equalsIgnoreCase(sliceKey, ServiceFinder.MAIN_SLICE)) {
        sliceKey = myIMTPManager.getLocalNode().getName();
      }

      return e.getSlice(sliceKey);
    }
  }

  public Vector findAllSlices(String serviceKey) throws IMTPException, ServiceException {
    ServiceEntry e = (ServiceEntry) services.get(serviceKey);
    if (e == null) {
      return null;
    } else {
      return e.getSlices();
    }
  }

  //////////////////////////////////////////////////////////////
  // Package-scoped methods called by the MainContainer only
  //////////////////////////////////////////////////////////////
  NodeDescriptor getDescriptor(String name) {
    return (NodeDescriptor) nodes.get(name);
  }

  /**
   Kill all auxiliary nodes not holding any container
   */
  void shutdown() {
    // FIXME: to be implemented
  }

  //////////////////////////////////
  // Private methods
  //////////////////////////////////
  private void issueNewNodeCommand(NodeDescriptor dsc) throws JADESecurityException {
    GenericCommand gCmd = new GenericCommand(Service.NEW_NODE, null, null);
    gCmd.addParam(dsc);
    Object result = myCommandProcessor.processIncoming(gCmd);
    if (result instanceof JADESecurityException) {
      throw (JADESecurityException) result;
    } else if (result instanceof Throwable) {
      myLogger.log(Logger.WARNING, "Unexpected error processing NEW_NODE command. Node is " + dsc.getName(), (Throwable) result);
    }
  }
 
  private void issueNewSliceCommand(String serviceName, String sliceKey) {
    GenericCommand gCmd = new GenericCommand(Service.NEW_SLICE, serviceName, null);
    gCmd.addParam(sliceKey);
    Object result = myCommandProcessor.processIncoming(gCmd);
    if (result instanceof Throwable) {
      myLogger.log(Logger.WARNING, "Unexpected error processing NEW_SLICE command. Service is " + serviceName + " node is " + sliceKey, (Throwable) result);
    }
  }
 
  private boolean isLocalNode(Node n) {
    try {
      return myIMTPManager.getLocalNode().equals(n);
    } catch (IMTPException imtpe) {
      // Should never happen
      imtpe.printStackTrace();
      return false;
    }
  }

  private NodeDescriptor adjustDescriptor(NodeDescriptor dsc) {
    NodeDescriptor originalDsc = (NodeDescriptor) nodes.get(dsc.getName());
    if (originalDsc != null) {
      ContainerID cid = originalDsc.getContainer();
      if (cid != null) {
        dsc = new NodeDescriptor(cid, dsc.getNode());
      }
      dsc.setParentNode(originalDsc.getParentNode());
    }
    return dsc;
  }

  private List getAllNodesInfo() {
    // Get all node descriptors and build the list of NodeInfo
    Object[] allNodes = nodes.values().toArray();
    List infos = new ArrayList(allNodes.length);
    for (int i = 0; i < allNodes.length; ++i) {
      NodeDescriptor nodeDsc = (NodeDescriptor) allNodes[i];
      infos.add(new NodeInfo(nodeDsc));
    }

    // Build the map of services for each node
    Map nodeServices = new HashMap();
    // Avoid concurrent modification exception
    Object[] allServices = services.values().toArray();
    for (int j = 0; j < allServices.length; ++j) {
      ServiceEntry e = (ServiceEntry) allServices[j];
      Node[] serviceNodes = e.getNodes();

      for (int i = 0; i < serviceNodes.length; i++) {
        String nodeName = serviceNodes[i].getName();

        Vector v = (Vector) nodeServices.get(nodeName);
        if (v == null) {
          v = new Vector();
          nodeServices.put(nodeName, v);
        }
        Service svc = e.getService();
        v.addElement(new ServiceDescriptor(svc.getName(), svc));
      }
    }

    // Now fill the services in the list of NodeInfo
    Iterator it = infos.iterator();
    while (it.hasNext()) {
      NodeInfo ni = (NodeInfo) it.next();
      Vector v = (Vector) nodeServices.get(ni.getNodeDescriptor().getName());
      ni.setServices(v);
    }
    return infos;
  }

  private Node[] getChildren(String name) {
    List children = new ArrayList();
    Object[] allNodes = nodes.values().toArray();
    for (int i = 0; i < allNodes.length; i++) {
      NodeDescriptor dsc = (NodeDescriptor) allNodes[i];
      Node parent = dsc.getParentNode();
      if (parent != null && name.equals(parent.getName())) {
        children.add(dsc.getNode());
      }
    }
    Node[] childrenArray = new Node[children.size()];
    for (int i = 0; i < childrenArray.length; ++i) {
      childrenArray[i] = (Node) children.get(i);
    }
    return childrenArray;
  }

  private void checkExistence(Node node) {
    // FIXME: To be implemented
  }
 
  private void adjustName(NodeDescriptor dsc, Node node) {
    ContainerID cid = dsc.getContainer();
    if (cid != null) {
      // If the node hosts a container, use the container naming convention
      adjustContainerName(node, cid);
      node.setName(cid.getName());
      dsc.setName(cid.getName());
    } else {
      // Otherwise use the node naming convention unless a custom name is specified
      if (node.getName() == null || node.getName().equals(NO_NAME)) {
        String name = null;
        NodeDescriptor old = null;
        do {
          name = AUX_NODE_NAME + '-' + nodeNo;
          nodeNo++;
          old = (NodeDescriptor) nodes.get(name);
        } while (old != null);
        node.setName(name);
      }
      dsc.setName(node.getName());
    }
  }

  private void adjustContainerName(Node n, ContainerID cid) {
    String name = null;
    NodeDescriptor old = null;
    if (n.hasPlatformManager()) {
      cid.setMain(new Boolean(true));
    }else{
      cid.setMain(new Boolean(false));
    }
   
    if (cid.getName() == null || cid.getName().equals(NO_NAME)) {
      if (n.hasPlatformManager()) {
        // Use the Main-Container-<N> name schema
        do {
          name = AgentContainer.MAIN_CONTAINER_NAME + (mainContainerNo == 0 ? "" : "-" + mainContainerNo);
          mainContainerNo++;
          old = (NodeDescriptor) nodes.get(name);
         
        } while (old != null);
      } else {
        do {
          name = AgentContainer.AUX_CONTAINER_NAME + '-' + containerNo;
          containerNo++;
          old = (NodeDescriptor) nodes.get(name);
        } while (old != null);
      }
      cid.setName(name);
    } else {
      // The new container comes with a user defined name.
      // If it is already in use add a progressive number
     
      name = cid.getName();
      int cnt = 1;
      old = (NodeDescriptor) nodes.get(name);
      while (old != null) {
        name = cid.getName() + '-' + cnt;
        cnt++;
        old = (NodeDescriptor) nodes.get(name);
      }
      cid.setName(name);
     
    }
  }

  private void monitor(NodeDescriptor dsc) {
    boolean needMonitor = true;
    Node node = dsc.getNode();
    Node parent = dsc.getParentNode();
    if (parent != null) {
      // This is a child node --> Do not monitor it directly if the parent is already monitored or is the local node
      if (isLocalNode(parent)) {
        needMonitor = false;
      }
      else {
        NodeFailureMonitor failureMonitor = (NodeFailureMonitor) monitors.get(parent.getName());
        if (failureMonitor != null) {
          failureMonitor.addChild(node);
          if (myLogger.isLoggable(Logger.CONFIG)) {
            myLogger.log(Logger.INFO, "Node <" + node.getName() + "> added as child of node " + parent.getName());
          }
          needMonitor = false;
        }
      }
    }
    if (needMonitor) {
      monitor(node);
    }
  }

  private NodeFailureMonitor monitor(Node target) {

    NodeEventListener listener = new NodeEventListener() {

      public void nodeAdded(Node n) {
        myLogger.log(Logger.INFO, "--- Node <" + n.getName() + "> ALIVE ---");
      }

      public void nodeRemoved(Node n) {
        removeTerminatedNode(n);
      }

      public void nodeUnreachable(Node n) {
        myLogger.log(Logger.WARNING, "--- Node <" + n.getName() + "> UNREACHABLE ---");
      }

      public void nodeReachable(Node n) {
        myLogger.log(Logger.INFO, "--- Node <" + n.getName() + "> REACHABLE ---");
      }

    };

    // Start a new node failure monitor
    NodeFailureMonitor failureMonitor = NodeFailureMonitor.getFailureMonitor();
    failureMonitor.start(target, listener);
    monitors.put(target.getName(), failureMonitor);

    return failureMonitor;
  }

  private void removeTerminatedNode(Node n) {
    if (myLogger.isLoggable(Logger.INFO)) {
      myLogger.log(Logger.INFO, "--- Node <" + n.getName() + "> TERMINATED ---");
    }

    try {
      removeNode(new NodeDescriptor(n), false);
    } catch (IMTPException imtpe) {
      // Should never happen since this is a local call
      imtpe.printStackTrace();
    } catch (ServiceException se) {
      // There is nothing we can do
      se.printStackTrace();
    }
  }

  /**
   Inner class NodeInfo.
   Embeds the node descriptor and the services currently installed
   on the node
   */
  private class NodeInfo {
    private NodeDescriptor nodeDsc;

    private Vector services;

    private NodeInfo(NodeDescriptor nd) {
      nodeDsc = nd;
    }

    public NodeDescriptor getNodeDescriptor() {
      return nodeDsc;
    }

    public Vector getServices() {
      return services;
    }

    public void setServices(Vector ss) {
      services = ss;
    }
  } // END of inner class NodeInfo
 
 
  // For debugging purpose only
  Map getServicesMap() {
    return services;
  }
 
  Map getReplicasMap() {
    return replicas;
  }

  Map getNodesMap() {
    return nodes;
  }

  Map getMonitorsMap() {
    return monitors;
  }
}
TOP

Related Classes of jade.core.PlatformManagerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.