local storage

This commit is contained in:
Michele Artini 2023-05-26 13:52:31 +02:00
parent f91e19e8f6
commit 71a72d0bb2
8 changed files with 128 additions and 138 deletions

View File

@ -27,10 +27,10 @@ import eu.dnetlib.apps.oai2ftp.model.CollectionCall;
import eu.dnetlib.apps.oai2ftp.model.CollectionInfo; import eu.dnetlib.apps.oai2ftp.model.CollectionInfo;
import eu.dnetlib.apps.oai2ftp.model.ExecutionStatus; import eu.dnetlib.apps.oai2ftp.model.ExecutionStatus;
import eu.dnetlib.apps.oai2ftp.repository.CollectionLogEntryRepository; import eu.dnetlib.apps.oai2ftp.repository.CollectionLogEntryRepository;
import eu.dnetlib.apps.oai2ftp.utils.FtpClientFactory;
import eu.dnetlib.apps.oai2ftp.utils.FtpClientWrapper;
import eu.dnetlib.apps.oai2ftp.utils.HttpFetcher; import eu.dnetlib.apps.oai2ftp.utils.HttpFetcher;
import eu.dnetlib.apps.oai2ftp.utils.SimpleUtils; import eu.dnetlib.apps.oai2ftp.utils.SimpleUtils;
import eu.dnetlib.apps.oai2ftp.utils.StorageClient;
import eu.dnetlib.apps.oai2ftp.utils.StorageClientFactory;
@Service @Service
public class Oai2FtpService { public class Oai2FtpService {
@ -42,7 +42,7 @@ public class Oai2FtpService {
private final Map<String, CollectionInfo> infoMap = new LinkedHashMap<>(); private final Map<String, CollectionInfo> infoMap = new LinkedHashMap<>();
@Autowired @Autowired
private FtpClientFactory ftpClientFactory; private StorageClientFactory storageClientFactory;
@Value("${oai2ftp.conf.execution.expirationTime}") @Value("${oai2ftp.conf.execution.expirationTime}")
private long fullInfoExpirationTime; // in hours private long fullInfoExpirationTime; // in hours
@ -57,7 +57,7 @@ public class Oai2FtpService {
final LocalDateTime until) { final LocalDateTime until) {
final String jobId = SimpleUtils.generateNewJobId(); final String jobId = SimpleUtils.generateNewJobId();
final FtpClientWrapper ftp = ftpClientFactory.newClientForJob(jobId); final StorageClient sc = storageClientFactory.newClientForJob(jobId);
final CollectionInfo info = new CollectionInfo(); final CollectionInfo info = new CollectionInfo();
info.setId(jobId); info.setId(jobId);
@ -80,14 +80,14 @@ public class Oai2FtpService {
jobExecutor.execute(() -> { jobExecutor.execute(() -> {
try { try {
info.setExecutionStatus(ExecutionStatus.RUNNING); info.setExecutionStatus(ExecutionStatus.RUNNING);
oaiCollect(baseUrl, format, setSpec, from, until, ftp, info); oaiCollect(baseUrl, format, setSpec, from, until, sc, info);
info.setExecutionStatus(ExecutionStatus.COMPLETED); info.setExecutionStatus(ExecutionStatus.COMPLETED);
} catch (final Throwable e) { } catch (final Throwable e) {
info.setExecutionStatus(ExecutionStatus.FAILED); info.setExecutionStatus(ExecutionStatus.FAILED);
info.setMessage(e.getMessage() + ": " + ExceptionUtils.getStackTrace(e)); info.setMessage(e.getMessage() + ": " + ExceptionUtils.getStackTrace(e));
} finally { } finally {
info.setEnd(LocalDateTime.now()); info.setEnd(LocalDateTime.now());
ftp.disconnect(); sc.disconnect();
collectionLogEntryRepository.save(SimpleUtils.infoToLog(info)); collectionLogEntryRepository.save(SimpleUtils.infoToLog(info));
} }
}); });
@ -100,7 +100,7 @@ public class Oai2FtpService {
final String setSpec, final String setSpec,
final LocalDateTime from, final LocalDateTime from,
final LocalDateTime until, final LocalDateTime until,
final FtpClientWrapper ftp, final StorageClient sc,
final CollectionInfo info) final CollectionInfo info)
throws Exception { throws Exception {
@ -118,8 +118,9 @@ public class Oai2FtpService {
call.setNumberOfRecords(records.size()); call.setNumberOfRecords(records.size());
for (final Node n : records) { for (final Node n : records) {
final String id = n.valueOf("/*[local-name()='record']/*[local-name()='header']/*[local-name()='identifier']"); final String id = n.valueOf(".//*[local-name()='header']/*[local-name()='identifier']");
ftp.saveFile(SimpleUtils.oaiIdToFilename(id), n.asXML());
sc.saveFile(SimpleUtils.oaiIdToFilename(id), n.asXML());
info.setTotal(info.getTotal() + 1); info.setTotal(info.getTotal() + 1);
} }

View File

@ -1,32 +0,0 @@
package eu.dnetlib.apps.oai2ftp.utils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class FtpClientFactory {
@Value("${oai2ftp.conf.ftp.server}")
private String ftpServer;
@Value("${oai2ftp.conf.ftp.user}")
private String ftpUser;
@Value("${oai2ftp.conf.ftp.password}")
private String ftpPassword;
@Value("${oai2ftp.conf.ftp.basedir}")
private String ftpBaseDir;
@Value("${oai2ftp.conf.ftp.secure}")
private boolean ftpSecure;
public FtpClientWrapper newClientForJob(final String jobId) {
final FtpClientWrapper ftp = new FtpClientWrapper(ftpServer, ftpSecure);
ftp.login(ftpUser, ftpPassword);
ftp.changeDir(ftpBaseDir);
ftp.changeDir(jobId);
return ftp;
}
}

View File

@ -4,29 +4,26 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPSClient; import org.apache.commons.net.ftp.FTPSClient;
public class FtpClientWrapper { public class FtpStorage implements StorageClient {
private static final Log log = LogFactory.getLog(FtpClientWrapper.class); private static final Log log = LogFactory.getLog(FtpStorage.class);
private final FTPClient ftp; private final FTPClient ftp;
public FtpClientWrapper(final String server, final boolean secure) { public FtpStorage(final String server, final int port, final boolean secure) {
this.ftp = ftpConnect(server, secure); this.ftp = ftpConnect(server, port, secure);
} }
private FTPClient ftpConnect(final String server, final boolean secure) { private FTPClient ftpConnect(final String server, final int port, final boolean secure) {
try { try {
if (StringUtils.isBlank(server)) { if (secure) {
return new MockFtpClient();
} else if (secure) {
final FTPSClient ftp = new FTPSClient(); final FTPSClient ftp = new FTPSClient();
ftp.connect(server); ftp.connect(server, port > 0 ? port : FTPSClient.DEFAULT_FTPS_PORT);
// Set protection buffer size // Set protection buffer size
ftp.execPBSZ(0); ftp.execPBSZ(0);
// Set data channel protection to private // Set data channel protection to private
@ -34,7 +31,7 @@ public class FtpClientWrapper {
return ftp; return ftp;
} else { } else {
final FTPClient ftp = new FTPClient(); final FTPClient ftp = new FTPClient();
ftp.connect(server); ftp.connect(server, port > 0 ? port : FTPClient.DEFAULT_PORT);
return ftp; return ftp;
} }
} catch (final IOException e) { } catch (final IOException e) {
@ -43,6 +40,7 @@ public class FtpClientWrapper {
} }
} }
@Override
public void disconnect() { public void disconnect() {
if (ftp != null && ftp.isConnected()) { if (ftp != null && ftp.isConnected()) {
try { try {
@ -55,6 +53,7 @@ public class FtpClientWrapper {
} }
} }
@Override
public void login(final String user, final String password) { public void login(final String user, final String password) {
try { try {
if (!ftp.login(user, password)) { throw new RuntimeException("FTP login failed"); } if (!ftp.login(user, password)) { throw new RuntimeException("FTP login failed"); }
@ -69,6 +68,7 @@ public class FtpClientWrapper {
} }
} }
@Override
public boolean changeDir(final String dir) { public boolean changeDir(final String dir) {
try { try {
if (!ftp.changeWorkingDirectory(dir)) { if (!ftp.changeWorkingDirectory(dir)) {
@ -83,6 +83,7 @@ public class FtpClientWrapper {
} }
} }
@Override
public void saveFile(final String filename, final String content) { public void saveFile(final String filename, final String content) {
try (InputStream is = new ByteArrayInputStream(content.getBytes())) { try (InputStream is = new ByteArrayInputStream(content.getBytes())) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {

View File

@ -0,0 +1,46 @@
package eu.dnetlib.apps.oai2ftp.utils;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class LocalStorage implements StorageClient {
private static final Log log = LogFactory.getLog(LocalStorage.class);
@Override
public void login(final String user, final String password) {}
@Override
public void disconnect() {}
public String currDir = "/tmp";
@Override
public boolean changeDir(final String dir) {
try {
final File d = new File(dir.startsWith("/") ? dir : currDir + "/" + dir);
FileUtils.forceMkdir(d);
currDir = d.getAbsolutePath();
return true;
} catch (final IOException e) {
return false;
}
}
@Override
public void saveFile(final String filename, final String body) {
try {
IOUtils.write(body, new FileWriter(currDir + "/" + filename));
} catch (final IOException e) {
log.error("Error saving info file");
throw new RuntimeException("Error saving info file", e);
}
}
}

View File

@ -1,81 +0,0 @@
package eu.dnetlib.apps.oai2ftp.utils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
public class MockFtpClient extends FTPClient {
private static final Log log = LogFactory.getLog(MockFtpClient.class);
public MockFtpClient() {
log.debug("MOCK FTP CLIENT - Constructor");
}
@Override
public boolean login(final String username, final String password) throws IOException {
log.debug("MOCK FTP CLIENT - login: " + username + ", " + password);
return true;
}
@Override
public boolean isConnected() {
log.debug("MOCK FTP CLIENT - isConnected");
return true;
}
@Override
public void disconnect() throws IOException {
log.debug("MOCK FTP CLIENT - disconnect");
}
@Override
public boolean setFileType(final int fileType) throws IOException {
log.debug("MOCK FTP CLIENT - setFileType");
return true;
}
@Override
public void setBufferSize(final int bufSize) {
log.debug("MOCK FTP CLIENT - setBufferSize");
}
@Override
public void enterLocalPassiveMode() {
log.debug("MOCK FTP CLIENT - enterLocalPassiveMode");
}
@Override
public boolean changeWorkingDirectory(final String pathname) throws IOException {
log.debug("MOCK FTP CLIENT - changeWorkingDirectory: " + pathname);
return true;
}
@Override
public boolean makeDirectory(final String pathname) throws IOException {
log.debug("MOCK FTP CLIENT - makeDirectory: " + pathname);
return true;
}
@Override
public boolean storeFile(final String remote, final InputStream local) throws IOException {
log.debug("MOCK FTP CLIENT - storeFile: " + remote);
return true;
}
@Override
public int getReplyCode() {
log.debug("MOCK FTP CLIENT - getReplyCode");
return -1;
}
@Override
public String getReplyString() {
log.debug("MOCK FTP CLIENT - getReplyString");
return "MOCK";
}
}

View File

@ -0,0 +1,13 @@
package eu.dnetlib.apps.oai2ftp.utils;
public interface StorageClient {
void login(String user, String password);
void disconnect();
boolean changeDir(String dir);
void saveFile(String filename, String body);
}

View File

@ -0,0 +1,44 @@
package eu.dnetlib.apps.oai2ftp.utils;
import java.net.URL;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class StorageClientFactory {
@Value("${oai2ftp.conf.storage.url}")
private URL storageUrl;
@Value("${oai2ftp.conf.storage.user}")
private String storageUser;
@Value("${oai2ftp.conf.storage.password}")
private String storagePassword;
public StorageClient newClientForJob(final String jobId) {
final String protocol = storageUrl.getProtocol();
final String host = storageUrl.getHost();
final int port = storageUrl.getPort();
final String path = storageUrl.getPath();
StorageClient client;
if (protocol.equalsIgnoreCase("ftp")) {
client = new FtpStorage(host, port, false);
} else if (protocol.equalsIgnoreCase("ftps")) {
client = new FtpStorage(host, port, true);
} else if (protocol.equalsIgnoreCase("file")) {
client = new LocalStorage();
} else {
throw new RuntimeException("Invalid storage protocol: " + protocol);
}
client.login(storageUser, storagePassword);
client.changeDir(path);
client.changeDir(jobId);
return client;
}
}

View File

@ -12,10 +12,8 @@ spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
oai2ftp.conf.ftp.server = oai2ftp.conf.storage.url = file:///tmp/test_oai
oai2ftp.conf.ftp.user = test oai2ftp.conf.storage.user =
oai2ftp.conf.ftp.password = testPwd oai2ftp.conf.storage.password =
oai2ftp.conf.ftp.basedir = /oai
oai2ftp.conf.ftp.secure = true
oai2ftp.conf.execution.expirationTime = 12 oai2ftp.conf.execution.expirationTime = 12