XMPP的一些工作

    最近做了一些xmpp方面的东西,把它写下来。

    最近选用了openfire做xmpp server。所以下面的内容都是基于openfire来做的。

    现在openfire最新的版本是3.7.1,下载下来,用eclipse来编译运行。或者下载安装包,可以安装在windows,Solaris上。

    这两种方式我都用了一下。

    关于在eclipse怎么编译运行openfire,可以参考下面这个链接,写的很全。照着做就可以了。

    http://wenku.baidu.com/view/8acbbb305a8102d276a22fb5.html

    我的计划是搭建一个HA的openfire系统。具体的讲就是部署两个openfire server,这两个server的domain都配置成一个(这里我用的是xmppservice)。然后在部署一个F5来做负载均衡和failover。这里我没有选择openfire的cluster plugin。因为我们是商业用途,cluster plugin需要买oracle coherence license。

    我的逻辑业务用external component的方式来实现,并连接到openfire server上。 

    在写一个客户端来测试整个系统。

    下面主要把external component的实现和客户端的实现记录下来。

    客户端的实现很简单,主要用到的包是smack。

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Message;

public class XmppClient {
	
	public static void main(String args[]) throws XMPPException{
		ConnectionConfiguration config = new ConnectionConfiguration(F5_ip_address,F5_port);
		XMPPConnection.DEBUG_ENABLED = true;

		XMPPConnection conn2 = new XMPPConnection(config);
		boolean auth = conn2.getSASLAuthentication().isAuthenticated();
		
		try {
			conn2.connect();
		} catch (XMPPException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(auth);
		
		try {
			conn2.login("client_name", "client_password");
		} catch (XMPPException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		String service = conn2.getServiceName();
		System.out.println(service);
		PacketListener listener = new SimplePacketListener();
		PacketFilter filter = new SimplePacketFilter();
		conn2.addPacketListener(listener, filter);
		buildMsg(conn2,i);
		System.out.println("finished");
	}
	
	static void buildMsg(XMPPConnection conn2){
		Message req = new Message();
		req.setFrom("ilxlf@mymachine_name");
		req.setTo("service1@service1.xmppservice");
		req.setBody("This is client message");
		System.out.println("message sent: "+req.toXML());
		conn2.sendPacket(req);
		System.out.println("finished");
	}
}

    这里用到了两个listener,现在没有什么太大的用途,主要用来显示server的response。

import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Packet;

public class SimplePacketFilter implements PacketFilter {

	@Override
	public boolean accept(Packet arg0) {
		// TODO Auto-generated method stub
		return true;
	}

}

import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.packet.Packet;

public class SimplePacketListener implements PacketListener {

	@Override
	public void processPacket(Packet arg0) {
		// TODO Auto-generated method stub
		System.out.println("received: "+arg0.toXML());
	}

}

下面来说说external component的实现。

先说说配置部署。当我们写了一个external component,我们就需要把他连接到openfire server上。打开openfire的管理页面,默认是在9090端口上。进入之后在server-->server setting -->external components里面配置,默认连接到openfire的5275端口。然后我们需要配置sub-domain和一些访问控制策略。简单点,把sub-domain配好就可以用了(这里我用service1表示sub-domain)。

为了让我们的测试客户端能连接上了,我们在openfire上创建一个测试用户。在Users/Groups-->create new user里面。主要是用户名和密码。对应到上面的代码就是"client_name","client_password"里面的值。

下面就是具体的实现代码。本质上external component可以做成一个war应用,我这里为了方案的验证就做一个普通的java应用。

这里用到的包主要是tinder和whack。 一共三个包。

com.ilxlf.component

org.dom4j.io

org.xmpp.component

后两个包看上去很奇怪,本来是不应该有的。但是在写代码的过程中发现一些问题只能先这么解决一下。

package com.ilxlf.component;

import org.jivesoftware.whack.ExternalComponentManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.component.AbstractComponent;
import org.xmpp.component.ComponentException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;

public class ExampleComponent extends AbstractComponent {
	
	private static final JID serviceAddress = new JID("service1@service1.xmppservice");
	Logger log = LoggerFactory.getLogger(getClass());

	public ExampleComponent(){
		super(2,1000,true);		
		
	}
	
	@Override
	public String getDomain() {
		// TODO Auto-generated method stub
		return "service1";
	}

	@Override
	protected void handleMessage(Message message) {
		// TODO Auto-generated method stub
		//super.handleMessage(message);
		System.out.println(message.toString());
		Message response = new Message();
		response.setFrom(serviceAddress);
		response.setTo(message.getFrom());
		response.setBody("give client a response.....");
		send(response);
	}

	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return "This is pengfu first xmpp component.";
	}

	@Override
	public String getName() {
		// TODO Auto-generated method stub
		return "service1.xmppservice";
	}
	
	
	public static void main(String args[]) throws ComponentException{
		ExampleComponent comp = new ExampleComponent();
		final ExternalComponentManager mgr = new ExternalComponentManager("xmppservice", 5275);
		mgr.setSecretKey("service1", "123456");
		mgr.addComponent("service1", comp);
		
		while(true){
			try {
				Thread.sleep(100000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
			
	}
}

package org.dom4j.io;

import org.dom4j.*;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
 
import java.io.*;
import java.net.URL;


public class XPPPacketReader {
	 
	   /**
	     * <code>DocumentFactory</code> used to create new document objects
	     */
	   private DocumentFactory factory;
	 
	   /**
	     * <code>XmlPullParser</code> used to parse XML
	     */
	   private XmlPullParser xppParser;
	 
	   /**
	     * <code>XmlPullParser</code> used to parse XML
	     */
	   private XmlPullParserFactory xppFactory;
	 
	   /**
	     * DispatchHandler to call when each <code>Element</code> is encountered
	     */
	   private DispatchHandler dispatchHandler;
	 
	 
	   public XPPPacketReader() {
	   }
	 
	   public XPPPacketReader(DocumentFactory factory) {
	       this.factory = factory;
	   }
	 
	 
	   /**
	     * <p>Reads a Document from the given <code>File</code></p>
	     *
	     * @param file is the <code>File</code> to read from.
	     * @return the newly created Document instance
	     * @throws DocumentException              if an error occurs during parsing.
	     * @throws java.net.MalformedURLException if a URL could not be made for the given File
	     */
	   public Document read(File file) throws DocumentException, IOException, XmlPullParserException {
	       String systemID = file.getAbsolutePath();
	       return read(new BufferedReader(new FileReader(file)), systemID);
	   }
	 
	   /**
	     * <p>Reads a Document from the given <code>URL</code></p>
	     *
	     * @param url <code>URL</code> to read from.
	     * @return the newly created Document instance
	     * @throws DocumentException if an error occurs during parsing.
	     */
	   public Document read(URL url) throws DocumentException, IOException, XmlPullParserException {
	       String systemID = url.toExternalForm();
	       return read(createReader(url.openStream()), systemID);
	   }
	 
	   /**
	     * <p>Reads a Document from the given URL or filename.</p>
	     * <p/>
	     * <p/>
	     * If the systemID contains a <code>':'</code> character then it is
	     * assumed to be a URL otherwise its assumed to be a file name.
	     * If you want finer grained control over this mechansim then please
	     * explicitly pass in either a {@link URL} or a {@link File} instance
	     * instead of a {@link String} to denote the source of the document.
	     * </p>
	     *
	     * @param systemID is a URL for a document or a file name.
	     * @return the newly created Document instance
	     * @throws DocumentException              if an error occurs during parsing.
	     * @throws java.net.MalformedURLException if a URL could not be made for the given File
	     */
	   public Document read(String systemID) throws DocumentException, IOException, XmlPullParserException {
	       if (systemID.indexOf(':') >= 0) {
	           // lets assume its a URL
	           return read(new URL(systemID));
	       }
	       else {
	           // lets assume that we are given a file name
	           return read(new File(systemID));
	       }
	   }
	 
	   /**
	     * <p>Reads a Document from the given stream</p>
	     *
	     * @param in <code>InputStream</code> to read from.
	     * @return the newly created Document instance
	     * @throws DocumentException if an error occurs during parsing.
	     */
	   public Document read(InputStream in) throws DocumentException, IOException, XmlPullParserException {
	       return read(createReader(in));
	   }
	 
	   /**
	     * <p>Reads a Document from the given <code>Reader</code></p>
	     *
	     * @param reader is the reader for the input
	     * @return the newly created Document instance
	     * @throws DocumentException if an error occurs during parsing.
	     */
	   public Document read(Reader reader) throws DocumentException, IOException, XmlPullParserException {
	       getXPPParser().setInput(reader);
	       return parseDocument();
	   }
	 
	   /**
	     * <p>Reads a Document from the given array of characters</p>
	     *
	     * @param text is the text to parse
	     * @return the newly created Document instance
	     * @throws DocumentException if an error occurs during parsing.
	     */
	   public Document read(char[] text) throws DocumentException, IOException, XmlPullParserException {
	       getXPPParser().setInput(new CharArrayReader(text));
	       return parseDocument();
	   }
	 
	   /**
	     * <p>Reads a Document from the given stream</p>
	     *
	     * @param in       <code>InputStream</code> to read from.
	     * @param systemID is the URI for the input
	     * @return the newly created Document instance
	     * @throws DocumentException if an error occurs during parsing.
	     */
	   public Document read(InputStream in, String systemID) throws DocumentException, IOException, XmlPullParserException {
	       return read(createReader(in), systemID);
	   }
	 
	   /**
	     * <p>Reads a Document from the given <code>Reader</code></p>
	     *
	     * @param reader   is the reader for the input
	     * @param systemID is the URI for the input
	     * @return the newly created Document instance
	     * @throws DocumentException if an error occurs during parsing.
	     */
	   public Document read(Reader reader, String systemID) throws DocumentException, IOException, XmlPullParserException {
	       Document document = read(reader);
	       document.setName(systemID);
	       return document;
	   }
	 
	 
	   // Properties
	   //-------------------------------------------------------------------------
	 
	   public XmlPullParser getXPPParser() throws XmlPullParserException {
	       if (xppParser == null) {
	           xppParser = getXPPFactory().newPullParser();
	       }
	       return xppParser;
	   }
	 
	   public XmlPullParserFactory getXPPFactory() throws XmlPullParserException {
	       if (xppFactory == null) {
	           xppFactory = XmlPullParserFactory.newInstance();
	       }
	       xppFactory.setNamespaceAware(true);
	       return xppFactory;
	   }
	 
	   public void setXPPFactory(XmlPullParserFactory xppFactory) {
	       this.xppFactory = xppFactory;
	   }
	 
	   /**
	     * @return the <code>DocumentFactory</code> used to create document objects
	     */
	   public DocumentFactory getDocumentFactory() {
	       if (factory == null) {
	           factory = DocumentFactory.getInstance();
	       }
	       return factory;
	   }
	 
	   /**
	     * <p>This sets the <code>DocumentFactory</code> used to create new documents.
	     * This method allows the building of custom DOM4J tree objects to be implemented
	     * easily using a custom derivation of {@link DocumentFactory}</p>
	     *
	     * @param factory <code>DocumentFactory</code> used to create DOM4J objects
	     */
	   public void setDocumentFactory(DocumentFactory factory) {
	       this.factory = factory;
	   }
	 
	 
	   /**
	     * Adds the <code>ElementHandler</code> to be called when the
	     * specified path is encounted.
	     *
	     * @param path    is the path to be handled
	     * @param handler is the <code>ElementHandler</code> to be called
	     *                by the event based processor.
	     */
	   public void addHandler(String path, ElementHandler handler) {
	       getDispatchHandler().addHandler(path, handler);
	   }
	 
	   /**
	     * Removes the <code>ElementHandler</code> from the event based
	     * processor, for the specified path.
	     *
	     * @param path is the path to remove the <code>ElementHandler</code> for.
	     */
	   public void removeHandler(String path) {
	       getDispatchHandler().removeHandler(path);
	   }
	 
	   /**
	     * When multiple <code>ElementHandler</code> instances have been
	     * registered, this will set a default <code>ElementHandler</code>
	     * to be called for any path which does <b>NOT</b> have a handler
	     * registered.
	     *
	     * @param handler is the <code>ElementHandler</code> to be called
	     *                by the event based processor.
	     */
	   public void setDefaultHandler(ElementHandler handler) {
	       getDispatchHandler().setDefaultHandler(handler);
	   }
	 
	   // Implementation methods
	   //-------------------------------------------------------------------------
	   public Document parseDocument() throws DocumentException, IOException, XmlPullParserException {
	       DocumentFactory df = getDocumentFactory();
	       Document document = df.createDocument();
	       Element parent = null;
	       XmlPullParser pp = getXPPParser();
	       int count = 0;
	       while (true) {
	           int type = -1;
	           type = pp.nextToken();
	           switch (type) {
	               case XmlPullParser.PROCESSING_INSTRUCTION: {
	                   String text = pp.getText();
	                   int loc = text.indexOf(" ");
	                   if (loc >= 0) {
	                       document.addProcessingInstruction(text.substring(0, loc), text.substring(loc + 1));
	                   }
	                   else
	                       document.addProcessingInstruction(text, "");
	                   break;
	               }
	               case XmlPullParser.COMMENT: {
	                   if (parent != null)
	                       parent.addComment(pp.getText());
	                   else
	                       document.addComment(pp.getText());
	                   break;
	               }
	               case XmlPullParser.CDSECT: {
	                   String text = pp.getText();
	                   if (parent != null) {
	                       parent.addCDATA(text);
	                   }
	                   else {
	                       if (text.trim().length() > 0) {
	                           throw new DocumentException("Cannot have text content outside of the root document");
	                       }
	                   }
	                   break;
	 
	               }
	               case XmlPullParser.ENTITY_REF: {
	                   String text = pp.getText();
	                   if (parent != null) {
	                       parent.addText(text);
	                   }
	                   else {
	                       if (text.trim().length() > 0) {
	                           throw new DocumentException("Cannot have an entityref outside of the root document");
	                       }
	                   }
	                   break;
	               }
	               case XmlPullParser.END_DOCUMENT: {
	                   return document;
	               }
	               case XmlPullParser.START_TAG: {
	                   QName qname = (pp.getPrefix() == null) ? df.createQName(pp.getName(), pp.getNamespace()) : df.createQName(pp.getName(), pp.getPrefix(), pp.getNamespace());
	                   Element newElement = null;
	                   // Do not include the namespace if this is the start tag of a new packet
	                   // This avoids including "jabber:client", "jabber:server" or
	                   // "jabber:component:accept"
	                   if ("jabber:client".equals(qname.getNamespaceURI()) ||
	                           "jabber:server".equals(qname.getNamespaceURI()) ||
	                           "jabber:component:accept".equals(qname.getNamespaceURI()) ||
	                           "http://jabber.org/protocol/httpbind".equals(qname.getNamespaceURI())) {
	                       newElement = df.createElement(pp.getName());
	                   }
	                   else {
	                       newElement = df.createElement(qname);
	                   }
	                   int nsStart = pp.getNamespaceCount(pp.getDepth() - 1);
	                   int nsEnd = pp.getNamespaceCount(pp.getDepth());
	                   for (int i = nsStart; i < nsEnd; i++)
	                       if (pp.getNamespacePrefix(i) != null)
	                           newElement.addNamespace(pp.getNamespacePrefix(i), pp.getNamespaceUri(i));
	                   for (int i = 0; i < pp.getAttributeCount(); i++) {
	                       QName qa = (pp.getAttributePrefix(i) == null) ? df.createQName(pp.getAttributeName(i)) : df.createQName(pp.getAttributeName(i), pp.getAttributePrefix(i), pp.getAttributeNamespace(i));
	                       newElement.addAttribute(qa, pp.getAttributeValue(i));
	                   }
	                   if (parent != null) {
	                       parent.add(newElement);
	                   }
	                   else {
	                       document.add(newElement);
	                   }
	                   parent = newElement;
	                   count++;
	                   break;
	               }
	               case XmlPullParser.END_TAG: {
	                   if (parent != null) {
	                       parent = parent.getParent();
	                   }
	                   count--;
	                   if (count < 1) {
	                       return document;
	                   }
	                   break;
	               }
	               case XmlPullParser.TEXT: {
	                   String text = pp.getText();
	                   if (parent != null) {
	                       parent.addText(text);
	                   }
	                   else {
	                       if (text.trim().length() > 0) {
	                           throw new DocumentException("Cannot have text content outside of the root document");
	                       }
	                   }
	                   break;
	               }
	               default:
	               {
	                   ;
	               }
	           }
	       }
	   }
	 
	   protected DispatchHandler getDispatchHandler() {
	       if (dispatchHandler == null) {
	           dispatchHandler = new DispatchHandler();
	       }
	       return dispatchHandler;
	   }
	 
	   protected void setDispatchHandler(DispatchHandler dispatchHandler) {
	       this.dispatchHandler = dispatchHandler;
	   }
	 
	   /**
	     * Factory method to create a Reader from the given InputStream.
	     */
	   protected Reader createReader(InputStream in) throws IOException {
	       return new BufferedReader(new InputStreamReader(in));
	   }
	}
	 
	/*
	 * Redistribution and use of this software and associated documentation
	 * ("Software"), with or without modification, are permitted provided
	 * that the following conditions are met:
	 *
	 * 1. Redistributions of source code must retain copyright
	 *    statements and notices.  Redistributions must also contain a
	 *    copy of this document.
	 *
	 * 2. Redistributions in binary form must reproduce the
	 *    above copyright notice, this list of conditions and the
	 *    following disclaimer in the documentation and/or other
	 *    materials provided with the distribution.
	 *
	 * 3. The name "DOM4J" must not be used to endorse or promote
	 *    products derived from this Software without prior written
	 *    permission of MetaStuff, Ltd.  For written permission,
	 *    please contact dom4j-info@metastuff.com.
	 *
	 * 4. Products derived from this Software may not be called "DOM4J"
	 *    nor may "DOM4J" appear in their names without prior written
	 *    permission of MetaStuff, Ltd. DOM4J is a registered
	 *    trademark of MetaStuff, Ltd.
	 *
	 * 5. Due credit should be given to the DOM4J Project -
	 *    http://www.dom4j.org
	 *
	 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
	 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
	 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
	 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
	 * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
	 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
	 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
	 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
	 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
	 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
	 * OF THE POSSIBILITY OF SUCH DAMAGE.
	 *
	 * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
	 *
	 * $Id: XPPPacketReader.java 6408 2006-12-15 23:35:30Z gato $
	 */

package org.xmpp.component;

public interface Log {

}

用到的jar包是:

下一步的工作:

如果一个server连接多个相同业务的external component,是否可以在这些component之间做负载均衡和failover。

openfire的pub-sub的使用。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

dd

转载于:https://my.oschina.net/u/145002/blog/33216

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值