fr.dyade.aaa.agent.Channel Maven / Gradle / Ivy
Show all versions of a3-rt Show documentation
/* * Copyright (C) 2001 - 2023 ScalAgent Distributed Technologies * Copyright (C) 1996 - 2000 BULL * Copyright (C) 1996 - 2000 INRIA * * 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; either * version 2.1 of the License, or any later version. * * 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 fr.dyade.aaa.agent; import java.io.IOException; import java.util.Vector; import org.objectweb.util.monolog.api.BasicLevel; import org.objectweb.util.monolog.api.Logger; import fr.dyade.aaa.common.Debug; /** * Class
. The messages are only validated in queues after * the commit of transaction. *Channel
realizes the interface for sending messages. * It defines function member SendTo to send a notification to an identified * agent.* Notifications are then routed to a message queue where they are * stored in chronological order. The Channel object is responsible for * localizing the target agent. */ public class Channel { static Channel channel = null; /** * Creates a new instance of channel (result depends of server type). * * @return the corresponding
Channel
's instance. * @throws Exception an error occurs. */ static Channel newInstance() throws Exception { String cname = AgentServer.getProperty("Channel", "fr.dyade.aaa.agent.Channel"); Class> cclass = Class.forName(cname); channel = (Channel) cclass.newInstance(); return channel; } protected Logger logmon = null; /** * Constructs a newChannel
object (can only be used by * subclasses). */ protected Channel() { consumers = new Vector<>(); // Get the logging monitor from current server MonologLoggerFactory logmon = Debug.getLogger(Channel.class.getName() + ".#" + AgentServer.getServerId()); logmon.log(BasicLevel.DEBUG, toString() + " created."); } // Temporary list of consumers involved in the current transaction and requiring a validate. static Vectorconsumers = null; /** * Sends a notification to an agent. It may be used anywhere, * from any object and any thread. However it is best practice to call * the sendTo
function defined in classAgent
from * an agent code executed during a reaction.* The destination agent receives the notification with a declared null * source agent id, which may be recognized using the
isNullId
* function of classAgentId
. * This is not true when this call is performed during an standard agent * reaction. In that case the current reacting agent, known by the engine, * is provided as source agent.* The notification is immediately validated, that is made persistent, * if it is not sent from an agent reaction. * Be careful, does not use this method in the engine thread, sometime * engine.agent is null and it throws a NullPointerException. * * @param to destination agent. * @param not notification. */ public final static void sendTo(AgentId to, Notification not) { // try { // EngineThread thread = (EngineThread) Thread.currentThread(); // // Use the engine's sendTo method that push message in temporary queue // // until the end of current reaction. // thread.engine.push(AgentServer.engine.agent.getId(), to, not); // } catch (ClassCastException exc) { // // Be careful, the destination node use the from.to field to // // get the from node id. // channel.directSendTo(AgentId.localId, to, not); // } // if (Class.EngineThread.isAssignable(Thread.currentThread())) { AgentServer.engine.push(to, not); } /** * Adds a message in "ready to deliver" list of right consumer. This method * set the logical date of message, push it in the corresponding queue, and * save it. * * @param msg The message to deliver. * @throws Exception an error occurs. */ static final void post(Message msg) throws Exception { try { MessageConsumer cons = AgentServer.getConsumer(msg.to.getTo()); if (! consumers.contains(cons)) { consumers.add(cons); } cons.post(msg); } catch (UnknownServerException exc) { channel.logmon.log(BasicLevel.ERROR, channel.toString() + ", can't post message: " + msg, exc); if ((msg.from != null) && (msg.from.stamp != AgentId.NullIdStamp)) post(Message.alloc(AgentId.localId, msg.from, new UnknownAgent(msg.to, msg.not))); } } static final void postAndValidate(Message msg) throws Exception { try { MessageConsumer cons = AgentServer.getConsumer(msg.to.getTo()); cons.postAndValidate(msg); } catch (UnknownServerException exc) { channel.logmon.log(BasicLevel.ERROR, channel.toString() + ", can't post message: " + msg, exc); if ((msg.from != null) && (msg.from.stamp != AgentId.NullIdStamp)) post(Message.alloc(AgentId.localId, msg.from, new UnknownAgent(msg.to, msg.not))); } } /** * Save state of all modified consumer. * @throws IOException an error occurs. */ static final void save() throws IOException { for (int i=0; i
Engine
* Be careful, this method must only be used during a transaction in * order to ensure the mutual exclusion. * * @see Engine#commit() */ static final void validate() { for (int i=0; iMessageConsumer. * Does not queue the notification in the local message queue. * Normally used uniquely in
sendTo
method. * * This function is designed to be indirectly used by secondary threads, * such asDriver
s. * * @param from source agent. * @param to destination agent. * @param not notification. */ void directSendTo(AgentId from, AgentId to, Notification not) { MessageConsumer consumer = null; Message msg = null; if (logmon.isLoggable(BasicLevel.DEBUG)) logmon.log(BasicLevel.DEBUG, toString() + ".directSendTo(" + from + ", " + to + ", " + not + ")"); if ((to == null) || to.isNullId()) return; msg = Message.alloc(from, to, not); try { consumer = AgentServer.getConsumer(to.to); } catch (UnknownServerException exc) { channel.logmon.log(BasicLevel.ERROR, toString() + ", can't post message: " + msg, exc); // TODO: Post an ErrorNotification ? return; } try { if (AgentServer.engine.isNoTxIfTransient() && msg.not != null && msg.not.persistent == false) { consumer.postAndValidate(msg); } else { AgentServer.getTransaction().begin(); consumer.post(msg); // if (AgentServer.sdf != null) { // // SDF generation // StringBuffer strbuf = new StringBuffer(); // strbuf.append("\n"); // strbuf.append(" \n"); // // AgentServer.sdf.println(strbuf.toString()); // } // // if (AgentServer.logsdf.isLoggable(BasicLevel.INFO)) // AgentServer.logsdf.log(BasicLevel.INFO, // " sendto " + msg.to + ' ' + StringId.toStringId('N', '_', msg.getSource(), msg.getDest(), msg.getStamp())); if (logmon.isLoggable(BasicLevel.DEBUG)) logmon.log(BasicLevel.DEBUG, toString() + ".directSendTo() -> " + msg.getStamp()); consumer.save(); AgentServer.getTransaction().commit(false); // then commit and validate the message. consumer.validate(); AgentServer.getTransaction().release(); } } catch (Exception exc) { // Should never happened (IOException or ClassNotFoundException). logmon.log(BasicLevel.FATAL, toString() + ", Transaction problem.", exc); throw new TransactionError(toString() + ", " + exc.getMessage()); } } /** * Returns a string representation of this").append(msg.not).append(" \n" + "Channel
object. * * @return A string representation of this object. */ public final String toString() { StringBuffer strbuf = new StringBuffer(); strbuf.append("Channel#").append(AgentServer.getServerId()); return strbuf.toString(); } }