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