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.commons.Configuration;
019import org.apache.tapestry5.commons.MappedConfiguration;
020import org.apache.tapestry5.commons.OrderedConfiguration;
021import org.apache.tapestry5.internal.beanvalidator.*;
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}