Source code: Freenet/node/StandardMessageHandler.java
1 package Freenet.node;
2 import Freenet.*;
3 import java.util.*;
4 import Freenet.support.*;
5 /*
6 This code is part of the Java Adaptive Network Client by Ian Clarke.
7 It is distributed under the GNU Public Licence (GPL) version 2. See
8 http://www.gnu.org/ for further details of the GPL.
9
10 Explanation of Code Versions:
11 0.0.0 = Initial Description
12 0.0.1 = API Specified
13 0.x (x>0) = Partial Implementation
14 x.0 (x>0) = Operational
15
16 */
17
18 /**
19 * This class handles incoming messages.
20 *
21 * @version $Revision: 1.3 $
22 * @author <A HREF="mailto:I.Clarke@strs.co.uk">Ian Clarke</A>
23 **/
24
25 public class StandardMessageHandler implements MessageHandler
26 {
27 // Public Fields
28 // Protected/Private Fields
29
30 public Node node;
31 private LimitedHashtable messageMemories;
32 private LimitedHashtable tickets;
33
34 public static void main(String[] args)
35 {
36 System.out.println("Testing limitedHashtable");
37 Hashtable t = new LimitedHashtable(3);
38 t.put(new Integer(1), new String("one"));
39 System.out.println(t.toString());
40 t.put(new Integer(2), new String("two"));
41 System.out.println(t.toString());
42 t.put(new Integer(3), new String("three"));
43 System.out.println(t.toString());
44 t.put(new Integer(4), new String("four"));
45 System.out.println(t.toString());
46 t.put(new Integer(5), new String("five"));
47 System.out.println(t.toString());
48 t.put(new Integer(6), new String("six"));
49 System.out.println(t.toString());
50 }
51
52 // Constructors
53
54 /**
55 * @param n The node that should be used to send messages
56 * and for which the datastore should be updated
57 * @param m The number of message objects that will be
58 * remembered
59 **/
60 public StandardMessageHandler(Node n, int m)
61 {
62 node = n;
63 messageMemories = new LimitedHashtable(m);
64 tickets = new LimitedHashtable(m);
65 }
66
67 // Public Methods
68
69 /**
70 * Handle a message
71 * @param message The message to handle
72 **/
73 public void handle(Message message)
74 {
75 try {
76 Long longid = new Long(message.id);
77 Object ticket = getTicket(longid);
78 synchronized(ticket) {
79 MessageMemory mm = (MessageMemory)messageMemories.get(longid);
80 MessageMemory newmm = message.received(node, mm);
81 if (newmm != mm) {
82 messageMemories.remove(longid);
83 if (newmm != null) {
84 Object[] lmm = messageMemories.limput(longid, newmm);
85 if (lmm != null) { // dispose of lost mm
86 ((MessageMemory) lmm[1]).lost((Long) lmm[0]);
87 }
88 }
89 }
90 }
91 } catch(Exception e) {e.printStackTrace();}
92 }
93
94 // Protected/Private Methods
95
96 // Return the canonical object corresponding to the messageid
97 // Create one if it does not already exist. Synchronize to
98 // protect against race conditions.
99 synchronized Object getTicket(Long longid)
100 {
101 Object ticket = tickets.get(longid);
102 if (ticket == null) {
103 ticket = new Object();
104 tickets.put(longid, ticket);
105 }
106 return ticket;
107 }
108
109 }
110
111
112 /**
113 * A variant on a Hashtable which only holds a limited number of
114 * messages. When more messages than that are put in, old ones are
115 * deleted, oldest first.
116 *
117 * @version Rrevision$
118 * @author <A HREF="mailto:I.Clarke@strs.co.uk">Ian Clarke</A>
119 **/
120 class LimitedHashtable extends Hashtable
121 {
122 Object[] ar;
123 int ptr = 0;
124 public LimitedHashtable(int size)
125 {
126 super();
127 ar = new Object[size];
128 }
129
130 /**
131 * @return If an old object was pushed out of Hashtable by this
132 * insert, it's an array containing it's key (0) and data (1)
133 * is returned. Otherwise null. Observe that
134 * any object previously under this key will _not_ be
135 * returned (use normal put for that).
136 **/
137 public synchronized Object[] limput(Object key, Object value)
138 {
139 Object[] old = null;
140 if (ar[ptr] != null)
141 {
142 Object oldkey = ar[ptr];
143 Object oldvalue = remove(ar[ptr]);
144 if (oldvalue != null) {
145 old = new Object[2];
146 old[0] = oldkey;
147 old[1] = oldvalue;
148 }
149 }
150 ar[ptr] = key;
151 ptr++;
152 if (ptr == ar.length)
153 {
154 ptr = 0;
155 }
156 super.put(key,value);
157 return old;
158 }
159
160 public synchronized Object put(Object key, Object value)
161 {
162 if (ar[ptr] != null)
163 {
164 remove(ar[ptr]);
165 }
166 ar[ptr] = key;
167 ptr++;
168 if (ptr == ar.length)
169 {
170 ptr = 0;
171 }
172 return super.put(key,value);
173 }
174
175 public String toString()
176 {
177 return super.toString() + ", max: "+ar.length;
178 }
179 }