XMPP的一些工做

    最近作了一些xmpp方面的東西,把它寫下來。html

    最近選用了openfire作xmpp server。因此下面的內容都是基於openfire來作的。java

    如今openfire最新的版本是3.7.1,下載下來,用eclipse來編譯運行。或者下載安裝包,能夠安裝在windows,Solaris上。windows

    這兩種方式我都用了一下。oracle

    關於在eclipse怎麼編譯運行openfire,能夠參考下面這個連接,寫的很全。照着作就能夠了。app

    http://wenku.baidu.com/view/8acbbb305a8102d276a22fb5.html負載均衡

    個人計劃是搭建一個HA的openfire系統。具體的講就是部署兩個openfire server,這兩個server的domain都配置成一個(這裏我用的是xmppservice)。而後在部署一個F5來作負載均衡和failover。這裏我沒有選擇openfire的cluster plugin。由於咱們是商業用途,cluster plugin須要買oracle coherence license。dom

    個人邏輯業務用external component的方式來實現,並鏈接到openfire server上。 eclipse

    在寫一個客戶端來測試整個系統。ide

    下面主要把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

相關文章
相關標籤/搜索