001/*
002 * Copyright (c) 2006-2012 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Nuxeo - Thierry Delprat <tdelprat@nuxeo.com> - Mock implementation
011 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
012 */
013
014package org.nuxeo.ecm.core.schema.types.constraints;
015
016import java.io.Serializable;
017import java.util.ArrayList;
018import java.util.Collections;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.List;
022import java.util.Locale;
023import java.util.Map;
024import java.util.Set;
025
026import org.apache.commons.lang.StringUtils;
027
028/**
029 * <p>
030 * This constraint ensures some object's String representation is in an enumeration.
031 * </p>
032 *
033 * @since 7.1
034 */
035public class EnumConstraint extends AbstractConstraint {
036
037    private static final long serialVersionUID = 1L;
038
039    private static final String NAME = "EnumConstraint";
040
041    private static final String PNAME_VALUES = "Values";
042
043    protected final Set<String> possibleValues;
044
045    /**
046     * Supports any objects, use their String representation.
047     */
048    public EnumConstraint(List<?> possibleValues) {
049        this.possibleValues = new HashSet<String>();
050        for (Object possibleValue : possibleValues) {
051            this.possibleValues.add(possibleValue.toString());
052        }
053    }
054
055    public EnumConstraint(Object... possibleValues) {
056        this.possibleValues = new HashSet<String>();
057        for (Object possibleValue : possibleValues) {
058            this.possibleValues.add(possibleValue.toString());
059        }
060    }
061
062    @Override
063    public boolean validate(Object object) {
064        if (object == null) {
065            return true;
066        }
067        return possibleValues.contains(object.toString());
068    }
069
070    /**
071     * Here, value is : <br>
072     * name = {@value #NAME} <br>
073     * parameter =
074     * <ul>
075     * <li>{@value #PNAME_VALUES} : List[value1, value2, value3]</li>
076     * </ul>
077     */
078    @Override
079    public Description getDescription() {
080        Map<String, Serializable> params = new HashMap<String, Serializable>();
081        params.put(EnumConstraint.PNAME_VALUES, new ArrayList<String>(possibleValues));
082        return new Description(EnumConstraint.NAME, params);
083    }
084
085    public Set<String> getPossibleValues() {
086        return Collections.unmodifiableSet(possibleValues);
087    }
088
089    @Override
090    public String getErrorMessage(Object invalidValue, Locale locale) {
091        // test whether there's a custom translation for this field constraint specific translation
092        // the expected key is label.schema.constraint.violation.[ConstraintName]
093        // follow the AbstractConstraint behavior otherwise
094        List<String> pathTokens = new ArrayList<String>();
095        pathTokens.add(MESSAGES_KEY);
096        pathTokens.add(EnumConstraint.NAME);
097        String key = StringUtils.join(pathTokens, '.');
098        Object[] params = new Object[] { StringUtils.join(getPossibleValues(), ", ") };
099        Locale computedLocale = locale != null ? locale : Constraint.MESSAGES_DEFAULT_LANG;
100        String message = getMessageString(MESSAGES_BUNDLE, key, params, computedLocale);
101        if (message != null && !message.trim().isEmpty() && !key.equals(message)) {
102            // use a custom constraint message if there's one
103            return message;
104        } else {
105            // follow AbstractConstraint behavior otherwise
106            return super.getErrorMessage(invalidValue, computedLocale);
107        }
108    }
109
110    @Override
111    public int hashCode() {
112        final int prime = 31;
113        int result = 1;
114        result = prime * result + ((possibleValues == null) ? 0 : possibleValues.hashCode());
115        return result;
116    }
117
118    @Override
119    public boolean equals(Object obj) {
120        if (this == obj) {
121            return true;
122        }
123        if (obj == null) {
124            return false;
125        }
126        if (getClass() != obj.getClass()) {
127            return false;
128        }
129        EnumConstraint other = (EnumConstraint) obj;
130        if (possibleValues == null) {
131            if (other.possibleValues != null) {
132                return false;
133            }
134        } else if (!possibleValues.equals(other.possibleValues)) {
135            return false;
136        }
137        return true;
138    }
139
140}