MtasSolrJoinCache.java.html 17.6 KB
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>MtasSolrJoinCache.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">MTAS</a> &gt; <a href="index.source.html" class="el_package">mtas.solr.search</a> &gt; <span class="el_source">MtasSolrJoinCache.java</span></div><h1>MtasSolrJoinCache.java</h1><pre class="source lang-java linenums">package mtas.solr.search;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.solr.common.util.Base64;

/**
 * The Class MtasSolrJoinCache.
 */
public class MtasSolrJoinCache {

  /** The Constant log. */
<span class="fc" id="L37">  private static final Log log = LogFactory.getLog(MtasSolrJoinCache.class);</span>

  /** The Constant DEFAULT_LIFETIME. */
  private static final long DEFAULT_LIFETIME = 86400;

  /** The Constant DEFAULT_MAXIMUM_NUMBER. */
  private static final int DEFAULT_MAXIMUM_NUMBER = 1000;

  /** The Constant DEFAULT_MAXIMUM_OVERFLOW. */
  private static final int DEFAULT_MAXIMUM_OVERFLOW = 10;

  /** The administration. */
  private HashMap&lt;MtasSolrJoinCacheItem, String&gt; administration;

  /** The index. */
  private HashMap&lt;String, MtasSolrJoinCacheItem&gt; index;

  /** The expiration. */
  private HashMap&lt;String, Long&gt; expiration;

  /** The join cache path. */
  private Path joinCachePath;

  /** The life time. */
  private long lifeTime;

  /** The maximum number. */
  private int maximumNumber;

  /** The maximum overflow. */
  private int maximumOverflow;

  /**
   * Instantiates a new mtas solr join cache.
   *
   * @param cacheDirectory the cache directory
   * @param lifeTime the life time
   * @param maximumNumber the maximum number
   * @param maximumOverflow the maximum overflow
   */
  public MtasSolrJoinCache(String cacheDirectory, Long lifeTime,
<span class="fc" id="L78">      Integer maximumNumber, Integer maximumOverflow) {</span>
<span class="fc" id="L79">    joinCachePath = null;</span>
<span class="pc bpc" id="L80" title="3 of 4 branches missed.">    this.lifeTime = (lifeTime != null &amp;&amp; lifeTime &gt; 0) ? lifeTime</span>
        : DEFAULT_LIFETIME;
<span class="pc bpc" id="L82" title="3 of 4 branches missed.">    this.maximumNumber = (maximumNumber != null &amp;&amp; maximumNumber &gt; 0)</span>
<span class="pc" id="L83">        ? maximumNumber : DEFAULT_MAXIMUM_NUMBER;</span>
<span class="pc bpc" id="L84" title="3 of 4 branches missed.">    this.maximumOverflow = (maximumOverflow != null &amp;&amp; maximumOverflow &gt; 0)</span>
<span class="pc" id="L85">        ? maximumOverflow : DEFAULT_MAXIMUM_OVERFLOW;</span>
<span class="pc bpc" id="L86" title="1 of 2 branches missed.">    if (cacheDirectory != null) {</span>
      try {
<span class="nc" id="L88">        joinCachePath = Files.createDirectories(Paths.get(cacheDirectory));</span>
<span class="nc" id="L89">        File[] fileList = joinCachePath.toFile().listFiles();</span>
<span class="nc bnc" id="L90" title="All 2 branches missed.">        if (fileList != null) {</span>
<span class="nc bnc" id="L91" title="All 2 branches missed.">          for (File file : fileList) {</span>
<span class="nc bnc" id="L92" title="All 4 branches missed.">            if (file.isFile() &amp;&amp; !file.delete()) {</span>
<span class="nc" id="L93">              log.error(&quot;couldn't delete &quot; + file);</span>
<span class="nc bnc" id="L94" title="All 2 branches missed.">            } else if (file.isDirectory()) {</span>
<span class="nc" id="L95">              log.info(&quot;unexpected directory &quot; + file.getName());</span>
            }
          }
        }
<span class="nc" id="L99">      } catch (IOException e) {</span>
<span class="nc" id="L100">        joinCachePath = null;</span>
<span class="nc" id="L101">        log.info(&quot;couldn't create cache directory &quot; + cacheDirectory, e);</span>
<span class="nc" id="L102">      }</span>
    }
<span class="fc" id="L104">    administration = new HashMap&lt;&gt;();</span>
<span class="fc" id="L105">    expiration = new HashMap&lt;&gt;();</span>
<span class="fc" id="L106">  }</span>

  /**
   * Creates the.
   *
   * @param url the url
   * @param request the request
   * @param data the data
   * @return the string
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public String create(String url, String request, Serializable data)
      throws IOException {
<span class="nc" id="L119">    MtasSolrJoinCacheItem item = new MtasSolrJoinCacheItem(url, request, null);</span>
<span class="nc" id="L120">    return create(item, data);</span>
  }

  /**
   * Creates the.
   *
   * @param item the item
   * @param data the data
   * @return the string
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private String create(MtasSolrJoinCacheItem item, Serializable data)
      throws IOException {
    // initialisation
<span class="nc" id="L134">    Date date = clear();</span>
<span class="nc" id="L135">    delete(item);</span>
    // create always new key
    String key;
    do {
<span class="nc" id="L139">      key = UUID.randomUUID().toString();</span>
<span class="nc bnc" id="L140" title="All 2 branches missed.">    } while (index.containsKey(key));</span>
    // register
<span class="nc" id="L142">    administration.put(item, key);</span>
<span class="nc" id="L143">    expiration.put(key, date.getTime() + lifeTime);</span>
<span class="nc" id="L144">    index.put(key, item);</span>
    // store data
<span class="nc bnc" id="L146" title="All 2 branches missed.">    if (joinCachePath != null) {</span>
<span class="nc" id="L147">      File file = joinCachePath.resolve(key).toFile();</span>
<span class="nc" id="L148">      try (OutputStream outputStream = new FileOutputStream(file);</span>
<span class="nc" id="L149">          Writer outputStreamWriter = new OutputStreamWriter(outputStream,</span>
              StandardCharsets.UTF_8);) {
<span class="nc" id="L151">        outputStreamWriter.write(encode(data));</span>
<span class="nc" id="L152">        return key;</span>
<span class="nc bnc" id="L153" title="All 16 branches missed.">      } catch (IOException e) {</span>
<span class="nc" id="L154">        administration.remove(item);</span>
<span class="nc" id="L155">        expiration.remove(key);</span>
<span class="nc" id="L156">        log.error(&quot;couldn't create &quot; + key, e);</span>
<span class="nc" id="L157">        return null;</span>
      }
    } else {
<span class="nc" id="L160">      item.data = encode(data);</span>
<span class="nc" id="L161">      return key;</span>
    }
  }

  /**
   * Gets the.
   *
   * @param url the url
   * @param request the request
   * @return the object
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public Object get(String url, String request) throws IOException {
<span class="nc" id="L174">    MtasSolrJoinCacheItem item = new MtasSolrJoinCacheItem(url, request, null);</span>
<span class="nc bnc" id="L175" title="All 2 branches missed.">    if (administration.containsKey(item)) {</span>
<span class="nc" id="L176">      return get(item);</span>
    } else {
<span class="nc" id="L178">      return null;</span>
    }
  }

  /**
   * Gets the.
   *
   * @param key the key
   * @return the object
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public Object get(String key) throws IOException {
<span class="nc bnc" id="L190" title="All 2 branches missed.">    if (index.containsKey(key)) {</span>
<span class="nc" id="L191">      return get(index.get(key));</span>
    } else {
<span class="nc" id="L193">      return null;</span>
    }
  }

  /**
   * Gets the.
   *
   * @param item the item
   * @return the object
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private Object get(MtasSolrJoinCacheItem item) throws IOException {
<span class="nc" id="L205">    Date date = clear();</span>
<span class="nc bnc" id="L206" title="All 2 branches missed.">    if (administration.containsKey(item)) {</span>
<span class="nc" id="L207">      String key = administration.get(item);</span>
<span class="nc" id="L208">      expiration.put(key, date.getTime() + lifeTime);</span>
<span class="nc bnc" id="L209" title="All 2 branches missed.">      if (joinCachePath != null) {</span>
        try {
<span class="nc" id="L211">          Path path = joinCachePath.resolve(key);</span>
<span class="nc" id="L212">          String data = new String(Files.readAllBytes(path),</span>
              StandardCharsets.UTF_8);
<span class="nc" id="L214">          return decode(data);</span>
<span class="nc" id="L215">        } catch (IOException e) {</span>
<span class="nc bnc" id="L216" title="All 2 branches missed.">          if (!joinCachePath.resolve(key).toFile().delete()) {</span>
<span class="nc" id="L217">            log.debug(&quot;couldn't delete &quot; + key);</span>
          }
<span class="nc" id="L219">          administration.remove(item);</span>
<span class="nc" id="L220">          expiration.remove(key);</span>
<span class="nc" id="L221">          log.error(&quot;couldn't get &quot; + key, e);</span>
<span class="nc" id="L222">        }</span>
      } else {
<span class="nc bnc" id="L224" title="All 2 branches missed.">        if (item.data != null) {</span>
<span class="nc" id="L225">          return decode(item.data);</span>
        } else {
<span class="nc" id="L227">          return null;</span>
        }
      }
<span class="nc" id="L230">    } else {</span>
<span class="nc" id="L231">      log.error(&quot;doesn't exist anymore&quot;);</span>
    }
<span class="nc" id="L233">    return null;</span>
  }

  /**
   * Delete.
   *
   * @param item the item
   */
  private void delete(MtasSolrJoinCacheItem item) {
<span class="nc bnc" id="L242" title="All 2 branches missed.">    if (administration.containsKey(item)) {</span>
<span class="nc" id="L243">      String key = administration.remove(item);</span>
<span class="nc" id="L244">      expiration.remove(key);</span>
<span class="nc" id="L245">      index.remove(key);</span>
<span class="nc bnc" id="L246" title="All 2 branches missed.">      if (joinCachePath != null</span>
<span class="nc bnc" id="L247" title="All 2 branches missed.">          &amp;&amp; !joinCachePath.resolve(key).toFile().delete()) {</span>
<span class="nc" id="L248">        log.debug(&quot;couldn't delete &quot; + key);</span>
      }
    }
<span class="nc" id="L251">  }</span>

  /**
   * Clear.
   *
   * @return the date
   */
  private Date clear() {
<span class="nc" id="L259">    Date date = new Date();</span>
<span class="nc" id="L260">    Long timestamp = date.getTime();</span>
<span class="nc" id="L261">    HashSet&lt;MtasSolrJoinCacheItem&gt; toBeRemoved = new HashSet&lt;&gt;();</span>
    // check expiration
<span class="nc bnc" id="L263" title="All 2 branches missed.">    for (Entry&lt;String, Long&gt; entry : expiration.entrySet()) {</span>
<span class="nc bnc" id="L264" title="All 2 branches missed.">      if (entry.getValue() &lt; timestamp) {</span>
<span class="nc bnc" id="L265" title="All 2 branches missed.">        for (Entry&lt;MtasSolrJoinCacheItem, String&gt; subEntry : administration</span>
<span class="nc" id="L266">            .entrySet()) {</span>
<span class="nc bnc" id="L267" title="All 2 branches missed.">          if (subEntry.getValue().equals(entry.getKey())) {</span>
<span class="nc" id="L268">            toBeRemoved.add(subEntry.getKey());</span>
          }
<span class="nc" id="L270">        }</span>
      }
<span class="nc" id="L272">    }</span>
<span class="nc bnc" id="L273" title="All 2 branches missed.">    for (MtasSolrJoinCacheItem item : toBeRemoved) {</span>
<span class="nc" id="L274">      delete(item);</span>
<span class="nc" id="L275">    }</span>
    // check size
<span class="nc bnc" id="L277" title="All 2 branches missed.">    if (expiration.size() &gt; maximumNumber + maximumOverflow) {</span>
<span class="nc" id="L278">      Set&lt;Entry&lt;String, Long&gt;&gt; mapEntries = expiration.entrySet();</span>
<span class="nc" id="L279">      List&lt;Entry&lt;String, Long&gt;&gt; aList = new LinkedList&lt;&gt;(mapEntries);</span>
<span class="nc" id="L280">      Collections.sort(aList,</span>
          (Entry&lt;String, Long&gt; ele1, Entry&lt;String, Long&gt; ele2) -&gt; ele2
<span class="nc" id="L282">              .getValue().compareTo(ele1.getValue()));</span>
<span class="nc" id="L283">      aList.subList(maximumNumber, aList.size()).clear();</span>
<span class="nc bnc" id="L284" title="All 2 branches missed.">      for (Entry&lt;String, MtasSolrJoinCacheItem&gt; entry : index.entrySet()) {</span>
<span class="nc bnc" id="L285" title="All 2 branches missed.">        if (!expiration.containsKey(entry.getKey())) {</span>
<span class="nc" id="L286">          toBeRemoved.add(entry.getValue());</span>
        }
<span class="nc" id="L288">      }</span>
<span class="nc bnc" id="L289" title="All 2 branches missed.">      for (MtasSolrJoinCacheItem item : toBeRemoved) {</span>
<span class="nc" id="L290">        delete(item);</span>
<span class="nc" id="L291">      }</span>
    }
<span class="nc" id="L293">    return date;</span>
  }

  /**
   * Encode.
   *
   * @param o the o
   * @return the string
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private String encode(Serializable o) throws IOException {
<span class="nc" id="L304">    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();</span>
    ObjectOutputStream objectOutputStream;
<span class="nc" id="L306">    objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);</span>
<span class="nc" id="L307">    objectOutputStream.writeObject(o);</span>
<span class="nc" id="L308">    objectOutputStream.close();</span>
<span class="nc" id="L309">    byte[] byteArray = byteArrayOutputStream.toByteArray();</span>
<span class="nc" id="L310">    return Base64.byteArrayToBase64(byteArray);</span>
  }

  /**
   * Decode.
   *
   * @param s the s
   * @return the object
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private Object decode(String s) throws IOException {
<span class="nc" id="L321">    byte[] bytes = Base64.base64ToByteArray(s);</span>
    ObjectInputStream objectInputStream;
<span class="nc" id="L323">    objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));</span>
    try {
<span class="nc" id="L325">      return objectInputStream.readObject();</span>
<span class="nc" id="L326">    } catch (ClassNotFoundException e) {</span>
<span class="nc" id="L327">      throw new IOException(e);</span>
    }
  }

}

class MtasSolrJoinCacheItem {

  public String url;
  public String request;
  public String data;

<span class="nc" id="L339">  public MtasSolrJoinCacheItem(String url, String request, String data) {</span>
<span class="nc bnc" id="L340" title="All 2 branches missed.">    this.url = url == null ? &quot;&quot; : url;</span>
<span class="nc bnc" id="L341" title="All 2 branches missed.">    this.request = request == null ? &quot;&quot; : request;</span>
<span class="nc bnc" id="L342" title="All 2 branches missed.">    this.data = data == null ? &quot;&quot; : data;</span>
<span class="nc" id="L343">  }</span>

  @Override
  public int hashCode() {
<span class="nc" id="L347">    int h = this.getClass().getSimpleName().hashCode();</span>
<span class="nc" id="L348">    h = (h * 3) ^ url.hashCode();</span>
<span class="nc" id="L349">    h = (h * 5) ^ request.hashCode();</span>
<span class="nc" id="L350">    return h;</span>
  }

  @Override
  public boolean equals(Object obj) {
<span class="nc bnc" id="L355" title="All 2 branches missed.">    if (this == obj)</span>
<span class="nc" id="L356">      return true;</span>
<span class="nc bnc" id="L357" title="All 2 branches missed.">    if (obj == null)</span>
<span class="nc" id="L358">      return false;</span>
<span class="nc bnc" id="L359" title="All 2 branches missed.">    if (getClass() != obj.getClass())</span>
<span class="nc" id="L360">      return false;</span>
<span class="nc" id="L361">    final MtasSolrJoinCacheItem that = (MtasSolrJoinCacheItem) obj;</span>
<span class="nc bnc" id="L362" title="All 4 branches missed.">    return (url.equals(that.url)) &amp;&amp; (request.equals(that.request));</span>
  }
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.7.9.201702052155</span></div></body></html>