001/*
002 * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Anahide Tchertchian
018 */
019package org.nuxeo.ecm.platform.ui.web.validator;
020
021import java.util.ArrayList;
022import java.util.List;
023import java.util.Map;
024
025import javax.faces.component.UIComponent;
026import javax.faces.context.FacesContext;
027import javax.faces.validator.Validator;
028import javax.faces.validator.ValidatorException;
029
030import org.apache.commons.lang3.StringUtils;
031import org.nuxeo.ecm.core.api.SortInfo;
032
033import com.sun.faces.util.MessageFactory;
034
035/**
036 * Validator for a list of {@link SortInfo} elements, checking that there is no conflicting sort information (several
037 * sorts on same criterion)
038 *
039 * @author Anahide Tchertchian
040 */
041public class SortInfoListValidator implements Validator {
042
043    public static final String VALIDATOR_ID = "SortInfoListValidator";
044
045    /**
046     * The message identifier of the {@link javax.faces.application.FacesMessage} to be created if the value to validate
047     * is not a list of sort infos.
048     */
049    public static final String INVALID_VALUE_MESSAGE_ID = "error.sortInfoValidator.invalidValue";
050
051    /**
052     * The message identifier of the {@link javax.faces.application.FacesMessage} to be created if the value to validate
053     * is a list of sort infos with conflicting criteria (several sorts on the same criterion).
054     * <p>
055     * The message format string for this message may optionally include the following placeholders:
056     * <ul>
057     * <li><code>{0}</code> replaced by the first found duplicate criterion.</li>
058     * </ul>
059     */
060    public static final String CONFLICTING_CRITERIA_MESSAGE_ID = "error.sortInfoValidator.conflictingCriteria";
061
062    /**
063     * The message identifier of the {@link javax.faces.application.FacesMessage} to be created if the value to validate
064     * contains a sort info with an empty sort criterion.
065     */
066    public static final String EMPTY_CRITERION_MESSAGE_ID = "error.sortInfoValidator.emptyCriterion";
067
068    @Override
069    @SuppressWarnings({ "unchecked", "rawtypes" })
070    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
071        if (context == null || component == null) {
072            throw new IllegalArgumentException();
073        }
074        if (value != null) {
075            if (value instanceof List) {
076                try {
077                    List sortInfos = (List) value;
078                    List<String> criteria = new ArrayList<String>();
079                    for (Object sortInfo : sortInfos) {
080                        String criterion = null;
081                        if (sortInfo instanceof SortInfo) {
082                            criterion = ((SortInfo) sortInfo).getSortColumn();
083                        } else {
084                            // assume it's a map
085                            SortInfo sortInfoValue = SortInfo.asSortInfo((Map) sortInfo);
086                            if (sortInfoValue == null) {
087                                throw new ValidatorException(MessageFactory.getMessage(context,
088                                        INVALID_VALUE_MESSAGE_ID));
089                            }
090                            criterion = sortInfoValue.getSortColumn();
091                        }
092                        if (criterion == null || StringUtils.isEmpty(criterion.trim())) {
093                            throw new ValidatorException(MessageFactory.getMessage(context, EMPTY_CRITERION_MESSAGE_ID));
094                        }
095                        if (criteria.contains(criterion)) {
096                            throw new ValidatorException(MessageFactory.getMessage(context,
097                                    CONFLICTING_CRITERIA_MESSAGE_ID, criterion));
098                        } else {
099                            criteria.add(criterion);
100                        }
101                    }
102                } catch (ClassCastException e) {
103                    throw new ValidatorException(MessageFactory.getMessage(context, INVALID_VALUE_MESSAGE_ID));
104                }
105            }
106        }
107    }
108}