import java.io.File; import java.io.FileInputStream; import java.security.MessageDigest; import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; import org.roller.presentation.pagecache.rollercache.LRUCacheHandler; /** * RFC 3229 "feed" instance manipulation - difference computation */ public class FeedDiff { /** * Return the current string with the entries which are also present * in the original removed. */ public static String diff(String original, String current, String element) { // entry delimiters String open = "<" + element + ">"; String close = ""; // parse the original feed into entries, adding each to the HashSet HashSet entries = new HashSet(); int cursor = original.length(); while (cursor > 0) { int right = original.lastIndexOf(close, cursor); if (right == -1) break; int left = original.lastIndexOf(open, right); if (left == -1) break; right += close.length(); cursor = left - 1; entries.add(original.substring(left, right)); } // parse the current feed into entries, removing any which are // present in the HashSet StringBuffer result = new StringBuffer(current); cursor = current.length(); while (cursor > 0) { int right = current.lastIndexOf(close, cursor); if (right == -1) break; int left = current.lastIndexOf(open, right); if (left == -1) break; right += close.length(); cursor = left - 1; // if this entry is in the original HashSet, remove it from the result if (entries.contains(current.substring(left, right))) { // also remove any preceeding whitespace while (cursor>=0 && Character.isWhitespace(current.charAt(cursor))) { cursor--; } // remove the entry from the result result.delete(cursor, right-1); } } // return result return new String(result); } /** * Compute a hash for the specified content */ public static String hash(String content) { try{ MessageDigest md = MessageDigest.getInstance("MD5"); md.update(content.getBytes()); return LRUCacheHandler.toBase64(md.digest()).replace('/', '_'); } catch (java.security.NoSuchAlgorithmException e) { // should never happen return null; } } /** * Parse If-None-Match headers */ public static Set parse(String header) { HashSet result = new HashSet(); StringTokenizer st = new StringTokenizer(header, ","); while(st.hasMoreTokens()){ String tag = (String)st.nextToken().trim(); if (tag.startsWith("W/")) tag=tag.substring(2); if (tag.startsWith("\"") && tag.endsWith("\"")) { tag=tag.substring(1,tag.length()-1); } result.add(tag); } return result; } /** * Main program, useful for testing diff and hash functions */ public static void main(String[] args) throws Exception { if (args.length != 3) { System.err.println("Usage: java FeedDiff original current element"); System.exit(8); } // read original into a string File file = new File(args[0]); byte[] bytes = new byte[(int)file.length()]; (new FileInputStream(file)).read(bytes, 0, bytes.length); String original = new String(bytes); // read current into a string file = new File(args[1]); bytes = new byte[(int)file.length()]; (new FileInputStream(file)).read(bytes, 0, bytes.length); String current = new String(bytes); // print diff System.out.println("ETag: " + hash(current)); System.out.println(); System.out.println(diff(original, current, args[2])); } }