Skip to content

Method: CardinalityConstraintsValidator()

1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.sessions.validator;
16:
17: import cz.cvut.kbss.jopa.exceptions.CardinalityConstraintViolatedException;
18: import cz.cvut.kbss.jopa.model.annotations.ParticipationConstraint;
19: import cz.cvut.kbss.jopa.model.annotations.ParticipationConstraints;
20: import cz.cvut.kbss.jopa.model.metamodel.Attribute;
21: import cz.cvut.kbss.jopa.model.metamodel.FieldSpecification;
22: import cz.cvut.kbss.jopa.utils.ErrorUtils;
23:
24: import java.lang.reflect.Field;
25: import java.util.Collection;
26: import java.util.Objects;
27:
28: /**
29: * Validator of participation constraints.
30: */
31: class CardinalityConstraintsValidator extends IntegrityConstraintsValidator {
32:
33: CardinalityConstraintsValidator() {
34: }
35:
36: /**
37: * Validates cardinality constraints defined in the {@link ParticipationConstraints} annotation.
38: *
39: * @param identifier Field owner identifier (individual URI)
40: * @param field Field on which the constraints are defined
41: * @param value The value to validate
42: */
43: public void validate(Object identifier, Field field, Object value) {
44: Objects.requireNonNull(field, ErrorUtils.getNPXMessageSupplier("field"));
45: final ParticipationConstraints constraints = field.getAnnotation(ParticipationConstraints.class);
46: if (constraints == null) {
47: return;
48: }
49: final int valueCount = extractValueCount(value);
50: for (ParticipationConstraint pc : constraints.value()) {
51: validateParticipationConstraint(identifier, field, valueCount, pc);
52: }
53: if (constraints.value().length == 0) {
54: validateNonEmpty(identifier, field, valueCount, constraints);
55: }
56: }
57:
58: @Override
59: public void validate(Object identifier, FieldSpecification<?, ?> attribute, Object attributeValue) {
60: if (!(attribute instanceof Attribute)) {
61: // Only proper attributes can have cardinality constraints
62: return;
63: }
64: final Attribute<?, ?> att = (Attribute<?, ?>) attribute;
65: final int valueCount = extractValueCount(attributeValue);
66: for (ParticipationConstraint pc : att.getConstraints()) {
67: validateParticipationConstraint(identifier, att.getJavaField(), valueCount, pc);
68: }
69: if (att.getConstraints().length == 0) {
70: validateNonEmpty(identifier, att, valueCount);
71: }
72: }
73:
74: private int extractValueCount(Object value) {
75: if (value == null) {
76: return 0;
77: }
78: return value instanceof Collection ? ((Collection<?>) value).size() : 1;
79: }
80:
81: private void validateParticipationConstraint(Object id, Field field, int valueCount, ParticipationConstraint pc) {
82: if (valueCount < pc.min()) {
83: throw new CardinalityConstraintViolatedException("At least " + pc.min() +
84: " values of attribute " + field.getDeclaringClass().getSimpleName() + "." + field.getName() +
85: " expected in instance " + id + ", but got only " + valueCount);
86: }
87: if (pc.max() >= 0 && pc.max() < valueCount) {
88: throw new CardinalityConstraintViolatedException("At most " + pc.max() +
89: " values of attribute " + field.getDeclaringClass().getSimpleName() + "." + field.getName() +
90: " expected in instance " + id + ", but got " + valueCount);
91: }
92: }
93:
94: private void validateNonEmpty(Object id, Field field, int valueCount, ParticipationConstraints constraints) {
95: if (valueCount == 0 && constraints.nonEmpty()) {
96: throw nonEmptyError(id, field.getDeclaringClass().getSimpleName(), field.getName());
97: }
98: }
99:
100: private CardinalityConstraintViolatedException nonEmptyError(Object id, String className, String fieldName) {
101: return new CardinalityConstraintViolatedException(
102: "Attribute " + className + "." + fieldName + " of instance " + id +
103: " was marked as nonEmpty, but contains no value.");
104: }
105:
106: private void validateNonEmpty(Object id, Attribute<?, ?> attribute, int valueCount) {
107: if (valueCount == 0 && attribute.isNonEmpty()) {
108: throw nonEmptyError(id, attribute.getDeclaringType().getJavaType().getSimpleName(), attribute.getName());
109: }
110: }
111: }