Changeset 7099 in josm


Ignore:
Timestamp:
2014-05-10T20:22:15+02:00 (6 years ago)
Author:
bastiK
Message:

see #9691 - mapcss: fix concurrency problem with Expressions (cannot save stuff to field of static singlton FUNCTIONS_INSTANCE)

Location:
trunk/src/org/openstreetmap/josm/gui/mappaint
Files:
3 edited

Legend:

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

    r7083 r7099  
    127127        Cascade c = env.mc.getCascade(env.layer);
    128128
    129         final IconReference iconRef = c.get(keys[ICON_IMAGE_IDX], null, IconReference.class);
     129        final IconReference iconRef = c.get(keys[ICON_IMAGE_IDX], null, IconReference.class, true);
    130130        if (iconRef == null)
    131131            return null;
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java

    r7083 r7099  
    419419    public static class ExpressionCondition extends Condition {
    420420
    421         private Expression e;
     421        private final Expression e;
    422422
    423423        public ExpressionCondition(Expression e) {
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java

    r7083 r7099  
    4747    private static final List<Method> arrayFunctions;
    4848    private static final List<Method> parameterFunctions;
    49     private static final Functions FUNCTIONS_INSTANCE = new Functions();
     49    private static final List<Method> parameterFunctionsEnv;
    5050
    5151    static {
    5252        arrayFunctions = new ArrayList<>();
    5353        parameterFunctions = new ArrayList<>();
     54        parameterFunctionsEnv = new ArrayList<>();
    5455        for (Method m : Functions.class.getDeclaredMethods()) {
    5556            Class<?>[] paramTypes = m.getParameterTypes();
     
    5758                arrayFunctions.add(m);
    5859            } else {
    59                 parameterFunctions.add(m);
     60                if (paramTypes[0].equals(Environment.class)) {
     61                    parameterFunctionsEnv.add(m);
     62                } else {
     63                    parameterFunctions.add(m);
     64                }
    6065            }
    6166        }
     
    9196    }
    9297
     98    /**
     99     * List of functions that can be used in MapCSS expressions.
     100     *
     101     * First parameter can be of type {@link Environment} (if needed). This is
     102     * automatically filled in by JOSM and the user only sees the remaining
     103     * arguments.
     104     * When one of the user supplied arguments cannot be converted the
     105     * expected type or is null, the function is not called and it returns null
     106     * immediately. Add the annotation {@link NullableArguments} to allow
     107     * null arguments.
     108     * Every method must be static.
     109     */
    93110    @SuppressWarnings("UnusedDeclaration")
    94111    public static class Functions {
    95 
    96         Environment env;
    97112
    98113        /**
     
    265280            return Utils.color_int2float(c.getAlpha());
    266281        }
    267 
     282       
    268283        /**
    269284         * Assembles the strings to one.
     
    287302         * Returns the value of the property {@code key}, e.g., {@code prop("width")}.
    288303         */
    289         public Object prop(String key) {
    290             return prop(key, null);
     304        public static Object prop(final Environment env, String key) {
     305            return prop(env, key, null);
    291306        }
    292307
     
    294309         * Returns the value of the property {@code key} from layer {@code layer}.
    295310         */
    296         public Object prop(String key, String layer) {
     311        public static Object prop(final Environment env, String key, String layer) {
    297312            return env.getCascade(layer).get(key);
    298313        }
     
    301316         * Determines whether property {@code key} is set.
    302317         */
    303         public Boolean is_prop_set(String key) {
    304             return is_prop_set(key, null);
     318        public static Boolean is_prop_set(final Environment env, String key) {
     319            return is_prop_set(env, key, null);
    305320        }
    306321
     
    308323         * Determines whether property {@code key} is set on layer {@code layer}.
    309324         */
    310         public Boolean is_prop_set(String key, String layer) {
     325        public static Boolean is_prop_set(final Environment env, String key, String layer) {
    311326            return env.getCascade(layer).containsKey(key);
    312327        }
     
    315330         * Gets the value of the key {@code key} from the object in question.
    316331         */
    317         public String tag(String key) {
     332        public static String tag(final Environment env, String key) {
    318333            return env.osm == null ? null : env.osm.get(key);
    319334        }
     
    322337         * Gets the first non-null value of the key {@code key} from the object's parent(s).
    323338         */
    324         public String parent_tag(String key) {
     339        public static String parent_tag(final Environment env, String key) {
    325340            if (env.parent == null) {
    326341                if (env.osm != null) {
     
    338353        }
    339354
    340         public String child_tag(String key) {
     355        public static String child_tag(final Environment env, String key) {
    341356            return env.child == null ? null : env.child.get(key);
    342357        }
     
    345360         * Determines whether the object has a tag with the given key.
    346361         */
    347         public boolean has_tag_key(String key) {
     362        public static boolean has_tag_key(final Environment env, String key) {
    348363            return env.osm.hasKey(key);
    349364        }
     
    352367         * Returns the index of node in parent way or member in parent relation.
    353368         */
    354         public Float index() {
     369        public static Float index(final Environment env) {
    355370            if (env.index == null) {
    356371                return null;
     
    359374        }
    360375
    361         public String role() {
     376        public static String role(final Environment env) {
    362377            return env.getRole();
    363378        }
     
    403418         * Determines whether the JOSM search with {@code searchStr} applies to the object.
    404419         */
    405         public Boolean JOSM_search(String searchStr) {
     420        public static Boolean JOSM_search(final Environment env, String searchStr) {
    406421            Match m;
    407422            try {
     
    498513         * @see OsmPrimitive#getUniqueId()
    499514         */
    500         public long osm_id() {
     515        public static long osm_id(final Environment env) {
    501516            return env.osm.getUniqueId();
    502517        }
     
    607622        for (Method m : parameterFunctions) {
    608623            if (m.getName().equals(name) && args.size() == m.getParameterTypes().length)
    609                 return new ParameterFunction(m, args);
     624                return new ParameterFunction(m, args, false);
     625        }
     626        for (Method m : parameterFunctionsEnv) {
     627            if (m.getName().equals(name) && args.size() == m.getParameterTypes().length-1)
     628                return new ParameterFunction(m, args, true);
    610629        }
    611630        return NullExpression.INSTANCE;
     
    717736        }
    718737    }
    719 
     738   
    720739    /**
    721740     * Function that takes a certain number of argument with specific type.
     
    727746
    728747        private final Method m;
     748        private final boolean nullable;
    729749        private final List<Expression> args;
    730750        private final Class<?>[] expectedParameterTypes;
    731 
    732         public ParameterFunction(Method m, List<Expression> args) {
     751        private final boolean needsEnvironment;
     752
     753        public ParameterFunction(Method m, List<Expression> args, boolean needsEnvironment) {
    733754            this.m = m;
     755            this.nullable = m.getAnnotation(NullableArguments.class) != null;
    734756            this.args = args;
    735             expectedParameterTypes = m.getParameterTypes();
     757            this.expectedParameterTypes = m.getParameterTypes();
     758            this.needsEnvironment = needsEnvironment;
    736759        }
    737760
    738761        @Override
    739762        public Object evaluate(Environment env) {
    740             FUNCTIONS_INSTANCE.env = env;
    741             Object[] convertedArgs = new Object[expectedParameterTypes.length];
    742             for (int i = 0; i < args.size(); ++i) {
    743                 convertedArgs[i] = Cascade.convertTo(args.get(i).evaluate(env), expectedParameterTypes[i]);
    744                 if (convertedArgs[i] == null && m.getAnnotation(NullableArguments.class) == null) {
    745                     return null;
     763            Object[] convertedArgs;
     764           
     765            if (needsEnvironment) {
     766                convertedArgs = new Object[args.size()+1];
     767                convertedArgs[0] = env;
     768                for (int i = 1; i < convertedArgs.length; ++i) {
     769                    convertedArgs[i] = Cascade.convertTo(args.get(i-1).evaluate(env), expectedParameterTypes[i]);
     770                    if (convertedArgs[i] == null && !nullable) {
     771                        return null;
     772                    }
     773                }
     774            } else {
     775                convertedArgs = new Object[args.size()];
     776                for (int i = 0; i < convertedArgs.length; ++i) {
     777                    convertedArgs[i] = Cascade.convertTo(args.get(i).evaluate(env), expectedParameterTypes[i]);
     778                    if (convertedArgs[i] == null && !nullable) {
     779                        return null;
     780                    }
    746781                }
    747782            }
    748783            Object result = null;
    749784            try {
    750                 result = m.invoke(FUNCTIONS_INSTANCE, convertedArgs);
     785                result = m.invoke(null, convertedArgs);
    751786            } catch (IllegalAccessException | IllegalArgumentException ex) {
    752787                throw new RuntimeException(ex);
     
    783818
    784819        private final Method m;
     820        private final boolean nullable;
    785821        private final List<Expression> args;
     822        private final Class<?>[] expectedParameterTypes;
    786823        private final Class<?> arrayComponentType;
    787         private final Object[] convertedArgs;
    788824
    789825        public ArrayFunction(Method m, List<Expression> args) {
    790826            this.m = m;
     827            this.nullable = m.getAnnotation(NullableArguments.class) != null;
    791828            this.args = args;
    792             Class<?>[] expectedParameterTypes = m.getParameterTypes();
    793             convertedArgs = new Object[expectedParameterTypes.length];
    794             arrayComponentType = expectedParameterTypes[0].getComponentType();
     829            this.expectedParameterTypes = m.getParameterTypes();
     830            this.arrayComponentType = expectedParameterTypes[0].getComponentType();
    795831        }
    796832
    797833        @Override
    798834        public Object evaluate(Environment env) {
     835            Object[] convertedArgs = new Object[expectedParameterTypes.length];
    799836            Object arrayArg = Array.newInstance(arrayComponentType, args.size());
    800837            for (int i = 0; i < args.size(); ++i) {
    801838                Object o = Cascade.convertTo(args.get(i).evaluate(env), arrayComponentType);
    802                 if (o == null && m.getAnnotation(NullableArguments.class) == null) {
     839                if (o == null && !nullable) {
    803840                    return null;
    804841                }
Note: See TracChangeset for help on using the changeset viewer.