    001// Copyright 2009-2013 The Apache Software Foundation
    002//
    003// Licensed under the Apache License, Version 2.0 (the "License");
    004// you may not use this file except in compliance with the License.
    005// You may obtain a copy of the License at
    006//
    007//     http://www.apache.org/licenses/LICENSE-2.0
    008//
    009// Unless required by applicable law or agreed to in writing, software
    010// distributed under the License is distributed on an "AS IS" BASIS,
    011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012// See the License for the specific language governing permissions and
    013// limitations under the License.
    014package org.apache.tapestry5.beanvalidator.modules;
    015
    016import org.apache.tapestry5.MarkupWriter;
    017import org.apache.tapestry5.beanvalidator.*;
    018import org.apache.tapestry5.internal.beanvalidator.*;
    019import org.apache.tapestry5.ioc.Configuration;
    020import org.apache.tapestry5.ioc.MappedConfiguration;
    021import org.apache.tapestry5.ioc.OrderedConfiguration;
    022import org.apache.tapestry5.ioc.ServiceBinder;
    023import org.apache.tapestry5.ioc.annotations.Local;
    024import org.apache.tapestry5.ioc.services.PropertyShadowBuilder;
    025import org.apache.tapestry5.ioc.services.ThreadLocale;
    026import org.apache.tapestry5.services.FieldValidatorDefaultSource;
    027import org.apache.tapestry5.services.javascript.DataConstants;
    028import org.apache.tapestry5.services.javascript.JavaScriptSupport;
    029
    030import javax.validation.MessageInterpolator;
    031import javax.validation.Validator;
    032import javax.validation.ValidatorFactory;
    033import javax.validation.constraints.*;
    034import javax.validation.groups.Default;
    035import java.util.Map;
    036
    037/**
    038 * Module for JSR-303 services.
    039 *
    040 * @since 5.2.0.0
    041 */
    042public class BeanValidatorModule
    043{
    044
    045    private static final String MODULE_NAME = "t5/beanvalidator/beanvalidator-validation";
    046
    047    public static void bind(final ServiceBinder binder)
    048    {
    049        binder.bind(FieldValidatorDefaultSource.class, BeanFieldValidatorDefaultSource.class).withSimpleId();
    050        binder.bind(BeanValidatorGroupSource.class, BeanValidationGroupSourceImpl.class);
    051        binder.bind(BeanValidatorSource.class, BeanValidatorSourceImpl.class);
    052        binder.bind(ClientConstraintDescriptorSource.class, ClientConstraintDescriptorImpl.class);
    053    }
    054
    055    public static void contributeServiceOverride(
    056            MappedConfiguration<Class<?>, Object> configuration,
    057            @Local FieldValidatorDefaultSource source)
    058    {
    059        configuration.add(FieldValidatorDefaultSource.class, source);
    060    }
    061
    062    public static Validator buildBeanValidator(ValidatorFactory validatorFactory, PropertyShadowBuilder propertyShadowBuilder)
    063    {
    064        return propertyShadowBuilder.build(validatorFactory, "validator", Validator.class);
    065    }
    066
    067
    068    public static ValidatorFactory buildValidatorFactory(BeanValidatorSource beanValidatorSource, PropertyShadowBuilder propertyShadowBuilder)
    069    {
    070        return propertyShadowBuilder.build(beanValidatorSource, "validatorFactory", ValidatorFactory.class);
    071    }
    072
    073    public static void contributeBeanValidatorGroupSource(
    074            final Configuration<Class<?>> configuration)
    075    {
    076        configuration.add(Default.class);
    077    }
    078
    079    public static void contributeBeanValidatorSource(
    080            final OrderedConfiguration<BeanValidatorConfigurer> configuration, final ThreadLocale threadLocale)
    081    {
    082        configuration.add("LocaleAwareMessageInterpolator", new BeanValidatorConfigurer()
    083        {
    084            @Override
    085            public void configure(javax.validation.Configuration<?> configuration)
    086            {
    087                MessageInterpolator defaultInterpolator = configuration.getDefaultMessageInterpolator();
    088
    089                configuration.messageInterpolator(new MessageInterpolatorImpl(defaultInterpolator, threadLocale));
    090            }
    091        });
    092    }
    093
    094    public static void contributeClientConstraintDescriptorSource(final JavaScriptSupport javaScriptSupport,
    095                                                                  final Configuration<ClientConstraintDescriptor> configuration)
    096    {
    097        configuration.add(new BaseCCD(Max.class, "value")
    098        {
    099            @Override
    100            public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes)
    101            {
    102                javaScriptSupport.require("t5/core/validation");
    103                writer.attributes(
    104                        "data-validate", true,
    105                        "data-validate-max", attributes.get("value"),
    106                        "data-max-message", message);
    107
    108            }
    109        });
    110
    111        configuration.add(new BaseCCD(Min.class, "value")
    112        {
    113            @Override
    114            public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes)
    115            {
    116                javaScriptSupport.require("t5/core/validation");
    117                writer.attributes(
    118                        DataConstants.VALIDATION_ATTRIBUTE, true,
    119                        "data-validate-min", attributes.get("value"),
    120                        "data-min-message", message);
    121
    122            }
    123        });
    124
    125        configuration.add(new BaseCCD(NotNull.class)
    126        {
    127            @Override
    128            public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes)
    129            {
    130                javaScriptSupport.require("t5/core/validation");
    131                writer.attributes(
    132                        DataConstants.VALIDATION_ATTRIBUTE, true,
    133                        "data-optionality", "required",
    134                        "data-required-message", message);
    135            }
    136        });
    137
    138        configuration.add(new BaseCCD(Null.class)
    139        {
    140            @Override
    141            public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes)
    142            {
    143                javaScriptSupport.require(MODULE_NAME);
    144                writer.attributes(
    145                        DataConstants.VALIDATION_ATTRIBUTE, true,
    146                        "data-optionality", "prohibited",
    147                        "data-prohibited-message", message);
    148            }
    149        });
    150
    151        configuration.add(new BaseCCD(Pattern.class, "regexp")
    152        {
    153            @Override
    154            public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes)
    155            {
    156                javaScriptSupport.require(MODULE_NAME);
    157                writer.attributes(
    158                        DataConstants.VALIDATION_ATTRIBUTE, true,
    159                        "data-validate-regexp", attributes.get("regexp"),
    160                        "data-regexp-message", message);
    161            }
    162        });
    163
    164        configuration.add(new BaseCCD(Size.class, "min", "max")
    165        {
    166            @Override
    167            public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes)
    168            {
    169                javaScriptSupport.require(MODULE_NAME);
    170                writer.attributes(
    171                        DataConstants.VALIDATION_ATTRIBUTE, true,
    172                        "data-range-message", message);
    173
    174                int min = (Integer) attributes.get("min");
    175
    176                if (min != 0)
    177                {
    178                    writer.attributes("data-range-min", min);
    179                }
    180
    181                int max = (Integer) attributes.get("max");
    182
    183                if (max != Integer.MAX_VALUE)
    184                {
    185                    writer.attributes("data-range-max", max);
    186                }
    187            }
    188        });
    189
    190        configuration.add(new BaseCCD(AssertTrue.class)
    191        {
    192            @Override
    193            public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes)
    194            {
    195                javaScriptSupport.require("t5/core/validation");
    196
    197                writer.attributes(
    198                        DataConstants.VALIDATION_ATTRIBUTE, true,
    199                        "data-expected-status", "checked",
    200                        "data-checked-message", message);
    201            }
    202        });
    203
    204        configuration.add(new BaseCCD(AssertFalse.class)
    205        {
    206            @Override
    207            public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes)
    208            {
    209                javaScriptSupport.require("t5/core/validation");
    210
    211                writer.attributes(
    212                        DataConstants.VALIDATION_ATTRIBUTE, true,
    213                        "data-expected-status", "unchecked",
    214                        "data-checked-message", message);
    215            }
    216        });
    217    }
    218}