//========================================================================
//Copyright 2007 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.mortbay.cometd.client;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.cometd.Client;
import org.cometd.Extension;
import org.cometd.Message;
import org.cometd.MessageListener;
import org.mortbay.cometd.client.ext.AckExtension;
import org.mortbay.component.AbstractLifeCycle;
import org.mortbay.jetty.client.Address;
import org.mortbay.jetty.client.HttpClient;
import org.mortbay.log.Log;
import org.mortbay.thread.QueuedThreadPool;
public class ChatRoomClient extends AbstractLifeCycle
{
private HttpClient _httpClient;
private BayeuxClient _bayeuxClient;
private QueuedThreadPool _threadPool;
private String _host;
private int _port;
private String _uri;
private String _metaChannel;
private String _publicChannel;
private String _privateChannel;
private String _username;
private List<Extension> _extensions;
private boolean _connected = false;
public ChatRoomClient()
{
this(System.getProperty("chatroom.host", "localhost"),
Integer.parseInt(System.getProperty("chatroom.port", "8080")),
System.getProperty("chatroom.uri", "/cometd/cometd"),
System.getProperty("chatroom.publicChannel", "/chat/demo"),
System.getProperty("chatroom.privateChannel", "/service/privatechat"),
System.getProperty("chatroom.metaChannel", "/cometd/meta"));
}
public ChatRoomClient(int port)
{
this(System.getProperty("chatroom.host", "localhost"),
port,
System.getProperty("chatroom.uri", "/cometd/cometd"),
System.getProperty("chatroom.publicChannel", "/chat/demo"),
System.getProperty("chatroom.privateChannel", "/service/privatechat"),
System.getProperty("chatroom.metaChannel", "/cometd/meta"));
}
public ChatRoomClient(String host, int port, String uri, String channel,
String privateChannel, String metaChannel)
{
_host = host;
_port = port;
_uri = uri;
_publicChannel = channel;
_privateChannel = privateChannel;
_metaChannel = metaChannel;
}
public String getMetaChannel()
{
return _metaChannel;
}
public String getPublicChannel()
{
return _publicChannel;
}
public boolean isConnected()
{
return _connected;
}
public void setHost(String host)
{
_host = host;
}
public void setPort(int port)
{
_port = port;
}
public void setUri(String uri)
{
_uri = uri;
}
public String getUsername()
{
return _username;
}
public HttpClient getHttpClient()
{
return _httpClient;
}
public List<Extension> getExtensions()
{
return _extensions;
}
public ChatRoomClient addExtension(Extension extension)
{
if(_extensions==null)
_extensions = new ArrayList<Extension>();
_extensions.add(extension);
return this;
}
protected void doStart() throws Exception
{
Log.info("{} {}", getClass().getSimpleName(), "starting chat client.");
if(_threadPool==null)
{
_threadPool = new QueuedThreadPool();
_threadPool.setMaxThreads(16);
_threadPool.setDaemon(true);
_threadPool.setName(getClass().getSimpleName());
_threadPool.start();
}
if(_httpClient==null)
{
_httpClient = new HttpClient();
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
_httpClient.setMaxConnectionsPerAddress(5);
_httpClient.setThreadPool(_threadPool);
_httpClient.start();
}
Log.info("{} {}", getClass().getSimpleName(), "http client started.");
if(_bayeuxClient==null)
{
Address address = new Address(_host, _port);
_bayeuxClient = new BayeuxClient(_httpClient, address, _uri);
if(_extensions!=null)
{
for(Extension ext : _extensions)
_bayeuxClient.addExtension(ext);
}
_bayeuxClient.addListener(new ChatListener());
}
_threadPool.dispatch(new Runnable()
{
public void run()
{
try
{
_bayeuxClient.start();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
Log.info("{} {}", getClass().getSimpleName(), "bayeux client started.");
}
});
Log.info("{} {}", getClass().getSimpleName(), "chat client started.");
}
protected void doStop() throws Exception
{
Log.info("{} {}", getClass().getSimpleName(), "stopping chat client.");
if(_connected && _username!=null)
{
Log.info("{} {}", getClass().getSimpleName(), "leaving chat room.");
//leave();
Log.info("{} {}", getClass().getSimpleName(), "removing client from chat room.");
_bayeuxClient.disconnect();
}
Log.info("{} {}", getClass().getSimpleName(), "chat client stopped.");
}
public void onMessageReceived(Client from, Map<String,Object> message)
{
if("private".equals(message.get("scope")))
onPrivateMessageReceived(from, message);
else
onPublicMessageReceived(from, message);
}
public void onPublicMessageReceived(Client from, Map<String,Object> message)
{
}
public void onPrivateMessageReceived(Client from, Map<String,Object> message)
{
}
public void onUserListRefreshed(Object[] users)
{
}
public boolean join(String username) throws Exception
{
if(_username!=null)
return false;
Log.info("{} {}", getClass().getSimpleName(), "joining channel: " + _publicChannel + " with " + username);
_bayeuxClient.startBatch();
_bayeuxClient.subscribe(_publicChannel);
_bayeuxClient.publish(_publicChannel,
new Msg().add("user", username)
.add("join", Boolean.TRUE)
.add("chat", username + " has joined"),
String.valueOf(System.currentTimeMillis()));
_bayeuxClient.endBatch();
_username = username;
return true;
}
public boolean leave() throws Exception
{
if(_username==null)
return false;
Log.info("{} {}", getClass().getSimpleName(), "leaving channel: " + _publicChannel + " with " + _username);
_bayeuxClient.startBatch();
_bayeuxClient.unsubscribe(_publicChannel);
_bayeuxClient.publish(_publicChannel,
new Msg().add("user", _username)
.add("leave", Boolean.TRUE)
.add("chat", _username + " has left"),
String.valueOf(System.currentTimeMillis()));
_bayeuxClient.endBatch();
_username = null;
return true;
}
public boolean chat(String message)
{
if(_username==null)
return false;
_bayeuxClient.publish(_publicChannel,
new Msg().add("user", _username)
.add("chat", message),
String.valueOf(System.currentTimeMillis()));
return true;
}
public boolean chat(String message, String user)
{
if(_username==null)
return false;
if(user==null)
return chat(message);
_bayeuxClient.publish(_privateChannel,
new Msg().add("user", _username)
.add("room", _publicChannel)
.add("chat", message)
.add("peer", user),
null);
return true;
}
class ChatListener implements MessageListener
{
public void deliver(Client from, Client to, Message message)
{
if(!_connected)
{
_connected = true;
synchronized(this)
{
this.notify();
}
}
Object data = message.getData();
if(data==null)
return;
if(data.getClass().isArray())
onUserListRefreshed((Object[])data);
else if(data instanceof Map)
onMessageReceived(from, (Map<String,Object>)data);
}
}
public static class Msg extends HashMap<String, Object>
{
Msg add(String name, Object value)
{
put(name, value);
return this;
}
}
public static void main(String[] args) throws Exception
{
ChatRoomClient room = new ChatRoomClient()
{
public void onUserListRefreshed(Object[] users)
{
for(Object u : users)
Log.info("user: {}", u);
}
public void onPublicMessageReceived(org.cometd.Client from, Map<String,Object> message)
{
Log.info("public message: {}", message);
String str = (String)message.get("chat");
//Is this a stats probe from the StatisticsExtension?
if (str != null && (str.startsWith("//stats-probe")))
{
str = "//stats-reply"+str.substring(7);
chat(str);
}
}
public void onPrivateMessageReceived(org.cometd.Client from, Map<String,Object> message)
{
Log.info("private message: {}", message);
}
};
room.start();
Thread.sleep(500);
room.join("foo" + System.currentTimeMillis());
LineNumberReader in = new LineNumberReader(new InputStreamReader(System.in));
for(;;)
{
System.err.print("enter chat message: ");
String message = in.readLine().trim();
int idx = message.indexOf("::");
if(idx==-1)
room.chat(message);
else
room.chat(message.substring(idx+1), message.substring(0, idx));
}
}
}