Author: bpoussin Date: 2010-10-14 17:21:42 +0200 (Thu, 14 Oct 2010) New Revision: 405 Url: http://nuiton.org/repositories/revision/wikitty/405 Log: Implantation du transporteur sur xmpp devrait fonctionner (a tester sur vradi) Added: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/XMPPNotifierTransporter.java trunk/wikitty-api/src/test/java/org/nuiton/wikitty/notification/ trunk/wikitty-api/src/test/java/org/nuiton/wikitty/notification/XMPPNotificationTest.java Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceEvent.java Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceEvent.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceEvent.java 2010-10-13 14:39:33 UTC (rev 404) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceEvent.java 2010-10-14 15:21:42 UTC (rev 405) @@ -18,6 +18,8 @@ package org.nuiton.wikitty; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver; import java.util.EventObject; import java.util.Map; import java.util.Set; @@ -101,6 +103,14 @@ this.source = source; } + public WikittyEventType getType() { + return type; + } + + public void setType(WikittyEventType type) { + this.type = type; + } + /** * Is event remote. * @@ -176,8 +186,34 @@ @Override public String toString() { String toString = getClass().getName() + "[source=" + source + + ", type=" + type + ", remote=" + remote + ", ids=" + ids + ", idExtensions=" + idExtensions + ", idVersions=" + idVersions + "]"; return toString; } + + /** + * Permet de serializer en XML l'event. Pourrait etre utilise pour l'envoi + * sur un transporteur qui ne peremt pas la serialisation java + * @return + */ + public String toXML() { + XStream xstream = new XStream(); + xstream.setMode(XStream.NO_REFERENCES); + xstream.alias("event", WikittyServiceEvent.class); + String result = xstream.toXML(this); + return result; + } + + /** + * Inverse de la methode toXML + * @param xml + * @return + */ + static public WikittyServiceEvent fromXML(String xml) { + XStream xstream = new XStream(); + xstream.alias("event", WikittyServiceEvent.class); + WikittyServiceEvent result = (WikittyServiceEvent)xstream.fromXML(xml); + return result; + } } Added: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/XMPPNotifierTransporter.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/XMPPNotifierTransporter.java (rev 0) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/XMPPNotifierTransporter.java 2010-10-14 15:21:42 UTC (rev 405) @@ -0,0 +1,235 @@ +/* *##% + * Copyright (c) 2010 Code Lutin, Benjamin Poussin. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + *##%*/ + +package org.nuiton.wikitty; + + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Date; +import java.util.Enumeration; +import java.util.Properties; +import java.util.UUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smackx.muc.DiscussionHistory; +import org.jivesoftware.smackx.muc.MultiUserChat; +import org.nuiton.util.ApplicationConfig; + +/** + * Transporter d'event via xmpp. Pour que ca fonctionne il faut un serveur + * xmpp avec une room + * <p> + * Configuration + * <li>wikitty.xmpp.server = adresse du serveur (ex: im.codelutin.com) + * <li>wikitty.xmpp.room = adresse de la room (ex: wikitty-event@im.codelutin.com) + * <li>wikitty.notification.persistent = [true|false] indique si on doit + * recevoir tous les messages sans en loupe un seul. Pour cela il faut que la + * room soit archivee. (FIXME poussin 20101014 pas encore implantee) + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class XMPPNotifierTransporter implements PacketListener, + WikittyServiceNotifier.RemoteNotifierTransporter { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(XMPPNotifierTransporter.class); + + static final public String PROPERTY_EVENT_NAME = "wikitty-event"; + static final public String WIKITTY_XMPP_SERVER = "wikitty.xmpp.server"; + static final public String WIKITTY_XMPP_ROOM = "wikitty.xmpp.room"; + static final public String WIKITTY_NOTIFICATION_PERSISTENT = + "wikitty.notification.persistent"; + + /** Notifier service reference reference. */ + protected WikittyServiceNotifier ws; + + /** if persistent is true use Chat otherwize use MUC. Chat permit to + received event missed after deconnection */ + protected boolean persistent = false; + + protected XMPPConnection connection; + protected MultiUserChat muc; + + /** + * + * @param ws + */ + public XMPPNotifierTransporter(WikittyServiceNotifier ws, Properties props) { + this.ws = ws; + initXMPP(props); + } + + /** + * Si persistent est vrai alors il faut toujours utilise le meme user id + * + * @param props + */ + protected void initXMPP(Properties props) { + ApplicationConfig config = new ApplicationConfig(props); + + persistent = config.getOptionAsBoolean(WIKITTY_NOTIFICATION_PERSISTENT); + String server = config.getOption(WIKITTY_XMPP_SERVER); + String room = config.getOption(WIKITTY_XMPP_ROOM); + + String pseudo = getUniqueLoginName(); + try { + if (log.isInfoEnabled()) { + log.info("Try to connect to xmpp serveur " + server + + " with pseudo " + pseudo + " in room " + room + + " persistent " + persistent); + } + connection = new XMPPConnection(server); + connection.connect(); + connection.loginAnonymously(); + + DiscussionHistory history = new DiscussionHistory(); + if (persistent) { + // FIXME poussin 20101113 compute amount of log history to retrieve + // MUC must be archived + Date date = new Date(); + history.setSince(date); + } else { + history.setMaxChars(0); + } + + // connection to the volatile room + muc = new MultiUserChat(connection, room); + muc.join(pseudo, "", history, 4000); + muc.addMessageListener(this); + } catch (Exception eee) { + throw new WikittyException("Can't connect to xmpp serveur", eee); + } + } + + @Override + public void sendMessage(WikittyServiceEvent event) throws Exception { + Message message = muc.createMessage(); + message.setBody(event.getType().toString()); + message.setProperty(PROPERTY_EVENT_NAME, event); + + muc.sendMessage(message); + } + + /** + * used for MUC message + * @param packet + */ + @Override + public void processPacket(Packet packet) { + Object event = packet.getProperty(PROPERTY_EVENT_NAME); + + if (log.isInfoEnabled()) { + log.info("Receive message : " + event); + } + + if (event instanceof WikittyServiceEvent) { + processEvent((WikittyServiceEvent)event); + } + } + + /** + * Process event + */ + protected void processEvent(WikittyServiceEvent event) { + //source is transient, add it here : + event.setSource(ws); + event.setRemote(true); // received event became remote + + switch (event.getType()) { + case PUT_WIKITTY: + ws.firePutWikitty(event); + break; + case REMOVE_WIKITTY: + ws.fireRemoveWikitty(event); + break; + case CLEAR_WIKITTY: + ws.fireClearWikitty(event); + break; + case PUT_EXTENSION: + ws.firePutExtension(event); + break; + case REMOVE_EXTENSION: + ws.fireRemoveExtension(event); + break; + case CLEAR_EXTENSION: + ws.fireClearExtension(event); + break; + default: + if (log.isDebugEnabled()) { + log.debug("Not managed xmpp message " + event.type); + } + } + } + + /** + * Recherche le meilleur nom a utiliser comme pseudo pour cette machine. + * Un UUID est toujours ajouter en debut, pour potentiellement lancer + * plusieurs application en meme temps sur la meme machine et etre sur que + * le pseudo soit bien unique. + * + * Le pseudo, n'est pas seulement un UUID, pour pouvoir facilement faire + * du debug en entrant dans le channel et voir les ip des machiens connectees + * + * @return + */ + static public String getUniqueLoginName() { + String result = UUID.randomUUID().toString(); + try { + String ipv4 = null; + String ipv6 = null; + for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements();) { + NetworkInterface netint = e.nextElement(); + + for (Enumeration<InetAddress> a = netint.getInetAddresses(); a.hasMoreElements();) { + InetAddress ip = a.nextElement(); + if (ip instanceof Inet4Address) { + if ((ipv4 == null || "127.0.0.1".equals(ipv4))) { + ipv4 = ip.getHostAddress(); + } + } else if (ip instanceof Inet6Address) { + if (ipv6 == null) { + ipv6 = ip.getHostAddress(); + } + } else { + log.error("Can't get ip from no ipv4 and no ipv6: " + ip); + } + } + } + + if (ipv4 != null) { + result = ipv4 + "=" + result; + } else if (ipv6 != null) { + result = ipv6 + "=" + result; + } + } catch (Exception eee) { + log.error("Can't compute unique name from network interface", eee); + } + return result; + } + +} Added: trunk/wikitty-api/src/test/java/org/nuiton/wikitty/notification/XMPPNotificationTest.java =================================================================== --- trunk/wikitty-api/src/test/java/org/nuiton/wikitty/notification/XMPPNotificationTest.java (rev 0) +++ trunk/wikitty-api/src/test/java/org/nuiton/wikitty/notification/XMPPNotificationTest.java 2010-10-14 15:21:42 UTC (rev 405) @@ -0,0 +1,105 @@ +/* *##% + * Copyright (c) 2010 poussin. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + *##%*/ + +package org.nuiton.wikitty.notification; + + +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smackx.muc.DiscussionHistory; +import org.jivesoftware.smackx.muc.MultiUserChat; +import org.jivesoftware.smackx.muc.RoomInfo; +import org.junit.Test; +import org.nuiton.wikitty.WikittyServiceEvent; +import org.nuiton.wikitty.XMPPNotifierTransporter; + +/** + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class XMPPNotificationTest { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(XMPPNotificationTest.class); + + @Test + public void testXMPP() throws Exception { + String server = "im.codelutin.com"; + String room = "test@conference.im.codelutin.com"; + Properties props = new Properties(); + props.setProperty(XMPPNotifierTransporter.WIKITTY_XMPP_SERVER, server); + props.setProperty(XMPPNotifierTransporter.WIKITTY_XMPP_ROOM, room); + + // Envoi d'un message avec le transporter normal + + XMPPNotifierTransporter xmpp = new XMPPNotifierTransporter(null, props); + WikittyServiceEvent event = new WikittyServiceEvent("test", + WikittyServiceEvent.WikittyEventType.PUT_WIKITTY); + Set<String> ids = new HashSet<String>(); + ids.add("id1"); + ids.add("id2"); + ids.add("id3"); + event.setIds(ids); + xmpp.sendMessage(event); + + + // essaie de recuperation du message + + XMPPConnection connection = new XMPPConnection(server); + connection.connect(); + connection.loginAnonymously(); + + MultiUserChat muc = new MultiUserChat(connection, room); + String pseudo = XMPPNotifierTransporter.getUniqueLoginName(); + System.out.println("pseudo: " + pseudo); + + DiscussionHistory history = new DiscussionHistory(); + history.setMaxStanzas(1); + muc.join(pseudo, "", history, 4000); + + muc.addMessageListener(new PacketListener() { + + @Override + public void processPacket(Packet packet) { + System.out.println("ext: " + packet.getExtensions()); + System.out.println("prop: " + packet.getPropertyNames()); + Object event = packet.getProperty(XMPPNotifierTransporter.PROPERTY_EVENT_NAME); + System.out.println("event " + event + " PACKET: " + + " xml: " + packet.toXML()); + } + }); + + // Discover information about the room roomName@conference.myserver + RoomInfo info = MultiUserChat.getRoomInfo(connection, room); + System.out.println("Number of occupants:" + info.getOccupantsCount()); + System.out.println("Room Subject:" + info.getSubject()); + +// Thread t = new Thread(); +// t.sleep(1000*60); + } + +}