org.sipfoundry.sipxconfig.site.setting.SettingEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.sipfoundry.sipxconfig.site.setting.SettingEditor.java

Source

/*
 *
 *
 * Copyright (C) 2007 Pingtel Corp., certain elements licensed under a Contributor Agreement.
 * Contributors retain copyright to elements licensed under a Contributor Agreement.
 * Licensed to the User under the LGPL license.
 *
 * $
 */
package org.sipfoundry.sipxconfig.site.setting;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.tapestry.BaseComponent;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.annotations.ComponentClass;
import org.apache.tapestry.annotations.InjectObject;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.form.IFormComponent;
import org.apache.tapestry.form.IPropertySelectionModel;
import org.apache.tapestry.form.validator.Max;
import org.apache.tapestry.form.validator.MaxLength;
import org.apache.tapestry.form.validator.Min;
import org.apache.tapestry.form.validator.MinLength;
import org.apache.tapestry.form.validator.Pattern;
import org.apache.tapestry.form.validator.Required;
import org.apache.tapestry.form.validator.Validator;
import org.sipfoundry.sipxconfig.components.LocalizationUtils;
import org.sipfoundry.sipxconfig.components.NamedValuesSelectionModel;
import org.sipfoundry.sipxconfig.components.TapestryContext;
import org.sipfoundry.sipxconfig.setting.CustomSettingMessages;
import org.sipfoundry.sipxconfig.setting.Setting;
import org.sipfoundry.sipxconfig.setting.type.BooleanSetting;
import org.sipfoundry.sipxconfig.setting.type.EnumSetting;
import org.sipfoundry.sipxconfig.setting.type.FileSetting;
import org.sipfoundry.sipxconfig.setting.type.HostnameSetting;
import org.sipfoundry.sipxconfig.setting.type.IntegerSetting;
import org.sipfoundry.sipxconfig.setting.type.IpAddrSetting;
import org.sipfoundry.sipxconfig.setting.type.PhonePadPinSetting;
import org.sipfoundry.sipxconfig.setting.type.RealSetting;
import org.sipfoundry.sipxconfig.setting.type.SettingType;
import org.sipfoundry.sipxconfig.setting.type.StringSetting;
import org.sipfoundry.sipxconfig.setting.type.UsernameSequenceSetting;
import org.springframework.context.MessageSource;

@ComponentClass(allowBody = true, allowInformalParameters = true)
public abstract class SettingEditor extends BaseComponent {

    private static final String LISTEN_ON_CHANGE = "ListenOnChange";

    @Parameter(required = true)
    public abstract Setting getSetting();

    public abstract void setSetting(Setting setting);

    @InjectObject(value = "spring:tapestry")
    public abstract TapestryContext getTapestry();

    /**
     * Should be called 'enforceRequired'. If it is set to false the 'required' constraints are
     * not enforced. It is used when editing group settings since groups do not have to provide
     * settings values even it the settings has required flag.
     */
    @Parameter(required = true)
    public abstract boolean isRequiredEnabled();

    @Parameter(defaultValue = "true")
    public abstract boolean isEnabled();

    /**
     * Set to false to render only setting widget without label, default value and description.
     */
    @Parameter(defaultValue = "true")
    public abstract boolean isDecorated();

    /**
     * Spring MessageSource interface based on resource bundle with translations for the model.
     */
    @Parameter
    public abstract MessageSource getMessageSource();

    public boolean isDisabled() {
        return !isEnabled();
    }

    /**
     * @return id of the widget that is used to edit setting value, it's different than the ID of
     *         the SettingEditorComponent
     */
    public String getWidgetId() {
        return "setting:" + getSetting().getName();
    }

    /**
     * @return block that contains HTML for the widget used to edit setting value
     */
    public IComponent getWidgetBlock() {
        SettingType type = getSetting().getType();
        String typeName = type.getName();
        if (type instanceof EnumSetting && ((EnumSetting) type).isListenOnChange()) {
            typeName += LISTEN_ON_CHANGE;
        }
        String blockName = typeName + "Block";
        return getComponent(blockName);
    }

    /**
     * @return list of Validator objects
     */
    public List getValidatorList() {
        SettingType type = getSetting().getType();
        // see XCF-1726 'required' constraint *is* enforced (even if isRequiredEnabled is false)
        // for all settings that have non empty default values
        boolean hasDefault = StringUtils.isNotEmpty(getSetting().getDefaultValue());
        Locale locale = getPage().getLocale();
        return validatorListForType(type, hasDefault || isRequiredEnabled(), locale);
    }

    static List validatorListForType(SettingType type, boolean enforceRequired, Locale locale) {
        List<Validator> validators = new ArrayList<Validator>();
        if (type.isRequired() && enforceRequired) {
            validators.add(new Required());
        }
        if (type instanceof IntegerSetting) {
            IntegerSetting integerType = (IntegerSetting) type;
            Min min = new Min();
            min.setMin(integerType.getMin());
            validators.add(min);
            Max max = new Max();
            max.setMax(integerType.getMax());
            validators.add(max);
        }
        if (type instanceof RealSetting) {
            RealSetting realType = (RealSetting) type;
            Min min = new Min();
            min.setMin(realType.getMin());
            validators.add(min);
            Max max = new Max();
            max.setMax(realType.getMax());
            validators.add(max);
        }
        if (type instanceof StringSetting) {
            StringSetting stringType = (StringSetting) type;
            MaxLength maxLen = new MaxLength();
            maxLen.setMaxLength(stringType.getMaxLen());
            validators.add(maxLen);
            int minLen = stringType.getMinLen();
            if (minLen > 0) {
                MinLength minLenValid = new MinLength();
                minLenValid.setMinLength(minLen);
                validators.add(minLenValid);
            }
            String patternString = stringType.getPattern();
            if (StringUtils.isNotEmpty(patternString)) {
                Pattern pattern = new Pattern();
                pattern.setPattern(patternString);

                // /////////////////////////////////////////////////////////////////
                // Settings with specific string pattern requirements might lead to
                // error messages with complicated regular expressions in them.
                // We want to display a custom message for these setting types.
                // (e.g IpAddrSetting and HostnameSetting).
                // /////////////////////////////////////////////////////////////////

                if (type instanceof HostnameSetting) {
                    String customMessage = CustomSettingMessages
                            .getMessagePattern(CustomSettingMessages.INVALID_HOSTNAME_PATTERN, locale);
                    pattern.setMessage(customMessage);
                } else if (type instanceof IpAddrSetting) {
                    String customMessage = CustomSettingMessages
                            .getMessagePattern(CustomSettingMessages.INVALID_IPADDR_PATTERN, locale);
                    pattern.setMessage(customMessage);
                } else if (type instanceof PhonePadPinSetting) {
                    String customMessage = CustomSettingMessages
                            .getMessagePattern(CustomSettingMessages.INVALID_PHONEPADPIN_PATTERN, locale);
                    pattern.setMessage(customMessage);
                } else if (type instanceof UsernameSequenceSetting) {
                    String customMessage = CustomSettingMessages
                            .getMessagePattern(CustomSettingMessages.INVALID_USERNAME_SEQUENCE_PATTERN, locale);
                    pattern.setMessage(customMessage);
                }

                validators.add(pattern);
            }
        }
        return validators;
    }

    /**
     * In order to make FieldLabel happy we need IFormComponent instance. In most cases this is
     * actually the widget directly passed to setting editor. However in some cases our widget is
     * a collection of components, and there is no easy way of extracting a usable IFormElement. I
     * tried searching for IFormComponent among component children: this does not work since there
     * is no guarantee that found component will be actually renderer (it can be inside of if
     * block)
     */
    /**
     * @return IFormComponent or null if labeled component is not IFormComponent
     */
    public IFormComponent getFormComponent() {
        SettingType type = getSetting().getType();
        String componentName = type.getName();
        if (type instanceof EnumSetting) {
            EnumSetting enumType = (EnumSetting) type;
            if (enumType.isListenOnChange()) {
                componentName += LISTEN_ON_CHANGE;
            }
        }
        if (type instanceof FileSetting) {
            FileSetting fsType = (FileSetting) type;
            if (fsType.isVariable()) {
                componentName += "Single";
            } else {
                componentName += "Multiple";
            }
        }
        if (type instanceof StringSetting) {
            StringSetting stringType = (StringSetting) type;
            if (stringType.isMultiLine()) {
                componentName += "TextArea";
            }
        }
        IComponent component = getComponent(componentName + "Field");
        if (component instanceof IFormComponent) {
            return (IFormComponent) component;
        }
        return null;
    }

    public IPropertySelectionModel getEnumModel() {
        Setting setting = getSetting();
        SettingType type = setting.getType();
        if (!(type instanceof EnumSetting)) {
            return null;
        }
        EnumSetting enumType = (EnumSetting) type;
        MessageSource messageSource = getMessageSource();
        IPropertySelectionModel model = null;
        model = (messageSource != null)
                ? localizedModelForType(setting, enumType, messageSource, getPage().getLocale())
                : enumModelForType(enumType);

        if (enumType.isPromptSelect()) {
            model = getTapestry().instructUserToSelect(model, getMessages());

        }

        return model;
    }

    /**
     * Retrieve default value for current setting. This is less than ideal implementation since
     * Enum and Boolean types are treated very differently from all other types.
     */
    public String getDefaultValue() {
        Setting setting = getSetting();
        SettingType type = setting.getType();
        String defaultValue = setting.getDefaultValue();
        if (defaultValue == null) {
            // no need to localize empty default labels
            return null;
        }
        String defaultValueLabel = type.getLabel(defaultValue);
        if (type instanceof EnumSetting) {
            MessageSource messageSource = getMessageSource();
            if (messageSource != null) {
                EnumSetting enumType = (EnumSetting) type;
                String code = enumType.getLabelKey(setting, defaultValue);
                Locale locale = getPage().getLocale();
                return messageSource.getMessage(code, null, defaultValueLabel, locale);
            }

        } else if (type instanceof BooleanSetting) {
            return LocalizationUtils.getMessage(getMessages(), defaultValueLabel, defaultValueLabel);
        }
        return defaultValueLabel;
    }

    public String getDescription() {
        Setting setting = getSetting();
        return LocalizationUtils.getSettingDescription(this, setting);
    }

    public String getLabel() {
        Setting setting = getSetting();
        return LocalizationUtils.getSettingLabel(this, setting);
    }

    static IPropertySelectionModel enumModelForType(EnumSetting enumType) {
        Map<String, String> enums = enumType.getEnums();
        return new NamedValuesSelectionModel(enums);
    }

    static IPropertySelectionModel localizedModelForType(Setting setting, EnumSetting enumType,
            MessageSource messageSource, Locale locale) {
        Map<String, String> enums = enumType.getEnums();
        int size = enums.size();
        String[] options = new String[size];
        String[] labels = new String[size];

        int i = 0;
        for (Map.Entry<String, String> entry : enums.entrySet()) {
            String key = entry.getKey();
            options[i] = key;
            String code = enumType.getLabelKey(setting, key);
            labels[i] = messageSource.getMessage(code, null, entry.getValue(), locale);
            i++;
        }
        return new NamedValuesSelectionModel(options, labels);
    }

    public boolean isModified() {
        Object val = getSetting().getValue();
        Object def = getSetting().getDefaultValue();
        return val == null ? def != null : !val.equals(def);
    }
}