/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.jsmodule.domain;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.Validate;
/** Manages the cache of the bundled files.
*
* @author ivan.bedecarats@globant.com.
*/
public class BundleCache {
/** Map that contains the cache of the bundled files.
*
* The key is a {@link String} generated by concatenating an MD5 hash with
* ".js". This MD5 hash was created by concatenating the paths of those files
* which had been used for looking for the dependency files of the bundled
* file. Each concatenated file path is ordered alphabetically and separated
* by a |.
* The value is a {@link String} which represents the content of the bundled
* file cached in the Map.
*
*/
private Map<String, String> bundledFiles =
new HashMap<String, String>();
/** Generates a Key for a bundled file which will be cached in the Map.
*
* Implementation note: the key is generated by concatenating the list of
* files separated by '|', calculating its MD5 hash, and concatenating a .js
* suffix. The key is order dependent (no sorting is done to calculate the
* key.)
*
* @param files The files used for generating the Key. These files are the
* ones used for looking for the dependency files of bundled file.
* Cannot be null nor empty.
*
* @return A unique key generated from the source files. Never return null.
*/
private String generateKey(final List<String> files) {
Validate.notEmpty(files, "There must be at least one file.");
StringBuilder concatenatedFile = new StringBuilder();
String generatedKey = null;
for (int i = 0; i < files.size(); i++) {
if (concatenatedFile.length() != 0) {
concatenatedFile.append("|");
}
concatenatedFile.append(files.get(i));
}
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Unable to generate the MD5 hash.", e);
}
messageDigest.reset();
String inputForHash = concatenatedFile.toString();
messageDigest.update(inputForHash.getBytes(Charset.forName("UTF8")));
byte[] resultBytes = messageDigest.digest();
generatedKey = new String(Hex.encodeHex(resultBytes)) + ".js";
return generatedKey;
}
/** Finds a {@link String} which represents the content of the Bundled File
* for the given Key in the Map of Cached Files.
*
* @param key The key in the Map of Cached Files for the given files. Cannot
* be null nor empty.
* @return Gets a {@link String} which represents the content of the Cached
* Bundled File for the given files. If there is no cached file in the map for
* the given files then it returns null.
*/
public String findContent(final String key) {
Validate.notEmpty(key, "The Key cannot be null nor empty.");
return bundledFiles.get(key);
}
/** Finds the key in Map that contains the cache of the bundled files.
*
* @param files The files used for generating the Key. These files are the
* ones used for looking for the dependency files which were later on bundled.
* Cannot be null nor empty.
* @return The key in the Map of Cached Files for the given files. If there is
* no cached file for them, then it returns null.
*/
public String findKey(final List<String> files) {
Validate.notEmpty(files, "There must be at least one file.");
String generatedKey = generateKey(files);
if (bundledFiles.containsKey(generatedKey)) {
return generatedKey;
}
return null;
}
/** Stores a bundled file for the given files in the Map of Cached Files.
*
* @param files The files used for generating the Key. These files are the
* ones used for looking for the dependency files which were later on bundled.
* Cannot be null nor empty.
* @param bundledContent A {@link String} which represents the of the Cached
* Bundled. Cannot be empty.
* File for the given files.
* @return The {@link String} which represents the key of the newly stored
* bundled file in the Map of Cached Files. It's never null.
*/
public String store(final List<String> files, final String bundledContent) {
Validate.notEmpty(files, "There must be at least one file.");
Validate.notEmpty(bundledContent,
"The bundled content cannot be null");
String bundleKey = generateKey(files);
bundledFiles.put(bundleKey, bundledContent);
return bundleKey;
}
}