001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.gwt.client.validation;
029
030import org.opencms.gwt.client.CmsCoreProvider;
031import org.opencms.gwt.client.rpc.CmsRpcAction;
032import org.opencms.gwt.client.ui.input.I_CmsFormField;
033import org.opencms.gwt.shared.CmsValidationQuery;
034import org.opencms.gwt.shared.CmsValidationResult;
035
036import java.util.ArrayList;
037import java.util.Collection;
038import java.util.HashMap;
039import java.util.HashSet;
040import java.util.Map;
041import java.util.Set;
042
043/**
044 * This class is responsible for coordinating the synchronous and asynchronous validation for
045 * a set of form fields.<p>
046 *
047 * @since 8.0.0
048 */
049public class CmsValidationController implements I_CmsValidationController {
050
051    /** A counter used to give newly created validation controllers unique ids. */
052    private static int counter;
053
054    /** The list of form fields which should be validated. */
055    protected Collection<I_CmsFormField> m_fields;
056
057    /** A map containing all validation queries which should be executed asynchronously. */
058    protected Map<String, CmsValidationQuery> m_validationQueries = new HashMap<String, CmsValidationQuery>();
059
060    /** The form validator class name. */
061    private String m_formValidatorClass;
062
063    /** The form validator configuration. */
064    private String m_formValidatorConfig;
065
066    /** The validation handler which will receive the results of the validation. */
067    private I_CmsValidationHandler m_handler;
068
069    /** The id of the validation controller. */
070    private int m_id;
071
072    /** A flag to make sure that the validation controller is not used twice. */
073    private boolean m_isNew = true;
074
075    /** The set of fields which have been validated. */
076    private Set<String> m_validatedFields = new HashSet<String>();
077
078    /** A flag indicating whether the validation has been successful. */
079    private boolean m_validationOk;
080
081    /**
082     * Creates a new validation controller for a list of form fields.<p>
083     *
084     * @param fields the fields which should be validated
085     * @param handler the validation handler
086     */
087    public CmsValidationController(Collection<I_CmsFormField> fields, I_CmsValidationHandler handler) {
088
089        m_fields = fields;
090        m_handler = handler;
091        m_id = counter++;
092    }
093
094    /**
095     * Creates a new validation controller for a single form field.<p>
096     *
097     * @param field the form field
098     * @param handler the validation handler
099     */
100    public CmsValidationController(I_CmsFormField field, I_CmsValidationHandler handler) {
101
102        m_fields = new ArrayList<I_CmsFormField>();
103        m_fields.add(field);
104        m_handler = handler;
105        m_id = counter++;
106    }
107
108    /**
109     * Returns the id of this validation controller.<p>
110     *
111     * @return an id
112     */
113    public int getId() {
114
115        return m_id;
116    }
117
118    /**
119     * Returns the set of fields which have been validated.
120     *
121     * @return the set of validated fields
122     */
123    public Set<String> getValidatedFields() {
124
125        return m_validatedFields;
126    }
127
128    /**
129     * @see org.opencms.gwt.client.validation.I_CmsValidationController#provideValidationResult(java.lang.String, org.opencms.gwt.shared.CmsValidationResult)
130     */
131    public void provideValidationResult(String field, CmsValidationResult result) {
132
133        if (result.getErrorMessage() != null) {
134            m_validationOk = false;
135        }
136
137        m_handler.onValidationResult(field, result);
138    }
139
140    /**
141     * Sets the form validator class name for this validation controller.<p>
142     *
143     * @param formValidatorClass the class name of  the form validator
144     */
145    public void setFormValidator(String formValidatorClass) {
146
147        m_formValidatorClass = formValidatorClass;
148    }
149
150    /**
151     * Sets the form validator configuration string.<p>
152     * a
153     * @param formValidatorConfig the form validator configuration string
154     */
155    public void setFormValidatorConfig(String formValidatorConfig) {
156
157        m_formValidatorConfig = formValidatorConfig;
158
159    }
160
161    /**
162     * Starts the validation.<p>
163     *
164     * This uses the {@link CmsValidationScheduler}, so the validation only starts after the currently running or scheduled
165     * validations have finished running.<p>
166     */
167    public void startValidation() {
168
169        CmsValidationScheduler.get().schedule(this);
170    }
171
172    /**
173     * @see org.opencms.gwt.client.validation.I_CmsValidationController#validateAsync(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
174     */
175    public void validateAsync(String field, String value, String validator, String config) {
176
177        m_validationQueries.put(field, new CmsValidationQuery(validator, value, config));
178    }
179
180    /**
181     * Starts the validation.<p>
182     */
183    protected void internalStartValidation() {
184
185        assert m_isNew : "A validation controller can only be used once!";
186        m_isNew = false;
187
188        m_validationOk = true;
189        for (I_CmsFormField field : m_fields) {
190            I_CmsFormField.ValidationStatus status = field.getValidationStatus();
191            if (status == I_CmsFormField.ValidationStatus.unknown) {
192                I_CmsValidator validator = field.getValidator();
193                validator.validate(field, this);
194                m_validatedFields.add(field.getId());
195            } else if (status == I_CmsFormField.ValidationStatus.invalid) {
196                m_validationOk = false;
197            }
198        }
199        if (m_validationQueries.isEmpty()) {
200            m_handler.onValidationFinished(m_validationOk);
201            CmsValidationScheduler.get().executeNext();
202        } else {
203            if (m_formValidatorClass == null) {
204                startAsyncValidation();
205            } else {
206                startAsyncValidation(m_formValidatorClass, m_formValidatorConfig);
207            }
208        }
209    }
210
211    /**
212     * Internal method which is executed when the results of the asynchronous validation are received from the server.<p>
213     *
214     * @param results the validation results
215     */
216    protected void onReceiveValidationResults(Map<String, CmsValidationResult> results) {
217
218        try {
219            for (Map.Entry<String, CmsValidationResult> resultEntry : results.entrySet()) {
220                String fieldName = resultEntry.getKey();
221                CmsValidationResult result = resultEntry.getValue();
222                provideValidationResult(fieldName, result);
223            }
224            m_handler.onValidationFinished(m_validationOk);
225        } finally {
226            CmsValidationScheduler.get().executeNext();
227        }
228    }
229
230    /**
231     * Starts the asynchronous validation.<p>
232     */
233    private void startAsyncValidation() {
234
235        CmsRpcAction<Map<String, CmsValidationResult>> action = new CmsRpcAction<Map<String, CmsValidationResult>>() {
236
237            /**
238             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
239             */
240            @Override
241            public void execute() {
242
243                start(0, false);
244                CmsCoreProvider.getService().validate(m_validationQueries, this);
245            }
246
247            @Override
248            public void onFailure(Throwable e) {
249
250                super.onFailure(e);
251                CmsValidationScheduler.get().executeNext();
252
253            }
254
255            /**
256             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
257             */
258            @Override
259            protected void onResponse(Map<String, CmsValidationResult> result) {
260
261                stop(false);
262                onReceiveValidationResults(result);
263            }
264
265        };
266        action.execute();
267    }
268
269    /**
270     * Starts the asynchronous validation.<p>
271     *
272     * @param formValidationHandler the form validator class to use
273     * @param config the form validator configuration string
274     */
275    private void startAsyncValidation(final String formValidationHandler, final String config) {
276
277        CmsRpcAction<Map<String, CmsValidationResult>> action = new CmsRpcAction<Map<String, CmsValidationResult>>() {
278
279            /**
280             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
281             */
282            @Override
283            public void execute() {
284
285                final Map<String, String> values = new HashMap<String, String>();
286                for (I_CmsFormField field : m_fields) {
287                    values.put(field.getId(), field.getModelValue());
288                }
289                start(0, false);
290                CmsCoreProvider.getService().validate(formValidationHandler, m_validationQueries, values, config, this);
291            }
292
293            /**
294             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
295             */
296            @Override
297            protected void onResponse(Map<String, CmsValidationResult> result) {
298
299                stop(false);
300                onReceiveValidationResults(result);
301            }
302
303        };
304        action.execute();
305    }
306}