1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2011 Florian Schmaus 3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Licensed under the Apache License, Version 2.0 (the "License"); 5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License. 6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at 7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * http://www.apache.org/licenses/LICENSE-2.0 9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software 11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS, 12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and 14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License. 15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smackx.entitycaps.cache; 18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.DataInputStream; 20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.DataOutputStream; 21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.File; 22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.FileInputStream; 23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.FileOutputStream; 24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.IOException; 25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.Reader; 26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.StringReader; 27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.IQ; 29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.provider.IQProvider; 30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.Base32Encoder; 31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.Base64Encoder; 32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.StringEncoder; 33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.entitycaps.EntityCapsManager; 34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverInfo; 35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.provider.DiscoverInfoProvider; 36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xmlpull.v1.XmlPullParserFactory; 37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xmlpull.v1.XmlPullParser; 38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xmlpull.v1.XmlPullParserException; 39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Simple implementation of an EntityCapsPersistentCache that uses a directory 42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * to store the Caps information for every known node. Every node is represented 43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * by an file. 44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Florian Schmaus 46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache { 49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private File cacheDir; 51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private StringEncoder filenameEncoder; 52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a new SimpleDirectoryPersistentCache Object. Make sure that the 55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * cacheDir exists and that it's an directory. 56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Default filename encoder {@link Base32Encoder}, as this will work on all 58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * filesystems, both case sensitive and case insensitive. It does however 59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * produce longer filenames. 60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param cacheDir 62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public SimpleDirectoryPersistentCache(File cacheDir) { 64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this(cacheDir, Base32Encoder.getInstance()); 65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a new SimpleDirectoryPersistentCache Object. Make sure that the 69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * cacheDir exists and that it's an directory. 70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * If your cacheDir is case insensitive then make sure to set the 72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * StringEncoder to {@link Base32Encoder} (which is the default). 73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param cacheDir The directory where the cache will be stored. 75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param filenameEncoder Encodes the node string into a filename. 76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder filenameEncoder) { 78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (!cacheDir.exists()) 79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new IllegalStateException("Cache directory \"" + cacheDir + "\" does not exist"); 80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (!cacheDir.isDirectory()) 81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new IllegalStateException("Cache directory \"" + cacheDir + "\" is not a directory"); 82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.cacheDir = cacheDir; 84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.filenameEncoder = filenameEncoder; 85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen @Override 88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info) { 89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String filename = filenameEncoder.encode(node); 90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen File nodeFile = new File(cacheDir, filename); 91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (nodeFile.createNewFile()) 93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen writeInfoToFile(nodeFile, info); 94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (IOException e) { 95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen e.printStackTrace(); 96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen @Override 100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void replay() throws IOException { 101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen File[] files = cacheDir.listFiles(); 102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (File f : files) { 103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String node = filenameEncoder.decode(f.getName()); 104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen DiscoverInfo info = restoreInfoFromFile(f); 105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (info == null) 106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen continue; 107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen EntityCapsManager.addDiscoverInfoByNode(node, info); 109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void emptyCache() { 113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen File[] files = cacheDir.listFiles(); 114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (File f : files) { 115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen f.delete(); 116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Writes the DiscoverInfo packet to an file 121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param file 123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param info 124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException 125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static void writeInfoToFile(File file, DiscoverInfo info) throws IOException { 127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen DataOutputStream dos = new DataOutputStream(new FileOutputStream(file)); 128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen dos.writeUTF(info.toXML()); 130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } finally { 131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen dos.close(); 132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Tries to restore an DiscoverInfo packet from a file. 137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param file 139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return 140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException 141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static DiscoverInfo restoreInfoFromFile(File file) throws IOException { 143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen DataInputStream dis = new DataInputStream(new FileInputStream(file)); 144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String fileContent = null; 145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String id; 146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String from; 147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String to; 148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen fileContent = dis.readUTF(); 151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } finally { 152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen dis.close(); 153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (fileContent == null) 155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return null; 156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Reader reader = new StringReader(fileContent); 158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen XmlPullParser parser; 159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen parser = XmlPullParserFactory.newInstance().newPullParser(); 161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen parser.setInput(reader); 163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (XmlPullParserException xppe) { 164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen xppe.printStackTrace(); 165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return null; 166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen DiscoverInfo iqPacket; 169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen IQProvider provider = new DiscoverInfoProvider(); 170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Parse the IQ, we only need the id 172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen parser.next(); 174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen id = parser.getAttributeValue("", "id"); 175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen from = parser.getAttributeValue("", "from"); 176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen to = parser.getAttributeValue("", "to"); 177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen parser.next(); 178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (XmlPullParserException e1) { 179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return null; 180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen iqPacket = (DiscoverInfo) provider.parseIQ(parser); 184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (Exception e) { 185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return null; 186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen iqPacket.setPacketID(id); 189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen iqPacket.setFrom(from); 190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen iqPacket.setTo(to); 191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen iqPacket.setType(IQ.Type.RESULT); 192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return iqPacket; 193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen} 195