使用OSGI写一个简单得Telnet聊天程序.(参考TutorialEclipseCon06)

来源:互联网 发布:快捷矩阵报价 编辑:程序博客网 时间:2024/06/08 10:19
最近使用OSGI原理写一个简单得聊天程序.
首先新建一个equinox得Plugin.再创建一个接口:
public interface IChannel {
    String CHANNEL_NAME 
= "channel.name";

    
void send(String form, String msg) throws IOException;
}
这个接口主要作用是一个频道发送信息.以此只定义了一个send方法.
再新建另一个equinox的Plugin,使用Component的方式创建一个OSGI-INF/telnet_component.xml.代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<component name="Telenet_Component">
    
<implementation class="org.dengues.zos.chat.telnet.TelnetChatComponent"></implementation>
    
<reference name="LOG" interface="org.osgi.service.log.LogService"></reference>
</component>
这样一来它的实现类就是TelnetChatComponent.java: 它的代码如下:
public class TelnetChatComponent extends Thread {

    
protected LogService log;

    
protected boolean quite;

    
protected List<Handler> handlers = new ArrayList<Handler>();

    
protected ServerSocket server;

    
private ComponentContext context;

    
protected void activate(ComponentContext context) {
        
this.context = context;
        log 
= (LogService) context.locateService("LOG");
        log.log(LogService.LOG_INFO, 
"Component active!!!!!");
        start();
    }


    
protected void deactivate(ComponentContext context) throws Exception {
        log.log(LogService.LOG_INFO, 
"Component deactive!!!!!");
        quite 
= true;
        
for (Handler handler : handlers) {
            handler.close();
        }

        server.close();
    }


    @Override
    
public void run() {
        
super.run();
        
while (!quite) {
            
try {
                server 
= new ServerSocket(55555);
                loop();
            }
 catch (Exception e) {
                log.log(LogService.LOG_ERROR, 
"[TelnetChat] Inner loop", e);
            }

        }

    }


    
private void loop() throws Exception {
        
while (!quite) {
            
try {
                Socket accept 
= server.accept();
                Handler handler 
= new Handler(context.getBundleContext(),
                        accept, 
this);
                handlers.add(handler);
                handler.start();
            }
 catch (Exception e) {
                e.printStackTrace();
            }

        }

    }


    
public void remove(IChannel channel) {
        
this.handlers.remove(channel);
    }


    
protected void sleep(int ms) {
        
try {
            Thread.sleep(ms);
        }
 catch (Exception e) {
        }

    }


}
由于使用的Component在激活的时候会默认调用activate方法.这里为了记录激活日志.在记录日志之后.我们先新建一个
ServerSocket端口是55555.另外还有一个类实现IChannel.就是Handler.java:
public class Handler extends Thread implements IChannel {
    
private BundleContext context;
    
private Socket socket;
    
private TelnetChatComponent component;

    
private PrintWriter writer;

    
private boolean quit;
    
private String user;
    
private IChannel channel;

    
public Handler(BundleContext context, Socket socket,
            TelnetChatComponent component) 
throws Exception {
        
this.context = context;
        
this.socket = socket;
        
this.component = component;
        writer 
= new PrintWriter(new OutputStreamWriter(socket
                .getOutputStream()));
    }


    @Override
    
public void send(String form, String msg) throws IOException {
        writer.println(form 
+ " -> " + msg);
        writer.flush();
    }


    
public void close() {
        
try {
            quit 
= true;
            
this.writer.close();
            
this.socket.close();
        }
 catch (Exception e) {
            e.printStackTrace();
        }

    }


    
public void run() {
        
super.run();
        writer.println(
"Welcome... Chat!");
        writer.print(
"Enter Name: ");
        writer.flush();
        
try {
            BufferedReader reader 
= new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            String line 
= "";
            
while (!quit && (line = reader.readLine()) != null{
                line 
= line.trim();
                process(line);
            }

        }
 catch (Exception e) {
            
if (!quit) {
                component.log.log(LogService.LOG_ERROR, 
"Reading User Name: ",
                        e);
            }

        }
 finally {
            
if(channel!=null{
                component.remove(channel);
            }

        }

    }


    
private void process(String line) throws Exception {
        
if (user == null{
            user 
= line;
            Hashtable
<String, String> props = new Hashtable<String, String>();
            props.put(CHANNEL_NAME, user);
            channel 
= (IChannel) context.registerService(IChannel.class
                    .getName(), 
this, props);
            send(
"info""set User to" + user);
        }
 else if (line.endsWith("/quit")) {
            writer.println(
"bye!!!");
        }
 else {
            dispatch(line);
        }

    }


    
private void dispatch(String line) throws Exception {
        String[] parts 
= line.split("/W");
        ServiceReference[] channels 
= context.getServiceReferences(
                IChannel.
class.getName(), "(" + CHANNEL_NAME + "=" + parts[0]
                        
+ ")");
        
if (channels != null{
            IChannel channel 
= (IChannel) context.getService(channels[0]);
            channel.send(user, line.substring(parts[
0].length()));
            context.ungetService(channels[
0]);
        }
 else {
            send(
"error""not such user" + user);
        }

    }

}
当有一个客户请求的时候,它就新建以个Handler.要发送信息的功能在Handler中实现.
就这么简单了,还有几个问题要注意:
这个Component插件的
META-INF/MANIFEST.MF:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Telnet Plug-in
Bundle-SymbolicName: org.dengues.zos.chat.telnet
Service-Component: OSGI-INF/telnet_component.xml
Bundle-Version: 1.0.0
Bundle-Activator: org.dengues.zos.chat.telnet.TelnetActivator
Import-Package: org.dengues.zos.chat.channel,
 org.osgi.framework;version="1.3.0",
 org.osgi.service.component;version="1.0.0",
 org.osgi.service.log;version="1.3.0"
Eclipse-LazyStart: true
还有在运行的时候要选中两个插件:org.eclipse.equinox.ds(如果没有这个需要到Eclipse官网下),org.eclipse.equinox.log.这样运行后的结果:

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      org.eclipse.osgi_3.3.0.v20070530
1    ACTIVE      javax.servlet_2.4.0.v200706111738
8    ACTIVE      org.eclipse.osgi.services_3.1.200.v20070605
17    ACTIVE      org.dengues.zos.chat_1.0.0
18    ACTIVE      org.dengues.zos.chat.telnet_1.0.0
19    ACTIVE      org.eclipse.equinox.ds_1.0.0.v20070226
20    ACTIVE      org.eclipse.equinox.log_1.0.100.v20070226

osgi> log
>Info 
[20] Log created; Log Size=100; Log Threshold=4 initial@reference:file:plugins/org.eclipse.equinox.log_1.0.100.v20070226.jar/
>Info [20] ServiceEvent REGISTERED {service.id=22}
>Info 
[20] ServiceEvent REGISTERED {service.id=23}
>Info 
[20] ServiceEvent REGISTERED {service.id=24}
>Info 
[20] BundleEvent STARTED initial@reference:file:plugins/org.eclipse.equinox.log_1.0.100.v20070226.jar/
>Info 
[0] FrameworkEvent STARTLEVEL CHANGED System Bundle
>Info 
[18] Component active!!!!! initial@reference:file:../workspaces/org.dengues.zos.chat.telnet/

osgi> 

可以看到Info[18],说明这个Component已经运行.
然后再打开两个Telnet, 使用 open localhost 55555.就可以聊天了!
注明:整个Dengues的代码文件太多,无法上传,如果需要源代码。请到用一下方式联系:
QQ群:24885404;Google群:http://groups.google.com/group/dengues.