KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > presumo > mobileagent > Agent


1 /**
2  * This file is part of Presumo.
3  *
4  * Presumo is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * Presumo is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Presumo; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  *
19  * Copyright (c) 2001 Dan Greff
20  */

21 package com.presumo.mobileagent;
22
23 import com.presumo.util.log.Logger;
24 import com.presumo.util.log.LoggerFactory;
25
26 import java.io.BufferedReader JavaDoc;
27 import java.io.InputStreamReader JavaDoc;
28 import java.io.Serializable JavaDoc;
29
30 import java.util.Vector JavaDoc;
31
32 import javax.jms.ExceptionListener JavaDoc;
33 import javax.jms.Topic JavaDoc;
34 import javax.jms.TopicConnection JavaDoc;
35 import javax.jms.TopicSession JavaDoc;
36 import javax.jms.TopicSubscriber JavaDoc;
37 import javax.jms.TopicPublisher JavaDoc;
38 import javax.jms.Message JavaDoc;
39 import javax.jms.MessageListener JavaDoc;
40 import javax.jms.ObjectMessage JavaDoc;
41 import javax.jms.JMSException JavaDoc;
42 import javax.jms.Session JavaDoc;
43
44
45 /**
46  * A very rough base class for mobile agents thrown together
47  * to support Presumo's test framework.
48  * <p>
49  * Currently your Agent implementation must be in the CLASSPATH
50  * of the JVM your agent moves to.
51  * <p>
52  * <note>
53  * It would be relativly trivial to have the Agent run
54  * against a ClassLoader running over JMS to remove this restriction.
55  * If you are reading this with interest in using MobileAgents
56  * over JMS contact the project admins at www.presumo.com and
57  * request the feature, or (if you are capable of doing so)
58  * volunteer to do it yourself and join the project. ;) DTG
59  * </note>
60  *
61  * @author Dan Greff
62  */

63 public abstract class Agent implements Serializable JavaDoc, Runnable JavaDoc
64 {
65   /** Topic name for which all agent JMS traffic runs across. **/
66   public static final String JavaDoc AGENT_TOPIC = "MobileAgentAdmin";
67   
68   /** Message property name for Runner targets a Agent is sent to. **/
69   public static final String JavaDoc RUNNER_PROP = "RunnerTargets";
70   
71   /** Message property name used to indicate a Runner identifier. **/
72   public static final String JavaDoc RUNNER_NAME = "RunnerName";
73   
74   /** Message property name used to indicate the type of message. **/
75   public static final String JavaDoc MESSAGE_TYPE = "AgentMessageType";
76   
77   public static final int AGENT_MOVE = 0;
78   public static final int AGENT_START = 1;
79   public static final int AGENT_STOP = 2;
80   public static final int RUNNER_QUERY = 3;
81   public static final int QUERY_RESPONSE = 4;
82
83   
84   /** Means by which the agent communicates witht he JMS layer **/
85   protected transient TopicConnection JavaDoc connx;
86   protected transient TopicSession JavaDoc agentSession;
87   private transient Topic JavaDoc agentTopic;
88
89     /////////////////////////////////////////////////////////////////////////
90
// Constructors //
91
/////////////////////////////////////////////////////////////////////////
92

93   /**
94    * Default constructor needed only for deserialization. When subclassing
95    * agent you must make sure <code>agentSession</code> is set.
96    */

97   public Agent()
98   {
99     logger.entry("Agent");
100     logger.exit("Agent", this);
101   }
102   
103   /**
104    * Preferred Constructor to invoke when subclassing. If you do not invoke
105    * this Constructor you must ensure that <code>agentSession</code> is set.
106    */

107   public Agent(TopicConnection JavaDoc connx)
108   {
109     logger.entry("Agent", connx);
110     setConnection(connx);
111     logger.exit("Agent", this);
112   }
113   
114     ///////////////////////////////////////////////////////////////////////////
115
// Public Methods //
116
///////////////////////////////////////////////////////////////////////////
117

118   /**
119    * Move the agent to the specified <code>AgentRunner</code>.
120    */

121   public void moveTo(String JavaDoc runnerName) throws JMSException JavaDoc
122   {
123     logger.entry("moveTo", runnerName);
124     moveTo(new String JavaDoc [] { runnerName });
125     logger.exit("moveTo");
126   }
127   
128   /**
129    * Broadcast the agent to all the specivied <code>AgentRunner</code>.
130    */

131   public synchronized void moveTo(String JavaDoc [] runnerNames)
132     throws JMSException JavaDoc
133   {
134     logger.entry("moveTo", runnerNames);
135     TopicPublisher JavaDoc publisher = agentSession.createPublisher(agentTopic);
136     try {
137       Message JavaDoc msg = createRunnerMoveMessage(runnerNames);
138       publisher.publish(msg);
139     } finally {
140       publisher.close();
141     }
142     logger.exit("moveTo");
143   }
144   
145   
146   /**
147    * Get all <code>AgentRunner</code>'s available to run Agents.
148    */

149   public synchronized String JavaDoc [] getAvailableRunners(long timeout)
150     throws JMSException JavaDoc
151   {
152     logger.entry("getAvailableRunners", new Long JavaDoc(timeout));
153
154     TopicSubscriber JavaDoc sub = null;
155     TopicPublisher JavaDoc pub = null;
156     Vector JavaDoc runners = new Vector JavaDoc();
157
158     try {
159       sub = createQueryResponseReceiver();
160       pub = agentSession.createPublisher(agentTopic);
161       pub.publish( createQueryMessage() );
162
163       
164       long start = System.currentTimeMillis();
165       long diff = 0;
166       while(diff < timeout) {
167         Message JavaDoc msg = sub.receive(timeout - diff);
168         if (msg != null) {
169           String JavaDoc name = (String JavaDoc) msg.getObjectProperty(RUNNER_NAME);
170           logger.debug("----> Found runner: " + name);
171           if (name != null && !runners.contains(name)) {
172             runners.add(name);
173           }
174         }
175         diff = System.currentTimeMillis() - start;
176       }
177     } finally {
178       if (sub != null) sub.close();
179       if (pub != null) pub.close();
180     }
181     
182     String JavaDoc [] retval = new String JavaDoc[runners.size()];
183     runners.toArray(retval);
184     
185     logger.exit("getAvailableRunners", retval);
186     return retval;
187   }
188   
189   /**
190    * Used by the AgentRunner to set the Agent's TopicConnection after it is
191    * deserialized.
192    */

193   public void setConnection(TopicConnection JavaDoc connx)
194   {
195     logger.entry("setConnection", connx);
196
197     try {
198       this.connx = connx;
199       agentSession = connx.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
200       agentTopic = agentSession.createTopic(AGENT_TOPIC);
201     } catch (JMSException JavaDoc jmsex) {
202       logger.exception(jmsex);
203     }
204
205     logger.exit("setConnection");
206   }
207
208   /**
209    * Implement this method if you want your agent to do special processing
210    * in response to a start broadcast. If you want your processing to
211    * start as soon as the agent is moved simply perform all work when the
212    * run() method is called.
213    *
214    * <note>Do not do much processing in the thread calling this method.
215    * instead a spin lock should be used to wake up thre Thread executing
216    * the run method.
217    * </note>
218    */

219   public abstract void startAgent();
220
221   /**
222    * Implement this method if you want your agent to do something when
223    * a stop is broadcast.
224    *
225    * <note>Implementations should cause the Thread executing your run()
226    * implementation to finish and return from the method gracefully.
227    * </note>
228    */

229   public abstract void stopAgent();
230
231
232   public abstract void runAgent();
233   
234   public final void run()
235   {
236     logger.entry("run");
237
238     runAgent();
239
240     if (agentSession != null) {
241       try {
242         agentSession.close();
243       } catch (JMSException JavaDoc jmsex) {
244         logger.exception(jmsex);
245       }
246     }
247
248     logger.exit("run");
249   }
250     ///////////////////////////////////////////////////////////////////////////
251
// Package Methods //
252
///////////////////////////////////////////////////////////////////////////
253
// None //
254
//////////
255

256     ///////////////////////////////////////////////////////////////////////////
257
// Protected Methods //
258
///////////////////////////////////////////////////////////////////////////
259

260   /**
261    * Encapsulates the creation of a message to move the Agent instance.
262    *
263    * @param runnerTargets All targets for which the Agent is destined.
264    *
265    * @return A JmsMessage containing a serialized instance of <code>this</code>
266    * Agent instance, and all necessary message properties to ensure
267    * the message is correctly received by all <code>AgentRunners</code>
268    */

269   protected Message JavaDoc createRunnerMoveMessage(String JavaDoc [] runnerTargets)
270           throws JMSException JavaDoc
271   {
272     logger.entry("createRunnerMoveMessage", runnerTargets);
273
274     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
275     for (int i=0; i < runnerTargets.length; ++i) {
276       buf.append(runnerTargets[i]);
277       if (i < (runnerTargets.length-1)) buf.append(';');
278     }
279       
280     ObjectMessage JavaDoc msg = agentSession.createObjectMessage(this);
281     msg.setIntProperty(MESSAGE_TYPE, AGENT_MOVE);
282     msg.setStringProperty(RUNNER_PROP, buf.toString());
283
284     logger.exit("createRunnerMoveMessage", msg);
285     return msg;
286   }
287   
288   
289   /**
290    * Encapsulates the creation of a message sent to request all runners to
291    * send their names.
292    */

293   protected Message JavaDoc createQueryMessage() throws JMSException JavaDoc
294   {
295     logger.entry("createQueryMessage");
296
297     Message JavaDoc msg = agentSession.createMessage();
298     msg.setIntProperty(MESSAGE_TYPE, RUNNER_QUERY);
299
300     logger.exit("createQueryMessage", msg);
301     return msg;
302   }
303
304   
305   /**
306    * Encapsulates creating a subscriber with the necessary filters to
307    * ensure retrieval of all responses to the query.
308    */

309   protected TopicSubscriber JavaDoc createQueryResponseReceiver() throws JMSException JavaDoc
310   {
311     logger.entry("createQueryResponseReceiver");
312     
313     StringBuffer JavaDoc filter = new StringBuffer JavaDoc();
314     filter.append(MESSAGE_TYPE);
315     filter.append("=");
316     filter.append(QUERY_RESPONSE);
317     
318     TopicSubscriber JavaDoc sub =
319       agentSession.createSubscriber(agentTopic, filter.toString(), false);
320
321     logger.exit("createqueryResponseReceiver", sub);
322     return sub;
323   }
324   
325
326
327   ////////////////////////////// Misc stuff ////////////////////////////////
328

329   private static Logger logger = LoggerFactory.getLogger(Agent.class, null);
330
331   ///////////////////////////////////////////////////////////////////////////
332

333 }
334
Popular Tags