Project

General

Profile

1
package eu.dnetlib.data.information.oai.publisher.core;
2

    
3
import java.util.Iterator;
4
import java.util.List;
5
import javax.annotation.Resource;
6

    
7
import com.google.common.collect.Lists;
8
import eu.dnetlib.data.information.oai.publisher.*;
9
import eu.dnetlib.data.information.oai.publisher.conf.OAIConfigurationReader;
10
import eu.dnetlib.data.information.oai.publisher.info.ListDocumentsInfo;
11
import eu.dnetlib.data.information.oai.publisher.info.MDFInfo;
12
import eu.dnetlib.data.information.oai.publisher.info.RecordInfo;
13
import eu.dnetlib.data.information.oai.publisher.info.ResumptionTokenImpl;
14
import eu.dnetlib.data.oai.store.Cursor;
15
import eu.dnetlib.data.oai.store.PublisherStore;
16
import eu.dnetlib.data.oai.store.PublisherStoreDAO;
17
import eu.dnetlib.miscutils.functional.UnaryFunction;
18
import org.apache.commons.lang3.StringUtils;
19
import org.apache.commons.logging.Log;
20
import org.apache.commons.logging.LogFactory;
21

    
22
public class DNetOAICore extends AbstractOAICore {
23

    
24
	private static final Log log = LogFactory.getLog(DNetOAICore.class); // NOPMD by marko on 11/24/08 5:02 PM
25

    
26
	@Resource(name = "mongodbPublisherStoreDao")
27
	private PublisherStoreDAO<PublisherStore<Cursor>, Cursor> publisherStoreDAO;
28

    
29
	private String defaultDate = "2008-01-01T12:00:00Z";
30

    
31
	@Override
32
	protected RecordInfo getRecordById(final MDFInfo mdf, final String id) throws OaiPublisherException {
33
		PublisherStore<Cursor> store = this.publisherStoreDAO.getStoreFor(mdf.getPrefix(), getCurrentDBName());
34
		if (store == null)
35
			throw new OaiPublisherRuntimeException("Missing store for metadata prefix " + mdf.getPrefix() + ". Please check OAI publisher configuration.");
36
		RecordInfo record = null;
37
		if (StringUtils.isBlank(mdf.getTransformationRuleID())) {
38
			record = store.getRecord(id);
39
		} else {
40
			UnaryFunction<String, String> function = getLookupClient().getUnaryFunctionFromTDSRule(mdf.getTransformationRuleID());
41
			record = store.getRecord(id, function);
42
		}
43
		if (record != null) {
44
			record.setPrefix(mdf.getPrefix());
45
		}
46
		return record;
47
	}
48

    
49
	/**
50
	 * 
51
	 * {@inheritDoc}
52
	 * 
53
	 * @see eu.dnetlib.data.information.oai.publisher.core.AbstractOAICore#getDocuments(boolean, java.lang.String, java.lang.String,
54
	 *      java.lang.String, java.lang.String)
55
	 */
56
	@Override
57
	protected ListDocumentsInfo getDocuments(final boolean onlyIdentifiers, final String set, final String metadataPrefix, final String from, final String until)
58
			throws OaiPublisherException {
59
		MDFInfo mdf = obtainMDFInfo(metadataPrefix);
60
		boolean hasDateRange = StringUtils.isNotBlank(from) || StringUtils.isNotBlank(until);
61
		String query = this.generateQuery(mdf, set, from, until, hasDateRange);
62
		int total = this.countTotal(hasDateRange, query, set, mdf);
63
		log.debug("Total number of records: " + total);
64
		Cursor results = this.getCursor(query, onlyIdentifiers, mdf);
65
		ListDocumentsInfo res = this.prepareListDocumentsInfo(results, mdf, query, set, 0, total, hasDateRange);
66
		log.debug("Delivering " + res.getDocs().size() + " in a page");
67
		return res;
68
	}
69

    
70
	@Override
71
	protected ListDocumentsInfo getDocuments(final boolean onlyIdentifiers, final String resumptionToken) throws OaiPublisherException {
72
		ResumptionTokenImpl resToken = new ResumptionTokenImpl();
73
		resToken.deserialize(resumptionToken);
74

    
75
		log.debug(resToken.toString());
76

    
77
		MDFInfo mdf = obtainMDFInfo(resToken.getMetadataPrefix());
78
		String lastID = resToken.getLastObjIdentifier();
79
		String query = resToken.getQuery();
80
		String newQuery = "";
81
		if (StringUtils.isNotBlank(query)) {
82
			newQuery = query + " AND ";
83
		}
84
		newQuery += " _id > \"" + lastID + "\"";
85
		log.debug("NEW QUERY BECAUSE of resumptionToken: " + newQuery);
86
		int total = this.countTotal(resToken.hasDateRange(), query, resToken.getRequestedSet(), mdf);
87
		Cursor results = this.getCursor(newQuery, onlyIdentifiers, mdf);
88
		int oldCount = resToken.getnMaxElements();
89
		// if the number of records changed, then for sure we can invalidate the resumption token, unless we have a new total of -1 (date
90
		// range queries can't be counted for performance reasons)
91
		if ((total != -1) && (oldCount != total)) throw new BadResumptionTokenException(resumptionToken);
92

    
93
		ListDocumentsInfo res = this.prepareListDocumentsInfo(results, mdf, query, resToken.getRequestedSet(), resToken.getnRead(), resToken.getnMaxElements(),
94
				resToken.hasDateRange());
95
		res.setCursor(resToken.getnRead());
96
		return res;
97
	}
98

    
99
	protected ListDocumentsInfo prepareListDocumentsInfo(final Cursor results,
100
			final MDFInfo mdf,
101
			final String query,
102
			final String requestedSet,
103
			final int read,
104
			final int totalNumber,
105
			final boolean hasDateRange) throws OaiPublisherException {
106
		ListDocumentsInfo documentList = new ListDocumentsInfo();
107
		documentList.setnMaxElements(totalNumber);
108
		documentList.setMetadataPrefix(mdf.getPrefix());
109
		documentList.setCursor(0);
110
		if (documentList.getnMaxElements() == 0) throw new NoRecordsMatchException(OAIError.noRecordsMatch.getMessage());
111

    
112
		List<RecordInfo> theRecords = this.generateOAIRecords(mdf, requestedSet, results);
113
		documentList.setDocs(theRecords);
114

    
115
		if ((theRecords == null) || theRecords.isEmpty()) throw new NoRecordsMatchException("noRecordsMatch: 'documents' is null or empty");
116

    
117
		if ((documentList.getnMaxElements() > (read + theRecords.size())) || (documentList.getnMaxElements() == -1)) {
118
			String lastID = theRecords.get(theRecords.size() - 1).getInternalId();
119
			ResumptionTokenImpl nextToken = new ResumptionTokenImpl();
120
			nextToken.setDateRange(hasDateRange);
121
			nextToken.setLastObjIdentifier(lastID);
122
			nextToken.setMetadataPrefix(mdf.getPrefix());
123
			nextToken.setnMaxElements(totalNumber);
124
			nextToken.setnRead(read + theRecords.size());
125
			nextToken.setQuery(query);
126
			nextToken.setRequestedSet(requestedSet);
127
			documentList.setResumptionToken(nextToken);
128
		}
129

    
130
		return documentList;
131
	}
132

    
133
	protected Cursor getCursor(final String query, final boolean onlyIdentifiers, final MDFInfo mdfInfo) {
134
		PublisherStore<Cursor> store = this.publisherStoreDAO.getStore(mdfInfo.getSourceFormatName(), mdfInfo.getSourceFormatInterpretation(),
135
				mdfInfo.getSourceFormatLayout(), getCurrentDBName());
136
		if (store == null)
137
			throw new OaiPublisherRuntimeException("Missing store for metadata prefix " + mdfInfo.getPrefix() + ". Please check OAI publisher configuration.");
138
		Cursor results = null;
139
		if (StringUtils.isBlank(mdfInfo.getTransformationRuleID())) {
140
			results = store.getRecords(query, !onlyIdentifiers, pageSize);
141
		} else {
142
			UnaryFunction<String, String> function = getLookupClient().getUnaryFunctionFromTDSRule(mdfInfo.getTransformationRuleID());
143
			results = store.getRecords(query, function, !onlyIdentifiers, pageSize);
144
		}
145
		return results;
146
	}
147

    
148
	/**
149
	 * Generates the List of RecordInfo to be delivered.
150
	 *
151
	 * @param mdf
152
	 *            MDFInfo, the requested metadata format information.
153
	 * @param requestedSet
154
	 *            set specified in the request. It is blank if no set was requested.
155
	 * @param cursor
156
	 *            Cursor instance to use to get the records.
157
	 * @return List of RecordInfo instances
158
	 */
159
	protected List<RecordInfo> generateOAIRecords(final MDFInfo mdf, final String requestedSet, final Cursor cursor) {
160
		final List<RecordInfo> documents = Lists.newArrayList();
161
		Iterator<RecordInfo> cursorIterator = cursor.iterator();
162
		while (cursorIterator.hasNext()) {
163
			RecordInfo current = cursorIterator.next();
164
			current.addSetspec(requestedSet);
165
			current.setPrefix(mdf.getPrefix());
166
			documents.add(current);
167
		}
168
		return documents;
169
	}
170

    
171
	protected String generateQuery(final MDFInfo mdf, final String set, final String from, final String until, final boolean hasDateRange) {
172
		String datestampIndexName = OAIConfigurationReader.DATESTAMP_FIELD;
173

    
174
		String query = mdf.getBaseQuery();
175
		if (!StringUtils.isBlank(set)) {
176
			if (!StringUtils.isBlank(query)) {
177
				query += " AND ";
178
			}
179
			query += getSetCollection().getSetQuery(set, getCurrentDBName());
180
		}
181
		if (hasDateRange) {
182
			if (!StringUtils.isBlank(query)) {
183
				query += " AND ";
184
			}
185
			if ((from != null) && (until != null)) {
186
				query += datestampIndexName + " >= " + from + " AND " + datestampIndexName + " <= " + until;
187
			} else if (from != null) {
188
				query += datestampIndexName + " >= " + from;
189
			} else if (until != null) {
190
				query += datestampIndexName + " <= " + until;
191
			}
192
		}
193

    
194
		log.info("QUERY GENERATED: \n" + query);
195
		return query;
196
	}
197

    
198
	private int countTotal(final boolean hasDateRange, final String query, final String set, final MDFInfo mdFormat) {
199
		int total = 0;
200
		if (hasDateRange) {
201
			// Counting in the store by date ranges is too expensive and delays to much the response
202
			total = -1;
203
		} else {
204
			String theSet = set;
205
			if (StringUtils.isBlank(set)) {
206
				theSet = "ALL";
207
			}
208
			log.debug("SET::: " + theSet);
209
			total = getSetCollection().count(theSet, mdFormat.getPrefix(), getCurrentDBName());
210
		}
211
		return total;
212
	}
213

    
214
	public String getDefaultDate() {
215
		return defaultDate;
216
	}
217

    
218
	public void setDefaultDate(final String defaultDate) {
219
		this.defaultDate = defaultDate;
220
	}
221

    
222
	public PublisherStoreDAO<PublisherStore<Cursor>, Cursor> getPublisherStoreDAO() {
223
		return publisherStoreDAO;
224
	}
225

    
226
	public void setPublisherStoreDAO(final PublisherStoreDAO<PublisherStore<Cursor>, Cursor> publisherStoreDAO) {
227
		this.publisherStoreDAO = publisherStoreDAO;
228
	}
229

    
230
	public int getPageSize() {
231
		return pageSize;
232
	}
233

    
234
	public void setPageSize(final int pageSize) {
235
		this.pageSize = pageSize;
236
	}
237

    
238
}
(2-2/2)