Project

General

Profile

1
package eu.dnetlib.data.mdstore.plugins;
2

    
3
import java.io.ByteArrayInputStream;
4
import java.io.IOException;
5
import java.io.InputStream;
6
import java.util.Arrays;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.Set;
10
import java.util.stream.Collectors;
11

    
12
import org.apache.commons.lang3.StringUtils;
13
import org.apache.commons.logging.Log;
14
import org.apache.commons.logging.LogFactory;
15
import org.apache.commons.net.ftp.FTPClient;
16
import org.apache.commons.net.ftp.FTPFile;
17
import org.apache.commons.net.ftp.FTPSClient;
18

    
19
import com.google.common.net.UrlEscapers;
20

    
21
import eu.dnetlib.data.mdstore.plugins.objects.MdRecord;
22
import eu.dnetlib.data.mdstore.plugins.objects.MyURL;
23

    
24
public class EnrichLocalLinksPlugin extends MdRecordPlugin {
25

    
26
	private static final String DEFAULT_RIGHTS = "Open Access";
27

    
28
	private static final String INFO_FILENAME = "info.txt";
29

    
30
	private static final Log log = LogFactory.getLog(EnrichLocalLinksPlugin.class);
31

    
32
	private FTPClient ftpClient;
33

    
34
	private String hostedBy;
35
	private String baseUrl;
36

    
37
	private String ftpServer;
38
	private String ftpUser;
39
	private String ftpPassword;
40
	private String ftpBaseDir;
41
	private boolean ftpSecure = false;
42

    
43
	@Override
44
	protected void reconfigure(final Map<String, String> params) {
45
		setHostedBy(params.get("hostedBy"));
46
		setBaseUrl(params.get("baseUrl"));
47
		setFtpServer(params.get("ftpServer"));
48
		setFtpUser(params.get("ftpUser"));
49
		setFtpPassword(params.get("ftpPassword"));
50
		setFtpBaseDir(params.get("ftpBaseDir"));
51
		setFtpSecure(params.containsKey("ftpSecure") && params.get("ftpSecure").equalsIgnoreCase("true"));
52

    
53
		if (!getFtpBaseDir().startsWith("/")) {
54
			setFtpBaseDir("/" + getFtpBaseDir());
55
		}
56

    
57
		try {
58
			if (isFtpSecure()) {
59
				ftpClient = new FTPSClient();
60
				ftpClient.connect(getFtpServer());
61
				// Set protection buffer size
62
				((FTPSClient) ftpClient).execPBSZ(0);
63
				// Set data channel protection to private
64
				((FTPSClient) ftpClient).execPROT("P");
65
			} else {
66
				ftpClient = new FTPClient();
67
				ftpClient.connect(getFtpServer());
68
			}
69

    
70
			if (!ftpClient.login(getFtpUser(), getFtpPassword())) { throw new RuntimeException("FTP login failed"); }
71

    
72
			ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
73
			ftpClient.enterLocalPassiveMode();
74
			ftpClient.setBufferSize(1024);
75

    
76
			log.info("Connected to " + ftpServer);
77
		} catch (final IOException e) {
78
			log.error("Connection Failed");
79
			throw new RuntimeException(e);
80
		}
81
	}
82

    
83
	@Override
84
	protected void resetConfiguration() {
85
		if (ftpClient.isConnected()) {
86
			try {
87
				ftpClient.disconnect();
88
				log.info("Disconnected from " + ftpServer);
89
			} catch (final IOException e) {
90
				log.error("Disconnection Failed");
91
				throw new RuntimeException(e);
92
			}
93
		}
94
		setHostedBy(null);
95
		setBaseUrl(null);
96
		setFtpServer(null);
97
		setFtpUser(null);
98
		setFtpPassword(null);
99
		setFtpBaseDir(null);
100
		setFtpClient(null);
101
		setFtpSecure(false);
102
	}
103

    
104
	@Override
105
	protected boolean updateRecord(final String recordId, final MdRecord doc) {
106

    
107
		final int year = doc.getDate();
108
		final String code = StringUtils.substringAfterLast(doc.getId(), ":");
109

    
110
		log.info(String.format("Processing record: %s (%s/%s)", doc.getId(), year, code));
111

    
112
		final List<String> files = touchAndListDir(doc.getTitle(), doc.getCreators(), doc.getType(), year, code);
113

    
114
		if (files.isEmpty()) {
115
			return false;
116
		} else {
117
			log.info("  - adding new urls: " + files.size());
118
			doc.setBestRights(DEFAULT_RIGHTS);
119
			for (final String f : files) {
120
				doc.getUrls().add(new MyURL(calculateUrl(recordId, code, year, f), getHostedBy(), DEFAULT_RIGHTS));
121
			}
122
		}
123
		return true;
124
	}
125

    
126
	private List<String> touchAndListDir(final String title, final Set<String> authors, final String type, final int year, final String code) {
127
		final String content = String.format(
128
				"TITLE     : %s\nAUTHOR(S) : %s\nTYPE      : %s\nYEAR      : %s\nCODE      : %s\n\n*** DO NOT EDIT THIS FILE ***\n\n",
129
				title,
130
				StringUtils.join(authors, ", "),
131
				type,
132
				year,
133
				code);
134

    
135
		if (ftpChangeDir(getFtpBaseDir()) && ftpChangeDir(Integer.toString(year)) && ftpChangeDir(code)) {
136

    
137
			try (InputStream is = new ByteArrayInputStream(content.getBytes())) {
138
				if (log.isDebugEnabled()) {
139
					log.debug(String.format(" - Saving file %s/%s/%s/%s", getFtpBaseDir(), year, code, INFO_FILENAME));
140
					log.debug(content);
141
				}
142
				if (!ftpClient.storeFile(INFO_FILENAME, is)) {
143
					log.error("Error saving file: " + ftpClient.getReplyCode() + " - " + ftpClient.getReplyString());
144
					throw new RuntimeException("Error saving file: " + ftpClient.getReplyString());
145
				}
146
			} catch (final IOException e) {
147
				log.error("Error saving info file");
148
				throw new RuntimeException("Error saving info file", e);
149
			}
150

    
151
			try {
152
				return Arrays.stream(ftpClient.listFiles())
153
						.map(FTPFile::getName)
154
						.filter(s -> s.toLowerCase().endsWith(".pdf"))
155
						.sorted()
156
						.collect(Collectors.toList());
157
			} catch (final IOException e) {
158
				log.error("Error listing files");
159
				throw new RuntimeException("Error listing files", e);
160
			}
161
		} else {
162
			log.error(String.format("Directory not found: %s/%s/%s", getFtpBaseDir(), year, code));
163
			throw new RuntimeException(String.format("Directory not found: %s/%s/%s", getFtpBaseDir(), year, code));
164
		}
165

    
166
	}
167

    
168
	private boolean ftpChangeDir(final String dir) {
169
		try {
170
			if (!ftpClient.changeWorkingDirectory(dir)) {
171
				ftpClient.makeDirectory(dir);
172
				return ftpClient.changeWorkingDirectory(dir);
173
			}
174
			return true;
175
		} catch (final IOException e) {
176
			log.error("Error changing or create dir: " + dir);
177
			throw new RuntimeException("Error changing or create dir: " + dir, e);
178
		}
179
	}
180

    
181
	private String calculateUrl(final String id, final String code, final int year, final String f) {
182
		// the parameter ID is necessary for a better integration with OpenAIRE
183
		return String.format("%s/%s/%s/%s?id=%s", getBaseUrl(), year, code, UrlEscapers.urlPathSegmentEscaper().escape(f),
184
				UrlEscapers.urlFormParameterEscaper().escape(id));
185
	}
186

    
187
	public String getHostedBy() {
188
		return hostedBy;
189
	}
190

    
191
	public void setHostedBy(final String hostedBy) {
192
		this.hostedBy = hostedBy;
193
	}
194

    
195
	public String getBaseUrl() {
196
		return baseUrl;
197
	}
198

    
199
	public void setBaseUrl(final String baseUrl) {
200
		this.baseUrl = baseUrl;
201
	}
202

    
203
	public String getFtpBaseDir() {
204
		return ftpBaseDir;
205
	}
206

    
207
	public void setFtpBaseDir(final String ftpBaseDir) {
208
		this.ftpBaseDir = ftpBaseDir;
209
	}
210

    
211
	public FTPClient getFtpClient() {
212
		return ftpClient;
213
	}
214

    
215
	public void setFtpClient(final FTPClient ftpClient) {
216
		this.ftpClient = ftpClient;
217
	}
218

    
219
	public String getFtpServer() {
220
		return ftpServer;
221
	}
222

    
223
	public void setFtpServer(final String ftpServer) {
224
		this.ftpServer = ftpServer;
225
	}
226

    
227
	public String getFtpUser() {
228
		return ftpUser;
229
	}
230

    
231
	public void setFtpUser(final String ftpUser) {
232
		this.ftpUser = ftpUser;
233
	}
234

    
235
	public String getFtpPassword() {
236
		return ftpPassword;
237
	}
238

    
239
	public void setFtpPassword(final String ftpPassword) {
240
		this.ftpPassword = ftpPassword;
241
	}
242

    
243
	public boolean isFtpSecure() {
244
		return ftpSecure;
245
	}
246

    
247
	public void setFtpSecure(final boolean ftpSecure) {
248
		this.ftpSecure = ftpSecure;
249
	}
250

    
251
}
(6-6/12)