001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.markup.html.form.validation;
018
019import java.util.HashMap;
020import java.util.Map;
021
022import org.apache.wicket.Component;
023import org.apache.wicket.WicketRuntimeException;
024import org.apache.wicket.behavior.Behavior;
025import org.apache.wicket.markup.html.form.Form;
026import org.apache.wicket.markup.html.form.FormComponent;
027import org.apache.wicket.model.IModel;
028import org.apache.wicket.util.lang.Args;
029import org.apache.wicket.util.lang.Classes;
030import org.apache.wicket.validation.ValidationError;
031
032
033/**
034 * Base class for {@link org.apache.wicket.markup.html.form.validation.IFormValidator}s.
035 * 
036 * @author Igor Vaynberg (ivaynberg)
037 */
038public abstract class AbstractFormValidator extends Behavior implements IFormValidator
039{
040        private static final long serialVersionUID = 1L;
041
042        /**
043         * Can be bound to {@link Form}s only.
044         * 
045         * @throws WicketRuntimeException
046         *             if component is not a form
047         */
048        @Override
049        public void bind(Component component)
050        {
051                if (!(component instanceof Form))
052                {
053                        throw new WicketRuntimeException("Behavior " + getClass().getName()
054                                + " can only be added to an instance of a Form");
055                }
056        }
057
058        /**
059         * Reports an error against validatable using the map returned by {@link #variablesMap()}for
060         * variable interpolations and message key returned by {@link #resourceKey()}.
061         * 
062         * @param fc
063         *            form component against which the error is reported
064         * 
065         */
066        public void error(FormComponent<?> fc)
067        {
068                error(fc, resourceKey(), variablesMap());
069        }
070
071        /**
072         * Reports an error against the validatable using the given resource key
073         * 
074         * @param fc
075         *            form component against which the error is reported
076         * @param resourceKey
077         *            The message resource key to use
078         */
079        public void error(FormComponent<?> fc, final String resourceKey)
080        {
081                if (resourceKey == null)
082                {
083                        throw new IllegalArgumentException("Argument [[resourceKey]] cannot be null");
084                }
085                error(fc, resourceKey, variablesMap());
086        }
087
088        /**
089         * Reports an error against the validatable using the given map for variable interpolations and
090         * message resource key provided by {@link #resourceKey()}
091         * 
092         * @param fc
093         *            form component against which the error is reported
094         * @param vars
095         *            variables for variable interpolation
096         */
097        public void error(FormComponent<?> fc, final Map<String, Object> vars)
098        {
099                if (vars == null)
100                {
101                        throw new IllegalArgumentException("Argument [[vars]] cannot be null");
102                }
103                error(fc, resourceKey(), vars);
104        }
105
106        /**
107         * Reports an error against the validatable using the specified resource key and variable map
108         * 
109         * @param fc
110         *            form component against which the error is reported
111         * @param resourceKey
112         *            The message resource key to use
113         * @param vars
114         *            The model for variable interpolation
115         */
116        public void error(FormComponent<?> fc, final String resourceKey, Map<String, Object> vars)
117        {
118                Args.notNull(fc, "fc");
119                Args.notNull(vars, "vars");
120                Args.notNull(resourceKey, "resourceKey");
121
122                ValidationError error = new ValidationError().addKey(resourceKey);
123                final String defaultKey = Classes.simpleName(getClass());
124                if (!resourceKey.equals(defaultKey))
125                {
126                        error.addKey(defaultKey);
127                }
128
129                error.setVariables(vars);
130                fc.error(error);
131        }
132
133        /**
134         * Gets the default variables for interpolation. These are for every component:
135         * <ul>
136         * <li>${input(n)}: the user's input</li>
137         * <li>${name(n)}: the name of the component</li>
138         * <li>${label(n)}: the label of the component - either comes from FormComponent.labelModel or
139         * resource key [form-id].[form-component-id] in that order</li>
140         * </ul>
141         * 
142         * @return a map with the variables for interpolation
143         */
144        protected Map<String, Object> variablesMap()
145        {
146                FormComponent<?>[] formComponents = getDependentFormComponents();
147
148                if (formComponents != null && formComponents.length > 0)
149                {
150                        Map<String, Object> args = new HashMap<String, Object>(formComponents.length * 3);
151                        for (int i = 0; i < formComponents.length; i++)
152                        {
153                                final FormComponent<?> formComponent = formComponents[i];
154
155                                String arg = "label" + i;
156                                IModel<?> label = formComponent.getLabel();
157                                if (label != null)
158                                {
159                                        args.put(arg, label.getObject());
160                                }
161                                else
162                                {
163                                        args.put(
164                                                arg,
165                                                formComponent.getLocalizer().getString(formComponent.getId(),
166                                                        formComponent.getParent(), formComponent.getId()));
167                                }
168
169                                args.put("input" + i, formComponent.getInput());
170                                args.put("name" + i, formComponent.getId());
171                        }
172                        return args;
173                }
174                else
175                {
176                        return new HashMap<String, Object>(2);
177                }
178        }
179
180        /**
181         * Gets the resource key for validator's error message from the ApplicationSettings class.
182         * 
183         * @return the resource key based on the form component
184         */
185        protected String resourceKey()
186        {
187                return Classes.simpleName(getClass());
188        }
189}