Ignore:
Timestamp:
2014-08-27T17:40:39+02:00 (10 years ago)
Author:
bastiK
Message:

fixed #10425 - ConcurrentModificationException when auto update mappaint file

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java

    r7248 r7447  
    7070
    7171    /**
     72     * This lock prevents concurrent execution of {@link MapCSSRuleIndex#clear() },
     73     * {@link MapCSSRuleIndex#initIndex()} and {@link MapCSSRuleIndex#getRuleCandidates }.
     74     *
     75     * For efficiency reasons, these methods are synchronized higher up the
     76     * stack trace.
     77     */
     78    public final static Object STYLE_SOURCE_LOCK = new Object();
     79   
     80    /**
    7281     * A collection of {@link MapCSSRule}s, that are indexed by tag key and value.
    7382     *
     
    91100        public final Set<MapCSSRule> remaining = new HashSet<>();
    92101       
     102        private static final boolean DEBUG_LOCKING = false;
     103       
    93104        public void add(MapCSSRule rule) {
    94105            rules.add(rule);
     
    97108        /**
    98109         * Initialize the index.
     110         *
     111         * You must own the lock STYLE_SOURCE_LOCK when calling this method.
    99112         */
    100113        public void initIndex() {
     114            if (DEBUG_LOCKING) {
     115                if (!Thread.holdsLock(STYLE_SOURCE_LOCK)) {
     116                    throw new RuntimeException();
     117                }
     118            }
    101119            for (MapCSSRule r: rules) {
    102120                // find the rightmost selector, this must be a GeneralSelector
     
    135153         * @return a Collection of rules that filters out most of the rules
    136154         * that cannot match, based on the tags of the primitive
     155         *
     156         * You must own the lock STYLE_SOURCE_LOCK when calling this method.
    137157         */
    138158        public Collection<MapCSSRule> getRuleCandidates(OsmPrimitive osm) {
     159            if (DEBUG_LOCKING) {
     160                if (!Thread.holdsLock(STYLE_SOURCE_LOCK)) {
     161                    throw new RuntimeException();
     162                }
     163            }
    139164            List<MapCSSRule> ruleCandidates = new ArrayList<>(remaining);
    140165            for (Map.Entry<String,String> e : osm.getKeys().entrySet()) {
     
    151176        }
    152177
     178        /**
     179         * Clear the index.
     180         *
     181         * You must own the lock STYLE_SOURCE_LOCK when calling this method.
     182         */
    153183        public void clear() {
     184            if (DEBUG_LOCKING) {
     185                if (!Thread.holdsLock(STYLE_SOURCE_LOCK)) {
     186                    throw new RuntimeException();
     187                }
     188            }
    154189            rules.clear();
    155190            index.clear();
     
    181216    @Override
    182217    public void loadStyleSource() {
    183         init();
    184         rules.clear();
    185         nodeRules.clear();
    186         wayRules.clear();
    187         wayNoAreaRules.clear();
    188         relationRules.clear();
    189         multipolygonRules.clear();
    190         canvasRules.clear();
    191         try (InputStream in = getSourceInputStream()) {
    192             try {
    193                 // evaluate @media { ... } blocks
    194                 MapCSSParser preprocessor = new MapCSSParser(in, "UTF-8", MapCSSParser.LexicalState.PREPROCESSOR);
    195                 String mapcss = preprocessor.pp_root(this);
    196 
    197                 // do the actual mapcss parsing
    198                 InputStream in2 = new ByteArrayInputStream(mapcss.getBytes(StandardCharsets.UTF_8));
    199                 MapCSSParser parser = new MapCSSParser(in2, "UTF-8", MapCSSParser.LexicalState.DEFAULT);
    200                 parser.sheet(this);
    201 
    202                 loadMeta();
    203                 loadCanvas();
    204             } finally {
    205                 closeSourceInputStream(in);
    206             }
    207         } catch (IOException e) {
    208             Main.warn(tr("Failed to load Mappaint styles from ''{0}''. Exception was: {1}", url, e.toString()));
    209             Main.error(e);
    210             logError(e);
    211         } catch (TokenMgrError e) {
    212             Main.warn(tr("Failed to parse Mappaint styles from ''{0}''. Error was: {1}", url, e.getMessage()));
    213             Main.error(e);
    214             logError(e);
    215         } catch (ParseException e) {
    216             Main.warn(tr("Failed to parse Mappaint styles from ''{0}''. Error was: {1}", url, e.getMessage()));
    217             Main.error(e);
    218             logError(new ParseException(e.getMessage())); // allow e to be garbage collected, it links to the entire token stream
    219         }
    220         // optimization: filter rules for different primitive types
    221         for (MapCSSRule r: rules) {
    222             // find the rightmost selector, this must be a GeneralSelector
    223             Selector selRightmost = r.selector;
    224             while (selRightmost instanceof ChildOrParentSelector) {
    225                 selRightmost = ((ChildOrParentSelector) selRightmost).right;
    226             }
    227             MapCSSRule optRule = new MapCSSRule(r.selector.optimizedBaseCheck(), r.declaration);
    228             final String base = ((GeneralSelector) selRightmost).getBase();
    229             switch (base) {
    230                 case "node":
    231                     nodeRules.add(optRule);
    232                     break;
    233                 case "way":
    234                     wayNoAreaRules.add(optRule);
    235                     wayRules.add(optRule);
    236                     break;
    237                 case "area":
    238                     wayRules.add(optRule);
    239                     multipolygonRules.add(optRule);
    240                     break;
    241                 case "relation":
    242                     relationRules.add(optRule);
    243                     multipolygonRules.add(optRule);
    244                     break;
    245                 case "*":
    246                     nodeRules.add(optRule);
    247                     wayRules.add(optRule);
    248                     wayNoAreaRules.add(optRule);
    249                     relationRules.add(optRule);
    250                     multipolygonRules.add(optRule);
    251                     break;
    252                 case "canvas":
    253                     canvasRules.add(r);
    254                     break;
    255                 case "meta":
    256                     break;
    257                 default:
    258                     final RuntimeException e = new RuntimeException(MessageFormat.format("Unknown MapCSS base selector {0}", base));
    259                     Main.warn(tr("Failed to parse Mappaint styles from ''{0}''. Error was: {1}", url, e.getMessage()));
    260                     Main.error(e);
    261                     logError(e);
    262             }
    263         }
    264         nodeRules.initIndex();
    265         wayRules.initIndex();
    266         wayNoAreaRules.initIndex();
    267         relationRules.initIndex();
    268         multipolygonRules.initIndex();
    269         canvasRules.initIndex();
     218        synchronized (STYLE_SOURCE_LOCK) {
     219            init();
     220            rules.clear();
     221            nodeRules.clear();
     222            wayRules.clear();
     223            wayNoAreaRules.clear();
     224            relationRules.clear();
     225            multipolygonRules.clear();
     226            canvasRules.clear();
     227            try (InputStream in = getSourceInputStream()) {
     228                try {
     229                    // evaluate @media { ... } blocks
     230                    MapCSSParser preprocessor = new MapCSSParser(in, "UTF-8", MapCSSParser.LexicalState.PREPROCESSOR);
     231                    String mapcss = preprocessor.pp_root(this);
     232
     233                    // do the actual mapcss parsing
     234                    InputStream in2 = new ByteArrayInputStream(mapcss.getBytes(StandardCharsets.UTF_8));
     235                    MapCSSParser parser = new MapCSSParser(in2, "UTF-8", MapCSSParser.LexicalState.DEFAULT);
     236                    parser.sheet(this);
     237
     238                    loadMeta();
     239                    loadCanvas();
     240                } finally {
     241                    closeSourceInputStream(in);
     242                }
     243            } catch (IOException e) {
     244                Main.warn(tr("Failed to load Mappaint styles from ''{0}''. Exception was: {1}", url, e.toString()));
     245                Main.error(e);
     246                logError(e);
     247            } catch (TokenMgrError e) {
     248                Main.warn(tr("Failed to parse Mappaint styles from ''{0}''. Error was: {1}", url, e.getMessage()));
     249                Main.error(e);
     250                logError(e);
     251            } catch (ParseException e) {
     252                Main.warn(tr("Failed to parse Mappaint styles from ''{0}''. Error was: {1}", url, e.getMessage()));
     253                Main.error(e);
     254                logError(new ParseException(e.getMessage())); // allow e to be garbage collected, it links to the entire token stream
     255            }
     256            // optimization: filter rules for different primitive types
     257            for (MapCSSRule r: rules) {
     258                // find the rightmost selector, this must be a GeneralSelector
     259                Selector selRightmost = r.selector;
     260                while (selRightmost instanceof ChildOrParentSelector) {
     261                    selRightmost = ((ChildOrParentSelector) selRightmost).right;
     262                }
     263                MapCSSRule optRule = new MapCSSRule(r.selector.optimizedBaseCheck(), r.declaration);
     264                final String base = ((GeneralSelector) selRightmost).getBase();
     265                switch (base) {
     266                    case "node":
     267                        nodeRules.add(optRule);
     268                        break;
     269                    case "way":
     270                        wayNoAreaRules.add(optRule);
     271                        wayRules.add(optRule);
     272                        break;
     273                    case "area":
     274                        wayRules.add(optRule);
     275                        multipolygonRules.add(optRule);
     276                        break;
     277                    case "relation":
     278                        relationRules.add(optRule);
     279                        multipolygonRules.add(optRule);
     280                        break;
     281                    case "*":
     282                        nodeRules.add(optRule);
     283                        wayRules.add(optRule);
     284                        wayNoAreaRules.add(optRule);
     285                        relationRules.add(optRule);
     286                        multipolygonRules.add(optRule);
     287                        break;
     288                    case "canvas":
     289                        canvasRules.add(r);
     290                        break;
     291                    case "meta":
     292                        break;
     293                    default:
     294                        final RuntimeException e = new RuntimeException(MessageFormat.format("Unknown MapCSS base selector {0}", base));
     295                        Main.warn(tr("Failed to parse Mappaint styles from ''{0}''. Error was: {1}", url, e.getMessage()));
     296                        Main.error(e);
     297                        logError(e);
     298                }
     299            }
     300            nodeRules.initIndex();
     301            wayRules.initIndex();
     302            wayNoAreaRules.initIndex();
     303            relationRules.initIndex();
     304            multipolygonRules.initIndex();
     305            canvasRules.initIndex();
     306        }
    270307    }
    271308   
Note: See TracChangeset for help on using the changeset viewer.