Changeset 5540 in josm


Ignore:
Timestamp:
2012-10-27T21:56:52+02:00 (11 years ago)
Author:
jttt
Message:

thread safety in ImageProvider

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/tools/ImageProvider.java

    r5275 r5540  
    3232import java.util.HashMap;
    3333import java.util.Map;
     34import java.util.concurrent.ExecutorService;
    3435import java.util.concurrent.Executors;
    35 import java.util.concurrent.ExecutorService;
    3636import java.util.regex.Matcher;
    3737import java.util.regex.Pattern;
     
    278278     * @param callback a callback. It is called, when the image is ready.
    279279     * This can happen before the call to this method returns or it may be
    280      * invoked some time (seconds) later. If no image is available, a null 
     280     * invoked some time (seconds) later. If no image is available, a null
    281281     * value is returned to callback (just like {@link #get}).
    282282     */
     
    326326
    327327    /**
    328      * @see #getIfAvailable(java.lang.String, java.lang.String) 
     328     * @see #getIfAvailable(java.lang.String, java.lang.String)
    329329     */
    330330    public static ImageIcon getIfAvailable(String name) {
     
    340340
    341341    private ImageResource getIfAvailableImpl(Collection<ClassLoader> additionalClassLoaders) {
    342         if (name == null)
    343             return null;
    344 
    345         try {
    346             if (name.startsWith("data:")) {
    347                 Matcher m = dataUrlPattern.matcher(name);
    348                 if (m.matches()) {
    349                     String mediatype = m.group(1);
    350                     String base64 = m.group(2);
    351                     String data = m.group(3);
    352                     byte[] bytes = ";base64".equals(base64)
    353                             ? Base64.decodeBase64(data)
    354                             : URLDecoder.decode(data, "utf-8").getBytes();
    355                     if (mediatype != null && mediatype.contains("image/svg+xml")) {
    356                         URI uri = getSvgUniverse().loadSVG(new StringReader(new String(bytes)), name);
    357                         return new ImageResource(getSvgUniverse().getDiagram(uri));
    358                     } else {
    359                         try {
    360                             return new ImageResource(ImageIO.read(new ByteArrayInputStream(bytes)));
    361                         } catch (IOException e) {}
     342        synchronized (cache) {
     343            // This method is called from different thread and modifying HashMap concurrently can result
     344            // for example in loops in map entries (ie freeze when such entry is retrieved)
     345            // Yes, it did happen to me :-)
     346            if (name == null)
     347                return null;
     348
     349            try {
     350                if (name.startsWith("data:")) {
     351                    Matcher m = dataUrlPattern.matcher(name);
     352                    if (m.matches()) {
     353                        String mediatype = m.group(1);
     354                        String base64 = m.group(2);
     355                        String data = m.group(3);
     356                        byte[] bytes = ";base64".equals(base64)
     357                                ? Base64.decodeBase64(data)
     358                                        : URLDecoder.decode(data, "utf-8").getBytes();
     359                                if (mediatype != null && mediatype.contains("image/svg+xml")) {
     360                                    URI uri = getSvgUniverse().loadSVG(new StringReader(new String(bytes)), name);
     361                                    return new ImageResource(getSvgUniverse().getDiagram(uri));
     362                                } else {
     363                                    try {
     364                                        return new ImageResource(ImageIO.read(new ByteArrayInputStream(bytes)));
     365                                    } catch (IOException e) {}
     366                                }
    362367                    }
    363368                }
    364             }
    365         } catch (UnsupportedEncodingException ex) {
    366             throw new RuntimeException(ex.getMessage(), ex);
    367         } catch (IOException ex) {
    368             throw new RuntimeException(ex.getMessage(), ex);
    369         }
    370 
    371         ImageType type = name.toLowerCase().endsWith(".svg") ? ImageType.SVG : ImageType.OTHER;
    372 
    373         if (name.startsWith("http://")) {
    374             String url = name;
    375             ImageResource ir = cache.get(url);
    376             if (ir != null) return ir;
    377             ir = getIfAvailableHttp(url, type);
    378             if (ir != null) {
    379                 cache.put(url, ir);
    380             }
    381             return ir;
    382         } else if (name.startsWith("wiki://")) {
    383             ImageResource ir = cache.get(name);
    384             if (ir != null) return ir;
    385             ir = getIfAvailableWiki(name, type);
    386             if (ir != null) {
    387                 cache.put(name, ir);
    388             }
    389             return ir;
    390         }
    391 
    392         if (subdir == null) {
    393             subdir = "";
    394         } else if (!subdir.equals("")) {
    395             subdir += "/";
    396         }
    397         String[] extensions;
    398         if (name.indexOf('.') != -1) {
    399             extensions = new String[] { "" };
    400         } else {
    401             extensions = new String[] { ".png", ".svg"};
    402         }
    403         final int ARCHIVE = 0, LOCAL = 1;
    404         for (int place : new Integer[] { ARCHIVE, LOCAL }) {
    405             for (String ext : extensions) {
    406 
    407                 if (".svg".equals(ext)) {
    408                     type = ImageType.SVG;
    409                 } else if (".png".equals(ext)) {
    410                     type = ImageType.OTHER;
    411                 }
    412 
    413                 String full_name = subdir + name + ext;
    414                 String cache_name = full_name;
    415                 /* cache separately */
    416                 if (dirs != null && dirs.size() > 0) {
    417                     cache_name = "id:" + id + ":" + full_name;
    418                     if(archive != null) {
    419                         cache_name += ":" + archive.getName();
     369            } catch (UnsupportedEncodingException ex) {
     370                throw new RuntimeException(ex.getMessage(), ex);
     371            } catch (IOException ex) {
     372                throw new RuntimeException(ex.getMessage(), ex);
     373            }
     374
     375            ImageType type = name.toLowerCase().endsWith(".svg") ? ImageType.SVG : ImageType.OTHER;
     376
     377            if (name.startsWith("http://")) {
     378                String url = name;
     379                ImageResource ir = cache.get(url);
     380                if (ir != null) return ir;
     381                ir = getIfAvailableHttp(url, type);
     382                if (ir != null) {
     383                    cache.put(url, ir);
     384                }
     385                return ir;
     386            } else if (name.startsWith("wiki://")) {
     387                ImageResource ir = cache.get(name);
     388                if (ir != null) return ir;
     389                ir = getIfAvailableWiki(name, type);
     390                if (ir != null) {
     391                    cache.put(name, ir);
     392                }
     393                return ir;
     394            }
     395
     396            if (subdir == null) {
     397                subdir = "";
     398            } else if (!subdir.equals("")) {
     399                subdir += "/";
     400            }
     401            String[] extensions;
     402            if (name.indexOf('.') != -1) {
     403                extensions = new String[] { "" };
     404            } else {
     405                extensions = new String[] { ".png", ".svg"};
     406            }
     407            final int ARCHIVE = 0, LOCAL = 1;
     408            for (int place : new Integer[] { ARCHIVE, LOCAL }) {
     409                for (String ext : extensions) {
     410
     411                    if (".svg".equals(ext)) {
     412                        type = ImageType.SVG;
     413                    } else if (".png".equals(ext)) {
     414                        type = ImageType.OTHER;
    420415                    }
    421                 }
    422 
    423                 ImageResource ir = cache.get(cache_name);
    424                 if (ir != null) return ir;
    425 
    426                 switch (place) {
     416
     417                    String full_name = subdir + name + ext;
     418                    String cache_name = full_name;
     419                    /* cache separately */
     420                    if (dirs != null && dirs.size() > 0) {
     421                        cache_name = "id:" + id + ":" + full_name;
     422                        if(archive != null) {
     423                            cache_name += ":" + archive.getName();
     424                        }
     425                    }
     426
     427                    ImageResource ir = cache.get(cache_name);
     428                    if (ir != null) return ir;
     429
     430                    switch (place) {
    427431                    case ARCHIVE:
    428432                        if (archive != null) {
     
    450454                        }
    451455                        break;
    452                 }
    453             }
    454         }
    455         return null;
     456                    }
     457                }
     458            }
     459            return null;
     460        }
    456461    }
    457462
     
    461466                    new File(Main.pref.getCacheDirectory(), "images").getPath());
    462467            switch (type) {
    463                 case SVG:
    464                     URI uri = getSvgUniverse().loadSVG(is, is.getFile().toURI().toURL().toString());
    465                     SVGDiagram svg = getSvgUniverse().getDiagram(uri);
    466                     return svg == null ? null : new ImageResource(svg);
    467                 case OTHER:
    468                     BufferedImage img = null;
    469                     try {
    470                         img = ImageIO.read(is.getFile().toURI().toURL());
    471                     } catch (IOException e) {}
    472                     return img == null ? null : new ImageResource(img);
    473                 default:
    474                     throw new AssertionError();
     468            case SVG:
     469                URI uri = getSvgUniverse().loadSVG(is, is.getFile().toURI().toURL().toString());
     470                SVGDiagram svg = getSvgUniverse().getDiagram(uri);
     471                return svg == null ? null : new ImageResource(svg);
     472            case OTHER:
     473                BufferedImage img = null;
     474                try {
     475                    img = ImageIO.read(is.getFile().toURI().toURL());
     476                } catch (IOException e) {}
     477                return img == null ? null : new ImageResource(img);
     478            default:
     479                throw new AssertionError();
    475480            }
    476481        } catch (IOException e) {
     
    484489                "http://upload.wikimedia.org/wikipedia/commons/",
    485490                "http://wiki.openstreetmap.org/wiki/File:"
    486         );
     491                );
    487492        final Collection<String> baseUrls = Main.pref.getCollection("image-provider.wiki.urls", defaultBaseUrls);
    488493
     
    524529                    is = zipFile.getInputStream(entry);
    525530                    switch (type) {
    526                         case SVG:
    527                             URI uri = getSvgUniverse().loadSVG(is, full_name);
    528                             SVGDiagram svg = getSvgUniverse().getDiagram(uri);
    529                             return svg == null ? null : new ImageResource(svg);
    530                         case OTHER:
    531                             while(size > 0)
    532                             {
    533                                 int l = is.read(buf, offs, size);
    534                                 offs += l;
    535                                 size -= l;
    536                             }
    537                             BufferedImage img = null;
    538                             try {
    539                                 img = ImageIO.read(new ByteArrayInputStream(buf));
    540                             } catch (IOException e) {}
    541                             return img == null ? null : new ImageResource(img);
    542                         default:
    543                             throw new AssertionError();
     531                    case SVG:
     532                        URI uri = getSvgUniverse().loadSVG(is, full_name);
     533                        SVGDiagram svg = getSvgUniverse().getDiagram(uri);
     534                        return svg == null ? null : new ImageResource(svg);
     535                    case OTHER:
     536                        while(size > 0)
     537                        {
     538                            int l = is.read(buf, offs, size);
     539                            offs += l;
     540                            size -= l;
     541                        }
     542                        BufferedImage img = null;
     543                        try {
     544                            img = ImageIO.read(new ByteArrayInputStream(buf));
     545                        } catch (IOException e) {}
     546                        return img == null ? null : new ImageResource(img);
     547                    default:
     548                        throw new AssertionError();
    544549                    }
    545550                } finally {
     
    564569    private static ImageResource getIfAvailableLocalURL(URL path, ImageType type) {
    565570        switch (type) {
    566             case SVG:
    567                 URI uri = getSvgUniverse().loadSVG(path);
    568                 SVGDiagram svg = getSvgUniverse().getDiagram(uri);
    569                 return svg == null ? null : new ImageResource(svg);
    570             case OTHER:
    571                 BufferedImage img = null;
    572                 try {
    573                     img = ImageIO.read(path);
    574                 } catch (IOException e) {}
    575                 return img == null ? null : new ImageResource(img);
    576             default:
    577                 throw new AssertionError();
     571        case SVG:
     572            URI uri = getSvgUniverse().loadSVG(path);
     573            SVGDiagram svg = getSvgUniverse().getDiagram(uri);
     574            return svg == null ? null : new ImageResource(svg);
     575        case OTHER:
     576            BufferedImage img = null;
     577            try {
     578                img = ImageIO.read(path);
     579            } catch (IOException e) {}
     580            return img == null ? null : new ImageResource(img);
     581        default:
     582            throw new AssertionError();
    578583        }
    579584    }
     
    696701                    base + fn,
    697702                    new File(Main.pref.getPreferencesDir(), "images").toString()
    698             )));
     703                    )));
    699704        } catch (SAXReturnException r) {
    700705            return r.getResult();
     
    734739    public static ImageIcon overlay(Icon ground, Icon overlay, OverlayPosition pos) {
    735740        GraphicsConfiguration conf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
    736         .getDefaultConfiguration();
     741                .getDefaultConfiguration();
    737742        int w = ground.getIconWidth();
    738743        int h = ground.getIconHeight();
Note: See TracChangeset for help on using the changeset viewer.