package netflix.nebula.dependency.recommender.provider;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

public abstract class FuzzyVersionResolver {
    private List<Glob> globs;

    abstract protected Collection<String> propertyNames();
    abstract protected String propertyValue(String name);

    private String resolveVersion(String value) {
        if(value == null) return null;
        if(!value.startsWith("$")) return value;
        return resolveVersion(versionOf(value.substring(1)));
    }

    public String versionOf(String key) {
        String version = propertyValue(key);
        if(version != null) return resolveVersion(version);

        if(globs == null) {
            // thread safety for parallel builds
            synchronized (this) {
                if(globs == null) {
                    initializeGlobCache();
                }
            }
        }

        for (Glob glob : globs) {
            if (glob.matches(key)) {
                return resolveVersion(glob.version);
            }
        }

        return null;
    }

    private void initializeGlobCache() {
        globs = new ArrayList<>();
        for (String name : propertyNames()) {
            if(name.contains("*")) {
                globs.add(Glob.compile(name, propertyValue(name)));
            }
        }
        Collections.sort(globs);
    }

    private static class Glob implements Comparable<Glob> {
        private final Pattern pattern;
        private final String version;
        private final int weight;

        private Glob(Pattern pattern, String version, int weight) {
            this.pattern = pattern;
            this.version = version;
            this.weight = weight;
        }

        private static Glob compile(String glob, String version) {
            StringBuilder patternBuilder = new StringBuilder();
            boolean first = true;
            int weight = 0;

            for (String token : glob.split("\\*", -1)) {
                if (first) {
                    first = false;
                } else {
                    patternBuilder.append(".*?");
                }

                weight += token.length();
                patternBuilder.append(Pattern.quote(token));
            }

            Pattern pattern = Pattern.compile(patternBuilder.toString());

            return new Glob(pattern, version, weight);
        }

        private boolean matches(String key) {
            return pattern.matcher(key).matches();
        }

        @Override
        public int compareTo(Glob o) {
            return Integer.compare(o.weight, weight);
        }
    }
}

@@ -250,16 +250,25 @@
 private 
+volatile 
 List%3CGlo
@@ -918,25 +918,29 @@
         
-initializ
+globs = creat
 eGlobCac
@@ -1181,22 +1181,24 @@
 ate 
-void initializ
+List%3CGlob%3E creat
 eGlo
@@ -1216,21 +1216,32 @@
         
-globs
+List%3CGlob%3E cache
  = new A
@@ -1353,21 +1353,21 @@
         
-globs
+cache
 .add(Glo
@@ -1454,22 +1454,44 @@
 ns.sort(
-globs)
+cache);%0A        return cache
 ;%0A    %7D%0A

Use volatile for glob cache.