partial implementation
This commit is contained in:
parent
92707fbc5f
commit
f88863cf87
|
@ -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/
|
||||
|
|
|
@ -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>
|
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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() {}
|
||||
|
||||
}
|
Loading…
Reference in New Issue