convert getdown to being completely type-safe, yarr.

This commit is contained in:
Elizabeth Fong
2006-04-11 02:45:14 +00:00
parent 7297af72af
commit 8327440736
11 changed files with 85 additions and 81 deletions
+3 -1
View File
@@ -43,7 +43,9 @@
<javac srcdir="${src.dir}" destdir="${deploy.dir}/classes" <javac srcdir="${src.dir}" destdir="${deploy.dir}/classes"
debug="on" optimize="off" deprecation="on" debug="on" optimize="off" deprecation="on"
classpathref="clazzpath" includeAntRuntime="no" classpathref="clazzpath" includeAntRuntime="no"
source="1.5" target="1.5"/> source="1.5" target="1.5">
<compilerarg value="-Xlint:unchecked"/>
</javac>
</target> </target>
<!-- build the javadoc documentation --> <!-- build the javadoc documentation -->
@@ -123,6 +123,7 @@ public class Application
try { try {
return createResource(CONFIG_FILE, false); return createResource(CONFIG_FILE, false);
} catch (Exception e) { } catch (Exception e) {
Thread.dumpStack();
throw new RuntimeException("Invalid appbase '" + _vappbase + "'."); throw new RuntimeException("Invalid appbase '" + _vappbase + "'.");
} }
} }
@@ -131,7 +132,7 @@ public class Application
* Returns a list of the code {@link Resource} objects used by this * Returns a list of the code {@link Resource} objects used by this
* application. * application.
*/ */
public List getCodeResources () public List<Resource> getCodeResources ()
{ {
return _codes; return _codes;
} }
@@ -140,7 +141,7 @@ public class Application
* Returns a list of the non-code {@link Resource} objects used by * Returns a list of the non-code {@link Resource} objects used by
* this application. * this application.
*/ */
public List getResources () public List<Resource> getResources ()
{ {
return _resources; return _resources;
} }
@@ -188,7 +189,7 @@ public class Application
throws IOException throws IOException
{ {
// parse our configuration file // parse our configuration file
HashMap cdata = null; HashMap<String, Object> cdata = null;
try { try {
cdata = ConfigUtil.parseConfig(_config, checkPlatform); cdata = ConfigUtil.parseConfig(_config, checkPlatform);
} catch (FileNotFoundException fnfe) { } catch (FileNotFoundException fnfe) {
@@ -319,9 +320,10 @@ public class Application
File file = getLocalPath("extra.txt"); File file = getLocalPath("extra.txt");
if (file.exists()) { if (file.exists()) {
try { try {
List args = ConfigUtil.parsePairs(file, false); List<String[]> args = ConfigUtil.parsePairs(file, false);
for (Iterator iter = args.iterator(); iter.hasNext(); ) { for (Iterator<String[]> iter = args.iterator();
String[] pair = (String[])iter.next(); iter.hasNext();) {
String[] pair = iter.next();
_jvmargs.add(pair[0] + "=" + pair[1]); _jvmargs.add(pair[0] + "=" + pair[1]);
} }
} catch (Throwable t) { } catch (Throwable t) {
@@ -423,15 +425,15 @@ public class Application
{ {
// create our classpath // create our classpath
StringBuffer cpbuf = new StringBuffer(); StringBuffer cpbuf = new StringBuffer();
for (Iterator iter = _codes.iterator(); iter.hasNext(); ) { for (Iterator<Resource> iter = _codes.iterator(); iter.hasNext(); ) {
if (cpbuf.length() > 0) { if (cpbuf.length() > 0) {
cpbuf.append(File.pathSeparator); cpbuf.append(File.pathSeparator);
} }
Resource rsrc = (Resource)iter.next(); Resource rsrc = iter.next();
cpbuf.append(rsrc.getLocal().getAbsolutePath()); cpbuf.append(rsrc.getLocal().getAbsolutePath());
} }
ArrayList args = new ArrayList(); ArrayList<String> args = new ArrayList<String>();
// reconstruct the path to the JVM // reconstruct the path to the JVM
args.add(LaunchUtil.getJVMPath(_windebug)); args.add(LaunchUtil.getJVMPath(_windebug));
@@ -468,16 +470,16 @@ public class Application
} }
// add the JVM arguments // add the JVM arguments
for (Iterator iter = _jvmargs.iterator(); iter.hasNext(); ) { for (Iterator<String> iter = _jvmargs.iterator(); iter.hasNext(); ) {
args.add(processArg((String)iter.next())); args.add(processArg(iter.next()));
} }
// add the application class name // add the application class name
args.add(_class); args.add(_class);
// finally add the application arguments // finally add the application arguments
for (Iterator iter = _appargs.iterator(); iter.hasNext(); ) { for (Iterator<String> iter = _appargs.iterator(); iter.hasNext(); ) {
args.add(processArg((String)iter.next())); args.add(processArg(iter.next()));
} }
String[] sargs = new String[args.size()]; String[] sargs = new String[args.size()];
@@ -618,20 +620,21 @@ public class Application
*/ */
public List verifyResources (ProgressObserver obs) public List verifyResources (ProgressObserver obs)
{ {
ArrayList rsrcs = new ArrayList(), failures = new ArrayList(); ArrayList<Resource> rsrcs = new ArrayList<Resource>();
ArrayList<Resource> failures = new ArrayList<Resource>();
rsrcs.addAll(_codes); rsrcs.addAll(_codes);
rsrcs.addAll(_resources); rsrcs.addAll(_resources);
// total up the file size of the resources to validate // total up the file size of the resources to validate
long totalSize = 0L; long totalSize = 0L;
for (Iterator iter = rsrcs.iterator(); iter.hasNext(); ) { for (Iterator<Resource> iter = rsrcs.iterator(); iter.hasNext(); ) {
Resource rsrc = (Resource)iter.next(); Resource rsrc = iter.next();
totalSize += rsrc.getLocal().length(); totalSize += rsrc.getLocal().length();
} }
MetaProgressObserver mpobs = new MetaProgressObserver(obs, totalSize); MetaProgressObserver mpobs = new MetaProgressObserver(obs, totalSize);
for (Iterator iter = rsrcs.iterator(); iter.hasNext(); ) { for (Iterator<Resource> iter = rsrcs.iterator(); iter.hasNext(); ) {
Resource rsrc = (Resource)iter.next(); Resource rsrc = iter.next();
mpobs.startElement(rsrc.getLocal().length()); mpobs.startElement(rsrc.getLocal().length());
if (rsrc.isMarkedValid()) { if (rsrc.isMarkedValid()) {
@@ -684,10 +687,10 @@ public class Application
/** Clears all validation marker files for the resources in the /** Clears all validation marker files for the resources in the
* supplied iterator. */ * supplied iterator. */
protected void clearValidationMarkers (Iterator iter) protected void clearValidationMarkers (Iterator<Resource> iter)
{ {
while (iter.hasNext()) { while (iter.hasNext()) {
((Resource)iter.next()).clearMarker(); iter.next().clearMarker();
} }
} }
@@ -761,7 +764,8 @@ public class Application
} }
/** Used to parse rectangle specifications from the config file. */ /** Used to parse rectangle specifications from the config file. */
protected Rectangle parseRect (HashMap cdata, String name, Rectangle def) protected Rectangle parseRect (HashMap<String, Object> cdata,
String name, Rectangle def)
{ {
String value = (String)cdata.get(name); String value = (String)cdata.get(name);
if (!StringUtil.isBlank(value)) { if (!StringUtil.isBlank(value)) {
@@ -777,7 +781,8 @@ public class Application
} }
/** Used to parse color specifications from the config file. */ /** Used to parse color specifications from the config file. */
protected Color parseColor (HashMap cdata, String name, Color def) protected Color parseColor (HashMap<String, Object> cdata, String name,
Color def)
{ {
String value = (String)cdata.get(name); String value = (String)cdata.get(name);
if (!StringUtil.isBlank(value)) { if (!StringUtil.isBlank(value)) {
@@ -804,9 +809,9 @@ public class Application
protected String _name; protected String _name;
protected boolean _windebug; protected boolean _windebug;
protected ArrayList _codes = new ArrayList(); protected ArrayList<Resource> _codes = new ArrayList<Resource>();
protected ArrayList _resources = new ArrayList(); protected ArrayList<Resource> _resources = new ArrayList<Resource>();
protected ArrayList _jvmargs = new ArrayList(); protected ArrayList<String> _jvmargs = new ArrayList<String>();
protected ArrayList _appargs = new ArrayList(); protected ArrayList<String> _appargs = new ArrayList<String>();
} }
@@ -85,7 +85,7 @@ public class Digest
{ {
try { try {
String cmd5 = resource.computeDigest(getMessageDigest(), obs); String cmd5 = resource.computeDigest(getMessageDigest(), obs);
String emd5 = (String)_digests.get(resource.getPath()); String emd5 = _digests.get(resource.getPath());
if (cmd5.equals(emd5)) { if (cmd5.equals(emd5)) {
return true; return true;
} }
@@ -102,7 +102,7 @@ public class Digest
* Creates a digest file at the specified location using the supplied * Creates a digest file at the specified location using the supplied
* list of resources. * list of resources.
*/ */
public static void createDigest (List resources, File output) public static void createDigest (List<Resource> resources, File output)
throws IOException throws IOException
{ {
MessageDigest md = getMessageDigest(); MessageDigest md = getMessageDigest();
@@ -111,8 +111,8 @@ public class Digest
new OutputStreamWriter(new FileOutputStream(output), "UTF-8")); new OutputStreamWriter(new FileOutputStream(output), "UTF-8"));
// compute and append the MD5 digest of each resource in the list // compute and append the MD5 digest of each resource in the list
for (Iterator iter = resources.iterator(); iter.hasNext(); ) { for (Iterator<Resource> iter = resources.iterator(); iter.hasNext();) {
Resource rsrc = (Resource)iter.next(); Resource rsrc = iter.next();
String path = rsrc.getPath(); String path = rsrc.getPath();
try { try {
String digest = rsrc.computeDigest(md, null); String digest = rsrc.computeDigest(md, null);
@@ -152,6 +152,6 @@ public class Digest
data.append(path).append(" = ").append(digest).append("\n"); data.append(path).append(" = ").append(digest).append("\n");
} }
protected HashMap _digests = new HashMap(); protected HashMap<String, String> _digests = new HashMap<String, String>();
protected String _metaDigest = ""; protected String _metaDigest = "";
} }
@@ -8,7 +8,6 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.security.MessageDigest; import java.security.MessageDigest;
@@ -204,7 +203,8 @@ public class Resource
if (target.getPath().endsWith(".jar")) { if (target.getPath().endsWith(".jar")) {
JarFile jar = new JarFile(target); JarFile jar = new JarFile(target);
try { try {
SortableArrayList entries = new SortableArrayList(); SortableArrayList<JarEntry> entries =
new SortableArrayList<JarEntry>();
CollectionUtil.addAll(entries, jar.entries()); CollectionUtil.addAll(entries, jar.entries());
entries.sort(ENTRY_COMP); entries.sort(ENTRY_COMP);
@@ -272,10 +272,9 @@ public class Resource
protected boolean _unpack; protected boolean _unpack;
/** Used to sort the entries in a jar file. */ /** Used to sort the entries in a jar file. */
protected static final Comparator ENTRY_COMP = new Comparator() { protected static final Comparator<JarEntry> ENTRY_COMP =
public int compare (Object o1, Object o2) { new Comparator<JarEntry>() {
JarEntry e1 = (JarEntry)o1; public int compare (JarEntry e1, JarEntry e2) {
JarEntry e2 = (JarEntry)o2;
return e1.getName().compareTo(e2.getName()); return e1.getName().compareTo(e2.getName());
} }
}; };
@@ -12,11 +12,9 @@ import java.util.ResourceBundle;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import com.samskivert.swing.GroupLayout; import com.samskivert.swing.GroupLayout;
import com.samskivert.swing.Spacer; import com.samskivert.swing.Spacer;
@@ -10,7 +10,6 @@ import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
@@ -26,7 +25,6 @@ import java.io.PrintStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@@ -390,7 +388,7 @@ public class Getdown extends Thread
final Resource patch = _app.getPatchResource(); final Resource patch = _app.getPatchResource();
if (patch != null) { if (patch != null) {
// download the patch file... // download the patch file...
ArrayList list = new ArrayList(); ArrayList<Resource> list = new ArrayList<Resource>();
list.add(patch); list.add(patch);
download(list); download(list);
@@ -495,8 +493,7 @@ public class Getdown extends Thread
InputStream stderr = proc.getErrorStream(); InputStream stderr = proc.getErrorStream();
BufferedReader reader = new BufferedReader( BufferedReader reader = new BufferedReader(
new InputStreamReader(stderr)); new InputStreamReader(stderr));
String line = null; while (reader.readLine() != null) {
while ((line = reader.readLine()) != null) {
// nothing doing! // nothing doing!
} }
Log.info("Process exited: " + proc.waitFor()); Log.info("Process exited: " + proc.waitFor());
@@ -3,7 +3,6 @@
package com.threerings.getdown.launcher; package com.threerings.getdown.launcher;
import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
import java.awt.Graphics2D; import java.awt.Graphics2D;
@@ -3,14 +3,12 @@
package com.threerings.getdown.tools; package com.threerings.getdown.tools;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
@@ -75,13 +73,13 @@ public class Differ
Application oapp = new Application(ovdir, null); Application oapp = new Application(ovdir, null);
oapp.init(false); oapp.init(false);
ArrayList orsrcs = new ArrayList(); ArrayList<Resource> orsrcs = new ArrayList<Resource>();
orsrcs.addAll(oapp.getCodeResources()); orsrcs.addAll(oapp.getCodeResources());
orsrcs.addAll(oapp.getResources()); orsrcs.addAll(oapp.getResources());
Application napp = new Application(nvdir, null); Application napp = new Application(nvdir, null);
napp.init(false); napp.init(false);
ArrayList nrsrcs = new ArrayList(); ArrayList<Resource> nrsrcs = new ArrayList<Resource>();
nrsrcs.addAll(napp.getCodeResources()); nrsrcs.addAll(napp.getCodeResources());
nrsrcs.addAll(napp.getResources()); nrsrcs.addAll(napp.getResources());
@@ -95,7 +93,7 @@ public class Differ
// for each file in the new application, it either already // for each file in the new application, it either already
// exists in the old application, or it is new // exists in the old application, or it is new
for (int ii = 0; ii < nrsrcs.size(); ii++) { for (int ii = 0; ii < nrsrcs.size(); ii++) {
Resource rsrc = (Resource)nrsrcs.get(ii); Resource rsrc = nrsrcs.get(ii);
int oidx = orsrcs.indexOf(rsrc); int oidx = orsrcs.indexOf(rsrc);
Resource orsrc = (oidx == -1) ? Resource orsrc = (oidx == -1) ?
null : (Resource)orsrcs.remove(oidx); null : (Resource)orsrcs.remove(oidx);
@@ -147,7 +145,7 @@ public class Differ
// now any file remaining in orsrcs needs to be removed // now any file remaining in orsrcs needs to be removed
for (int ii = 0; ii < orsrcs.size(); ii++) { for (int ii = 0; ii < orsrcs.size(); ii++) {
Resource rsrc = (Resource)orsrcs.get(ii); Resource rsrc = orsrcs.get(ii);
// simply add an entry with the resource name and the // simply add an entry with the resource name and the
// deletion suffix // deletion suffix
if (verbose) { if (verbose) {
@@ -12,6 +12,7 @@ import org.apache.tools.ant.Task;
import com.threerings.getdown.data.Application; import com.threerings.getdown.data.Application;
import com.threerings.getdown.data.Digest; import com.threerings.getdown.data.Digest;
import com.threerings.getdown.data.Resource;
/** /**
* An ant task used to create a <code>digest.txt</code> for a Getdown * An ant task used to create a <code>digest.txt</code> for a Getdown
@@ -60,7 +61,7 @@ public class DigesterTask extends Task
Application app = new Application(appdir, null); Application app = new Application(appdir, null);
app.init(false); app.init(false);
ArrayList rsrcs = new ArrayList(); ArrayList<Resource> rsrcs = new ArrayList<Resource>();
rsrcs.add(app.getConfigResource()); rsrcs.add(app.getConfigResource());
rsrcs.addAll(app.getCodeResources()); rsrcs.addAll(app.getCodeResources());
rsrcs.addAll(app.getResources()); rsrcs.addAll(app.getResources());
@@ -62,21 +62,21 @@ public class JarDiffPatcher
JarOutputStream jos = new JarOutputStream(target); JarOutputStream jos = new JarOutputStream(target);
JarFile oldJar = new JarFile(oldFile); JarFile oldJar = new JarFile(oldFile);
JarFile jarDiff = new JarFile(diffFile); JarFile jarDiff = new JarFile(diffFile);
Set ignoreSet = new HashSet(); Set<String> ignoreSet = new HashSet<String>();
Map renameMap = new HashMap(); Map<String, String> renameMap = new HashMap<String, String>();
determineNameMapping(jarDiff, ignoreSet, renameMap); determineNameMapping(jarDiff, ignoreSet, renameMap);
// get all keys in renameMap // get all keys in renameMap
Object[] keys = renameMap.keySet().toArray(); Object[] keys = renameMap.keySet().toArray();
// Files to implicit move // Files to implicit move
Set oldjarNames = new HashSet(); Set<String> oldjarNames = new HashSet<String>();
Enumeration oldEntries = oldJar.entries(); Enumeration<JarEntry> oldEntries = oldJar.entries();
if (oldEntries != null) { if (oldEntries != null) {
while (oldEntries.hasMoreElements()) { while (oldEntries.hasMoreElements()) {
oldjarNames.add(((JarEntry)oldEntries.nextElement()).getName()); oldjarNames.add(oldEntries.nextElement().getName());
} }
} }
@@ -94,10 +94,10 @@ public class JarDiffPatcher
size -= ignoreSet.size(); size -= ignoreSet.size();
// Add content from JARDiff // Add content from JARDiff
Enumeration entries = jarDiff.entries(); Enumeration<JarEntry> entries = jarDiff.entries();
if (entries != null) { if (entries != null) {
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
JarEntry entry = (JarEntry)entries.nextElement(); JarEntry entry = entries.nextElement();
if (!INDEX_NAME.equals(entry.getName())) { if (!INDEX_NAME.equals(entry.getName())) {
updateObserver(observer, currentEntry, size); updateObserver(observer, currentEntry, size);
currentEntry++; currentEntry++;
@@ -188,55 +188,56 @@ public class JarDiffPatcher
} }
} }
protected void determineNameMapping (JarFile jarDiff, Set ignoreSet, protected void determineNameMapping (JarFile jarDiff, Set<String> ignoreSet,
Map renameMap) Map<String, String> renameMap)
throws IOException throws IOException
{ {
InputStream is = jarDiff.getInputStream(jarDiff.getEntry(INDEX_NAME)); InputStream is = jarDiff.getInputStream(jarDiff.getEntry(INDEX_NAME));
if (is == null) { if (is == null) {
throw new IOException("error.noindex"); throw new IOException("error.noindex");
} }
LineNumberReader indexReader = LineNumberReader indexReader =
new LineNumberReader(new InputStreamReader(is, "UTF-8")); new LineNumberReader(new InputStreamReader(is, "UTF-8"));
String line = indexReader.readLine(); String line = indexReader.readLine();
if (line == null || !line.equals(VERSION_HEADER)) { if (line == null || !line.equals(VERSION_HEADER)) {
throw new IOException("jardiff.error.badheader: " + line); throw new IOException("jardiff.error.badheader: " + line);
} }
while ((line = indexReader.readLine()) != null) { while ((line = indexReader.readLine()) != null) {
if (line.startsWith(REMOVE_COMMAND)) { if (line.startsWith(REMOVE_COMMAND)) {
List sub = getSubpaths( List<String> sub = getSubpaths(
line.substring(REMOVE_COMMAND.length())); line.substring(REMOVE_COMMAND.length()));
if (sub.size() != 1) { if (sub.size() != 1) {
throw new IOException("error.badremove: " + line); throw new IOException("error.badremove: " + line);
} }
ignoreSet.add(sub.get(0)); ignoreSet.add(sub.get(0));
} else if (line.startsWith(MOVE_COMMAND)) { } else if (line.startsWith(MOVE_COMMAND)) {
List sub = getSubpaths(line.substring(MOVE_COMMAND.length())); List<String> sub = getSubpaths(line.substring(
MOVE_COMMAND.length()));
if (sub.size() != 2) { if (sub.size() != 2) {
throw new IOException("error.badmove: " + line); throw new IOException("error.badmove: " + line);
} }
// target of move should be the key // target of move should be the key
if (renameMap.put(sub.get(1), sub.get(0)) != null) { if (renameMap.put(sub.get(1), sub.get(0)) != null) {
// invalid move - should not move to same target twice // invalid move - should not move to same target twice
throw new IOException("error.badmove: " + line); throw new IOException("error.badmove: " + line);
} }
} else if (line.length() > 0) { } else if (line.length() > 0) {
throw new IOException("error.badcommand: " + line); throw new IOException("error.badcommand: " + line);
} }
} }
} }
protected List getSubpaths (String path) protected List<String> getSubpaths (String path)
{ {
int index = 0; int index = 0;
int length = path.length(); int length = path.length();
ArrayList sub = new ArrayList(); ArrayList<String> sub = new ArrayList<String>();
while (index < length) { while (index < length) {
while (index < length && Character.isWhitespace while (index < length && Character.isWhitespace
@@ -33,10 +33,10 @@ public class ConfigUtil
* @return a list of <code>String[]</code> instances containing the * @return a list of <code>String[]</code> instances containing the
* key/value pairs in the order they were parsed from the file. * key/value pairs in the order they were parsed from the file.
*/ */
public static List parsePairs (File config, boolean checkPlatform) public static List<String[]> parsePairs (File config, boolean checkPlatform)
throws IOException throws IOException
{ {
ArrayList pairs = new ArrayList(); ArrayList<String[]> pairs = new ArrayList<String[]>();
String osname = System.getProperty("os.name"); String osname = System.getProperty("os.name");
osname = (osname == null) ? "" : osname.toLowerCase(); osname = (osname == null) ? "" : osname.toLowerCase();
@@ -118,12 +118,16 @@ public class ConfigUtil
* of strings if more than one key/value pair in the config file was * of strings if more than one key/value pair in the config file was
* associated with the same key. * associated with the same key.
*/ */
public static HashMap parseConfig (File config, boolean checkPlatform) public static HashMap<String, Object> parseConfig (File config,
boolean checkPlatform)
throws IOException throws IOException
{ {
List pairs = parsePairs(config, checkPlatform); List<String[]> pairs = parsePairs(config, checkPlatform);
HashMap data = new HashMap(); HashMap<String, Object> data = new HashMap<String, Object>();
// I thought that we could use HashMap<String, String[]> and put
// new String[] {pair[1]} for the null case, but it mysteriously dies
// on launch, so leaving it as HashMap<String, Object> for now
for (Iterator iter = pairs.iterator(); iter.hasNext(); ) { for (Iterator iter = pairs.iterator(); iter.hasNext(); ) {
String[] pair = (String[])iter.next(); String[] pair = (String[])iter.next();
Object value = data.get(pair[0]); Object value = data.get(pair[0]);