Source code: mucode/abstractions/MuAgent.java
1 /* mucode - A lightweight and flexible mobile code toolkit
2 * Copyright (C) 2000, Gian Pietro Picco
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 package mucode.abstractions;
19
20 import mucode.util.*;
21 import mucode.*;
22 import java.io.*;
23 import java.net.*;
24
25 /** Provides a <i>"mobile agent"</i> abstraction. <br>
26 *
27 * Migration is obtained by invoking the {@link #go go} method as in
28 * <code>myAgent.go("myhost:2000")</code>. After migration, the agent is
29 * removed from the source host.<BR>
30 *
31 * Only <a href="">weak mobility</a> is provided, in that the <a
32 * href="">execution state</a> of the agent (i.e., its instruction pointer and
33 * call stack) is not preserved across migration---a limitation coming from
34 * the Java VM. However, the <a href="">data state</a> of the agent, i.e.,
35 * the values of its object fields, is preserved. <p>
36 *
37 * The agent can determine, from time to time, which classes should be shipped
38 * at destination along with it. This is accomplished by the
39 * <code>classNames</code> parameter in {@link #go(String, String[], String,
40 * boolean)}. The methods provided by {@link ClassInspector} and {@link
41 * java.lang.Class} may be useful in determining such classes.<br> The method
42 * {@link #go(String)} provides a simplified version of the previous method,
43 * where the agent is shipped along with its complete class closure (excluding
44 * classes that are ubiquitous in the <i>µ</i>Server hosting the
45 * agent). <p>
46 *
47 * The only requirement imposed on subclasses of this class is that they
48 * <u>must implement a public, parameterless constructor</u>, the reason being
49 * that the agent class serves both as a root and a handler class for the
50 * group that is being shipped and reconstructed being the scenes. <p>
51 *
52 * The mobile agent abstraction provided by this class is more powerful than
53 * the ones found in the majority of current mobile agent systems, in that the
54 * amount of code to be transferred at destination is completely under the
55 * control of the programmer. Still, it is just <i>one</i> example of the many
56 * flavors of mobile agent one could build on top of the fundamental
57 * primitives provided by the {@link mucode} package.
58 *
59 * @author <a href="mailto:picco@elet.polimi.it">Gian Pietro Picco</a>
60 * @version 1.0
61 * @see Thread
62 * @see GroupHandler
63 * @see MuServer */
64 public abstract class MuAgent extends Thread
65 implements GroupHandler, Serializable {
66 private transient MuServer server = null;
67 private static final String AGENTLABEL = "_MuAgent_";
68
69 /** Creates a new agent and binds it to a <i>µ</i>Server, that will
70 handle agent migration upon invocation of the {@link #go go} method. */
71 public MuAgent(MuServer server) { this.server = server; }
72
73 /** (<u>This constructor should never be used by the programmer</u>.) The
74 * public, parameterless constructor that must be implemented by a root
75 * or handler class. In this case, subclasses of <code>MuAgent</code>
76 * actually represent both. */
77 public MuAgent() { super(); }
78
79 /** Determines the migration of the agent. The execution state is discarded,
80 * while the data state is preserved and restored at the destination
81 * <i>µ</i>Server. Since this method is <code>public</code>, any
82 * object is allowed to determine the migration of this agent.<BR>
83 *
84 * @param destination the address of the target <code>MuServer</code> object,
85 * specified as <code>hostname:port</code>.
86 * @param classNames the names of the classes needed by the agent at
87 * destination, that will be loaded in its private class space.
88 * @param dynLink the address of a <i>µ</i>Server from which classes
89 * not shipped along with the <code>Runnable</code>object can be retrieved
90 * through dynamic linking. If <code>null</code>, remote dynamic linking is
91 * prevented.
92 * @param synch if <code>true</code>, the operation is blocking for the
93 * caller, that is suspended until a return value is received after the
94 * thread is restarted on the target <i>µ</i>Server. Otherwise, the
95 * method returns immediately after group transmission is completed.
96 * @exception NotSerializableException if some of the fields of the agent
97 * are not serializable, i.e., they do not implement the {@link
98 * java.io.Serializable} interface.
99 * @exception IOException if the symbolic name given as
100 * destination cannot be resolved in a proper IP address, or some problem
101 * occurs with connection or serialization.
102 * @exception ClassNotFoundException if some of the classes referenced
103 * by the group cannot be resolved. */
104 public final void go(String destination, String[] classNames,
105 String dynLink, boolean synch)
106 throws IOException, ClassNotFoundException {
107
108 // This guarantees that the server grabs automatically the server where it
109 // has been created, when and if it gets launched using rSpawnThread.
110 if (server == null) server = MuServer.getServer(this);
111
112 // Determines the agent's classname.
113 String agentClassName = this.getClass().getName();
114 // Requests a new group to the agent server.
115 Group group = server.createGroup(agentClassName, agentClassName);
116 // Add the agent to the group, identified by the system-defined label.
117 group.addObject(AGENTLABEL, this);
118 // Add the class closure
119 group.addClasses(classNames);
120 group.setDynamicLinkSource(dynLink);
121 group.setSynchronousTransfer(synch);
122 // The group containing the agent's code and state is sent at destination.
123 group.ship(destination);
124 // The agent thread is stopped and eventually removed from the server.
125 this.stop();
126 }
127
128
129 /**
130 * Same as {@link #go(String, String[], String, boolean)} but with
131 * <code>classNames</code> containing the full class closure of the agent
132 * class, remote dynamic linking disabled, and asynchronous transfer.
133 *
134 * @param destination the address of the target <code>MuServer</code>
135 * object, specified as <code>hostname:port</code>. */
136 public final void go(String destination)
137 throws IOException, ClassNotFoundException {
138 // This guarantees that the server grabs automatically the server where it
139 // has been created, when and if it gets launched using rSpawnThread.
140 if (server == null) server = MuServer.getServer(this);
141
142 go(destination,
143 ClassInspector.getClassClosure(this.getClass().getName(),
144 server, ClassInspector.FULLCLOSURE),
145 null, false);
146 }
147
148 /** Provides specialized handling of the group containing the object, as
149 * defined by <code>GroupHandler</code>.
150 *
151 * @param group the group to be handled. It is passed to the method directly
152 * by the <i>µ</i>Server thread running on the host.
153 * @return in this case, the agent's thread to be restarted.
154 * @exception MuCodeException may be thrown within the method to signal
155 * abnormal conditions, and can contain internal exceptions.
156 */
157 public final Thread unpack(Group group) throws MuCodeException {
158 MuAgent agent = (MuAgent) group.getObject(AGENTLABEL);
159 agent.server = group.getServer();
160 return agent;
161 }
162
163 /** Must be redefined by the programmer with the behavior of the agent. */
164 public abstract void run();
165 }
166