/***************************************************************** 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.leap.Serializable; /** The <code>Service</code> interface represents a centralized view of a JADE kernel-level service. Most JADE services are actually distributed, and each part of theirs, that is deployed at a given network node (container), is called <em>service slice</em>. The various slices of a service work together to carry out that service's task. @author Giovanni Rimassa - FRAMeTech s.r.l. */ public interface Service { /** Service independent vertical command issued on the Main container whenever a new node is added */ public static final String NEW_NODE = "New-Node"; /** Service independent vertical command issued on the Main container whenever a node is removed */ public static final String DEAD_NODE = "Dead-Node"; /** Service independent vertical command issued on the Main container whenever a node that was monitored by a Main container replica is adopted (i.e. the local Main container starts monitoring it) */ public static final String ADOPTED_NODE = "Adopted-Node"; /** Service independent vertical command issued on the Main container whenever a new slice of a given service is added */ public static final String NEW_SLICE = "New-Slice"; /** Service independent vertical command issued on the Main container whenever a slice of a given service is removed */ public static final String DEAD_SLICE = "Dead-Slice"; /** Service independent vertical command issued on the Main container whenever a new main replica is added */ public static final String NEW_REPLICA = "New-Replica"; /** Service independent vertical command issued on the Main container whenever a main replica is removed */ public static final String DEAD_REPLICA = "Dead-Replica"; /** Service independent vertical command issued on a peripheral container when a fault of the PlatformManager is detected */ public static final String DEAD_PLATFORM_MANAGER = "Dead-Platform-Manager"; /** Service independent vertical command issued on a peripheral container when it re-attaches to a recovered Main Container */ public static final String REATTACHED = "Reattached"; /** Service independent vertical command issued on a peripheral container when it reconnects to a new master Main Container */ public static final String RECONNECTED = "Reconnected"; /** The <code>Slice</code> nested interface represents that part of a service that is deployed at a given network node. */ public interface Slice extends Serializable { /** Access the service object which this slice is a part of. @return A <code>Service</code> object, that has <code>this</code> as one of its slices. @see jade.core.Service#getSlice(String name) */ Service getService(); /** Access the node where this slice resides. @returns The node where this service slice is actually running. @throws ServiceException If some problems occur in retrieving the local node. */ Node getNode() throws ServiceException; /** Serves an incoming horizontal command, performing any required immediate processing, before turning it into a vertical command to be processed by the incoming filter chain. @param cmd The command that is to be served. @return A vertical command, that will be processed by the incoming filter chain of the receiving node. If <code>null</code> is returned, no filter/sink processing will happen. This feature can be used to decouple incoming horizontal interaction patterns from vertical incoming commands (e.g. no incoming vertical command is generated until a required set of horizontal commands has been received). */ VerticalCommand serve(HorizontalCommand cmd); } //#APIDOC_EXCLUDE_BEGIN //#DOTNET_EXCLUDE_BEGIN // 15/4/05 We had to deprecate this class because of the .NET integration /** An implementation of the <code>Slice</code> interface, supporting routed dispatching of horizontal commands. @deprecated use the class jade.core.SliceProxy instead of this inner class */ public class SliceProxy extends jade.core.SliceProxy implements Slice { public SliceProxy() { super(); } public SliceProxy(Service svc, Node n) { super(svc, n); } /*public SliceProxy() { this(null, null); } public SliceProxy(Service svc, Node n) { myService = svc; myNode = n; } public Service getService() { return myService; } public Node getNode() throws ServiceException { return myNode; } public void setNode(Node n) { myNode = n; }*/ /** Try to serve an incoming horizontal command, routing it to a remote slice implementation. @param cmd The command to serve, possibly through the network. * public VerticalCommand serve(HorizontalCommand cmd) { try { cmd.setReturnValue(myNode.accept(cmd)); } catch(IMTPException imtpe) { cmd.setReturnValue(new ServiceException("An error occurred while routing the command to the remote implementation", imtpe)); } // No local processing of this command is required return null; } private Node myNode; private transient Service myService; */ } //#DOTNET_EXCLUDE_END //#APIDOC_EXCLUDE_END /** Retrieve the name of this service, that can be used to look up its slices in the Service Finder. @return The name of this service. @see jade.core.ServiceFinder */ String getName(); /** Retrieve by name a slice of this service. For distributed services, the returned slice will generally be some kind of proxy object to the real, remote slice. The actual proxy management policy (caching, reconnection, etc.) is decided by concrete services. @param name A name for the requested slice. The name must be unique within this service. @return The <code>Slice<code> object that is a part of this service and is identified by the given name, or <code>null</code> if no such slice exists. @throws ServiceException If some underlying error (e.g. a network problem) occurs, that does not allow to decide whether the requested slice exists or not. */ Slice getSlice(String name) throws ServiceException; /** Retrieve the locally installed slice of this service. A service without horizontal interfaces can safely return <code>null</code> from this method. @return The slice of this service that resides on the local platform node, or <code>null</code> if no such slice exists. */ Slice getLocalSlice(); /** Retrieve the whole array of slices that compose this service. @return An array of <code>Service.Slice</code> objects, whose elements are the slices of this service deployed at the different platform nodes. @throws ServiceException If some underlying error (e.g. a network problem) occurs, that does not allow to retrieve the full slice list. */ Slice[] getAllSlices() throws ServiceException; /** Retrieve the interface through which the different service slices will communicate, that is, the service <i>Horizontal Interface</i>. @return A <code>Class</code> object, representing the interface that is implemented by the slices of this service. Let <code>s</code> be the <code>Class</code> object corresponding to the <code>Service.Slice</code> interface, and let <code>c</code> be the returned <code>Class</code> object. Then, the two following conditions must hold: <ol> <li><code>c.isInterface() == true</code></li> <li><code>s.isAssignableFrom(c) == true</code></li> </ol> */ Class getHorizontalInterface(); /** Query by how many slices this service is composed at present. @return The number of slices belonging to this service. An active service must have at least one slice. */ int getNumberOfSlices(); /** Access the command filter this service needs to perform its tasks. This filter will be installed within the local command processing engine. Note that when called multiple times with the same value of the <code>direction</code> parameter this method MUST always return the same object! @param direction One of the two constants <code>Filter.INCOMING</code> and <code>Filter.OUTGOING</code>, distinguishing between the two filter chains managed by the command processor. @return A <code>Filter</code> object, used by this service to intercept and process kernel-level commands. If the service does not wish to install a command filter for one or both directions, it can just return <code>null</code> when appropriate. @see jade.core.CommandProcessor */ Filter getCommandFilter(boolean direction); /** Access the command sink this service uses to handle its own vertical commands. @param side One of the two constants <code>Sink.COMMAND_SOURCE</code> or <code>Sink.COMMAND_TARGET</code>, to state whether this sink will handle locally issued commands or commands incoming from remote nodes. @return Concrete services must return their own implementation of the <code>Sink</code> interface, that will be invoked by the kernel in order to consume any incoming vertical command owned by this service. If the service does not wish to install a command sink, it can just return <code>null</code>. @see jade.core.Service#getOwnedCommands() */ Sink getCommandSink(boolean side); /** Access the names of the vertical commands this service wants to handle as their final destination. This set must not overlap with the owned commands set of any previously installed service, or an exception will be raised and service activation will fail. @return An array containing the names of all the vertical commands this service wants to own. If this service has no such commands (it acts purely as a command filter), it can return an empty array, or <code>null</code> as well. @see jade.core.Service#getCommandSink() */ String[] getOwnedCommands(); /** Get the helper for accessing this service. @param a The agent which the helper is requested for. @return The ServiceHelper to be used by the agent. @see AgentToolkit#getHelper @see Agent#getHelper */ ServiceHelper getHelper(Agent a) throws ServiceException; /** Retrieve a behaviour that is associated with this service, and that will be deployed within the AMS. Typical uses for this behaviour will be to handle a service-specific ontology and actions. @return A <code>Behaviour</code> object associated with this service, or <code>null</code> if no such behaviour exists. */ Behaviour getAMSBehaviour(); /** Performs the passive initialization step of the service. This method is called <b>before</b> activating the service. Its role should be simply the one of a constructor, setting up the internal data as needed. Service implementations should not use the Service Manager and Service Finder facilities from within this method. A distributed initialization protocol, if needed, should be exectuted within the <code>boot()</code> method. @param ac The agent container this service is activated on. @param p The configuration profile for this service. @throws ProfileException If the given profile is not valid. */ void init(AgentContainer ac, Profile p) throws ProfileException; /** Performs the active initialization step of a kernel-level service. When JADE kernel calls this method, the service has already been already associated with its container and registered with the Service Manager. @param p The configuration profile for this service. @throws ServiceException If a problem occurs during service initialization. */ void boot(Profile p) throws ServiceException; /** Performs the shutdown step of a kernel-level service. The JADE kernel calls this method just before uninstalling this service */ void shutdown(); /** Allows submitting a vertical command for processing. The given vertical command must be owned by this service (i.e. its name must be one of the constants contained in the array returned by <code>getOwnedCommands()</code>, or an exception is thrown @param cmd The command to submit to the service. @return The result of the command, or <code>null</code> if this command produced no result. If an exception was produced, it will not be thrown, but will be returned as well. @throws ServiceException If the passed command does not belong to this service. */ Object submit(VerticalCommand cmd) throws ServiceException; }