-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
35463 add identifier type base entity (#480)
* 35463 Add identifier type base entity Added IdentifierType class * Added service and validator + integration test * Fixed Checkstyle * Added dinaComponent to IdentifierType * Use a list for dinaComponents * Allow existing valid keys * Changed IdentifierType to an interface easier to use with Hibernate
- Loading branch information
Showing
7 changed files
with
256 additions
and
28 deletions.
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
dina-base-api/src/main/java/ca/gc/aafc/dina/entity/IdentifierType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package ca.gc.aafc.dina.entity; | ||
|
||
import java.util.List; | ||
|
||
import ca.gc.aafc.dina.vocabulary.VocabularyElement; | ||
|
||
public interface IdentifierType extends VocabularyElement, DinaEntity { | ||
|
||
/** | ||
* The key should not contain dot(.) See {@link VocabularyElement#getKey()} | ||
* @param key | ||
*/ | ||
void setKey(String key); | ||
|
||
/** | ||
* The component (material-sample, project) where this identifier type is expected to be used. | ||
*/ | ||
List<String> getDinaComponents(); | ||
|
||
/** | ||
* Like wikidata. A URI template where "$1" can be automatically replaced with the value | ||
* assigned to the identifier. | ||
*/ | ||
String getUriTemplate(); | ||
|
||
} |
46 changes: 46 additions & 0 deletions
46
dina-base-api/src/main/java/ca/gc/aafc/dina/service/IdentifierTypeService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package ca.gc.aafc.dina.service; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
import org.springframework.validation.SmartValidator; | ||
|
||
import ca.gc.aafc.dina.entity.IdentifierType; | ||
import ca.gc.aafc.dina.jpa.BaseDAO; | ||
import ca.gc.aafc.dina.validation.IdentifierTypeValidator; | ||
import ca.gc.aafc.dina.vocabulary.VocabularyKeyHelper; | ||
|
||
import lombok.NonNull; | ||
|
||
/** | ||
* Service to handle {@link IdentifierType} | ||
* @param <T> | ||
*/ | ||
public class IdentifierTypeService<T extends IdentifierType> extends DefaultDinaService<T> { | ||
|
||
private final IdentifierTypeValidator identifierTypeValidator; | ||
|
||
public IdentifierTypeService(@NonNull BaseDAO baseDAO, | ||
@NonNull SmartValidator validator, | ||
IdentifierTypeValidator identifierTypeValidator) { | ||
super(baseDAO, validator); | ||
this.identifierTypeValidator = identifierTypeValidator; | ||
} | ||
|
||
@Override | ||
protected void preCreate(T entity) { | ||
// Do we need to generate a key ? | ||
if (StringUtils.isBlank(entity.getKey())) { | ||
if (StringUtils.isNotBlank(entity.getName())) { | ||
entity.setKey(VocabularyKeyHelper.generateKeyFromName(entity.getName())); | ||
} | ||
} else { | ||
if (!VocabularyKeyHelper.isKeyValid(entity.getKey())) { | ||
throw new IllegalArgumentException("Invalid key"); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void validateBusinessRules(T identifierType) { | ||
applyBusinessRule(identifierType, identifierTypeValidator); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
dina-base-api/src/main/java/ca/gc/aafc/dina/validation/IdentifierTypeValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package ca.gc.aafc.dina.validation; | ||
|
||
import javax.inject.Named; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
import org.springframework.context.MessageSource; | ||
import org.springframework.validation.Errors; | ||
|
||
import ca.gc.aafc.dina.entity.IdentifierType; | ||
|
||
public class IdentifierTypeValidator extends DinaBaseValidator<IdentifierType> { | ||
|
||
private static final String MISSING_PLACEHOLDER_KEY = "identifierType.uriTemplate.missingPlaceholder"; | ||
|
||
public IdentifierTypeValidator(@Named("validationMessageSource") MessageSource messageSource) { | ||
super(IdentifierType.class, messageSource); | ||
} | ||
|
||
@Override | ||
public void validateTarget(IdentifierType target, Errors errors) { | ||
|
||
if (StringUtils.isNotBlank(target.getUriTemplate())) { | ||
if (!target.getUriTemplate().contains("$1")) { | ||
errors.reject(MISSING_PLACEHOLDER_KEY, getMessage(MISSING_PLACEHOLDER_KEY)); | ||
} | ||
} | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
dina-base-api/src/main/java/ca/gc/aafc/dina/vocabulary/VocabularyKeyHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package ca.gc.aafc.dina.vocabulary; | ||
|
||
import java.util.Arrays; | ||
import java.util.Objects; | ||
import java.util.regex.Pattern; | ||
import java.util.stream.Collectors; | ||
|
||
import org.apache.commons.lang3.RegExUtils; | ||
import org.apache.commons.lang3.StringUtils; | ||
|
||
/** | ||
* Utility class to have uniform handling of key generation from a name. | ||
*/ | ||
public final class VocabularyKeyHelper { | ||
|
||
private static final Pattern NON_ALPHANUMERICAL = Pattern.compile("[^a-z0-9]"); | ||
|
||
private VocabularyKeyHelper() { | ||
// utility class | ||
} | ||
|
||
/** | ||
* Transforms a name into a key. camelCase is supported. | ||
* "Aa bb !! mySuperAttribute # 11" will become aa_bb_my_super_attribute_11 | ||
* @param name | ||
* @return | ||
*/ | ||
public static String generateKeyFromName(String name) { | ||
Objects.requireNonNull(name); | ||
|
||
return Arrays.stream(StringUtils. | ||
splitByCharacterTypeCamelCase(StringUtils.normalizeSpace(name))) | ||
.filter(StringUtils::isNotBlank) | ||
.map(VocabularyKeyHelper::processName) | ||
.filter(StringUtils::isNotBlank) | ||
.collect(Collectors.joining("_")); | ||
} | ||
|
||
private static String processName(String name) { | ||
return RegExUtils.removeAll(name.toLowerCase(), NON_ALPHANUMERICAL); | ||
} | ||
|
||
public static boolean isKeyValid(String key) { | ||
if (StringUtils.isBlank(key)) { | ||
return false; | ||
} | ||
// use the key as the name and check if we get the same result | ||
return key.equals(generateKeyFromName(key)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
dina-base-api/src/test/java/ca/gc/aafc/dina/service/IdentifierTypeServiceIT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package ca.gc.aafc.dina.service; | ||
|
||
import org.hibernate.annotations.Type; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.boot.autoconfigure.domain.EntityScan; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.context.TestConfiguration; | ||
import org.springframework.context.MessageSource; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.test.context.ContextConfiguration; | ||
import org.springframework.validation.SmartValidator; | ||
|
||
import ca.gc.aafc.dina.TestDinaBaseApp; | ||
import ca.gc.aafc.dina.entity.IdentifierType; | ||
import ca.gc.aafc.dina.i18n.MultilingualTitle; | ||
import ca.gc.aafc.dina.jpa.BaseDAO; | ||
import ca.gc.aafc.dina.testsupport.PostgresTestContainerInitializer; | ||
import ca.gc.aafc.dina.validation.IdentifierTypeValidator; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
import java.time.OffsetDateTime; | ||
import java.util.List; | ||
import java.util.UUID; | ||
import javax.inject.Inject; | ||
import javax.inject.Named; | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
import javax.transaction.Transactional; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import lombok.experimental.SuperBuilder; | ||
|
||
@SpringBootTest(classes = {TestDinaBaseApp.class, IdentifierTypeServiceIT.IdentifierTypeServiceConfig.class}) | ||
@ContextConfiguration(initializers = { PostgresTestContainerInitializer.class }) | ||
public class IdentifierTypeServiceIT { | ||
|
||
@Inject | ||
private IdentifierTypeService<IdentifierType> identifierTypeService; | ||
|
||
@Test | ||
@Transactional | ||
public void identifierTypeService_OnCreate_KeyCorrectlyGenerated() { | ||
|
||
IdentifierType identifierType = identifierTypeService | ||
.create(TestIdentifierType.builder() | ||
.id(11) | ||
.uuid(UUID.randomUUID()) | ||
.uriTemplate("https://abc.abc/$1") | ||
.dinaComponents(List.of("project", "person")) | ||
.name("dina specialIdentifier #11").build()); | ||
|
||
assertEquals("dina_special_identifier_11", identifierType.getKey()); | ||
} | ||
|
||
@TestConfiguration | ||
@EntityScan(basePackageClasses = TestIdentifierType.class) | ||
static class IdentifierTypeServiceConfig { | ||
|
||
@Bean | ||
public IdentifierTypeService<IdentifierType> identifierTypeService(BaseDAO baseDAO, | ||
SmartValidator sv, | ||
IdentifierTypeValidator iv) { | ||
return new IdentifierTypeService<>(baseDAO, sv, iv) { | ||
}; | ||
} | ||
|
||
@Bean | ||
public IdentifierTypeValidator identifierTypeValidator(@Named("validationMessageSource") | ||
MessageSource messageSource) { | ||
return new IdentifierTypeValidator(messageSource); | ||
} | ||
} | ||
|
||
@Getter | ||
@Setter | ||
@SuperBuilder | ||
@Entity | ||
static class TestIdentifierType implements IdentifierType { | ||
|
||
@Id | ||
private Integer id; | ||
private UUID uuid; | ||
private String key; | ||
|
||
private String name; | ||
private String term; | ||
|
||
@Type(type = "jsonb") | ||
private MultilingualTitle multilingualTitle; | ||
|
||
@Type(type = "list-array") | ||
private List<String> dinaComponents; | ||
|
||
private String uriTemplate; | ||
private String createdBy; | ||
private OffsetDateTime createdOn; | ||
} | ||
|
||
} |