Index: trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java	(revision 10611)
+++ trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java	(revision 10612)
@@ -11,8 +11,13 @@
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import javax.imageio.ImageIO;
@@ -25,5 +30,4 @@
 import org.openstreetmap.josm.data.projection.Projections;
 import org.openstreetmap.josm.tools.HttpClient;
-import org.openstreetmap.josm.tools.Predicate;
 import org.openstreetmap.josm.tools.Utils;
 import org.w3c.dom.Document;
@@ -35,6 +39,43 @@
 import org.xml.sax.SAXException;
 
+/**
+ * This class represents the capabilites of a WMS imagery server.
+ */
 public class WMSImagery {
 
+    private static final class ChildIterator implements Iterator<Element> {
+        private Element child;
+
+        ChildIterator(Element parent) {
+            child = advanceToElement(parent.getFirstChild());
+        }
+
+        private static Element advanceToElement(Node firstChild) {
+            Node node = firstChild;
+            while (node != null && !(node instanceof Element)) {
+                node = node.getNextSibling();
+            }
+            return (Element) node;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return child != null;
+        }
+
+        @Override
+        public Element next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException("No next sibling.");
+            }
+            Element next = child;
+            child = advanceToElement(child.getNextSibling());
+            return next;
+        }
+    }
+
+    /**
+     * An exception that is thrown if there was an error while getting the capabilities of the WMS server.
+     */
     public static class WMSGetCapabilitiesException extends Exception {
         private final String incomingData;
@@ -62,6 +103,6 @@
 
         /**
-         * Returns the answer from WMS server.
-         * @return the answer from WMS server
+         * The data that caused this exception.
+         * @return The server response to the capabilites request.
          */
         public String getIncomingData() {
@@ -79,5 +120,5 @@
      */
     public List<LayerDetails> getLayers() {
-        return layers;
+        return Collections.unmodifiableList(layers);
     }
 
@@ -98,9 +139,18 @@
     }
 
+    /**
+     * Gets the preffered format for this imagery layer.
+     * @return The preffered format as mime type.
+     */
     public String getPreferredFormats() {
-        return formats.contains("image/jpeg") ? "image/jpeg"
-                : formats.contains("image/png") ? "image/png"
-                : formats.isEmpty() ? null
-                : formats.get(0);
+        if (formats.contains("image/jpeg")) {
+            return "image/jpeg";
+        } else if (formats.contains("image/png")) {
+            return "image/png";
+        } else if (formats.isEmpty()) {
+            return null;
+        } else {
+            return formats.get(0);
+        }
     }
 
@@ -129,17 +179,11 @@
 
     public String buildGetMapUrl(Collection<LayerDetails> selectedLayers, String format) {
-        return buildRootUrl()
-                + "FORMAT=" + format + (imageFormatHasTransparency(format) ? "&TRANSPARENT=TRUE" : "")
+        return buildRootUrl() + "FORMAT=" + format + (imageFormatHasTransparency(format) ? "&TRANSPARENT=TRUE" : "")
                 + "&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&LAYERS="
-                + Utils.join(",", Utils.transform(selectedLayers, new Utils.Function<LayerDetails, String>() {
-            @Override
-            public String apply(LayerDetails x) {
-                return x.ident;
-            }
-        }))
+                + Utils.join(",", Utils.transform(selectedLayers, x -> x.ident))
                 + "&STYLES=&SRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}";
     }
 
-    public void attemptGetCapabilities(String serviceUrlStr) throws MalformedURLException, IOException, WMSGetCapabilitiesException {
+    public void attemptGetCapabilities(String serviceUrlStr) throws IOException, WMSGetCapabilitiesException {
         URL getCapabilitiesUrl = null;
         try {
@@ -162,4 +206,5 @@
             serviceUrl = new URL(serviceUrlStr);
         } catch (HeadlessException e) {
+            Main.warn(e);
             return;
         }
@@ -192,22 +237,8 @@
             child = getChild(child, "GetMap");
 
-            formats = new ArrayList<>(Utils.filter(Utils.transform(getChildren(child, "Format"),
-                    new Utils.Function<Element, String>() {
-                        @Override
-                        public String apply(Element x) {
-                            return x.getTextContent();
-                        }
-                    }),
-                    new Predicate<String>() {
-                        @Override
-                        public boolean evaluate(String format) {
-                            boolean isFormatSupported = isImageFormatSupported(format);
-                            if (!isFormatSupported) {
-                                Main.info("Skipping unsupported image format {0}", format);
-                            }
-                            return isFormatSupported;
-                        }
-                    }
-            ));
+            formats = getChildrenStream(child, "Format")
+                    .map(x -> x.getTextContent())
+                    .filter(WMSImagery::isImageFormatSupportedWarn)
+                    .collect(Collectors.toList());
 
             child = getChild(child, "DCPType");
@@ -231,8 +262,17 @@
     }
 
+    private static boolean isImageFormatSupportedWarn(String format) {
+        boolean isFormatSupported = isImageFormatSupported(format);
+        if (!isFormatSupported) {
+            Main.info("Skipping unsupported image format {0}", format);
+        }
+        return isFormatSupported;
+    }
+
     static boolean isImageFormatSupported(final String format) {
         return ImageIO.getImageReadersByMIMEType(format).hasNext()
                 // handles image/tiff image/tiff8 image/geotiff image/geotiff8
-                || (format.startsWith("image/tiff") || format.startsWith("image/geotiff")) && ImageIO.getImageReadersBySuffix("tiff").hasNext()
+                || (format.startsWith("image/tiff") || format.startsWith("image/geotiff"))
+                        && ImageIO.getImageReadersBySuffix("tiff").hasNext()
                 || format.startsWith("image/png") && ImageIO.getImageReadersBySuffix("png").hasNext()
                 || format.startsWith("image/svg") && ImageIO.getImageReadersBySuffix("svg").hasNext()
@@ -276,13 +316,10 @@
         // Parse the CRS/SRS pulled out of this layer's XML element
         // I think CRS and SRS are the same at this point
-        List<Element> crsChildren = getChildren(element, "CRS");
-        crsChildren.addAll(getChildren(element, "SRS"));
-        for (Element child : crsChildren) {
-            String crs = (String) getContent(child);
-            if (!crs.isEmpty()) {
-                String upperCase = crs.trim().toUpperCase(Locale.ENGLISH);
-                crsList.add(upperCase);
-            }
-        }
+        getChildrenStream(element)
+            .filter(child -> "CRS".equals(child.getNodeName()) || "SRS".equals(child.getNodeName()))
+            .map(child -> (String) getContent(child))
+            .filter(crs -> !crs.isEmpty())
+            .map(crs -> crs.trim().toUpperCase(Locale.ENGLISH))
+            .forEach(crsList::add);
 
         // Check to see if any of the specified projections are supported by JOSM
@@ -351,38 +388,49 @@
     }
 
+    private static Stream<Element> getChildrenStream(Element parent) {
+        if (parent == null) {
+            // ignore missing elements
+            return Stream.empty();
+        } else {
+            Iterable<Element> it = () -> new ChildIterator(parent);
+            return StreamSupport.stream(it.spliterator(), false);
+        }
+    }
+
+    private static Stream<Element> getChildrenStream(Element parent, String name) {
+        return getChildrenStream(parent).filter(child -> name.equals(child.getNodeName()));
+    }
+
     private static List<Element> getChildren(Element parent, String name) {
-        List<Element> retVal = new ArrayList<>();
-        if (parent != null) {
-            for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
-                if (child instanceof Element && name.equals(child.getNodeName())) {
-                    retVal.add((Element) child);
-                }
-            }
-        }
-        return retVal;
+        return getChildrenStream(parent, name).collect(Collectors.toList());
     }
 
     private static Element getChild(Element parent, String name) {
-        if (parent == null)
-            return null;
-        for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
-            if (child instanceof Element && name.equals(child.getNodeName()))
-                return (Element) child;
-        }
-        return null;
-    }
-
+        return getChildrenStream(parent, name).findFirst().orElse(null);
+    }
+
+    /**
+     * The details of a layer of this wms server.
+     */
     public static class LayerDetails {
 
+        /**
+         * The layer name
+         */
         public final String name;
         public final String ident;
+        /**
+         * The child layers of this layer
+         */
         public final List<LayerDetails> children;
+        /**
+         * The bounds this layer can be used for
+         */
         public final Bounds bounds;
         public final Set<String> crsList;
         public final boolean supported;
 
-        public LayerDetails(String name, String ident, Set<String> crsList,
-                            boolean supportedLayer, Bounds bounds,
-                            List<LayerDetails> childLayers) {
+        public LayerDetails(String name, String ident, Set<String> crsList, boolean supportedLayer, Bounds bounds,
+                List<LayerDetails> childLayers) {
             this.name = name;
             this.ident = ident;
