Package jade.core

Source Code of jade.core.BaseService

/*****************************************************************
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;


import jade.core.behaviours.Behaviour;
import jade.util.Logger;
import jade.util.leap.HashMap;
import jade.util.leap.Iterator;
import jade.util.leap.Map;

/**
The <code>BaseService</code> abstract class partially implements
the <code>Service</code> interface, providing a simple and uniform
mechanism for slice management and service discovery.
Developers interested in creating JADE kernel level services should
extend <code>BaseService</code> instead of directly implementing the
<code>Service</code> interface
@author Giovanni Rimassa - FRAMeTech s.r.l.
*/
public abstract class BaseService implements Service {
 
  public static final String MAIN_SLICE = ServiceFinder.MAIN_SLICE;
  public static final String THIS_SLICE = ServiceFinder.THIS_SLICE;
 
  public static final String ALL_DUMP_KEY = "ALL";
 
  public void init(AgentContainer ac, Profile p) throws ProfileException {
    myFinder = p.getServiceFinder();
    myIMTPManager = p.getIMTPManager();
   
    slices = new HashMap(5);
    aliases = new HashMap(1);
   
    myLogger.log(jade.util.Logger.INFO, "Service "+getName()+" initialized");
  }
 
  // Package scoped method to receive the Command Processor from the
  // agent container at startup time. The rationale for avoiding
  // passing this to the constructor is to prevent concrete services
  // from accessing the Command Processor (they are less trusted than jade.core).
  // Notice that, for further measure, this method only works the first time it
  // is called.
  void setCommandProcessor(CommandProcessor cp) {
    if(myCommandProcessor == null) {
      myCommandProcessor = cp;
    }
  }
 
 
  /**
   The <code>getSlice()</code> implementation of this class works
   as follows:
   <ol>
   <li><i>First, the name alias table is used to convert the given
   slice name into another name, if any</i></li>
  
   <li><i>Then, the new name (which may or may not be different
   from the original one) is used to look up an internal table
   keeping the service slices</i></li>
  
   <li><i>If no slice was found, the</i>
   <code>ServiceFinder</code> <i>is asked to provide the slice,
   which is then put into the local table.</i></li>
   </ol>
   */
  public Service.Slice getSlice(String name) throws ServiceException {
   
    // First look through the name alias table
    String realName = lookupAlias(name);
   
    // Then look up in the slice table
    Service.Slice s = (Service.Slice)slices.get(realName);
   
    // if there's not a suitable slice, ask the service finder,
    // then cache the result in the slices table.
      if(s == null) {
      try {
        s = myFinder.findSlice(getName(), realName);
        slices.put(realName, s);
      }
      catch(IMTPException imtpe) {
        throw new ServiceException("IMTP Error while using the Service Finder", imtpe);
      }
    }
   
    return s;
   
  }
 
  /**
   This method returns the current number of slices known to this
   service <b>on this node</b>. Due to the distributed nature of
   many JADE services, there is no guaranteed that calling this
   method for the same service on different nodes will actually
   result on the same number.
  
   @return The number of slices of this service that are known to
   this node.
   */
  public int getNumberOfSlices() {
    return slices.size();
  }
 
  public Node getLocalNode() throws IMTPException {
    return myIMTPManager.getLocalNode();
  }
 
  /**
   The <code>getAllSlices()</code> implementation of this class
   directly retrieves the current list of slices from the Service
   Manager. Note that slices are retrieved directly from the Main and not
   from the cache.
   */
  public Service.Slice[] getAllSlices() throws ServiceException {
    try {
      return myFinder.findAllSlices(getName());
    }
    catch(IMTPException imtpe) {
      throw new ServiceException("IMTP Error while using the Service Finder", imtpe);
    }
  }
 
  public void broadcast(HorizontalCommand cmd, boolean includeMyself) throws IMTPException, ServiceException {
    Service.Slice[] slices = myFinder.findAllSlices(getName());
    String localNodeName = getLocalNode().getName();
    for (int i = 0; i < slices.length; i++) {
      Service.Slice s = slices[i];
      String sliceName = s.getNode().getName();
      if (includeMyself || !sliceName.equals(localNodeName)) {
        s.serve(cmd);
        Object ret = cmd.getReturnValue();
        if (ret instanceof Throwable) {
          myLogger.log(Logger.WARNING, "Error propagating H-command " + cmd.getName() + " to slice " + sliceName, ((Throwable) ret));
        }
      }
    }
  }
 
 
  /**
   This protected method allows subclasses to define their own
   naming schemes, by adding aliases for existing slice names.
  
   @param alias The new alias name.
   @param name The real name this alias must be mapped to.
   */
  protected void addAlias(String alias, String name) {
    aliases.put(alias, name);
  }
 
  /**
   This protected method is used by <code>getSlice()</code> to
   dereference aliases for slice names. Subclasses can override
   this method to build their own service-specific naming schema.
  
   @param alias The alias name to map to a real slice name.
   @return A mapped name, or the original one if no mapping was
   found.
   */
  protected String lookupAlias(String alias) {
    String result = (String)aliases.get(alias);
    if(result != null) {
      return result;
    }
    else {
      return alias;
    }
  }
 
  /**
   This should be properly implemented
   by the services that have filters.
   Note that when called multiple times with the same value of the <code>direction</code>
   parameter this method MUST always return the same object!
   */
  public Filter getCommandFilter(boolean direction) {
    return null;
  }
 
  /**
   This should be properly implemented
   by the services that have sinks.
   */
  public Sink getCommandSink(boolean direction) {
    return null;
  }
 
  /**
   This should be properly implemented
   by the services that owns vertival commands.
   */
  public String[] getOwnedCommands() {
    return null;
  }
 
  /**
   This should be properly implemented
   by the services that have non-empty slices.
   */
  public Class getHorizontalInterface() {
    return null;
  }
 
  /**
   This should be properly implemented
   by the services that have non-empty slices.
   */
  public Service.Slice getLocalSlice() {
    return null;
  }
 
  public boolean isLocal() {
    return false;
  }
 
  /**
   This should be properly implemented
   by the services that have helpers.
   */
  public ServiceHelper getHelper(Agent a) throws ServiceException {
    return null;
  }
 
  /**
   This should be properly implemented
   by the services that require a service specific Behaviour
   running in the AMS.
   */
  public Behaviour getAMSBehaviour() {
    return null;
  }
 
  public void boot(Profile p) throws ServiceException {
    // Empty placeholder method
  }
 
  public void shutdown() {
    // Empty placeholder method
  }
 
  public Object submit(VerticalCommand cmd) throws ServiceException {
    String cmdName = cmd.getName();
    String[] ownedCommands = getOwnedCommands();
   
    for(int i = 0; i < ownedCommands.length; i++) {
      if(cmdName.equals(ownedCommands[i])) {
        return myCommandProcessor.processOutgoing(cmd);
      }
    }
   
    throw new ServiceException("Command <" + cmdName + "> does not belong to service <" + getName() + ">");
   
  }
 
  protected Service.Slice getFreshSlice(String name) throws ServiceException {
    clearCachedSlice(name);
    // Get a newer slice and return it
    return getSlice(name);
  }
 
  protected IMTPManager getIMTPManager() {
    return myIMTPManager;
  }

  protected void clearCachedSlice(String name) {
    // slices may be null when calling this method on the Main Container, but on a service not active on the Main Container
    // --> In this case the service has not been initialized.
    if (slices != null) {
      // First look through the name alias table
      String realName = lookupAlias(name);
      // Invalidate the cache entry
      slices.remove(realName);
    }
  }
 
  /**
   * This method can be redefined to support service internal data inspection by means of the ContainerMonitorAgent
   * included in the misc add-on.
   * The default implementation just dumps the map of cached slices
   * @param key A hint indicating which service data should be dumped
   * @return A string representation of the service internal data
   */
  public String dump(String key) {
    if (key == null || key.equals(ALL_DUMP_KEY)) {
      StringBuffer sb = new StringBuffer("LOCAL: ").append(isLocal()).append('\n');
      sb.append("CACHED SLICES:\n");
      Iterator it = slices.keySet().iterator();
      while (it.hasNext()) {
        String name = (String) it.next();
        sb.append("- ").append(name).append(" --> "+stringifySlice((Slice) slices.get(name))).append("\n");
      }
     
      return sb.toString();
    }
    else {
      return "";
    }
  }

  public static final String stringifySlice(Slice s) {
    StringBuffer sb = new StringBuffer("SLICE ");
    try {
      sb.append(s.getClass().getName()).append(": node = "+s.getNode().getName());
    }
    catch (ServiceException se) {
      // Should never happen as this is a local call
      se.printStackTrace();
    }
    return sb.toString();
  }
 
  //#MIDP_EXCLUDE_BEGIN
  protected CallbackInvokator createInvokator() {
    return new CallbackInvokator();
  }
  //#MIDP_EXCLUDE_END
 
  private IMTPManager myIMTPManager;
 
  private CommandProcessor myCommandProcessor = null;
 
  private Map slices;
  private Map aliases;
 
  protected ServiceFinder myFinder;
  protected transient jade.util.Logger myLogger = jade.util.Logger.getMyLogger(getName());
}
TOP

Related Classes of jade.core.BaseService

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.