2020-10-06 15:44:53 +02:00
|
|
|
|
|
|
|
package eu.dnetlib.dhp.schema.oaf.utils;
|
|
|
|
|
2020-12-09 09:10:33 +01:00
|
|
|
import java.io.Serializable;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Objects;
|
|
|
|
import java.util.Optional;
|
|
|
|
import java.util.stream.Collectors;
|
2020-10-06 15:44:53 +02:00
|
|
|
|
2021-03-09 11:37:41 +01:00
|
|
|
import com.google.common.collect.HashBiMap;
|
|
|
|
import com.google.common.collect.Maps;
|
|
|
|
import com.google.common.collect.Sets;
|
|
|
|
import eu.dnetlib.dhp.schema.common.ModelConstants;
|
|
|
|
import eu.dnetlib.dhp.schema.oaf.KeyValue;
|
2020-12-09 17:07:20 +01:00
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
|
|
|
import eu.dnetlib.dhp.schema.oaf.CleaningFunctions;
|
|
|
|
import eu.dnetlib.dhp.schema.oaf.OafEntity;
|
|
|
|
import eu.dnetlib.dhp.schema.oaf.StructuredProperty;
|
|
|
|
import eu.dnetlib.dhp.utils.DHPUtils;
|
|
|
|
|
2020-10-06 15:44:53 +02:00
|
|
|
/**
|
|
|
|
* Factory class for OpenAIRE identifiers in the Graph
|
|
|
|
*/
|
|
|
|
public class IdentifierFactory implements Serializable {
|
|
|
|
|
|
|
|
public static final String ID_SEPARATOR = "::";
|
|
|
|
public static final String ID_PREFIX_SEPARATOR = "|";
|
2020-11-03 18:43:37 +01:00
|
|
|
|
|
|
|
public final static String DOI_REGEX = "(^10\\.[0-9]{4,9}\\/[-._;()\\/:a-zA-Z0-9]+$)|" +
|
|
|
|
"(^10\\.1002\\/[^\\s]+$)|" +
|
|
|
|
"(^10\\.1021\\/[a-zA-Z0-9_][a-zA-Z0-9_][0-9]++$)|" +
|
|
|
|
"(^10\\.1207\\/[a-zA-Z0-9_]+\\&[0-9]+_[0-9]+$)";
|
|
|
|
|
2020-10-06 15:44:53 +02:00
|
|
|
public static final int ID_PREFIX_LEN = 12;
|
|
|
|
|
2021-03-09 11:37:41 +01:00
|
|
|
public static final HashBiMap<String, String> PID_AUTHORITY = HashBiMap.create(2);
|
|
|
|
|
|
|
|
static {
|
|
|
|
PID_AUTHORITY.put(ModelConstants.CROSSREF_ID, "Crossref");
|
|
|
|
PID_AUTHORITY.put(ModelConstants.DATACITE_ID, "Datacite");
|
|
|
|
}
|
|
|
|
|
2020-10-30 10:56:42 +01:00
|
|
|
/**
|
|
|
|
* Creates an identifier from the most relevant PID (if available) in the given entity T. Returns entity.id
|
|
|
|
* when no PID is available
|
|
|
|
* @param entity the entity providing PIDs and a default ID.
|
|
|
|
* @param <T> the specific entity type. Currently Organization and Result subclasses are supported.
|
2020-11-30 12:00:38 +01:00
|
|
|
* @param md5 indicates whether should hash the PID value or not.
|
2020-10-30 10:56:42 +01:00
|
|
|
* @return an identifier from the most relevant PID, entity.id otherwise
|
|
|
|
*/
|
2020-11-30 12:00:38 +01:00
|
|
|
public static <T extends OafEntity> String createIdentifier(T entity, boolean md5) {
|
2020-10-06 15:44:53 +02:00
|
|
|
if (Objects.isNull(entity.getPid()) || entity.getPid().isEmpty()) {
|
|
|
|
return entity.getId();
|
|
|
|
}
|
|
|
|
|
2021-03-09 11:37:41 +01:00
|
|
|
if (Optional.ofNullable(
|
|
|
|
entity.getCollectedfrom())
|
|
|
|
.map(c -> c.stream()
|
|
|
|
.noneMatch(cf -> PID_AUTHORITY.containsKey(cf.getKey()) || PID_AUTHORITY.containsValue(cf.getValue())))
|
|
|
|
.orElse(true)) {
|
|
|
|
return entity.getId();
|
|
|
|
}
|
|
|
|
|
2020-11-23 19:16:40 +01:00
|
|
|
Map<String, List<StructuredProperty>> pids = entity
|
2020-11-24 14:41:39 +01:00
|
|
|
.getPid()
|
|
|
|
.stream()
|
2020-12-02 09:30:34 +01:00
|
|
|
.map(CleaningFunctions::normalizePidValue)
|
|
|
|
.filter(IdentifierFactory::pidFilter)
|
2020-11-24 14:41:39 +01:00
|
|
|
.collect(
|
|
|
|
Collectors
|
|
|
|
.groupingBy(
|
|
|
|
p -> p.getQualifier().getClassid(),
|
|
|
|
Collectors.mapping(p -> p, Collectors.toList())));
|
2020-11-23 19:16:40 +01:00
|
|
|
|
|
|
|
return pids
|
2020-11-24 14:41:39 +01:00
|
|
|
.values()
|
|
|
|
.stream()
|
|
|
|
.flatMap(s -> s.stream())
|
|
|
|
.min(new PidComparator<>(entity))
|
|
|
|
.map(
|
|
|
|
min -> Optional
|
|
|
|
.ofNullable(pids.get(min.getQualifier().getClassid()))
|
|
|
|
.map(
|
|
|
|
p -> p
|
|
|
|
.stream()
|
|
|
|
.sorted(new PidValueComparator())
|
|
|
|
.findFirst()
|
2020-11-30 12:00:38 +01:00
|
|
|
.map(s -> idFromPid(entity, s, md5))
|
2020-11-24 14:41:39 +01:00
|
|
|
.orElseGet(entity::getId))
|
|
|
|
.orElseGet(entity::getId))
|
|
|
|
.orElseGet(entity::getId);
|
2020-10-06 15:44:53 +02:00
|
|
|
}
|
|
|
|
|
2020-11-30 12:00:38 +01:00
|
|
|
/**
|
|
|
|
* @see {@link IdentifierFactory#createIdentifier(OafEntity, boolean)}
|
|
|
|
*/
|
|
|
|
public static <T extends OafEntity> String createIdentifier(T entity) {
|
|
|
|
|
|
|
|
return createIdentifier(entity, true);
|
|
|
|
}
|
|
|
|
|
2020-11-02 14:25:26 +01:00
|
|
|
protected static boolean pidFilter(StructuredProperty s) {
|
2020-12-02 09:30:34 +01:00
|
|
|
final String pidValue = s.getValue();
|
2020-11-03 18:43:37 +01:00
|
|
|
if (Objects.isNull(s.getQualifier()) ||
|
2020-12-02 09:30:34 +01:00
|
|
|
StringUtils.isBlank(pidValue) ||
|
|
|
|
StringUtils.isBlank(pidValue.replaceAll("(?:\\n|\\r|\\t|\\s)", ""))) {
|
2020-11-30 12:00:38 +01:00
|
|
|
return false;
|
|
|
|
}
|
2020-12-02 09:30:34 +01:00
|
|
|
if (CleaningFunctions.PID_BLACKLIST.contains(pidValue)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (PidBlacklistProvider.getBlacklist(s.getQualifier().getClassid()).contains(pidValue)) {
|
2020-11-03 18:43:37 +01:00
|
|
|
return false;
|
|
|
|
}
|
2020-11-30 16:52:40 +01:00
|
|
|
switch (PidType.tryValueOf(s.getQualifier().getClassid())) {
|
|
|
|
case doi:
|
2020-12-02 09:30:34 +01:00
|
|
|
final String doi = StringUtils.trim(StringUtils.lowerCase(pidValue));
|
2020-11-30 16:52:40 +01:00
|
|
|
return doi.matches(DOI_REGEX);
|
|
|
|
case original:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
return true;
|
2020-11-03 18:43:37 +01:00
|
|
|
}
|
2020-10-30 10:56:42 +01:00
|
|
|
}
|
|
|
|
|
2020-11-30 12:00:38 +01:00
|
|
|
private static <T extends OafEntity> String idFromPid(T entity, StructuredProperty s, boolean md5) {
|
2020-10-06 15:44:53 +02:00
|
|
|
return new StringBuilder()
|
2020-10-07 13:14:31 +02:00
|
|
|
.append(StringUtils.substringBefore(entity.getId(), ID_PREFIX_SEPARATOR))
|
|
|
|
.append(ID_PREFIX_SEPARATOR)
|
|
|
|
.append(createPrefix(s.getQualifier().getClassid()))
|
|
|
|
.append(ID_SEPARATOR)
|
2020-12-02 09:30:34 +01:00
|
|
|
.append(md5 ? DHPUtils.md5(s.getValue()) : s.getValue())
|
2020-10-07 13:14:31 +02:00
|
|
|
.toString();
|
2020-10-06 15:44:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// create the prefix (length = 12)
|
|
|
|
private static String createPrefix(String pidType) {
|
|
|
|
StringBuilder prefix = new StringBuilder(StringUtils.left(pidType, ID_PREFIX_LEN));
|
|
|
|
while (prefix.length() < ID_PREFIX_LEN) {
|
|
|
|
prefix.append("_");
|
|
|
|
}
|
|
|
|
return prefix.substring(0, ID_PREFIX_LEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|