[原创]使用Smack库实现Google Talk XMPP Extensions - Gmail Notifications (含完整的实现代码以及例子)
注意: 这里有本人所写的完整的代码, 所以如果要转载, 请征得本人同意然后加上原文出处; 如果使用代码, 只需要加上本文的Link就可以了.
Gmail Notifications的是Google Talk XMPP Extensions其中之一, 它的用途是Gmail服务器有新邮件的时候, 会通过XMPP协议Push给客户端, 然后客户端可以通过XMPP协议去查询新邮件的信息, 包括新邮件的标题,摘要,发件人邮件地址等.
这个功能其实GTalk客户端已经有了, 但既然已经有了标准的文档, 何不妨把这个功能也加到自己的IM客户端上呢. 当然这个Extension只能用于GTalk服务器.
关于这个Extension的介绍, 请看Google的文档:
http://code.google.com/intl/zh-CN/apis/talk/jep_extensions/gmail.html
下面就直接上传代码, 代码不介绍了, 对照文档应该很好理解的, 其实也很简单.
package com.hj.smack.demo.gmailnotif;import org.jivesoftware.smack.packet.IQ;public class EmailNotification extends IQ {@Overridepublic String getChildElementXML() {StringBuilder buf = new StringBuilder();buf.append("<new-mail xmlns="").append("google:mail:notify").append(""");buf.append("/>");return buf.toString();}}
package com.hj.smack.demo.gmailnotif;import org.jivesoftware.smack.packet.IQ;public class EmailQueryRequest extends IQ {private Long newerThanTime;private Long newThanTid;private String query;@Overridepublic String getChildElementXML() {StringBuilder buf = new StringBuilder();buf.append("<query xmlns="").append("google:mail:notify").append(""");if (newerThanTime != null) {buf.append(" newer-than-time="").append(newerThanTime).append(""");}if (newThanTid != null) {buf.append(" newer-than-tid="").append(newThanTid).append(""");}if (query != null) {buf.append(" q="").append(query).append(""");}buf.append("/>");return buf.toString();}public void setNewerThanTime(Long newerThanTime) {this.newerThanTime = newerThanTime;}public Long getNewerThanTime() {return newerThanTime;}public void setNewThanTid(Long newThanTid) {this.newThanTid = newThanTid;}public Long getNewThanTid() {return newThanTid;}public void setQuery(String query) {this.query = query;}public String getQuery() {return query;}}
package com.hj.smack.demo.gmailnotif;import java.util.Collections;import java.util.Iterator;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;import org.jivesoftware.smack.packet.IQ;public class EmailQueryResponse extends IQ {private Mailbox mailbox;@Overridepublic String getChildElementXML() {StringBuilder buf = new StringBuilder();if (mailbox != null) {buf.append(mailbox.toXML());}return buf.toString();}public Mailbox getMailbox() {return mailbox;}public void setMailbox(Mailbox mailbox) {this.mailbox = mailbox;}public static class Mailbox {private Long resultTime;private Integer totalMatched;private Boolean totalEstimated;private String url;private List<MailThreadInfo> mailThreadInfos = new CopyOnWriteArrayList<MailThreadInfo>();public String toXML() {StringBuilder buf = new StringBuilder();buf.append("<mailbox xmlns="").append("google:mail:notify").append(""");buf.append(" result-time="").append(resultTime).append(""");buf.append(" total-matched="").append(totalMatched).append(""");if (totalEstimated != null) {if (totalEstimated) {buf.append(" total-estimate="").append("1").append(""");} else {buf.append(" total-estimate="").append("0").append(""");}}buf.append(">");synchronized (mailThreadInfos) {for (MailThreadInfo mailThreadInfo : mailThreadInfos) {buf.append(mailThreadInfo.toXML());}}buf.append("</mailbox>"); return buf.toString();}public void addMailThreadInfo(MailThreadInfo mailThreadInfo) {synchronized (mailThreadInfos) {mailThreadInfos.add(mailThreadInfo); }}public Iterator<MailThreadInfo> getMailThreadInfos() {synchronized (mailThreadInfos) { return Collections.unmodifiableList(mailThreadInfos).iterator(); }}public Long getResultTime() {return resultTime;}public void setResultTime(Long resultTime) {this.resultTime = resultTime;}public Integer getTotalMatched() {return totalMatched;}public void setTotalMatched(Integer totalMatched) {this.totalMatched = totalMatched;}public Boolean getTotalEstimated() {return totalEstimated;}public void setTotalEstimated(Boolean totalEstimated) {this.totalEstimated = totalEstimated;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public static class MailThreadInfo {private Long tid;private Integer participation;private Integer messages;private Long date;private String url;private String labels;private String subject;private String snippet;private List<Sender> senders = new CopyOnWriteArrayList<Sender>();public String toXML() {StringBuilder buf = new StringBuilder();buf.append("<mail-thread-info tid="").append(tid).append(""");buf.append(" participation="").append(participation).append(""");buf.append(" date="").append(date).append(""");buf.append(" url="").append(url).append(""");buf.append(">");buf.append("<senders>");synchronized (senders) {for (Sender sender : senders) {buf.append(sender.toXML());}}buf.append("</senders>");buf.append("<labels>").append(labels).append("</labels>");buf.append("<subject>").append(subject).append("</subject>");buf.append("<snippet>").append(snippet).append("</snippet>");buf.append("</mail-thread-info>"); return buf.toString();}public void addSender(Sender sender) {synchronized (senders) {senders.add(sender); }}public Iterator<Sender> getSenders() {synchronized (senders) { return Collections.unmodifiableList(senders).iterator(); }}public String getLabels() {return labels;}public void setLabels(String labels) {this.labels = labels;}public String getSubject() {return subject;}public void setSubject(String subject) {this.subject = subject;}public String getSnippet() {return snippet;}public void setSnippet(String snippet) {this.snippet = snippet;}public Long getTid() {return tid;}public void setTid(Long tid) {this.tid = tid;}public Integer getParticipation() {return participation;}public void setParticipation(Integer participation) {this.participation = participation;}public Integer getMessages() {return messages;}public void setMessages(Integer messages) {this.messages = messages;}public Long getDate() {return date;}public void setDate(Long date) {this.date = date;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public static class Sender {private String name;private String address;private Boolean originator;private Boolean unread;public String toXML() {StringBuilder buf = new StringBuilder();buf.append("<sender name="").append(name).append(""");buf.append(" address="").append(address).append(""");if (originator != null) {if (originator) {buf.append(" originator="").append("1").append(""");} else {buf.append(" originator="").append("0").append(""");}}if (unread != null) {if (unread) {buf.append(" unread="").append("1").append(""");} else {buf.append(" unread="").append("0").append(""");}}buf.append("/>"); return buf.toString();}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Boolean getOriginator() {return originator;}public void setOriginator(Boolean originator) {this.originator = originator;}public Boolean getUnread() {return unread;}public void setUnread(Boolean unread) {this.unread = unread;}}}}}
package com.hj.smack.demo.gmailnotif;import org.jivesoftware.smack.PacketCollector;import org.jivesoftware.smack.PacketListener;import org.jivesoftware.smack.SmackConfiguration;import org.jivesoftware.smack.XMPPConnection;import org.jivesoftware.smack.XMPPException;import org.jivesoftware.smack.filter.PacketFilter;import org.jivesoftware.smack.filter.PacketIDFilter;import org.jivesoftware.smack.filter.PacketTypeFilter;import org.jivesoftware.smack.packet.IQ;import org.jivesoftware.smack.packet.Packet;import org.jivesoftware.smack.util.StringUtils;public class GmailNotificationManager {private XMPPConnection connection;private GmailNotificationListener listener;public GmailNotificationManager(XMPPConnection connection) { this.connection = connection; init();}private void init() {// Listen for new-email notificationPacketFilter packetFilter = new PacketTypeFilter(EmailNotification.class);PacketListener packetListener = new PacketListener() { public void processPacket(Packet packet) { EmailNotification notif = (EmailNotification)packet; // Notify registered listener if (listener != null) { listener.hasNewEmail(); } // Should respond to the server IQ req = new IQ() {@Overridepublic String getChildElementXML() {return null;} }; req.setType(IQ.Type.RESULT); req.setFrom(notif.getTo()); req.setTo(notif.getFrom()); req.setPacketID(notif.getPacketID()); connection.sendPacket(req); }};connection.addPacketListener(packetListener, packetFilter);}public void setGmailNotificationListener(GmailNotificationListener listener) {this.listener = listener;}public EmailQueryResponse.Mailbox checkMailbox(String jid) throws XMPPException {EmailQueryRequest req = new EmailQueryRequest();req.setType(IQ.Type.GET);String bare = StringUtils.parseBareAddress(jid);req.setFrom(jid);req.setTo(bare);// Create a packet collector to listen for a response. PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(req.getPacketID())); connection.sendPacket(req); // Wait up to 5 seconds for a result. IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); // Stop queuing results collector.cancel(); if (result == null) { throw new XMPPException("No response from the server."); } if (result.getType() == IQ.Type.ERROR) { throw new XMPPException(result.getError()); } return ((EmailQueryResponse) result).getMailbox();}public static interface GmailNotificationListener {public void hasNewEmail();}}
package com.hj.smack.demo.gmailnotif;import org.jivesoftware.smack.packet.IQ;import org.jivesoftware.smack.provider.IQProvider;import org.xmlpull.v1.XmlPullParser;public class GmailNotificationProvider implements IQProvider {@Overridepublic IQ parseIQ(XmlPullParser parser) throws Exception {EmailQueryResponse gmailQueryResp = null;EmailNotification gmailNotif = null;boolean done = false;EmailQueryResponse.Mailbox mailbox = null;EmailQueryResponse.Mailbox.MailThreadInfo mailThreadInfo = null;EmailQueryResponse.Mailbox.MailThreadInfo.Sender sender = null;// Cache the textString cachedText = "";// Mailbox attributesString resultTime = "";String totalMatched = "";String totalEstimated = null;String mailboxUrl = "";// MailThreadInfo attributesString tid = "";String participation = "";String messages = "";String date = "";String mailThreadInfoUrl = "";String labels = "";String subject = "";String snippet = "";// Sender attributesString name = "";String address = "";String originator = null;String unread = null;if (parser.getName().equals("new-mail")) {gmailNotif = new EmailNotification();} else {// Initialize the variables from the parsed XMLresultTime = parser.getAttributeValue("", "result-time");totalMatched = parser.getAttributeValue("", "total-matched");totalEstimated = parser.getAttributeValue("", "total-estimate");mailboxUrl = parser.getAttributeValue("", "mailboxUrl");// Create a new Mailbox and add it to the GmailNotificationsgmailQueryResp = new EmailQueryResponse();mailbox = new EmailQueryResponse.Mailbox();mailbox.setResultTime(Long.parseLong(resultTime));mailbox.setTotalMatched(Integer.parseInt(totalMatched));mailbox.setTotalEstimated(totalEstimated != null ? Boolean.parseBoolean(totalEstimated) : null);mailbox.setUrl(mailboxUrl);gmailQueryResp.setMailbox(mailbox);}while (!done) {int eventType = parser.next();if (eventType == XmlPullParser.START_TAG) {if (parser.getName().equals("mail-thread-info")) {// Initialize the variables from the parsed XMLtid = parser.getAttributeValue("", "tid");participation = parser.getAttributeValue("","participation");messages = parser.getAttributeValue("", "messages");date = parser.getAttributeValue("", "date");mailThreadInfoUrl = parser.getAttributeValue("", "url");// Create a new MailThreadInfo and add it to the MailboxmailThreadInfo = new EmailQueryResponse.Mailbox.MailThreadInfo();mailThreadInfo.setTid(Long.parseLong(tid));mailThreadInfo.setParticipation(Integer.parseInt(participation));mailThreadInfo.setMessages(Integer.parseInt(messages));mailThreadInfo.setDate(Long.parseLong(date));mailThreadInfo.setUrl(mailThreadInfoUrl);mailbox.addMailThreadInfo(mailThreadInfo);} else if (parser.getName().equals("sender")) {// Initialize the variables from the parsed XMLname = parser.getAttributeValue("", "name");address = parser.getAttributeValue("", "address");originator = parser.getAttributeValue("", "originator");unread = parser.getAttributeValue("", "unread");// Create a new Sender and add it to the MailThreadInfosender = new EmailQueryResponse.Mailbox.MailThreadInfo.Sender();sender.setName(name);sender.setAddress(address);sender.setOriginator(originator != null ? Boolean.parseBoolean(totalEstimated) : null);sender.setUnread(unread != null ? Boolean.parseBoolean(unread) : null);mailThreadInfo.addSender(sender);}} else if (eventType == XmlPullParser.TEXT) {cachedText = parser.getText();} else if (eventType == XmlPullParser.END_TAG) {if (parser.getName().equals("new-mail") || parser.getName().equals("mailbox")) {done = true;} else if (parser.getName().equals("mail-thread-info")) {} else if (parser.getName().equals("sender")) {} else if (parser.getName().equals("labels")) {labels = cachedText;mailThreadInfo.setLabels(labels);} else if (parser.getName().equals("subject")) {subject = cachedText;mailThreadInfo.setSubject(subject);} else if (parser.getName().equals("snippet")) {snippet = cachedText;mailThreadInfo.setSnippet(snippet);}}}if (gmailNotif != null) {return gmailNotif;} else {return gmailQueryResp;}}}
package com.hj.smack.demo;import org.jivesoftware.smack.ConnectionConfiguration;import org.jivesoftware.smack.XMPPConnection;import org.jivesoftware.smack.XMPPException;import org.jivesoftware.smack.provider.ProviderManager;import com.hj.smack.demo.gmailnotif.EmailQueryResponse;import com.hj.smack.demo.gmailnotif.GmailNotificationManager;import com.hj.smack.demo.gmailnotif.GmailNotificationProvider;import com.hj.smack.demo.gmailnotif.GmailNotificationManager.GmailNotificationListener;public class GmailNotifTest {/** * @param args */public static void main(String[] args) {XMPPConnection.DEBUG_ENABLED = false;ProviderManager providerManager = ProviderManager.getInstance();providerManager.addIQProvider("mailbox", "google:mail:notify", new GmailNotificationProvider());providerManager.addIQProvider("new-mail", "google:mail:notify", new GmailNotificationProvider()); ConnectionConfiguration config = new ConnectionConfiguration("talk.google.com", 5222, "gmail.com");config.setCompressionEnabled(true);config.setSASLAuthenticationEnabled(true);XMPPConnection connection = new XMPPConnection(config);try {connection.connect(); connection.login("xxxxxx@gmail.com", "*******");demoGmailNotif(connection);Thread.sleep(500000);} catch (Exception e) {e.printStackTrace();} finally {connection.disconnect();}}public static void demoGmailNotif(XMPPConnection connection) {String my = connection.getUser();GmailNotificationManager m = new GmailNotificationManager(connection);m.setGmailNotificationListener(new MyGmailNotificationListener(connection));try {EmailQueryResponse.Mailbox mailbox = m.checkMailbox(my);System.out.println(mailbox.toXML());} catch (XMPPException e) {e.printStackTrace();}}private static class MyGmailNotificationListener implements GmailNotificationListener {private XMPPConnection connection;public MyGmailNotificationListener(XMPPConnection connection) {this.connection = connection;}@Overridepublic void hasNewEmail() {System.out.println("You have new emails in your gmail inbox!");String my = connection.getUser();GmailNotificationManager m = new GmailNotificationManager(connection);EmailQueryResponse.Mailbox mailbox;try {mailbox = m.checkMailbox(my);System.out.println(mailbox.toXML());} catch (XMPPException e) {e.printStackTrace();}}}}