SimpleDirectoryPersistentCache.java

  1. /**
  2.  *
  3.  * Copyright © 2011-2014 Florian Schmaus
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smackx.caps.cache;

  18. import java.io.DataInputStream;
  19. import java.io.DataOutputStream;
  20. import java.io.File;
  21. import java.io.FileInputStream;
  22. import java.io.FileOutputStream;
  23. import java.io.IOException;
  24. import java.util.logging.Level;
  25. import java.util.logging.Logger;

  26. import org.jivesoftware.smack.util.PacketParserUtils;
  27. import org.jivesoftware.smack.util.stringencoder.Base32;
  28. import org.jivesoftware.smack.util.stringencoder.StringEncoder;
  29. import org.jivesoftware.smackx.disco.packet.DiscoverInfo;

  30. /**
  31.  * Simple implementation of an EntityCapsPersistentCache that uses a directory
  32.  * to store the Caps information for every known node. Every node is represented
  33.  * by a file.
  34.  *
  35.  * @author Florian Schmaus
  36.  *
  37.  */
  38. public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache {
  39.     private static final Logger LOGGER = Logger.getLogger(SimpleDirectoryPersistentCache.class.getName());
  40.    
  41.     private File cacheDir;
  42.     private StringEncoder filenameEncoder;

  43.     /**
  44.      * Creates a new SimpleDirectoryPersistentCache Object. Make sure that the
  45.      * cacheDir exists and that it's an directory.
  46.      * <p>
  47.      * Default filename encoder {@link Base32}, as this will work on all
  48.      * file systems, both case sensitive and case insensitive.  It does however
  49.      * produce longer filenames.
  50.      *
  51.      * @param cacheDir
  52.      */
  53.     public SimpleDirectoryPersistentCache(File cacheDir) {
  54.         this(cacheDir, Base32.getStringEncoder());
  55.     }

  56.     /**
  57.      * Creates a new SimpleDirectoryPersistentCache Object. Make sure that the
  58.      * cacheDir exists and that it's an directory.
  59.      *
  60.      * If your cacheDir is case insensitive then make sure to set the
  61.      * StringEncoder to {@link Base32} (which is the default).
  62.      *
  63.      * @param cacheDir The directory where the cache will be stored.
  64.      * @param filenameEncoder Encodes the node string into a filename.
  65.      */
  66.     public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder filenameEncoder) {
  67.         if (!cacheDir.exists())
  68.             throw new IllegalStateException("Cache directory \"" + cacheDir + "\" does not exist");
  69.         if (!cacheDir.isDirectory())
  70.             throw new IllegalStateException("Cache directory \"" + cacheDir + "\" is not a directory");

  71.         this.cacheDir = cacheDir;
  72.         this.filenameEncoder = filenameEncoder;
  73.     }

  74.     @Override
  75.     public void addDiscoverInfoByNodePersistent(String nodeVer, DiscoverInfo info) {
  76.         File nodeFile = getFileFor(nodeVer);
  77.         try {
  78.             if (nodeFile.createNewFile())
  79.                 writeInfoToFile(nodeFile, info);
  80.         } catch (IOException e) {
  81.             LOGGER.log(Level.SEVERE, "Failed to write disco info to file", e);
  82.         }
  83.     }

  84.     @Override
  85.     public DiscoverInfo lookup(String nodeVer) {
  86.         File nodeFile = getFileFor(nodeVer);
  87.         if (!nodeFile.isFile()) {
  88.             return null;
  89.         }
  90.         DiscoverInfo info = null;
  91.         try {
  92.             info = restoreInfoFromFile(nodeFile);
  93.         }
  94.         catch (Exception e) {
  95.             LOGGER.log(Level.WARNING, "Coud not restore info from file", e);
  96.         }
  97.         return info;
  98.     }

  99.     private File getFileFor(String nodeVer) {
  100.         String filename = filenameEncoder.encode(nodeVer);
  101.         File nodeFile = new File(cacheDir, filename);
  102.         return nodeFile;
  103.     }

  104.     @Override
  105.     public void emptyCache() {
  106.         File[] files = cacheDir.listFiles();
  107.         for (File f : files) {
  108.             f.delete();
  109.         }
  110.     }

  111.     /**
  112.      * Writes the DiscoverInfo packet to an file
  113.      *
  114.      * @param file
  115.      * @param info
  116.      * @throws IOException
  117.      */
  118.     private static void writeInfoToFile(File file, DiscoverInfo info) throws IOException {
  119.         DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
  120.         try {
  121.             dos.writeUTF(info.toXML().toString());
  122.         } finally {
  123.             dos.close();
  124.         }
  125.     }

  126.     /**
  127.      * Tries to restore an DiscoverInfo packet from a file.
  128.      *
  129.      * @param file
  130.      * @return the restored DiscoverInfo
  131.      * @throws Exception
  132.      */
  133.     private static DiscoverInfo restoreInfoFromFile(File file) throws Exception {
  134.         DataInputStream dis = new DataInputStream(new FileInputStream(file));
  135.         String fileContent = null;
  136.         try {
  137.             fileContent = dis.readUTF();
  138.         } finally {
  139.             dis.close();
  140.         }
  141.         if (fileContent == null) {
  142.             return null;
  143.         }
  144.         DiscoverInfo info = (DiscoverInfo) PacketParserUtils.parseStanza(fileContent);

  145.         return info;
  146.     }
  147. }