<commit_before>/*******************************************************************************
 * Copyright (c) 2015-2016 Oak Ridge National Laboratory.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package org.csstudio.display.builder.model;

import static org.csstudio.display.builder.model.ModelPlugin.logger;

import java.util.logging.Level;

import org.csstudio.display.builder.model.macros.MacroHandler;
import org.csstudio.display.builder.model.macros.MacroValueProvider;
import org.csstudio.display.builder.model.properties.IntegerWidgetProperty;

/** Base for Property that supports macros.
 *
 *  <p>Properties are typed.
 *  For example, the {@link IntegerWidgetProperty} has
 *  a value of type Integer.
 *
 *  <p>Macro-based properties have an additional 'specification',
 *  a text that may contain macros, for example "$(SOME_MACRO)".
 *
 *  <p>A model editor presents the specification to the user,
 *  and macro based properties persist the specification.
 *
 *  <p>At runtime, the specification is evaluated by
 *  replacing macros, setting the actual value.
 *
 *  @author <NAME>
 */
@SuppressWarnings("nls")
abstract public class MacroizedWidgetProperty<T> extends WidgetProperty<T>
{
// Also allow entering dynamic value description
// (PVManager formula "=`pv1`*2" ?)?
// Runtime then establishes subscription and updates value?

    /** Specification of the value, may contain macros that need to be expanded */
    protected volatile String specification;

    /** Constructor
     *  @param descriptor Property descriptor
     *  @param widget Widget that holds the property and handles listeners
     *  @param default_value Default and initial value
     */
    public MacroizedWidgetProperty(
            final WidgetPropertyDescriptor<T> descriptor,
            final Widget widget,
            final T default_value)
    {
        super(descriptor, widget, default_value);
        // XXX Should null become "null" or ""?
        specification = computeSpecification(default_value);
        // If specification contains macro,
        // clear value to force evaluation of macro on first value request.
        // Can't evaluate now because macros may not be available.
        if (MacroHandler.containsMacros(specification))
            value = null;
    }

    /** @return Value specification. Text that may contain macros */
    public String getSpecification()
    {
        return specification;
    }

    /** Update the specification.
     *
     *  <p>Invalidates the typed value of the property,
     *  which is re-calculated when fetched the next time.
     *
     *  @param specification Specification of the value. Text that may contain macros
     */
    public void setSpecification(final String specification)
    {
        this.specification = specification;
        this.value = null;
        firePropertyChange(this, null, null);
    }

    /** Determine specification for a value
     *  @param value Value
     *  @return Specification for that value
     */
    protected String computeSpecification(T value)
    {
        return String.valueOf(value);
    }

    /** Macro-based properties implement this to parse
     *  a specification text where all macros have been
     *  evaluated into the typed value.
     *
     *  <p>If implementation throws an exception,
     *  the default value of the property is used.
     *
     *  @param text Specification text, all known macros have been resolved
     *  @return Typed value
     *  @throws Exception on parse error.
     */
    abstract protected T parseExpandedSpecification(String text) throws Exception;

    /** Evaluates value based on specification
     *  @return Current value of the property
     */
    @Override
    public synchronized T getValue()
    {
        if (value == null)
        {
            final MacroValueProvider macros = widget.getMacrosOrProperties();
            String expanded;
            try
            {
                expanded = MacroHandler.replace(macros, specification);
            }
            catch (final Exception ex)
            {
                logger.log(Level.WARNING, widget + " property " + getName() + " cannot expand macros for " + specification, ex);
                expanded = specification;
            }

            // TODO Do not allow this...
            if (MacroHandler.containsMacros(expanded))
                logger.log(Level.WARNING, widget + " '" + getName() + "' is not fully resolved: " + expanded);

            try
            {
                // Do NOT notify listeners.
                // Otherwise, if property.getValue() is called within a listener
                // and the listener is registered to fire when setValue() is called
                // then listener -> getValue() -> setValue() -> call listener again ..
                doSetValue(parseExpandedSpecification(expanded), false);
            }
            catch (final Exception ex)
            {
                logger.log(Level.WARNING, widget + " property " + getName() + " cannot evaluate " + expanded, ex);
                value = default_value;
            }
        }
        return value;
    }<commit_msg>Macro prop: Log unresolved macro as INFO<commit_after>/*******************************************************************************
 * Copyright (c) 2015-2016 Oak Ridge National Laboratory.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package org.csstudio.display.builder.model;

import static org.csstudio.display.builder.model.ModelPlugin.logger;

import java.util.logging.Level;

import org.csstudio.display.builder.model.macros.MacroHandler;
import org.csstudio.display.builder.model.macros.MacroValueProvider;
import org.csstudio.display.builder.model.properties.IntegerWidgetProperty;

/** Base for Property that supports macros.
 *
 *  <p>Properties are typed.
 *  For example, the {@link IntegerWidgetProperty} has
 *  a value of type Integer.
 *
 *  <p>Macro-based properties have an additional 'specification',
 *  a text that may contain macros, for example "$(SOME_MACRO)".
 *
 *  <p>A model editor presents the specification to the user,
 *  and macro based properties persist the specification.
 *
 *  <p>At runtime, the specification is evaluated by
 *  replacing macros, setting the actual value.
 *
 *  @author <NAME>
 */
@SuppressWarnings("nls")
abstract public class MacroizedWidgetProperty<T> extends WidgetProperty<T>
{
// Also allow entering dynamic value description
// (PVManager formula "=`pv1`*2" ?)?
// Runtime then establishes subscription and updates value?

    /** Specification of the value, may contain macros that need to be expanded */
    protected volatile String specification;

    /** Constructor
     *  @param descriptor Property descriptor
     *  @param widget Widget that holds the property and handles listeners
     *  @param default_value Default and initial value
     */
    public MacroizedWidgetProperty(
            final WidgetPropertyDescriptor<T> descriptor,
            final Widget widget,
            final T default_value)
    {
        super(descriptor, widget, default_value);
        // XXX Should null become "null" or ""?
        specification = computeSpecification(default_value);
        // If specification contains macro,
        // clear value to force evaluation of macro on first value request.
        // Can't evaluate now because macros may not be available.
        if (MacroHandler.containsMacros(specification))
            value = null;
    }

    /** @return Value specification. Text that may contain macros */
    public String getSpecification()
    {
        return specification;
    }

    /** Update the specification.
     *
     *  <p>Invalidates the typed value of the property,
     *  which is re-calculated when fetched the next time.
     *
     *  @param specification Specification of the value. Text that may contain macros
     */
    public void setSpecification(final String specification)
    {
        this.specification = specification;
        this.value = null;
        firePropertyChange(this, null, null);
    }

    /** Determine specification for a value
     *  @param value Value
     *  @return Specification for that value
     */
    protected String computeSpecification(T value)
    {
        return String.valueOf(value);
    }

    /** Macro-based properties implement this to parse
     *  a specification text where all macros have been
     *  evaluated into the typed value.
     *
     *  <p>If implementation throws an exception,
     *  the default value of the property is used.
     *
     *  @param text Specification text, all known macros have been resolved
     *  @return Typed value
     *  @throws Exception on parse error.
     */
    abstract protected T parseExpandedSpecification(String text) throws Exception;

    /** Evaluates value based on specification
     *  @return Current value of the property
     */
    @Override
    public synchronized T getValue()
    {
        if (value == null)
        {
            final MacroValueProvider macros = widget.getMacrosOrProperties();
            String expanded;
            try
            {
                expanded = MacroHandler.replace(macros, specification);
            }
            catch (final Exception ex)
            {
                logger.log(Level.WARNING, widget + " property " + getName() + " cannot expand macros for " + specification, ex);
                expanded = specification;
            }

            if (MacroHandler.containsMacros(expanded))
                logger.log(Level.INFO, widget + " '" + getName() + "' is not fully resolved: " + expanded);

            try
            {
                // Do NOT notify listeners.
                // Otherwise, if property.getValue() is called within a listener
                // and the listener is registered to fire when setValue() is called
                // then listener -> getValue() -> setValue() -> call listener again ..
                doSetValue(parseExpandedSpecification(expanded), false);
            }
            catch (final Exception ex)
            {
                logger.log(Level.WARNING, widget + " property " + getName() + " cannot evaluate " + expanded, ex);
                value = default_value;
            }
        }
        return value;
    }
{'fraction_non_alphanumeric': 0.1088735632183908, 'fraction_numerical': 0.002574712643678161, 'mean_word_length': 2.5265888456549934, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1225369', 'n_tokens_mistral': 2731, 'n_tokens_neox': 2596, 'n_words': 937}