| package org.eclipse.jst.validation.sample.parser; |
| /* |
| * Licensed Material - Property of IBM |
| * (C) Copyright IBM Corp. 2002, 2003 - All Rights Reserved. |
| * US Government Users Restricted Rights - Use, duplication or disclosure |
| * restricted by GSA ADP Schedule Contract with IBM Corp. |
| * |
| * DISCLAIMER OF WARRANTIES. |
| * The following [enclosed] code is sample code created by IBM |
| * Corporation. This sample code is not part of any standard or IBM |
| * product and is provided to you solely for the purpose of assisting |
| * you in the development of your applications. The code is provided |
| * "AS IS". IBM MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT |
| * NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE, REGARDING THE FUNCTION OR PERFORMANCE OF |
| * THIS CODE. THIS CODE MAY CONTAIN ERRORS. IBM shall not be liable |
| * for any damages arising out of your use of the sample code, even |
| * if it has been advised of the possibility of such damages. |
| * |
| */ |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| /** |
| * This class compares two .properties file and outputs a list |
| * of the differences. This class is used to count the number |
| * of words that have changed. |
| */ |
| public class CompareProperties { |
| public static final String lineSeparator = java.lang.System.getProperty("line.separator"); //$NON-NLS-1$ |
| private TreeSet _deleted = null; |
| private TreeMap _changed = null; |
| private TreeSet _added = null; |
| // private PropertyFile _oldFile = null; |
| private PropertyFile _newFile = null; |
| |
| /** |
| * This class is used to store PropertyLine instances which have the same |
| * message id, but different values. When the list of differences is output, |
| * all values are output so that the user can compare the lines manually, to |
| * see what's different. |
| */ |
| class CompareLine implements Comparable { |
| private ArrayList _lines; |
| private final String _messageId; |
| |
| public CompareLine(String messageId) { |
| _messageId = messageId; |
| _lines = new ArrayList(); |
| } |
| |
| public void add(PropertyLine oldLine, PropertyLine newLine) { |
| _lines.add(new PropertyLine[]{oldLine, newLine}); |
| } |
| |
| public String toString() { |
| StringBuffer buffer = new StringBuffer(); |
| Iterator iterator = _lines.iterator(); |
| while (iterator.hasNext()) { |
| buffer.append(lineSeparator); |
| buffer.append("\t"); //$NON-NLS-1$ |
| PropertyLine[] lines = (PropertyLine[])iterator.next(); |
| |
| buffer.append(lines[0]); |
| buffer.append("\n"); //$NON-NLS-1$ |
| buffer.append(lines[1]); |
| } |
| return buffer.toString(); |
| } |
| |
| /** |
| * Since this is a changed string, return the absolute difference of words between the strings. |
| */ |
| public int getNumWords() { |
| int numWords = 0; |
| Iterator iterator = _lines.iterator(); |
| while (iterator.hasNext()) { |
| PropertyLine[] lines = (PropertyLine[])iterator.next(); |
| numWords = numWords + compare(lines[0], lines[1]); |
| } |
| return numWords; |
| } |
| |
| private int compare(PropertyLine oldLine, PropertyLine newLine) { |
| // For every word in the old string, see if it exists in the new |
| // string. The position of the word doesn't matter - if the word |
| // exists in the new, then the word is not counted as a "changed" |
| // word. |
| // 1. If the word exists, remove the word from the newLine and |
| // advance to the next old token. (Remove word from newLine |
| // in case the word existed twice in the old string but only |
| // once in the new. The second oldWord should be counted as |
| // a changed word.) |
| // 2. If the word doesn't exist, numChanged++ and advance to the |
| // next old token. |
| // 3. Once all of the oldWords have been checked, tokenize the |
| // remaining newWord and count the number of words in the string. |
| // These words have been added and each one counts as a |
| // changed word. |
| int numChangedWords = 0; |
| StringTokenizer oldTokenizer = new StringTokenizer(oldLine.getMessage()); |
| |
| // Need to be careful...want the entire word, not oldWord="on" mistaken for newWord="one" or newWord="bond" |
| // Easier to create a list of new words to compare against. |
| StringTokenizer newTokenizer = new StringTokenizer(newLine.getMessage()); |
| List newWords = new ArrayList(); // Can't use a set in case the newLine uses a word, e.g. "the", more than once. |
| while(newTokenizer.hasMoreTokens()) { |
| newWords.add(newTokenizer.nextToken()); |
| } |
| |
| while(oldTokenizer.hasMoreTokens()) { |
| String oldWord = oldTokenizer.nextToken(); |
| if(newWords.contains(oldWord)) { |
| newWords.remove(oldWord); |
| } |
| else { |
| numChangedWords++; |
| } |
| } |
| |
| // Can count the tokens but not the elments. |
| numChangedWords += newWords.size(); |
| return numChangedWords; |
| } |
| |
| public String getMessageId() { |
| return _messageId; |
| } |
| |
| public int compareTo(Object o) { |
| // by default, sort by message id |
| if (!(o instanceof CompareLine)) { |
| // then how on earth did this method get called?? |
| // put it at the end of the list |
| return 1; |
| } |
| |
| return getMessageId().compareTo(((CompareLine) o).getMessageId()); |
| } |
| } |
| |
| /** |
| * Compare the two PropertyFile and print out a list of the differences; |
| * the first parameter is the older .properties file, and the second |
| * parameter is the newer .properties file. |
| */ |
| public CompareProperties(PropertyFile oldFile, PropertyFile newFile) { |
| _deleted = new TreeSet(); |
| _changed = new TreeMap(); |
| _added = new TreeSet(); |
| |
| // _oldFile = oldFile; |
| _newFile = newFile; |
| |
| compare(oldFile, newFile); |
| } |
| |
| /** |
| * In the older PropertyFile, the message text was different; cache the |
| * older version of the PropertyLine and the newer version of the PropertyLine. |
| */ |
| private void addChanged(PropertyLine oldLine, PropertyLine newLine) { |
| CompareLine cl = (CompareLine) _changed.get(oldLine.getMessageId()); |
| if (cl == null) { |
| cl = new CompareLine(oldLine.getMessageId()); |
| } |
| cl.add(oldLine, newLine); |
| _changed.put(oldLine.getMessageId(), cl); |
| } |
| |
| /** |
| * Compare the two property files and build the collections of variable names with |
| * their associated values. |
| */ |
| public void compare(PropertyFile oldFile, PropertyFile newFile) { |
| _added.clear(); |
| _deleted.clear(); |
| _changed.clear(); |
| |
| // For each element in file 1, see if it exists in file 2 |
| // a) if it doesn't exist, add it to the list of "deleted" strings |
| // b) if it exists, and if the value is different, add it to the list of "changed" strings |
| // c) if it exists, and if the value is the same, add it to the list of "not changed" strings |
| // d) delete the entry, if it exists, from file 2's hashtable so we don't check it twice. |
| // For each element in file 2 not checked already, it cannot exist in file 1, so add it to the list of "new" strings |
| // |
| // Need some way to abort comparison if either of the files contains duplicate |
| // message ids. |
| // |
| List oldKeys = new ArrayList(oldFile.getPropertyLines()); |
| List newKeys = new ArrayList(newFile.getPropertyLines()); |
| Collections.sort(oldKeys, PropertyLineComparator.getMessageIdComparator()); |
| Collections.sort(newKeys, PropertyLineComparator.getMessageIdComparator()); |
| Iterator oldIterator = oldKeys.iterator(); |
| Iterator newIterator = newKeys.iterator(); |
| PropertyLine oldLine = (oldIterator.hasNext()) ? (PropertyLine) oldIterator.next() : null; |
| PropertyLine newLine = (newIterator.hasNext()) ? (PropertyLine) newIterator.next() : null; |
| while ((oldLine != null) && (newLine != null)) { |
| // oldLine message id is either <, =, or > newLine message id. |
| // if <, message id has been deleted. |
| // if =, see if changed (or just compare message ids.) |
| // if >, new line is a new message id. |
| // to increment, increment only the < (whether it's oldLine or newLine). |
| int compare = oldLine.getMessageId().compareTo(newLine.getMessageId()); |
| if (compare < 0) { |
| // deleted |
| _deleted.add(oldLine); |
| if (oldIterator.hasNext()) { |
| oldLine = (PropertyLine) oldIterator.next(); |
| } |
| else { |
| oldLine = null; |
| } |
| } |
| else if (compare == 0) { |
| // existed before. Check if changed. |
| if (!oldLine.getMessage().equals(newLine.getMessage())) { |
| // changed |
| addChanged(oldLine, newLine); |
| } |
| if (oldIterator.hasNext() && newIterator.hasNext()) { |
| oldLine = (PropertyLine) oldIterator.next(); |
| newLine = (PropertyLine) newIterator.next(); |
| } |
| else { |
| oldLine = null; |
| newLine = null; |
| } |
| |
| } |
| else { |
| // added |
| _added.add(newLine); |
| if (newIterator.hasNext()) { |
| newLine = (PropertyLine) newIterator.next(); |
| } |
| else { |
| newLine = null; |
| } |
| } |
| } |
| |
| if (oldLine != null) { |
| _deleted.add(oldLine); |
| } |
| |
| if (newLine != null) { |
| _added.add(newLine); |
| } |
| |
| while (oldIterator.hasNext()) { |
| // all of the rest have been deleted |
| _deleted.add(oldIterator.next()); |
| } |
| |
| while (newIterator.hasNext()) { |
| // all of the rest have been added |
| _added.add(newIterator.next()); |
| } |
| } |
| |
| /** |
| * Return a Collction of PropertyLine instances that exist in |
| * the newer PropertyFile that aren't in the older PropertyFile. |
| */ |
| public Set getAdded() { |
| return _added; |
| } |
| |
| /** |
| * Return a Collection of CompareLine instances that represent |
| * the two PropertyLine instances; one from the older PropertyFile, |
| * and one from the newer PropertyFile. |
| */ |
| public Collection getChanged() { |
| return _changed.values(); |
| } |
| |
| /** |
| * Return a Collection of PropertyLine instances that do not |
| * exist in the newer PropertyFile yet that exist in the older |
| * PropertyFile. |
| */ |
| public Set getDeleted() { |
| return _deleted; |
| } |
| |
| /** |
| * Print out all of the collections of variable strings. |
| */ |
| public void printResults() { |
| // create an output log in the current directory, and in it list the strings in a section each. |
| int numNew = printStrings("NEW PROPERTIES", _added); //$NON-NLS-1$ |
| |
| int numWordsDeleted = printStrings("DELETED PROPERTIES", _deleted); //$NON-NLS-1$ |
| int numWordsChanged = printStrings("CHANGED PROPERTIES", _changed.values()); //$NON-NLS-1$ |
| float totalChange = numNew + numWordsDeleted + numWordsChanged; |
| float numWords = _newFile.getNumWords(); |
| float percent = totalChange / numWords * 100; |
| |
| System.out.println(); |
| System.out.println("Number of new words: " + numNew); //$NON-NLS-1$ |
| System.out.println("Number of words in deleted messages: " + numWordsDeleted); //$NON-NLS-1$ |
| System.out.println("Number of changed words in modified messages: " + numWordsChanged); //$NON-NLS-1$ |
| System.out.println("Number of words in file " + _newFile.getQualifiedFileName() + ": " + numWords); //$NON-NLS-1$ //$NON-NLS-2$ |
| System.out.println("Total change of words: " + totalChange + ", which is a " + percent + "% change."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| public void printResultsForTranslation() { |
| // create an output log in the current directory, and in it list the strings in a section each. |
| printStringsForTranslation("DELETED PROPERTIES", _deleted); //$NON-NLS-1$ |
| printStringsForTranslation("NEW PROPERTIES", _added); //$NON-NLS-1$ |
| printStringsForTranslation("CHANGED PROPERTIES", _changed.values()); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Print the number of lines in the .properties file. |
| */ |
| private int printStrings(String header, Collection lines) { |
| System.out.println(); |
| System.out.println(header); |
| int count = 0; |
| int numWords = 0; |
| Iterator iterator = lines.iterator(); |
| while (iterator.hasNext()) { |
| Object line = iterator.next(); |
| if(line instanceof PropertyLine) { |
| numWords += ((PropertyLine)line).getNumWords(); |
| } |
| else { |
| // must be a compare line |
| numWords += ((CompareLine)line).getNumWords(); |
| } |
| |
| count++; |
| System.out.println(line); |
| } |
| System.out.println("Number of properties: " + count); //$NON-NLS-1$ |
| System.out.println(); |
| return numWords; |
| } |
| |
| /** |
| * Print the contents of the sorted collection of lines from the .properties file. |
| */ |
| private void printStringsForTranslation(String header, Collection lines) { |
| System.out.println(); |
| System.out.println(header); |
| int count = 0; |
| Iterator iterator = lines.iterator(); |
| while (iterator.hasNext()) { |
| count++; |
| Object line = iterator.next(); |
| if (line instanceof PropertyLine) { |
| PropertyLine propline = (PropertyLine) line; |
| System.out.println(propline.getMessageId()); |
| } |
| else if (line instanceof CompareLine) { |
| CompareLine propline = (CompareLine) line; |
| System.out.println(propline.getMessageId()); |
| } |
| else { |
| System.out.println("instance of " + line.getClass().getName()); //$NON-NLS-1$ |
| } |
| } |
| System.out.println("Total: " + count); //$NON-NLS-1$ |
| System.out.println(); |
| } |
| } |