1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
|
package com.itmill.toolkit.demo;
import java.io.*;
import java.util.*;
import java.lang.ref.WeakReference;
import com.itmill.toolkit.terminal.StreamResource;
import com.itmill.toolkit.ui.*;
/** Chat example application.
*
* <p>This example application implements Internet chatroom with the
* following features:
* <ul>
* <li>Continuosly streaming chat discussion. This is implemented
* with StreamResource that is kept open during the discussion.
* <li>Dynamically changing frames.
* <li>Chatroom that is implemented with static list of chatters
* referenced by weak references.
* </ul>
* </p>
*
* @see com.itmill.toolkit.Application
* @see com.itmill.toolkit.ui.FrameWindow
* @see com.itmill.toolkit.terminal.StreamResource
*/
public class Chat
extends com.itmill.toolkit.Application
implements StreamResource.StreamSource, Button.ClickListener {
/** Linked list of Chat applications who participate the discussion */
private static LinkedList chatters = new LinkedList();
/** Reference (to this application) stored in chatters list */
private WeakReference listEntry = null;
/** Writer for writing to open chat stream */
private PrintWriter chatWriter = null;
/** Login name / Alias for chat */
private TextField loginName = new TextField("Your name?", "");
/** Login button */
private Button loginButton = new Button("Enter chat");
/** Text to be said to discussion */
private TextField sayText = new TextField();
/** Button for sending the sayTest to discussion */
private Button say = new Button("Say");
/** Button for listing the people in the chatroom */
private Button listUsers = new Button("List chatters");
/** Last time this chat application said something */
private long idleSince = (new Date()).getTime();
/** framewindow for following the discussion and control */
FrameWindow frames = new FrameWindow("Chat");
/** Last messages */
private static LinkedList lastMessages = new LinkedList();
/** Initialize the chat application */
public void init() {
// Initialize user interface
say.dependsOn(sayText);
say.addListener((Button.ClickListener) this);
listUsers.addListener((Button.ClickListener) this);
StreamResource chatStream =
new StreamResource(this, "discussion.html", this);
chatStream.setBufferSize(1);
chatStream.setCacheTime(0);
frames.getFrameset().newFrame(chatStream, "chatDiscussion");
Window controls =
new Window(
"",
new OrderedLayout(OrderedLayout.ORIENTATION_HORIZONTAL));
controls.setName("chatControls");
controls.addComponent(sayText);
sayText.setColumns(40);
controls.addComponent(say);
controls.addComponent(loginName);
loginName.focus();
controls.addComponent(loginButton);
loginButton.dependsOn(loginName);
loginButton.addListener(this);
controls.addComponent(listUsers);
Button leaveButton = new Button("Leave", this, "leave");
controls.addComponent(leaveButton);
say.setVisible(false);
sayText.setVisible(false);
frames.getFrameset().newFrame(controls).setAbsoluteSize(60);
frames.getFrameset().setVertical(true);
frames.setName("chatMain");
setMainWindow(frames);
// Register chat application
synchronized (chatters) {
chatters.add(listEntry = new WeakReference(this));
}
}
/** Handle button actions for login, user listing and saying */
public void buttonClick(Button.ClickEvent event) {
// Say something in discussion
if (event.getSource() == say && sayText.toString().length() > 0) {
// Say something to chatstream
say("<b>" + getUser() + ": </b>" + sayText + "<br>");
// Clear the saytext field
sayText.setValue("");
sayText.focus();
}
// List the users
else if (event.getSource() == listUsers)
listUsers();
// Login to application
else if (
event.getSource() == loginButton
&& loginName.toString().length() > 0) {
// Set user name
setUser(loginName.toString());
// Hide logins controls
loginName.setVisible(false);
loginButton.setVisible(false);
// Show say controls
say.setVisible(true);
sayText.setVisible(true);
sayText.focus();
// Announce discussion joining
say(
"<i>"
+ getUser()
+ " joined the discussion ("
+ (new Date()).toString()
+ ")</i><br>");
}
}
/** List chatters to chat stream */
private void listUsers() {
// Compose userlist
StringBuffer userlist = new StringBuffer();
userlist.append(
"<div style=\"background-color: #ffffd0;\"><b>Chatters ("
+ (new Date())
+ ")</b><ul>");
synchronized (chatters) {
for (Iterator i = chatters.iterator(); i.hasNext();) {
try {
Chat c = (Chat) ((WeakReference) i.next()).get();
String name = (String) c.getUser();
if (name != null && name.length() > 0) {
userlist.append("<li>" + name);
userlist.append(
" (idle "
+ ((new Date()).getTime() - c.idleSince) / 1000
+ "s)");
}
} catch (NullPointerException ignored) {
}
}
}
userlist.append("</ul></div><script>self.scroll(0,71234);</script>\n");
// Print the user list to chatstream
printToStream(userlist.toString());
}
/** Print to chatstream and scroll the window */
private void printToStream(String text) {
if (chatWriter != null) {
chatWriter.println(text);
chatWriter.println("<script>self.scroll(0,71234);</script>\n");
chatWriter.flush();
}
}
/** Say to all chat streams */
private void say(String text) {
// Get all the listeners
Object[] listener;
synchronized (chatters) {
listener = chatters.toArray();
}
// Put the saytext to listener streams
// Remove dead listeners
for (int i = 0; i < listener.length; i++) {
Chat c = (Chat) ((WeakReference) listener[i]).get();
if (c != null)
c.printToStream(text);
else
chatters.remove(listener[i]);
}
// Update idle time
idleSince = (new Date()).getTime();
// Update last messages
synchronized (lastMessages) {
lastMessages.addLast(text);
while (lastMessages.size() > 5)
lastMessages.removeFirst();
}
}
/** Open chat stream */
public InputStream getStream() {
// Close any existing streams
if (chatWriter != null)
chatWriter.close();
// Create piped stream
PipedOutputStream chatStream = new PipedOutputStream();
chatWriter = new PrintWriter(chatStream);
InputStream is = null;
try {
is = new PipedInputStream(chatStream);
} catch (IOException ignored) {
chatWriter = null;
return null;
};
// Write headers
printToStream(
"<html><head><title>Discussion "
+ (new Date())
+ "</title>"
+ "</head><body>\n");
// Print last messages
Object[] msgs;
synchronized (lastMessages) {
msgs = lastMessages.toArray();
}
for (int i = 0; i < msgs.length; i++)
printToStream(msgs[i].toString());
// Allways list the users
listUsers();
return is;
}
/** Leave the chat */
public void leave() {
// If we have been logged in, say goodbye
if (listEntry != null) {
if (getUser() != null)
say(
"<i>"
+ getUser()
+ " left the chat ("
+ (new Date())
+ ")</i><br>");
synchronized (chatters) {
chatters.remove(listEntry);
listEntry = null;
}
}
if (chatWriter != null)
chatWriter.close();
// Close the chat frames
if (frames != null) {
frames.getFrameset().removeAllFrames();
Window restartWin = new Window();
frames.getFrameset().newFrame(restartWin);
restartWin.addComponent(new Button("Restart chat", this, "close"));
frames = null;
}
}
/** Make sure that everybody leaves the chat */
public void finalize() {
leave();
}
}
|