Implement a disk cache for Capabilities.
authorDa Risk <darisk972@gmail.com>
Tue, 10 Aug 2010 01:46:51 +0200
changeset 795 b2572c048dd7
parent 794 5dd9d68b6ad3
child 796 e85bccf2d817
Implement a disk cache for Capabilities. #286 almost done.
src/com/beem/project/beem/service/BeemCapsManager.java
src/com/beem/project/beem/service/XmppConnectionAdapter.java
src/com/beem/project/beem/smack/caps/CapsExtension.java
src/com/beem/project/beem/smack/caps/CapsManager.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/service/BeemCapsManager.java	Tue Aug 10 01:46:51 2010 +0200
@@ -0,0 +1,162 @@
+/*
+    BEEM is a videoconference application on the Android Platform.
+
+    Copyright (C) 2009 by Frederic-Charles Barthelery,
+                          Jean-Manuel Da Silva,
+                          Nikita Kozlov,
+                          Philippe Lago,
+                          Jean Baptiste Vergely,
+                          Vincent Veronis.
+
+    This file is part of BEEM.
+
+    BEEM 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.
+
+    BEEM 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 BEEM.  If not, see <http://www.gnu.org/licenses/>.
+
+    Please send bug reports with examples or suggestions to
+    contact@beem-project.com or http://dev.beem-project.com/
+
+    Epitech, hereby disclaims all copyright interest in the program "Beem"
+    written by Frederic-Charles Barthelery,
+               Jean-Manuel Da Silva,
+               Nikita Kozlov,
+               Philippe Lago,
+               Jean Baptiste Vergely,
+               Vincent Veronis.
+
+    Nicolas Sadirac, November 26, 2009
+    President of Epitech.
+
+    Flavien Astraud, November 26, 2009
+    Head of the EIP Laboratory.
+
+*/
+package com.beem.project.beem.service;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
+import org.jivesoftware.smackx.ServiceDiscoveryManager;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+import android.util.Log;
+import java.io.FileReader;
+import java.io.Reader;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.Writer;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.content.Context;
+
+import com.beem.project.beem.smack.caps.CapsManager;
+
+/**
+ * An implementation of CapsManager which keeps DiscoverInfo on the Cache directory of the android application.
+ */
+public class BeemCapsManager extends CapsManager {
+
+    private static final String TAG = "BeemCapsManager";
+
+    private Context mContext;
+    private File mCacheDir;
+    private XmlPullParser mParser;
+
+    /**
+     * Create a BeemCapsManager.
+     *
+     * @param sdm the ServiceDiscoveryManager to use
+     * @param conn the connection to use
+     * @param context the Android context to use to store data
+     */
+    public BeemCapsManager(final ServiceDiscoveryManager sdm, final Connection conn, final Context context) {
+	super(sdm, conn);
+	mContext = context;
+	initCacheDirectory();
+    }
+
+
+    @Override
+    protected DiscoverInfo load(String ver) {
+	File fver = new File(mCacheDir, ver);
+	try {
+	    Reader fr = new BufferedReader(new FileReader(fver));
+	    try {
+		if (mParser == null)
+		    mParser = makeParser();
+		mParser.setInput(fr);
+		return (DiscoverInfo) PacketParserUtils.parsePacketExtension("query",
+			"http://jabber.org/protocol/disco#info", mParser);
+
+	    } finally {
+		fr.close();
+	    }
+	} catch (Exception e) {
+	    // The parsePacketExtension throw Exception on error
+	    Log.d(TAG, "Error while loading Capabilities " + ver, e);
+	}
+	return null;
+    }
+
+    @Override
+    protected void store(String ver, DiscoverInfo info) {
+	File fver = new File(mCacheDir, ver);
+	try {
+	    Writer fw = new BufferedWriter(new FileWriter(fver));
+	    try {
+		String data  = info.toXML();
+		fw.write(data, 0, data.length());
+	    } finally {
+		fw.close();
+	    }
+	} catch (IOException e) {
+	    Log.d(TAG, "Error while saving Capabilities " + ver, e);
+	}
+    }
+
+    @Override
+    protected boolean isInCache(String ver) {
+	boolean result = super.isInCache(ver);
+	if (!result) {
+	    File fver = new File(mCacheDir, ver);
+	    result = fver.exists();
+	}
+	return result;
+    }
+
+    /**
+     * Init the cache directory.
+     */
+    private void initCacheDirectory() {
+	File dir = mContext.getCacheDir();
+	mCacheDir = new File(dir, "capabilities");
+	mCacheDir.mkdir();
+    }
+
+    /**
+     * Make an Xml parser.
+     *
+     * @return the created xml parser.
+     * @throws XmlPullParserException if an error occurs while creating the parser.
+     */
+    private XmlPullParser makeParser() throws XmlPullParserException {
+	XmlPullParserFactory fact = XmlPullParserFactory.newInstance();
+	fact.setNamespaceAware(true);
+	return fact.newPullParser();
+    }
+}
--- a/src/com/beem/project/beem/service/XmppConnectionAdapter.java	Mon Jul 26 01:21:28 2010 +0200
+++ b/src/com/beem/project/beem/service/XmppConnectionAdapter.java	Tue Aug 10 01:46:51 2010 +0200
@@ -76,7 +76,6 @@
 import com.beem.project.beem.ui.Subscription;
 import com.beem.project.beem.utils.BeemBroadcastReceiver;
 import com.beem.project.beem.utils.Status;
-import com.beem.project.beem.smack.caps.CapsManager;
 
 /**
  * This class implements an adapter for XMPPConnection.
@@ -397,7 +396,7 @@
 	sdm.addFeature("jabber:iq:privacy");
 	sdm.addFeature("http://jabber.org/protocol/caps");
 	mChatStateManager = ChatStateManager.getInstance(mAdaptee);
-	CapsManager caps = new CapsManager(sdm, mAdaptee);
+	BeemCapsManager caps = new BeemCapsManager(sdm, mAdaptee, mService);
 	caps.setNode("http://www.beem-project.com");
     }
 
--- a/src/com/beem/project/beem/smack/caps/CapsExtension.java	Mon Jul 26 01:21:28 2010 +0200
+++ b/src/com/beem/project/beem/smack/caps/CapsExtension.java	Tue Aug 10 01:46:51 2010 +0200
@@ -49,8 +49,6 @@
 /**
  * This extension represents a capability of XEP-0115.
  *
- * @author 	Frédéric Barthéléry
- * @version 	$Revision$
  */
 public class CapsExtension implements PacketExtension {
 
--- a/src/com/beem/project/beem/smack/caps/CapsManager.java	Mon Jul 26 01:21:28 2010 +0200
+++ b/src/com/beem/project/beem/smack/caps/CapsManager.java	Tue Aug 10 01:46:51 2010 +0200
@@ -70,9 +70,8 @@
 
 /**
  * Capabilities manager to implements XEP-0115.
+ * The DiscoverInfo are cached in memory.
  *
- * @author 	Frédéric Barthéléry
- * @version 	$Revision$
  */
 public class CapsManager {
     // the verCache should be stored on disk
@@ -97,6 +96,76 @@
     }
 
     /**
+     * Get the discover info associated with a ver attribute.
+     *
+     * @param ver the ver attribute.
+     * @return the discover info or null if it was not cached.
+     */
+    public DiscoverInfo getDiscoverInfo(String ver) {
+	return mVerCache.get(ver);
+    }
+
+    /**
+     * Get the discover info of a contact.
+     *
+     * @param jid the jid of the contact.
+     * @param ver the ver attribute of the contact capability.
+     * @return The info of the client null if the info was not cached.
+     */
+    public DiscoverInfo getDiscoverInfo(String jid, String ver) {
+	DiscoverInfo info = mVerCache.get(ver);
+	if (info == null) {
+	    info = load(ver);
+	    if (info == null)
+		info = mJidCache.get(jid);
+	}
+	return info;
+    }
+
+    /**
+     * Set the node attribute to send in your capability.
+     * This is usually an uri to identify the client.
+     *
+     * @param node the node attribute to set.
+     */
+    public void setNode(String node) {
+	mNode = node;
+    }
+
+    /**
+     * Load a persistent DiscoverInfo.
+     * The default implementation does nothing and always return null.
+     *
+     * @param ver the ver hash of the discoverInfo.
+     * @return The discover info or null if not present.
+     */
+    protected DiscoverInfo load(String ver) {
+	return null;
+    }
+
+    /**
+     * Store a DiscoverInfo for persistence.
+     * The default implementation does nothing.
+     *
+     * @param ver the ver hash of the DiscoverInfo
+     * @param info the DiscoverInfo to store
+     */
+    protected void store(String ver, DiscoverInfo info) {
+    }
+
+    /**
+     * Check if the discover info correspondig to the ver hash is in cache.
+     * This implementation checks the memory cache.
+     * If the info is not in cache it is necessary to request it from the network.
+     *
+     * @param ver the ver hash
+     * @return true if it is in cache false otherwise
+     */
+    protected boolean isInCache(String ver) {
+	return mVerCache.containsKey(ver);
+    }
+
+    /**
      * Initialize this CapsManageer.
      */
     private void init() {
@@ -104,10 +173,13 @@
 	PacketFilter filter = new PacketExtensionFilter("c", "http://jabber.org/protocol/caps");
 	mConnection.addPacketListener(new PacketListener() {
 	    public void processPacket(Packet packet) {
+		if (packet.getFrom().equals(mConnection.getUser()))
+		    return;
 		PacketExtension p = packet.getExtension("c", "http://jabber.org/protocol/caps");
 		CapsExtension caps = (CapsExtension) p;
-		if (!mVerCache.containsKey(caps.getVer()))
+		if (!isInCache(caps.getVer())) {
 		    validate(packet.getFrom(), caps.getVer(), caps.getHash());
+		}
 	    }
 	}, filter);
 	mConnection.addPacketInterceptor(new PacketInterceptor() {
@@ -129,40 +201,6 @@
     }
 
     /**
-     * Get the discover info associated with a ver attribute.
-     *
-     * @param ver the ver attribute.
-     * @return the discover info or null if it was not cached.
-     */
-    public DiscoverInfo getDiscoverInfo(String ver) {
-	return mVerCache.get(ver);
-    }
-
-    /**
-     * Get the discover info of a contact.
-     *
-     * @param jid the jid of the contact.
-     * @param ver the ver attribute of the contact capability.
-     * @return The info of the client null if the info was not cached.
-     */
-    public DiscoverInfo getDiscoverInfo(String jid, String ver) {
-	DiscoverInfo info = mVerCache.get(ver);
-	if (info == null)
-	    info = mJidCache.get(jid);
-	return info;
-    }
-
-    /**
-     * Set the node attribute to send in your capability.
-     * This is usually an uri to identify the client.
-     *
-     * @param node the node attribute to set.
-     */
-    public void setNode(String node) {
-	mNode = node;
-    }
-
-    /**
      * Validate the ver attribute of a received capability.
      *
      * @param jid the jid of the sender of the capability.
@@ -179,8 +217,10 @@
 	    }
 	    String v = calculateVer(info, hashMethod);
 	    boolean res = v.equals(ver);
-	    if (res)
+	    if (res) {
 		mVerCache.put(ver, info);
+		store(ver, info);
+	    }
 	    return res;
 	} catch (XMPPException e) {
 	    e.printStackTrace();