Ignore:
Timestamp:
2011-06-01T03:55:44+02:00 (14 years ago)
Author:
yellowbkpk
Message:

Switching to use XPath for parsing the metadata and add a retry to the metadata retrieval.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java

    r25376 r26084  
    88import java.util.ArrayList;
    99import java.util.List;
     10import java.util.Locale;
    1011import java.util.concurrent.Callable;
    1112import java.util.concurrent.Executors;
    1213import java.util.concurrent.Future;
     14import java.util.regex.Pattern;
    1315
    1416import javax.imageio.ImageIO;
     17import javax.xml.parsers.DocumentBuilder;
     18import javax.xml.parsers.DocumentBuilderFactory;
     19import javax.xml.parsers.ParserConfigurationException;
     20import javax.xml.xpath.XPath;
     21import javax.xml.xpath.XPathConstants;
     22import javax.xml.xpath.XPathExpression;
     23import javax.xml.xpath.XPathExpressionException;
     24import javax.xml.xpath.XPathFactory;
    1525
    1626import org.openstreetmap.gui.jmapviewer.Coordinate;
    17 import org.xml.sax.Attributes;
    18 import org.xml.sax.InputSource;
     27import org.w3c.dom.Document;
     28import org.w3c.dom.Node;
     29import org.w3c.dom.NodeList;
    1930import org.xml.sax.SAXException;
    20 import org.xml.sax.XMLReader;
    21 import org.xml.sax.helpers.DefaultHandler;
    22 import org.xml.sax.helpers.XMLReaderFactory;
    2331
    2432public class BingAerialTileSource extends AbstractOsmTileSource {
    2533    private static String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU";
    2634    private static Future<List<Attribution>> attributions;
     35    private String imageUrlTemplate;
     36    private Integer imageryZoomMax;
     37    private String[] subdomains;
     38
     39    private static final Pattern subdomainPattern = Pattern.compile("\\{subdomain\\}");
     40    private static final Pattern quadkeyPattern = Pattern.compile("\\{quadkey\\}");
     41    private static final Pattern culturePattern = Pattern.compile("\\{culture\\}");
    2742
    2843    public BingAerialTileSource() {
    29         super("Bing Aerial Maps", "http://ecn.t2.tiles.virtualearth.net/tiles/");
     44        super("Bing Aerial Maps", "http://example.com/");
    3045
    3146        if (attributions == null) {
    3247            attributions = Executors.newSingleThreadExecutor().submit(new Callable<List<Attribution>>() {
    3348                public List<Attribution> call() throws Exception {
    34                     return loadAttributionText();
     49                    List<Attribution> attrs = null;
     50                    int waitTime = 1;
     51                    do {
     52
     53                        try {
     54                            attrs = loadAttributionText();
     55                            System.out.println("Successfully loaded Bing attribution data.");
     56                            return attrs;
     57                        } catch(IOException e) {
     58                            System.err.println("Could not connect to Bing API. Will retry in " + waitTime + " seconds.");
     59                            Thread.sleep(waitTime * 1000L);
     60                            waitTime *= 2;
     61                        }
     62
     63                    } while(true);
    3564                }
    3665            });
     
    4675    }
    4776
    48     class AttrHandler extends DefaultHandler {
    49 
    50         private String string;
    51         private Attribution curr;
    52         private List<Attribution> attributions = new ArrayList<Attribution>();
    53         private double southLat;
    54         private double northLat;
    55         private double eastLon;
    56         private double westLon;
    57         private boolean inCoverage = false;
    58 
    59         @Override
    60         public void startElement(String uri, String stripped, String tagName, Attributes attrs) throws SAXException {
    61             if ("ImageryProvider".equals(tagName)) {
    62                 curr = new Attribution();
    63             } else if ("CoverageArea".equals(tagName)) {
    64                 inCoverage = true;
    65             }
    66         }
    67 
    68         @Override
    69         public void characters(char[] ch, int start, int length) throws SAXException {
    70             string = new String(ch, start, length);
    71         }
    72 
    73         @Override
    74         public void endElement(String uri, String stripped, String tagName) throws SAXException {
    75             if ("ImageryProvider".equals(tagName)) {
    76                 attributions.add(curr);
    77             } else if ("Attribution".equals(tagName)) {
    78                 curr.attribution = string;
    79             } else if (inCoverage && "ZoomMin".equals(tagName)) {
    80                 curr.minZoom = Integer.parseInt(string);
    81             } else if (inCoverage && "ZoomMax".equals(tagName)) {
    82                 curr.maxZoom = Integer.parseInt(string);
    83             } else if (inCoverage && "SouthLatitude".equals(tagName)) {
    84                 southLat = Double.parseDouble(string);
    85             } else if (inCoverage && "NorthLatitude".equals(tagName)) {
    86                 northLat = Double.parseDouble(string);
    87             } else if (inCoverage && "EastLongitude".equals(tagName)) {
    88                 eastLon = Double.parseDouble(string);
    89             } else if (inCoverage && "WestLongitude".equals(tagName)) {
    90                 westLon = Double.parseDouble(string);
    91             } else if ("BoundingBox".equals(tagName)) {
    92                 curr.min = new Coordinate(southLat, westLon);
    93                 curr.max = new Coordinate(northLat, eastLon);
    94             } else if ("CoverageArea".equals(tagName)) {
    95                 inCoverage = false;
    96             }
    97             string = "";
    98         }
    99     }
    100 
    101     private List<Attribution> loadAttributionText() {
     77    @Override
     78    public String getTileUrl(int zoom, int tilex, int tiley) throws IOException {
     79        int t = (zoom + tilex + tiley) % subdomains.length;
     80        String subdomain = subdomains[t];
     81
     82        String url = new String(imageUrlTemplate);
     83        url = subdomainPattern.matcher(url).replaceAll(subdomain);
     84        url = quadkeyPattern.matcher(url).replaceAll(computeQuadTree(zoom, tilex, tiley));
     85
     86        return url;
     87    }
     88
     89    private List<Attribution> loadAttributionText() throws IOException {
    10290        try {
    103             URL u = new URL("http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/0,0?zl=1&mapVersion=v1&key="
    104                     + API_KEY + "&include=ImageryProviders&output=xml");
     91            URL u = new URL("http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&output=xml&key="
     92                    + API_KEY);
    10593            URLConnection conn = u.openConnection();
    10694
    107             // This is not JOSM! Do not use anything other than standard JRE classes within this package!
    108             // See package.html for details
    109             //conn.setConnectTimeout(Main.pref.getInteger("imagery.bing.load-attribution-text.timeout", 4000));
    110 
    11195            InputStream stream = conn.getInputStream();
    11296
    113             XMLReader parser = XMLReaderFactory.createXMLReader();
    114             AttrHandler handler = new AttrHandler();
    115             parser.setContentHandler(handler);
    116             parser.parse(new InputSource(stream));
    117             //System.err.println("Added " + handler.attributions.size() + " attributions.");
    118             return handler.attributions;
    119         } catch (IOException e) {
    120             System.err.println("Could not open Bing aerials attribution metadata.");
     97            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
     98            DocumentBuilder builder = factory.newDocumentBuilder();
     99            Document document = builder.parse(stream);
     100
     101            XPathFactory xPathFactory = XPathFactory.newInstance();
     102            XPath xpath = xPathFactory.newXPath();
     103            imageUrlTemplate = xpath.compile("//ImageryMetadata/ImageUrl/text()").evaluate(document);
     104            imageUrlTemplate = culturePattern.matcher(imageUrlTemplate).replaceAll(Locale.getDefault().toString());
     105            imageryZoomMax = Integer.parseInt(xpath.compile("//ImageryMetadata/ZoomMax/text()").evaluate(document));
     106
     107            NodeList subdomainTxt = (NodeList) xpath.compile("//ImageryMetadata/ImageUrlSubdomains/string/text()").evaluate(document, XPathConstants.NODESET);
     108            subdomains = new String[subdomainTxt.getLength()];
     109            for(int i = 0; i < subdomainTxt.getLength(); i++) {
     110                subdomains[i] = subdomainTxt.item(i).getNodeValue();
     111            }
     112
     113            XPathExpression attributionXpath = xpath.compile("Attribution/text()");
     114            XPathExpression coverageAreaXpath = xpath.compile("CoverageArea");
     115            XPathExpression zoomMinXpath = xpath.compile("ZoomMin/text()");
     116            XPathExpression zoomMaxXpath = xpath.compile("ZoomMax/text()");
     117            XPathExpression southLatXpath = xpath.compile("BoundingBox/SouthLatitude/text()");
     118            XPathExpression westLonXpath = xpath.compile("BoundingBox/WestLongitude/text()");
     119            XPathExpression northLatXpath = xpath.compile("BoundingBox/NorthLatitude/text()");
     120            XPathExpression eastLonXpath = xpath.compile("BoundingBox/EastLongitude/text()");
     121
     122            NodeList imageryProviderNodes = (NodeList) xpath.compile("//ImageryMetadata/ImageryProvider").evaluate(document, XPathConstants.NODESET);
     123            List<Attribution> attributions = new ArrayList<Attribution>(imageryProviderNodes.getLength());
     124            for (int i = 0; i < imageryProviderNodes.getLength(); i++) {
     125                Node providerNode = imageryProviderNodes.item(i);
     126
     127                String attribution = attributionXpath.evaluate(providerNode);
     128
     129                NodeList coverageAreaNodes = (NodeList) coverageAreaXpath.evaluate(providerNode, XPathConstants.NODESET);
     130                for(int j = 0; j < coverageAreaNodes.getLength(); j++) {
     131                    Node areaNode = coverageAreaNodes.item(j);
     132                    Attribution attr = new Attribution();
     133                    attr.attribution = attribution;
     134
     135                    attr.maxZoom = Integer.parseInt(zoomMaxXpath.evaluate(areaNode));
     136                    attr.minZoom = Integer.parseInt(zoomMinXpath.evaluate(areaNode));
     137
     138                    Double southLat = Double.parseDouble(southLatXpath.evaluate(areaNode));
     139                    Double northLat = Double.parseDouble(northLatXpath.evaluate(areaNode));
     140                    Double westLon = Double.parseDouble(westLonXpath.evaluate(areaNode));
     141                    Double eastLon = Double.parseDouble(eastLonXpath.evaluate(areaNode));
     142                    attr.min = new Coordinate(southLat, westLon);
     143                    attr.max = new Coordinate(northLat, eastLon);
     144
     145                    attributions.add(attr);
     146                }
     147            }
     148
     149            return attributions;
    121150        } catch (SAXException e) {
    122151            System.err.println("Could not parse Bing aerials attribution metadata.");
    123152            e.printStackTrace();
     153        } catch (ParserConfigurationException e) {
     154            e.printStackTrace();
     155        } catch (XPathExpressionException e) {
     156            e.printStackTrace();
    124157        }
    125158        return null;
     
    128161    @Override
    129162    public int getMaxZoom() {
    130         return 22;
    131     }
    132 
    133     @Override
    134     public String getExtension() {
    135         return ("jpeg");
    136     }
    137 
    138     @Override
    139     public String getTilePath(int zoom, int tilex, int tiley) throws IOException {
    140         try {
    141             if (attributions.get() == null)
    142                 throw new IOException("Cannot load Bing attribution");
    143             String quadtree = computeQuadTree(zoom, tilex, tiley);
    144             return "/tiles/a" + quadtree + "." + getExtension() + "?g=587";
    145         } catch (Exception e) {
    146             throw new IOException("Cannot load Bing attribution", e);
    147         }
     163        if(imageryZoomMax != null)
     164            return imageryZoomMax;
     165        else
     166            return 22;
    148167    }
    149168
Note: See TracChangeset for help on using the changeset viewer.