Project

General

Profile

Revision 3f88d296

ID3f88d296ddea2907b41f3ac100cf8fa4e15cc9d7
Parent 680b19b1
Child 7e7e032e

Added by Andreas Müller over 3 years ago

fix #6363 Implement validation rules for all taxon names

View differences:

cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/name/TaxonNameBase.java
91 91
import eu.etaxonomy.cdm.strategy.parser.ParserProblem;
92 92
import eu.etaxonomy.cdm.validation.Level2;
93 93
import eu.etaxonomy.cdm.validation.Level3;
94
import eu.etaxonomy.cdm.validation.annotation.NameMustFollowCode;
94 95
import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
95 96
import eu.etaxonomy.cdm.validation.annotation.ValidTaxonomicYear;
96 97

  
......
164 165
@Audited
165 166
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
166 167
@Table(appliesTo="TaxonNameBase", indexes = { @org.hibernate.annotations.Index(name = "taxonNameBaseTitleCacheIndex", columnNames = { "titleCache" }),  @org.hibernate.annotations.Index(name = "taxonNameBaseNameCacheIndex", columnNames = { "nameCache" }) })
168
@NameMustFollowCode
167 169
public abstract class TaxonNameBase<T extends TaxonNameBase<?,?>, S extends INameCacheStrategy>
168 170
            extends IdentifiableEntity<S>
169 171
            implements ITaxonNameBase, INonViralName, IViralName, IBacterialName, IZoologicalName,
cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/annotation/NameMustFollowCode.java
1
/**
2
* Copyright (C) 2009 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

  
10
package eu.etaxonomy.cdm.validation.annotation;
11

  
12
import static java.lang.annotation.ElementType.TYPE;
13
import static java.lang.annotation.RetentionPolicy.RUNTIME;
14

  
15
import java.lang.annotation.Documented;
16
import java.lang.annotation.Retention;
17
import java.lang.annotation.Target;
18

  
19
import javax.validation.Constraint;
20
import javax.validation.Payload;
21

  
22
import eu.etaxonomy.cdm.validation.constraint.NameMustFollowCodeValidator;
23

  
24
@Target( { TYPE })
25
@Retention(RUNTIME)
26
@Constraint(validatedBy = NameMustFollowCodeValidator.class)
27
@Documented
28
public @interface NameMustFollowCode {
29

  
30
	String message() default "{eu.etaxonomy.cdm.validation.annotation.NameMustFollowCode.message}";
31

  
32
	Class<? extends Payload>[] payload() default {};
33

  
34
	Class<?>[] groups() default {};
35
}
cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/constraint/NameMustFollowCodeValidator.java
1
/**
2
* Copyright (C) 2017 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.validation.constraint;
10

  
11
import java.util.Collection;
12

  
13
import javax.validation.ConstraintValidator;
14
import javax.validation.ConstraintValidatorContext;
15

  
16
import org.apache.commons.lang.StringUtils;
17

  
18
import eu.etaxonomy.cdm.model.common.CdmBase;
19
import eu.etaxonomy.cdm.model.name.BacterialName;
20
import eu.etaxonomy.cdm.model.name.CultivarPlantName;
21
import eu.etaxonomy.cdm.model.name.NonViralName;
22
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
23
import eu.etaxonomy.cdm.model.name.ViralName;
24
import eu.etaxonomy.cdm.model.name.ZoologicalName;
25
import eu.etaxonomy.cdm.validation.annotation.NameMustFollowCode;
26

  
27
/**
28
 * Validator for name parts. Required since {@link TaxonNameBase} has
29
 * no subclasses anymore. This validator checks if the names follow
30
 * the old sublassing rules.
31
 * <BR><BR>
32
 * https://dev.e-taxonomy.eu/redmine/issues/6363
33
 *
34
 * @author a.mueller
35
 * @date 11.03.2017
36
 *
37
 */
38
public class NameMustFollowCodeValidator implements
39
        ConstraintValidator<NameMustFollowCode, TaxonNameBase<?,?>> {
40

  
41
    @Override
42
    public void initialize(NameMustFollowCode nameMustFollowTheirCode) { }
43

  
44
    @Override
45
    public boolean isValid(TaxonNameBase<?,?> name, ConstraintValidatorContext constraintContext) {
46
        name = CdmBase.deproxy(name);
47
        boolean valid = true;
48

  
49
        //CultivarPlantName
50
        if (! (name instanceof CultivarPlantName)){
51
            if (name.getCultivarName() != null){
52
                valid = false;
53
            }
54
        }
55
        //BacterialName
56
        if (! (name instanceof BacterialName)){
57
            if (isNotNull(name.getSubGenusAuthorship(), name.getNameApprobation())){
58
                valid = false;
59
            }
60
        }
61
        //BacterialName
62
        if (! (name instanceof ViralName)){
63
            if (name.getAcronym() != null){
64
                valid = false;
65
            }
66
        }
67
        //ZoologicalName
68
        if (! (name instanceof ZoologicalName)){
69
            if (isNotNull(name.getBreed(), name.getOriginalPublicationYear()
70
                    , name.getPublicationYear())){
71
                valid = false;
72
            }
73
        }
74
        //NonViralName
75
        if (! (name instanceof NonViralName)){
76
            if (    isNotNull(name.getGenusOrUninomial(), name.getSpecificEpithet()
77
                        , name.getInfraGenericEpithet(), name.getInfraSpecificEpithet() )
78
                    || isNotEmpty(name.getNameRelations() , name.getHybridParentRelations()
79
                        , name.getHybridChildRelations())
80
                    || isNotFalse(name.hasAuthors(), name.isHybrid()
81
                        , name.isProtectedAuthorshipCache(), name.isProtectedNameCache())
82
                    || isNotBlank(name.getNameCache(), name.getAuthorshipCache())
83
                    ){
84
                valid = false;
85
            }
86
        }
87
        return valid;
88
    }
89

  
90
    private boolean isNotFalse(boolean ... shouldBeFalse) {
91
        for (boolean bool : shouldBeFalse){
92
            if (bool){
93
                return true;
94
            }
95
        }
96
        return false;
97
    }
98

  
99
    private boolean isNotEmpty(Collection<?> ... shouldBeEmpty) {
100
        for (Collection<?> coll : shouldBeEmpty){
101
            if (!coll.isEmpty()){
102
                return true;
103
            }
104
        }
105
        return false;
106
    }
107

  
108
    /**
109
     * @param nameCache
110
     * @param authorshipCache
111
     * @return
112
     */
113
    private boolean isNotBlank(String ... shouldBeBlank) {
114
        for (String str : shouldBeBlank){
115
            if (StringUtils.isNotBlank(str)){
116
                return true;
117
            }
118
        }
119
        return false;
120
    }
121

  
122
    /**
123
     * @param subGenusAuthorship
124
     * @param nameApprobation
125
     * @return
126
     */
127
    private boolean isNotNull(Object ... shouldBeNullObjects) {
128
        for (Object obj : shouldBeNullObjects){
129
            if (obj != null){
130
                return true;
131
            }
132
        }
133
        return false;
134
    }
135
}
136

  
cdmlib-model/src/main/resources/ValidationMessages.properties
28 28
eu.etaxonomy.cdm.validation.annotation.InReference.ReferenceShouldNotHaveIsbn.message=the reference should not have an isbn
29 29
eu.etaxonomy.cdm.validation.annotation.InReference.JournalShouldNotHaveDatePublished.message=a journal must not have a date published
30 30
eu.etaxonomy.cdm.validation.annotation.ValidTaxonomicYear.message=a valid taxon name year must be after 1753
31
eu.etaxonomy.cdm.validation.annotation.name.ValidTypeDesignation.message = Type designations must belong to a name and must either link to a specimen/name or be flagged as 'not designated'
31
eu.etaxonomy.cdm.validation.annotation.name.ValidTypeDesignation.message = Type designations must belong to a name and must either link to a specimen/name or be flagged as 'not designated'
32
eu.etaxonomy.cdm.validation.annotation.NameMustFollowCode.message = Taxon name must only have attributes set that are available according to their code. E.g. 'acronym name' should only be available for viral names.
cdmlib-model/src/test/java/eu/etaxonomy/cdm/validation/NameMustFollowCodeTest.java
1
/**
2
* Copyright (C) 2009 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

  
10
package eu.etaxonomy.cdm.validation;
11

  
12
import static org.junit.Assert.assertFalse;
13
import static org.junit.Assert.assertTrue;
14

  
15
import java.util.Set;
16

  
17
import javax.validation.ConstraintViolation;
18

  
19
import org.apache.log4j.Logger;
20
import org.junit.Assert;
21
import org.junit.Before;
22
import org.junit.Test;
23

  
24
import eu.etaxonomy.cdm.model.common.DefaultTermInitializer;
25
import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
26
import eu.etaxonomy.cdm.model.name.Rank;
27
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
28
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
29
import eu.etaxonomy.cdm.validation.constraint.NameMustFollowCodeValidator;
30

  
31

  
32

  
33
/**
34
 * Test class for {@link NameMustFollowCodeValidator}
35
 *
36
 * @author a.mueller
37
 * @date 11.03.2017
38
 */
39
public class NameMustFollowCodeTest extends ValidationTestBase {
40
	@SuppressWarnings("unused")
41
    private static final Logger logger = Logger.getLogger(NameMustFollowCodeTest.class);
42

  
43
	private TaxonNameBase<?,?> nonViralName;
44
    private TaxonNameBase<?,?> viralName;
45
    private TaxonNameBase<?,?> bacterialName;
46
    private TaxonNameBase<?,?> zoologicalName;
47
    private TaxonNameBase<?,?> cultivarName;
48

  
49
	@Before
50
	public void setUp() {
51
		DefaultTermInitializer vocabularyStore = new DefaultTermInitializer();
52
		vocabularyStore.initialize();
53
		nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
54
		viralName = TaxonNameFactory.NewViralInstance(Rank.SPECIES());
55
		zoologicalName = TaxonNameFactory.NewZoologicalInstance(Rank.SPECIES());
56
		bacterialName = TaxonNameFactory.NewBacterialInstance(Rank.SPECIES());
57
	    cultivarName = TaxonNameFactory.NewCultivarInstance(Rank.SPECIES());
58
	}
59

  
60

  
61
/****************** TESTS *****************************/
62

  
63
    @Test
64
    public void testValidEmptyNames() {
65
        Set<ConstraintViolation<TaxonNameBase<?,?>>> constraintViolations
66
                            = validator.validate(cultivarName);
67
        assertTrue("There should be no constraint violations as this name has data set and therefore no unvalid attributes set", constraintViolations.isEmpty());
68

  
69
        constraintViolations  = validator.validate(nonViralName);
70
        assertTrue("There should be no constraint violations as this name has data set and therefore no unvalid attributes set", constraintViolations.isEmpty());
71

  
72
        constraintViolations  = validator.validate(viralName);
73
        assertTrue("There should be no constraint violations as this name has data set and therefore no unvalid attributes set", constraintViolations.isEmpty());
74

  
75
        constraintViolations  = validator.validate(zoologicalName);
76
        assertTrue("There should be no constraint violations as this name has data set and therefore no unvalid attributes set", constraintViolations.isEmpty());
77

  
78
        constraintViolations  = validator.validate(bacterialName);
79
        assertTrue("There should be no constraint violations as this name has data set and therefore no unvalid attributes set", constraintViolations.isEmpty());
80
    }
81

  
82
    @Test
83
    public void testMessage() {
84
        nonViralName.setAcronym("acronym");
85
        Set<ConstraintViolation<TaxonNameBase<?,?>>> constraintViolations  = validator.validate(nonViralName);
86
        assertFalse("There should be a constraint violation as a nonViralName must not have an acronym", constraintViolations.isEmpty());
87
        String message = constraintViolations.iterator().next().getMessage();
88
        String expected = "Taxon name must only have attributes set that are available according to their code. E.g. 'acronym name' should only be available for viral names.";
89
        Assert.assertEquals(expected, message);
90
    }
91

  
92
	@Test
93
	public void testValidNonViralName() {
94
	    nonViralName.setAcronym("acronym");
95
	    Set<ConstraintViolation<TaxonNameBase<?,?>>> constraintViolations  = validator.validate(nonViralName);
96
        assertFalse("There should be a constraint violation as a nonViralName must not have an acronym", constraintViolations.isEmpty());
97

  
98
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
99
        nonViralName.setBreed("Breed");
100
        constraintViolations  = validator.validate(nonViralName);
101
        assertFalse("There should be a constraint violation as a pure NonViralNamen must not have a breed", constraintViolations.isEmpty());
102

  
103
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
104
        nonViralName.setOriginalPublicationYear(1987);
105
        constraintViolations  = validator.validate(nonViralName);
106
        assertFalse("There should be a constraint violation as a pure NonViralNamen must not have an original publication year", constraintViolations.isEmpty());
107

  
108
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
109
        nonViralName.setPublicationYear(2001);
110
        constraintViolations  = validator.validate(nonViralName);
111
        assertFalse("There should be a constraint violation as a pure NonViralNamen must not have a publication year", constraintViolations.isEmpty());
112

  
113
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
114
        nonViralName.setSubGenusAuthorship("SubGenusAuthor");
115
        constraintViolations  = validator.validate(nonViralName);
116
        assertFalse("There should be a constraint violation as a pure NonViralNamen must not have a subgenus author", constraintViolations.isEmpty());
117

  
118
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
119
        nonViralName.setNameApprobation("Name approbation");
120
        constraintViolations  = validator.validate(nonViralName);
121
        assertFalse("There should be a constraint violation as a pure NonViralNamen must not have a name approbation", constraintViolations.isEmpty());
122

  
123
        //Valid
124
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
125
        nonViralName.setMonomHybrid(true);
126
        constraintViolations  = validator.validate(nonViralName);
127
        assertTrue("There should be no constraint violation as a NonViralNamen may have a hybrid flag set", constraintViolations.isEmpty());
128

  
129
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
130
        nonViralName.setGenusOrUninomial("Genus");
131
        constraintViolations  = validator.validate(nonViralName);
132
        assertTrue("There should be no constraint violation as a NonViralNamen may have a genus name set", constraintViolations.isEmpty());
133

  
134
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
135
        nonViralName.setNameCache("NameCache");
136
        constraintViolations  = validator.validate(nonViralName);
137
        assertTrue("There should be no constraint violation as a NonViralNamen may have the name cache set", constraintViolations.isEmpty());
138

  
139
        nonViralName = TaxonNameFactory.NewNonViralInstance(Rank.SPECIES());
140
        TaxonNameBase<?,?> childName = TaxonNameFactory.NewViralInstance(Rank.SPECIES());
141
        nonViralName.addHybridChild(childName, HybridRelationshipType.FIRST_PARENT(), null);
142
        constraintViolations  = validator.validate(nonViralName);
143
        assertTrue("There should be no constraint violation as a NonViralNamen may have a hybrid child", constraintViolations.isEmpty());
144

  
145
        //TBC
146
	}
147

  
148
    @Test
149
    public void testValidViralName() {
150
        viralName.setAcronym("acronym");
151
        Set<ConstraintViolation<TaxonNameBase<?,?>>> constraintViolations  = validator.validate(viralName);
152
        assertTrue("There should be no constraint violation as a viral name may have acronym set", constraintViolations.isEmpty());
153

  
154
        //Invalid
155
        viralName = TaxonNameFactory.NewViralInstance(Rank.SPECIES());
156
        viralName.setMonomHybrid(true);
157
        constraintViolations  = validator.validate(viralName);
158
        assertFalse("There should be a constraint violation as a ViralName must not have a hybrid flag set", constraintViolations.isEmpty());
159

  
160
        viralName = TaxonNameFactory.NewViralInstance(Rank.SPECIES());
161
        viralName.setGenusOrUninomial("Genus");
162
        constraintViolations  = validator.validate(viralName);
163
        assertFalse("There should be a constraint violation as a ViralName must not have the genus name set", constraintViolations.isEmpty());
164

  
165
        viralName = TaxonNameFactory.NewViralInstance(Rank.SPECIES());
166
        viralName.setNameCache("NameCache");
167
        constraintViolations  = validator.validate(viralName);
168
        assertFalse("There should be a constraint violation as a ViralName must not have the nameCache set", constraintViolations.isEmpty());
169

  
170
        viralName = TaxonNameFactory.NewViralInstance(Rank.SPECIES());
171
        TaxonNameBase<?,?> childName = TaxonNameFactory.NewViralInstance(Rank.SPECIES());
172
        viralName.addHybridChild(childName, HybridRelationshipType.FIRST_PARENT(), null);
173
        constraintViolations  = validator.validate(viralName);
174
        assertFalse("There should be a constraint violation as a ViralName must not have hybrid child", constraintViolations.isEmpty());
175

  
176
        //TBC
177

  
178
    }
179

  
180
    @Test
181
    public void testValidZoologicalName() {
182
        zoologicalName.setBreed("Breed");
183
        zoologicalName.setOriginalPublicationYear(1987);
184
        zoologicalName.setPublicationYear(2001);
185

  
186
        Set<ConstraintViolation<TaxonNameBase<?,?>>> constraintViolations  = validator.validate(zoologicalName);
187
        assertTrue("There should be no constraint violation as a zoological name may have breed and years set", constraintViolations.isEmpty());
188
    }
189

  
190
    @Test
191
    public void testValidBacterialName() {
192
        bacterialName.setSubGenusAuthorship("Subgenus author");
193
        bacterialName.setNameApprobation("Name approbation");
194

  
195
        Set<ConstraintViolation<TaxonNameBase<?,?>>> constraintViolations  = validator.validate(bacterialName);
196
        assertTrue("There should be no constraint violation as a bacterial name may have subgenus authorship or name approbation set", constraintViolations.isEmpty());
197
    }
198

  
199
}

Also available in: Unified diff

Add picture from clipboard (Maximum size: 40 MB)