1 /*********************************************************************
2 Copyright 2012, Ralph Ronnquist.
4 This file is part of GORITE.
6 GORITE is free software: you can redistribute it and/or modify it
7 under the terms of the Lesser GNU General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GORITE is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the Lesser GNU General Public
17 License along with GORITE. If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
20 package com.intendico.gorite.addon;
22 import com.intendico.gorite.*;
23 import java.util.Hashtable;
27 * This is a {@link Capability} (type) that provides a simple
28 * inter-model messaging service within a single JVM. It uses the
29 * {@link Performer#getName()} method of the containing {@link
30 * Performer} as messaging end point identity. The idea is that all
31 * communicating performers are set up to have their own instance of
32 * this capability type. The following is an example of use, with a
33 * receive plan outline:
36 * new Performer( "morgan" ) {{
37 * addCapability( new BellBoy() );
38 * addPlan( new Plan( BellBoy.RECV, new Goal [] {
39 * .... deal with received message in "percept"
44 * <p><i>Sending Messages</i>
46 * <p> The capability handles a {@link #SEND "Send BellBoy message"}
47 * {@link Goal goal}, with {@link #MSG "bellboy message"} holding a
48 * {@link BellBoy.Envelope message envelope}, by delivering that
49 * message to the {@link Envelope#getWhom() indicated recipient}.
51 * <p> Sending can also be done directly in Java code by using the
52 * static {@link BellBoy#send(Envelope)} or {@link
53 * BellBoy#send(String,Object)} methods.
55 * <p><i>Receiving Messages</i>
57 * <p> Upon receiving a message, the capability triggers a {@link
58 * #RECV "Got BellBoy message"} {@link BDIGoal} goal, on the {@link
59 * #TODO "bellboy"} {@link com.intendico.gorite.Performer.TodoGroup
60 * TodoGroup} and with {@link Perceptor#data_name "percept"} holding
63 * <p> Reception can also be triggered in Java code by using the
64 * {@link #receive(Object)} method.
68 * <p>Messages are delivered through in-core sharing, and they are not
69 * copied! <b>Not copied!</b> This means that the sender and receiver
70 * end up sharing the one message object. In proper use, the sender
71 * should release all its handles to the message object after having
72 * sent it. The capability supports this by {@link
73 * Data#forget(String) forgetting} {@link #MSG "bellboy message"}
74 * after having sent the message.
76 public class BellBoy extends Capability {
79 * The interface for standard BellBoy messages.
81 public interface Envelope {
83 * Returns message recipient identity.
85 public String getWhom();
88 * Returns the message payload, i.e., the "actual" message.
90 public Object getPayload();
94 * Convenience constant for the send goal.
96 public final static String SEND = "Send BellBoy message";
99 * Convenience constant for the receive goal.
101 public final static String RECV = "Got BellBoy message";
104 * Convenience constant for the send goal data element.
106 public final static String MSG = "bellboy message";
109 * Convenience constant for BellBoy messaging {@link
110 * com.intendico.gorite.Performer.TodoGroup TodoGroup}.
112 public final static String TODO = "bellboy";
115 * The table of communicating BellBoy instances within this JVM.
117 public static Hashtable/*<String,BellBoy>*/ club =
118 new Hashtable/*<String,BellBoy>*/();
121 * The {@link Perceptor} for receiving BellBoy messages. This is
122 * set up by the {@link #initialize()}, which is invoked
123 * automatically by GORITE. The installed {@link Perceptor}
124 * triggers {@link #RECV "Got BellBoy message"} goals on the
125 * {@link #TODO "bellboy"} {@link
126 * com.intendico.gorite.Performer.TodoGroup TodoGroup} with the
127 * received messages as the {@link Perceptor#data_name "percept"}
130 public Perceptor recv;
133 * Binds a BellBoy to be a {@link #club} member under a given
134 * name. This replaces any previous binding, and binding
135 * <tt>null</tt> removes the previous binding.
137 public static void bind(String name,BellBoy b) {
139 synchronized ( club ) {
143 synchronized ( club ) {
150 * Returns the BellBoy bound to a given name.
152 public static BellBoy find(String name) {
153 synchronized ( club ) {
154 return (BellBoy) club.get( name );
159 * Returns the names of the current {@link BellBoy#club} members.
161 public static Set/*<String>*/ getMembers() {
162 synchronized ( club ) {
163 return club.keySet();
168 * Creates a standard BellBoy {@link Envelope}.
170 public static Envelope pack(final String whom,final Object what) {
171 return new Envelope() {
172 public String getWhom() {
175 public Object getPayload() {
182 * Receives a message. This causes a percept on the {@link #recv}
183 * {@link Perceptor}. The method returns false if {@link #recv} is
184 * unassigned, otherwise it returns true.
186 public boolean receive(Object m) {
194 * Sends a named recipient a message.
196 public static boolean send(String to,Object message) {
197 BellBoy whom = find( to );
198 return ( whom == null )? false : whom.receive( message );
204 public static boolean send(Envelope m) {
205 return ( m == null )? false : send( m.getWhom(), m.getPayload() );
209 * Initializes the capability with the abilities to send and
210 * receive messages, and then it joins the BellBoy club.
212 * <p> The capability is set up to handle a {@link #SEND "Send
213 * BellBoy message"} {@link Goal goal}, with {@link #MSG "bellboy
214 * message"} holding a {@link BellBoy.Envelope message envelope},
215 * by delivering that message to the {@link Envelope#getWhom()
216 * indicated recipient}.
218 * The goal fails if {@link #MSG "bellboy message"} is null. If
219 * it's non-null but not a {@link BellBoy.Envelope}, then a {@link
220 * ClassCastException} is thrown.
222 * The goal also fails if the {@link BellBoy#club} doesn't include
223 * the desired recipient.
225 public void initialize() {
226 // Prepare to receive messages
227 recv = new Perceptor( getPerformer(), RECV, TODO );
228 // Define ability to send message as goal
229 addGoal( new Goal( SEND ) {
230 public States execute(Data data) {
231 if ( send( (Envelope) data.getValue( MSG ) ) ) {
233 return States.PASSED;
235 return States.FAILED;
239 bind( getPerformer().getName(), this );