partial implementation

This commit is contained in:
Michele Artini 2024-04-23 10:22:00 +02:00
parent 92707fbc5f
commit f88863cf87
19 changed files with 959 additions and 4 deletions

9
.gitignore vendored
View File

@ -82,7 +82,8 @@ local.properties
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
# my exclusions
.project
.classpath
.java-version
target/

112
pom.xml Normal file
View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>eu.dnetlib</groupId>
<artifactId>dnet-oai-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dnet-oai-server</name>
<description>Simple OAI-PMH server</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jakarta-xmlbind-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

BIN
src/main/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,13 @@
package eu.dnetlib.apps.oai;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OaiServerApplication {
public static void main(final String[] args) {
SpringApplication.run(OaiServerApplication.class, args);
}
}

View File

@ -0,0 +1,42 @@
package eu.dnetlib.apps.oai;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Component
@Configuration
@ConfigurationProperties(prefix = "oai.server")
public class OaiServerConf {
private String baseUrl;
private String repositoryName;
private String adminEmail;
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(final String baseUrl) {
this.baseUrl = baseUrl;
}
public String getRepositoryName() {
return repositoryName;
}
public void setRepositoryName(final String repositoryName) {
this.repositoryName = repositoryName;
}
public String getAdminEmail() {
return adminEmail;
}
public void setAdminEmail(final String adminEmail) {
this.adminEmail = adminEmail;
}
}

View File

@ -0,0 +1,282 @@
package eu.dnetlib.apps.oai;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import eu.dnetlib.apps.oai.domain.OaiError;
import eu.dnetlib.apps.oai.domain.OaiMetadataFormat;
import eu.dnetlib.apps.oai.domain.OaiPage;
import eu.dnetlib.apps.oai.domain.OaiRecord;
import eu.dnetlib.apps.oai.domain.OaiSet;
import eu.dnetlib.apps.oai.domain.OaiVerb;
import eu.dnetlib.apps.oai.utils.DateUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Controller
public class OaiServerController {
private static final String DEFAULT_CONTENT_TYPE = "text/xml;charset=utf-8";
@Autowired
private OaiService oaiService;
@Autowired
private OaiServerConf oaiConf;
private static final Log log = LogFactory.getLog(OaiServerController.class);
@RequestMapping("/oai")
public void oaiCall(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
response.setContentType(OaiServerController.DEFAULT_CONTENT_TYPE);
final Map<String, String> params = cleanParameters(request.getParameterMap());
try (final OutputStream out = response.getOutputStream()) {
IOUtils.write(oaiResponse(params), out, StandardCharsets.UTF_8);
}
}
private String oaiResponse(final Map<String, String> params) {
if (params == null) { return prepareErrorResponseXml(OaiError.badArgument); }
final String verb = params.remove("verb");
return switch (OaiVerb.validate(verb)) {
case IDENTIFY -> oaiIdentify(params);
case LIST_METADATA_FORMATS -> oaiListMetadataFormats(params);
case LIST_SETS -> oaiListSets(params);
case GET_RECORD -> oaiGetRecord(params);
case LIST_IDENTIFIERS -> oaiListIdentifiers(params);
case LIST_RECORDS -> oaiListRecords(params);
default -> prepareErrorResponseXml(OaiError.badVerb);
};
}
private String oaiIdentify(final Map<String, String> params) {
if (!params.isEmpty()) { return prepareErrorResponseXml(OaiError.badArgument); }
final Document doc = genericOaiResponse(OaiVerb.IDENTIFY.getVerb());
final Element dataNode = doc.getRootElement().addElement(OaiVerb.IDENTIFY.getVerb());
dataNode.addElement("baseURL").setText(oaiConf.getBaseUrl());
dataNode.addElement("repositoryName").setText(oaiConf.getRepositoryName());
dataNode.addElement("protocolVersion").setText("2.0");
dataNode.addElement("adminEmail").setText(oaiConf.getAdminEmail());
dataNode.addElement("earliestDatestamp").setText("1900-01-01T00:00:00Z");
dataNode.addElement("deletedRecord").setText("transient");
dataNode.addElement("granularity").setText("YYYY-MM-DDThh:mm:ssZ");
return doc.asXML();
}
private String oaiListMetadataFormats(final Map<String, String> params) {
final String id = params.remove("identifier");
if (!params.isEmpty()) { return prepareErrorResponseXml(OaiError.badArgument); }
final Document doc = genericOaiResponse(OaiVerb.LIST_METADATA_FORMATS.getVerb());
final Element dataNode = doc.getRootElement().addElement(OaiVerb.LIST_METADATA_FORMATS.getVerb());
final List<OaiMetadataFormat> formats =
StringUtils.isBlank(id) ? this.oaiService.listMetadataFormats(id) : this.oaiService.listMetadataFormats();
for (final OaiMetadataFormat oaiFormat : formats) {
final Element formatNode = dataNode.addElement("metadataFormat");
formatNode.addElement("metadataPrefix").setText(oaiFormat.getMetadataPrefix());
formatNode.addElement("schema").setText(oaiFormat.getMetadataSchema());
formatNode.addElement("metadataNamespace").setText(oaiFormat.getMetadataNamespace());
}
return doc.asXML();
}
private String oaiListSets(final Map<String, String> params) {
if (!params.isEmpty()) { return prepareErrorResponseXml(OaiError.badArgument); }
final Document doc = genericOaiResponse(OaiVerb.LIST_SETS.getVerb());
final Element dataNode = doc.getRootElement().addElement(OaiVerb.LIST_SETS.getVerb());
for (final OaiSet oaiSet : this.oaiService.listSets()) {
final Element setNode = dataNode.addElement("set");
setNode.addElement("setSpec").setText(oaiSet.getSetSpec());
setNode.addElement("setName").setText(oaiSet.getSetName());
setNode.addElement("setDescription").setText(oaiSet.getDescription());
}
return doc.asXML();
}
private String oaiGetRecord(final Map<String, String> params) {
final String prefix = params.remove("metadataPrefix");
final String identifier = params.remove("identifier");
if (!params.isEmpty() || StringUtils.isAnyBlank(prefix, identifier)) { return prepareErrorResponseXml(OaiError.badArgument); }
final OaiRecord record = this.oaiService.getRecord(identifier, prefix);
if (record == null) { return prepareErrorResponseXml(OaiError.idDoesNotExist); }
final Document doc = genericOaiResponse(OaiVerb.GET_RECORD.getVerb());
final Element dataNode = doc.getRootElement().addElement(OaiVerb.GET_RECORD.getVerb());
insertSingleRecord(dataNode, record);
return doc.asXML();
}
private String oaiListRecords(final Map<String, String> params) {
final OaiPage page;
if (params.containsKey("resumptionToken")) {
final String resumptionToken = params.remove("resumptionToken");
if (!params.isEmpty()) { return prepareErrorResponseXml(OaiError.badArgument); }
page = this.oaiService.listRecords(resumptionToken);
} else {
final String metadataPrefix = params.remove("metadataPrefix");
final String from = params.remove("from");
final String until = params.remove("until");
final String set = params.remove("set");
if (!StringUtils.isNotBlank(metadataPrefix) || !this.oaiService.verifySet(set)) { return prepareErrorResponseXml(OaiError.badArgument); }
page = this.oaiService.listRecords(metadataPrefix, set, from, until);
}
final Document doc = genericOaiResponse(OaiVerb.LIST_RECORDS.getVerb());
final Element dataNode = doc.getRootElement().addElement(OaiVerb.LIST_RECORDS.getVerb());
page.getList().forEach(record -> insertSingleRecord(dataNode, record));
insertResumptionToken(dataNode, page);
return doc.asXML();
}
private void insertSingleRecord(final Element parentNode, final OaiRecord record) {
final Element recordNode = parentNode.addElement("record");
insertRecordHeader(recordNode, record);
try {
final Document doc2 = DocumentHelper.parseText(record.getBody());
recordNode.addElement("metadata").add(doc2.getRootElement());
} catch (final DocumentException e) {
log.warn("Error parsing record: " + record.getBody());
}
}
private String oaiListIdentifiers(final Map<String, String> params) {
final OaiPage page;
if (params.containsKey("resumptionToken")) {
final String resumptionToken = params.remove("resumptionToken");
if (!params.isEmpty()) { return prepareErrorResponseXml(OaiError.badArgument); }
page = this.oaiService.listRecords(resumptionToken);
} else {
final String metadataPrefix = params.remove("metadataPrefix");
final String from = params.remove("from");
final String until = params.remove("until");
final String set = params.remove("set");
if (!StringUtils.isNotBlank(metadataPrefix) || !this.oaiService.verifySet(set)) { return prepareErrorResponseXml(OaiError.badArgument); }
page = this.oaiService.listRecords(metadataPrefix, set, from, until);
}
final Document doc = genericOaiResponse(OaiVerb.LIST_IDENTIFIERS.getVerb());
final Element dataNode = doc.getRootElement().addElement(OaiVerb.LIST_IDENTIFIERS.getVerb());
page.getList().forEach(r -> insertRecordHeader(dataNode, r));
insertResumptionToken(dataNode, page);
return doc.asXML();
}
private void insertRecordHeader(final Element parentNode, final OaiRecord r) {
final Element headerNode = parentNode.addElement("header");
headerNode.addElement("identifier").setText(r.getId());
headerNode.addElement("datestamp").setText(DateUtils.calculate_ISO8601(r.getDate()));
if (StringUtils.isNotBlank(r.getOaiSet())) {
headerNode.addElement("setSpec").setText(r.getOaiSet());
}
}
private void insertResumptionToken(final Element parentNode, final OaiPage page) {
if (StringUtils.isNotBlank(page.getResumptionToken())) {
final Element tokenNode = parentNode.addElement("resumptionToken");
tokenNode.addAttribute("completeListSize", Long.toString(page.getTotal()));
tokenNode.addAttribute("cursor", Long.toString(page.getCursor()));
tokenNode.setText(page.getResumptionToken());
}
}
private Map<String, String> cleanParameters(final Map<?, ?> startParams) {
final HashMap<String, String> params = new HashMap<>();
final Iterator<?> iter = startParams.entrySet().iterator();
while (iter.hasNext()) {
final Entry<?, ?> entry = (Entry<?, ?>) iter.next();
final String key = entry.getKey().toString();
final String[] arr = (String[]) entry.getValue();
if (arr.length == 0) { return null; }
final String value = arr[0];
if ("verb".equals(key)) {
params.put("verb", value);
} else if ("from".equals(key)) {
params.put("from", value);
} else if ("until".equals(key)) {
params.put("until", value);
} else if ("metadataPrefix".equals(key)) {
params.put("metadataPrefix", value);
} else if ("identifier".equals(key)) {
params.put("identifier", value);
} else if ("set".equals(key)) {
params.put("set", value);
} else if ("resumptionToken".equals(key)) {
params.put("resumptionToken", value);
} else {
return null;
}
}
return params;
}
private Document genericOaiResponse(final String verb) {
try (InputStream is = getClass().getResourceAsStream("/oai/oai_response.xml")) {
final Document doc = new SAXReader().read(is);
doc.selectSingleNode("//*[local-name() = 'responseDate']").setText(DateUtils.now_ISO8601());
doc.selectSingleNode("//*[local-name() = 'request']").setText(oaiConf.getBaseUrl());
if (StringUtils.isNotBlank(verb)) {
doc.selectSingleNode("//*[local-name() = 'request']/@verb").setText(verb);
}
return doc;
} catch (final DocumentException | IOException e) {
throw new RuntimeException("Error generataing oai response", e);
}
}
private String prepareErrorResponseXml(final OaiError error) {
final Document doc = genericOaiResponse(null);
final Element errorNode = doc.getRootElement().addElement("error");
errorNode.addAttribute("code", error.name());
errorNode.setText(error.getMessage());
return doc.asXML();
}
}

View File

@ -0,0 +1,50 @@
package eu.dnetlib.apps.oai;
import java.util.List;
import org.springframework.stereotype.Service;
import eu.dnetlib.apps.oai.domain.OaiMetadataFormat;
import eu.dnetlib.apps.oai.domain.OaiPage;
import eu.dnetlib.apps.oai.domain.OaiRecord;
import eu.dnetlib.apps.oai.domain.OaiSet;
@Service
public class OaiService {
public boolean verifySet(final String set) {
// TODO Auto-generated method stub
return false;
}
public OaiPage listRecords(final String resumptionToken) {
// TODO Auto-generated method stub
return null;
}
public OaiPage listRecords(final String metadataPrefix, final String set, final String from, final String until) {
// TODO Auto-generated method stub
return null;
}
public List<OaiMetadataFormat> listMetadataFormats(final String id) {
// TODO Auto-generated method stub
return null;
}
public List<OaiMetadataFormat> listMetadataFormats() {
// TODO Auto-generated method stub
return null;
}
public OaiRecord getRecord(final String identifier, final String prefix) {
// TODO Auto-generated method stub
return null;
}
public OaiSet[] listSets() {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,26 @@
package eu.dnetlib.apps.oai.domain;
public enum OaiError {
badArgument(
"The request includes illegal arguments, is missing required arguments, includes a repeated argument, or values for arguments have an illegal syntax."),
badVerb("Value of the verb argument is not a legal OAI-PMH verb, the verb argument is missing, or the verb argument is repeated."),
cannotDisseminateFormat(
"The metadata format identified by the value given for the metadataPrefix argument is not supported by the item or by the repository."),
idDoesNotExist("The value of the identifier argument is unknown or illegal in this repository."),
noMetadataFormats("There are no metadata formats available for the specified item."),
noSetHierarchy("The repository does not support sets."),
noRecordsMatch("The combination of the values of the from, until, set and metadataPrefix arguments results in an empty list."),
badResumptionToken("The value of the resumptionToken argument is invalid or expired.");
private final String message;
OaiError(final String message) {
this.message = message;
}
public final String getMessage() {
return message;
}
}

View File

@ -0,0 +1,49 @@
package eu.dnetlib.apps.oai.domain;
import java.io.Serializable;
public class OaiMetadataFormat implements Serializable {
private static final long serialVersionUID = -3225471556469204065L;
private String metadataPrefix;
private String metadataSchema;
private String metadataNamespace;
private String xslt;
public String getMetadataPrefix() {
return this.metadataPrefix;
}
public void setMetadataPrefix(final String metadataPrefix) {
this.metadataPrefix = metadataPrefix;
}
public String getMetadataSchema() {
return this.metadataSchema;
}
public void setMetadataSchema(final String metadataSchema) {
this.metadataSchema = metadataSchema;
}
public String getMetadataNamespace() {
return this.metadataNamespace;
}
public void setMetadataNamespace(final String metadataNamespace) {
this.metadataNamespace = metadataNamespace;
}
public String getXslt() {
return this.xslt;
}
public void setXslt(final String xslt) {
this.xslt = xslt;
}
}

View File

@ -0,0 +1,50 @@
package eu.dnetlib.apps.oai.domain;
import java.io.Serializable;
import java.util.List;
public class OaiPage implements Serializable {
private static final long serialVersionUID = -7512951692582271344L;
private List<OaiRecord> list;
private long total;
private long cursor;
private String resumptionToken;
public List<OaiRecord> getList() {
return list;
}
public void setList(final List<OaiRecord> list) {
this.list = list;
}
public long getTotal() {
return total;
}
public void setTotal(final long total) {
this.total = total;
}
public long getCursor() {
return cursor;
}
public void setCursor(final long cursor) {
this.cursor = cursor;
}
public String getResumptionToken() {
return resumptionToken;
}
public void setResumptionToken(final String resumptionToken) {
this.resumptionToken = resumptionToken;
}
}

View File

@ -0,0 +1,114 @@
package eu.dnetlib.apps.oai.domain;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import eu.dnetlib.apps.oai.utils.DateUtils;
public class OaiPageRequest {
private static final String SEPARATOR = "@@@";
private String metadataPrefix;
private String set;
private LocalDate from;
private LocalDate until;
private int pageNumber;
private int pageSize;
private OaiPageRequest(final String metadataPrefix, final String set, final LocalDate from, final LocalDate until, final int pageNumber,
final int pageSize) {
super();
this.metadataPrefix = metadataPrefix;
this.set = set;
this.from = from;
this.until = until;
this.pageNumber = pageNumber;
this.pageSize = pageSize;
}
public static OaiPageRequest prepareRequest(final String metadataPrefix,
final String set,
final LocalDate from,
final LocalDate until,
final int pageNumber,
final int pageSize) {
return new OaiPageRequest(metadataPrefix, set, from, until, pageNumber, pageSize);
}
public static OaiPageRequest fromResumptionToken(final String resumptionToken) {
final String[] arr = StringUtils.split(new String(Base64.decodeBase64(resumptionToken)), SEPARATOR);
if (arr.length != 6) { throw new RuntimeException("Invalid token"); }
final String metadataPrefix = arr[0];
final String set = arr[1];
final LocalDate from = DateUtils.parseDate(arr[2]);
final LocalDate until = DateUtils.parseDate(arr[3]);
final int pageNumber = Integer.parseInt(arr[4]);
final int pageSize = Integer.parseInt(arr[5]);
return new OaiPageRequest(metadataPrefix, set, from, until, pageNumber, pageSize);
}
public String getMetadataPrefix() {
return metadataPrefix;
}
public void setMetadataPrefix(final String metadataPrefix) {
this.metadataPrefix = metadataPrefix;
}
public String getSet() {
return set;
}
public void setSet(final String set) {
this.set = set;
}
public LocalDate getFrom() {
return from;
}
public void setFrom(final LocalDate from) {
this.from = from;
}
public LocalDate getUntil() {
return until;
}
public void setUntil(final LocalDate until) {
this.until = until;
}
public String nextResumptionToken() {
final List<String> list = Arrays.asList(metadataPrefix, set, from.toString(), until.toString(), Integer.toString(pageNumber + 1), Integer
.toString(pageSize));
final String s = StringUtils.join(list, SEPARATOR);
return Base64.encodeBase64URLSafeString(s.getBytes());
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(final int pageNumber) {
this.pageNumber = pageNumber;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(final int pageSize) {
this.pageSize = pageSize;
}
}

View File

@ -0,0 +1,59 @@
package eu.dnetlib.apps.oai.domain;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
public class OaiRecord implements Serializable {
private static final long serialVersionUID = -8383104201424481929L;
private String id;
private String body;
private LocalDateTime date;
private String oaiSet;
public String getId() {
return this.id;
}
public void setId(final String id) {
this.id = id;
}
public String getBody() {
return this.body;
}
public void setBody(final String body) {
this.body = body;
}
public LocalDateTime getDate() {
return this.date;
}
public void setDate(final LocalDateTime date) {
this.date = date;
}
public String getOaiSet() {
return this.oaiSet;
}
public void setOaiSet(final String oaiSet) {
this.oaiSet = oaiSet;
}
public List<String> getSets() {
return Arrays.asList(this.oaiSet);
}
public boolean isDeleted() {
return false;
}
}

View File

@ -0,0 +1,53 @@
package eu.dnetlib.apps.oai.domain;
import java.io.Serializable;
public class OaiSet implements Serializable {
private static final long serialVersionUID = 1995486356252936048L;
private String setSpec;
private String setName;
private String description;
private String dsId;
public String getSetSpec() {
return this.setSpec;
}
public void setSetSpec(final String setSpec) {
this.setSpec = setSpec;
}
public String getSetName() {
return this.setName;
}
public void setSetName(final String setName) {
this.setName = setName;
}
public String getDescription() {
return this.description;
}
public void setDescription(final String description) {
this.description = description;
}
public String getDsId() {
return this.dsId;
}
public void setDsId(final String dsId) {
this.dsId = dsId;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}

View File

@ -0,0 +1,36 @@
package eu.dnetlib.apps.oai.domain;
import org.apache.commons.lang3.StringUtils;
public enum OaiVerb {
IDENTIFY("Identify"),
LIST_IDENTIFIERS("ListIdentifiers"),
LIST_RECORDS("ListRecords"),
LIST_METADATA_FORMATS("ListMetadataFormats"),
LIST_SETS("ListSets"),
GET_RECORD("GetRecord"),
UNSUPPORTED_VERB("");
private final String verb;
public static OaiVerb validate(final String verb) {
if (StringUtils.isBlank(verb)) { return UNSUPPORTED_VERB; }
for (final OaiVerb v : OaiVerb.values()) {
if (v.getVerb().equalsIgnoreCase(verb)) { return v; }
}
return UNSUPPORTED_VERB;
}
private OaiVerb(final String verb) {
this.verb = verb;
}
public String getVerb() {
return verb;
}
}

View File

@ -0,0 +1,39 @@
package eu.dnetlib.apps.oai.utils;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.TimeZone;
public class DateUtils {
private static final DateTimeFormatter DATEFORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.getDefault());
private static final DateTimeFormatter ISO8601FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
public static LocalDate parseDate(final String s) {
return LocalDate.parse(s, DATEFORMAT);
}
public static String calculate_ISO8601(final LocalDateTime time) {
final String result = time.format(ISO8601FORMAT);
return result.substring(0, result.length() - 2) + ":" + result.substring(result.length() - 2);
}
public static String calculate_ISO8601(final long l) {
return calculate_ISO8601(LocalDateTime.ofInstant(Instant.ofEpochMilli(l), TimeZone
.getDefault()
.toZoneId()));
}
public static long now() {
return Instant.now().toEpochMilli();
}
public static String now_ISO8601() {
return calculate_ISO8601(now());
}
}

View File

@ -0,0 +1,17 @@
spring.application.name=dnet-oai-server
oai.server.baseUrl = http://localhost:8080/oai
oai.server.repositoryName = TEST repository
oai.server.adminEmail = test@test
spring.datasource.url=jdbc:postgresql://localhost:5432/oai_server_test
spring.datasource.username=
spring.datasource.password=
spring.jpa.hibernate.ddl-auto = validate
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.open-in-view=true
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.use_sql_comments=false
spring.jpa.properties.hibernate.format_sql=false

View File

View File

@ -0,0 +1,12 @@
package eu.dnetlib.apps.oai;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class OaiServerApplicationTests {
@Test
void contextLoads() {}
}