diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
index bb94d5c..2eedd48 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
@@ -3,10 +3,8 @@ package org.openstreetmap.gui.jmapviewer.tilesources;
 //License: GPL.
 
 import java.awt.Image;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.net.URL;
-import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
@@ -26,9 +24,12 @@ import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
 
 import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.josm.io.CacheCustomContent;
+import org.openstreetmap.josm.io.UTFInputStreamReader;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
 public class BingAerialTileSource extends AbstractTMSTileSource {
@@ -47,27 +48,47 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
 
         if (attributions == null) {
             attributions = Executors.newSingleThreadExecutor().submit(new Callable<List<Attribution>>() {
-                public List<Attribution> call() throws Exception {
-                    List<Attribution> attrs = null;
-                    int waitTime = 1;
-                    do {
 
+                @Override
+                public List<Attribution> call() throws Exception {
+                    BingAttributionData attributionLoader = new BingAttributionData();
+                    int waitTimeSec = 1;
+                    while (true) {
                         try {
-                            attrs = loadAttributionText();
-                            System.out.println("Successfully loaded Bing attribution data.");
-                            return attrs;
-                        } catch(IOException e) {
-                            System.err.println("Could not connect to Bing API. Will retry in " + waitTime + " seconds.");
-                            Thread.sleep(waitTime * 1000L);
-                            waitTime *= 2;
+                            return parseAttributionText(attributionLoader.updateIfRequiredString());
+                        } catch (IOException ex) {
+                            System.err.println("Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds.");
+                            Thread.sleep(waitTimeSec * 1000L);
+                            waitTimeSec *= 2;
                         }
-
-                    } while(true);
+                    }
                 }
             });
         }
     }
 
+    private static class BingAttributionData extends CacheCustomContent<IOException> {
+
+        public BingAttributionData() {
+            super("bing.attribution.xml", CacheCustomContent.INTERVAL_WEEKLY);
+        }
+
+        @Override
+        protected byte[] updateData() throws IOException {
+            URL u = new URL("http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&output=xml&key="
+                    + API_KEY);
+            BufferedReader in = new BufferedReader(new InputStreamReader(u.openStream()));
+            StringBuilder content = new StringBuilder(4096);
+            String line;
+            while ((line = in.readLine()) != null) {
+                content.append(line);
+            }
+            in.close();
+            System.out.println("Successfully loaded Bing attribution data.");
+            return content.toString().getBytes();
+        }
+    }
+
     class Attribution {
         String attribution;
         int minZoom;
@@ -88,17 +109,12 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
         return url;
     }
 
-    private List<Attribution> loadAttributionText() throws IOException {
+    private List<Attribution> parseAttributionText(String xml) throws IOException {
         try {
-            URL u = new URL("http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&output=xml&key="
-                    + API_KEY);
-            URLConnection conn = u.openConnection();
-
-            InputStream stream = conn.getInputStream();
-
             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
             DocumentBuilder builder = factory.newDocumentBuilder();
-            Document document = builder.parse(stream);
+            Document document = builder.parse(new InputSource(
+                    UTFInputStreamReader.create(new ByteArrayInputStream(xml.getBytes()), "UTF-8")));
 
             XPathFactory xPathFactory = XPathFactory.newInstance();
             XPath xpath = xPathFactory.newXPath();
