-
Notifications
You must be signed in to change notification settings - Fork 13
MCR-3578 Changes modsperson attribute handling #2773
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1bd71fc
cbcfb05
fff7193
2df6d0e
b11cd3c
3007f9c
6bf8d8a
fb2ec01
b73e199
a2b3298
4e5f633
94f1811
b8ba51c
12415b3
e548f01
b621947
abf299f
7f8554e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| /* | ||
| * This file is part of *** M y C o R e *** | ||
| * See https://www.mycore.de/ for details. | ||
| * | ||
| * MyCoRe is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation, either version 3 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * MyCoRe is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with MyCoRe. If not, see <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| package org.mycore.datamodel.legalentity; | ||
|
|
||
| import java.util.Locale; | ||
| import java.util.Objects; | ||
|
|
||
| /** | ||
| * Class to store IDs. | ||
| */ | ||
| public class MCRIdentifier { | ||
|
|
||
| private final String type; | ||
|
|
||
| private final String value; | ||
|
|
||
| /** | ||
| * Constructs new MCRIdentifier object with type and value. | ||
| * | ||
| * @param type the id type | ||
| * @param value the id value | ||
| */ | ||
| public MCRIdentifier(String type, String value) { | ||
| this.type = type; | ||
| this.value = value; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the id type. | ||
| * | ||
| * @return id type | ||
| */ | ||
| public String getType() { | ||
| return type; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the id value. | ||
| * | ||
| * @return id value | ||
| */ | ||
| public String getValue() { | ||
| return value; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(type, value); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object obj) { | ||
| if (this == obj) { | ||
| return true; | ||
| } | ||
| if (obj == null) { | ||
| return false; | ||
| } | ||
| if (getClass() != obj.getClass()) { | ||
| return false; | ||
| } | ||
| final MCRIdentifier identifier = (MCRIdentifier) obj; | ||
| return Objects.equals(type, identifier.type) && Objects.equals(value, identifier.value); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return String.format(Locale.ROOT, "%s:%s", type, value); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /* | ||
| * This file is part of *** M y C o R e *** | ||
| * See https://www.mycore.de/ for details. | ||
| * | ||
| * MyCoRe is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation, either version 3 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * MyCoRe is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with MyCoRe. If not, see <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| package org.mycore.datamodel.legalentity; | ||
|
|
||
| import java.util.Set; | ||
|
|
||
| import org.mycore.common.config.MCRConfiguration2; | ||
|
|
||
| /** | ||
| * Services that implement this interface should search for all identifiers of a specific legal entity (e.g. a person) | ||
| * using a specific, identifying {@link MCRIdentifier}, or add an identifier to the legal entity. The identifier | ||
| * can be any key-value pair that can uniquely identify a legal entity. The interface is intentionally generic to allow | ||
| * different identifier schemes and lookup implementations. | ||
| */ | ||
| public interface MCRLegalEntityService { | ||
|
|
||
| /** | ||
| * Finds all identifiers of a legal entity determined by a specific identifier. | ||
| * @param identifier unique identifier of legal entity, not null | ||
| * @return a set of identifiers a legal entity owns | ||
| */ | ||
| Set<MCRIdentifier> findAllIdentifiers(MCRIdentifier identifier); | ||
|
|
||
| /** | ||
| * Adds an identifier to a legal entity. The entity is determined by a specific, given identifier | ||
| * @param primaryIdentifier unique identifier of legal entity, not null | ||
| * @param identifierToAdd the identifier to add, not null | ||
| */ | ||
| void addIdentifier(MCRIdentifier primaryIdentifier, MCRIdentifier identifierToAdd); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't there be an exception if no identifier could be added? Otherwise, it might also be useful to signal via a boolean whether an identifier was ultimately added. |
||
|
|
||
| /** | ||
| * Get configured singleton service implementation. | ||
| */ | ||
| static MCRLegalEntityService obtainInstance() { | ||
| return InstanceHolder.SHARED_INSTANCE; | ||
| } | ||
|
|
||
| class InstanceHolder { | ||
| private static final MCRLegalEntityService SHARED_INSTANCE = MCRConfiguration2.getInstanceOfOrThrow( | ||
| MCRLegalEntityService.class, "MCR.LegalEntityService.Class"); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /* | ||
| * This file is part of *** M y C o R e *** | ||
| * See https://www.mycore.de/ for details. | ||
| * | ||
| * MyCoRe is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation, either version 3 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * MyCoRe is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with MyCoRe. If not, see <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| package org.mycore.datamodel.legalentity; | ||
|
|
||
| import java.util.Set; | ||
|
|
||
| /** | ||
| * This implementation is a fallback only. Another implementation of {@link MCRLegalEntityService} should | ||
| * be configured when using the service. | ||
| */ | ||
| public class MCRNoOpLegalEntityService implements MCRLegalEntityService { | ||
|
|
||
| @Override | ||
| public Set<MCRIdentifier> findAllIdentifiers(MCRIdentifier identifier) { | ||
| return Set.of(); | ||
| } | ||
|
|
||
| @Override | ||
| public void addIdentifier(MCRIdentifier primaryIdentifier, MCRIdentifier identifierToAdd) { | ||
| // no-op | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -759,3 +759,9 @@ MCR.Category.LinkService=org.mycore.datamodel.classifications2.impl.MCRCategLink | |
| # Rate-Limit-Resolver | ||
| ############################################################################## | ||
| MCR.URIResolver.ModuleResolver.ratelimit=org.mycore.common.xml.MCRRateLimitResolver | ||
|
|
||
| ############################################################################## | ||
| # LegalEntityService | ||
| ############################################################################## | ||
| # No-op Implementation of MCRLegalEntityService for querying UserIdentifier | ||
| MCR.LegalEntityService.Class=org.mycore.datamodel.legalentity.MCRNoOpLegalEntityService | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn’t it be better to just leave it empty? It doesn’t seem to serve any purpose… |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| /* | ||
| * This file is part of *** M y C o R e *** | ||
| * See https://www.mycore.de/ for details. | ||
| * | ||
| * MyCoRe is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation, either version 3 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * MyCoRe is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with MyCoRe. If not, see <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| package org.mycore.mods; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.Optional; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.Logger; | ||
| import org.jdom2.Element; | ||
| import org.mycore.access.MCRAccessException; | ||
| import org.mycore.common.MCRConstants; | ||
| import org.mycore.common.MCRPersistenceException; | ||
| import org.mycore.datamodel.legalentity.MCRIdentifier; | ||
| import org.mycore.datamodel.legalentity.MCRLegalEntityService; | ||
| import org.mycore.datamodel.metadata.MCRMetadataManager; | ||
| import org.mycore.datamodel.metadata.MCRObject; | ||
| import org.mycore.datamodel.metadata.MCRObjectID; | ||
| import org.mycore.user2.MCRUser; | ||
| import org.mycore.user2.MCRUserAttribute; | ||
| import org.mycore.user2.MCRUserManager; | ||
|
|
||
| /** | ||
| * This class identifies {@link MCRUser users} by their user ID and looks up their identifiers by loading the | ||
| * correlating modsperson metadata through the modsperson-{@link MCRUserAttribute attribute} | ||
| * attached to the user entity. | ||
| * If this attribute is not present, an empty set is returned. | ||
| * New attributes are added to the modsperson metadata and are not added to the user entity. | ||
| */ | ||
| public class MCRMODSPersonIdentifierService implements MCRLegalEntityService { | ||
toKrause marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| private static final Logger LOGGER = LogManager.getLogger(); | ||
|
|
||
| public static final String MODSPERSON_ATTR_NAME = "id_modsperson"; | ||
|
|
||
| public static final String USERID = "userid"; | ||
|
|
||
| public static final String MODS_NAME = "name"; | ||
|
|
||
| public static final String MODS_NAMEIDENTIFIER = "nameIdentifier"; | ||
|
|
||
| public static final String TYPE = "type"; | ||
|
|
||
|
|
||
| /** | ||
| * Gets all {@link MCRIdentifier MCRIdentifiers} of a modsperson by reference to a {@link org.mycore.user2.MCRUser} | ||
| * and its modsperson id. | ||
| * @param userId the user id connected to the modsperson | ||
| * @return all known identifiers or an empty set | ||
| */ | ||
| @Override | ||
| public Set<MCRIdentifier> findAllIdentifiers(MCRIdentifier userId) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see comment for |
||
| return getIdentifiers(userId, null); | ||
| } | ||
|
|
||
| /** | ||
| * Adds a {@link MCRIdentifier MCRIdentifiers} to a modsperson by reference to a {@link org.mycore.user2.MCRUser} | ||
| * and its modsperson id. | ||
| * @param userId the user id connected to the modsperson | ||
| * @param attributeToAdd the nameIdentifier to add to the modsperson | ||
| */ | ||
| @Override | ||
| public void addIdentifier(MCRIdentifier userId, MCRIdentifier attributeToAdd) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see comment for |
||
| Optional<MCRObject> modspersonOptional = findModspersonByUsername(userId); | ||
| if (modspersonOptional.isEmpty()) { | ||
| return; | ||
| } | ||
| MCRMODSWrapper wrapper = new MCRMODSWrapper(modspersonOptional.get()); | ||
| Element modsName = wrapper.getMODS().getChild(MODS_NAME, MCRConstants.MODS_NAMESPACE); | ||
| if (modsName == null) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How could that happen? |
||
| return; | ||
| } | ||
| Element nameIdentifier = new Element(MODS_NAMEIDENTIFIER, MCRConstants.MODS_NAMESPACE) | ||
| .setAttribute(TYPE, attributeToAdd.getType()) | ||
| .setText(attributeToAdd.getValue()); | ||
| modsName.addContent(nameIdentifier); | ||
| try { | ||
| MCRMetadataManager.update(modspersonOptional.get()); | ||
| } catch (MCRAccessException | MCRPersistenceException e) { | ||
| if (LOGGER.isWarnEnabled()) { | ||
| LOGGER.warn("Could not update modsperson object for user id {}", | ||
| userId.getValue(), e); | ||
| } | ||
|
Comment on lines
+98
to
+101
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would be an inconsistent state or a general error. In that case, I would rather expect an exception. |
||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Helper method to search for identifiers in a modsperson by a user-ID. | ||
| * @param userId the user id connected to the modsperson | ||
| * @param identifierType optional type filter, leave null for no filter | ||
| * @return a set of all identifiers found | ||
| */ | ||
| private Set<MCRIdentifier> getIdentifiers(MCRIdentifier userId, String identifierType) { | ||
| Optional<MCRObject> modspersonOptional = findModspersonByUsername(userId); | ||
| if (modspersonOptional.isEmpty()) { | ||
| return Collections.emptySet(); | ||
| } | ||
| MCRMODSWrapper wrapper = new MCRMODSWrapper(modspersonOptional.get()); | ||
| Element modsName = wrapper.getMODS().getChild(MODS_NAME, MCRConstants.MODS_NAMESPACE); | ||
| if (modsName == null) { | ||
| return Collections.emptySet(); | ||
| } | ||
| if (identifierType != null) { | ||
| return modsName.getChildren(MODS_NAMEIDENTIFIER, MCRConstants.MODS_NAMESPACE) | ||
| .stream().filter(e -> identifierType.equals(e.getAttributeValue(TYPE))) | ||
| .map(e -> new MCRIdentifier(e.getAttributeValue(TYPE), e.getText())) | ||
| .collect(Collectors.toSet()); | ||
| } | ||
| return modsName.getChildren(MODS_NAMEIDENTIFIER, MCRConstants.MODS_NAMESPACE) | ||
| .stream().map(e -> new MCRIdentifier(e.getAttributeValue(TYPE), e.getText())) | ||
| .collect(Collectors.toSet()); | ||
| } | ||
|
|
||
| /** | ||
| * Takes a username and returns an Optional with the referenced modsperson. | ||
| * @param userId the user id | ||
| * @return a nullable Optional that might contain a modsperson | ||
| */ | ||
| private Optional<MCRObject> findModspersonByUsername(MCRIdentifier userId) { | ||
| if (userId == null || !USERID.equals(userId.getType())) { | ||
| return Optional.empty(); | ||
| } | ||
| MCRUser user = MCRUserManager.getUser(userId.getValue()); | ||
| if (user == null) { | ||
| return Optional.empty(); | ||
| } | ||
| String modspersonId = user.getUserAttribute(MODSPERSON_ATTR_NAME); | ||
| if (modspersonId == null) { | ||
| return Optional.empty(); | ||
| } | ||
| try { | ||
| MCRObject modsperson = MCRMetadataManager.retrieveMCRObject(MCRObjectID.getInstance(modspersonId)); | ||
| return Optional.of(modsperson); | ||
| } catch (MCRPersistenceException e) { | ||
| if (LOGGER.isWarnEnabled()) { | ||
| LOGGER.warn("Could not retrieve modsperson object for user id {} (modspersonId={})", | ||
| userId.getValue(), modspersonId, e); | ||
| } | ||
| return Optional.empty(); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't an exception be thrown here if the reference does not exist?