001/*
002 * (C) Copyright 2006-2011 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 *     Nuxeo - Bogdan Stefanescu <bs@nuxeo.com> - Constraint API skeleton.
018 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
019 */
020
021package org.nuxeo.ecm.core.schema.types.constraints;
022
023import java.io.Serializable;
024import java.util.Collections;
025import java.util.Locale;
026import java.util.Map;
027
028/**
029 * A constraint object defines a constraint on a custom type. Method {@link #getDescription()} allows anyone to
030 * dynamically redefine this constraint in another language (for example in javascript to make client-side validation).
031 *
032 * @since 7.1
033 */
034public interface Constraint extends Serializable {
035
036    String MESSAGES_BUNDLE = "messages";
037
038    Locale MESSAGES_DEFAULT_LANG = Locale.ENGLISH;
039
040    String MESSAGES_KEY = "label.schema.constraint.violation";
041
042    /**
043     * Validates the given object against this constraint.
044     * <p>
045     * If some object is null. Constraint should return true while validating unless the constraint deals with nullable
046     * state.
047     * </p>
048     *
049     * @param object the object to validate
050     * @return true if the object was successfully validated, false otherwise
051     */
052    boolean validate(Object object);
053
054    /**
055     * Provides an error message to display when some invalid value does not match existing entity.
056     *
057     * @param invalidValue The invalid value that don't match any entity.
058     * @param locale The language in which the message should be generated.
059     * @return A message in the specified language or
060     * @since 7.1
061     */
062    String getErrorMessage(Object invalidValue, Locale locale);
063
064    /**
065     * Provides the message key.
066     *
067     * @return The message key
068     * @since 11.1
069     */
070    String getMessageKey();
071
072    /**
073     * Provides a description of a constraint. For example, a constraint which control String format could return
074     * {@code name=PatternMatchingConstraint
075     * | parameters= "pattern":"[0-9]+"}
076     *
077     * @return The constraint description.
078     * @since 7.1
079     */
080    Description getDescription();
081
082    /**
083     * Represent the description of a constraint.
084     * <p>
085     * In the map, key are parameter names, value are parameter values.
086     * </p>
087     *
088     * @since 7.1
089     */
090    class Description {
091
092        private String name;
093
094        private Map<String, Serializable> parameters;
095
096        public Description(String name, Map<String, Serializable> parameters) {
097            super();
098            this.name = name;
099            this.parameters = parameters;
100        }
101
102        public String getName() {
103            return name;
104        }
105
106        public Map<String, Serializable> getParameters() {
107            return Collections.unmodifiableMap(parameters);
108        }
109
110        @Override
111        public int hashCode() {
112            final int prime = 31;
113            int result = 1;
114            result = prime * result + ((name == null) ? 0 : name.hashCode());
115            result = prime * result + ((parameters == null) ? 0 : parameters.hashCode());
116            return result;
117        }
118
119        @Override
120        public boolean equals(Object obj) {
121            if (this == obj) {
122                return true;
123            }
124            if (obj == null) {
125                return false;
126            }
127            if (getClass() != obj.getClass()) {
128                return false;
129            }
130            Description other = (Description) obj;
131            if (name == null) {
132                if (other.name != null) {
133                    return false;
134                }
135            } else if (!name.equals(other.name)) {
136                return false;
137            }
138            if (parameters == null) {
139                if (other.parameters != null) {
140                    return false;
141                }
142            } else if (!parameters.equals(other.parameters)) {
143                return false;
144            }
145            return true;
146        }
147
148        @Override
149        public String toString() {
150            StringBuilder builder = new StringBuilder(name);
151            builder.append(parameters.toString());
152            return builder.toString();
153        }
154    }
155
156}